mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
612 lines
15 KiB
612 lines
15 KiB
#include "precomp.h"
|
|
#include "devenum.h"
|
|
|
|
#define NUMDRIVELETTERS 26
|
|
|
|
// drvletter struct.
|
|
typedef struct _DRIVELETTERS {
|
|
|
|
BOOL ExistsOnSystem[NUMDRIVELETTERS];
|
|
DWORD Type[NUMDRIVELETTERS]; // Returned from GetDriveType
|
|
TCHAR IdentifierString[NUMDRIVELETTERS][MAX_PATH]; // Varies by Drive type.
|
|
|
|
} DRIVELETTERS, *PDRIVELETTERS;
|
|
|
|
DRIVELETTERS g_DriveLetters;
|
|
|
|
PCTSTR DriveTypeAsString(
|
|
IN UINT Type
|
|
)
|
|
{
|
|
static PCTSTR driveTypeStrings[] = {
|
|
TEXT("DRIVE_UNKNOWN"), //The drive type cannot be determined.
|
|
TEXT("DRIVE_NO_ROOT_DIR"), //The root directory does not exist.
|
|
TEXT("DRIVE_REMOVABLE"), //The disk can be removed from the drive.
|
|
TEXT("DRIVE_FIXED"), //The disk cannot be removed from the drive.
|
|
TEXT("DRIVE_REMOTE"), //The drive is a remote (network) drive.
|
|
TEXT("DRIVE_CDROM"), //The drive is a CD-ROM drive.
|
|
TEXT("DRIVE_RAMDISK"), //The drive is a RAM disk.
|
|
};
|
|
|
|
return driveTypeStrings[Type];
|
|
}
|
|
|
|
BOOL
|
|
InitializeDriveLetterStructure (
|
|
VOID
|
|
)
|
|
{
|
|
DWORD DriveLettersOnSystem = GetLogicalDrives();
|
|
BYTE bitPosition;
|
|
DWORD maxBitPosition = NUMDRIVELETTERS;
|
|
TCHAR rootPath[4];
|
|
BOOL driveExists;
|
|
UINT type;
|
|
BOOL rf = TRUE;
|
|
|
|
|
|
//
|
|
//rootPath[0] will be set to the drive letter of interest.
|
|
//
|
|
rootPath[1] = TEXT(':');
|
|
rootPath[2] = TEXT('\\');
|
|
rootPath[3] = TEXT('\0');
|
|
|
|
//
|
|
// GetLogicalDrives returns a bitmask of all of the drive letters
|
|
// in use on the system. (i.e. bit position 0 is turned on if there is
|
|
// an 'A' drive, 1 is turned on if there is a 'B' drive, etc.
|
|
// This loop will use this bitmask to fill in the global drive
|
|
// letters structure with information about what drive letters
|
|
// are available and what there drive types are.
|
|
//
|
|
|
|
for (bitPosition = 0; bitPosition < maxBitPosition; bitPosition++) {
|
|
|
|
//
|
|
// Initialize the entry to safe values.
|
|
//
|
|
g_DriveLetters.Type[bitPosition] = 0;
|
|
g_DriveLetters.ExistsOnSystem[bitPosition] = FALSE;
|
|
*g_DriveLetters.IdentifierString[bitPosition] = 0;
|
|
|
|
//
|
|
// Now, determine if there is a drive in this spot.
|
|
//
|
|
driveExists = DriveLettersOnSystem & (1 << bitPosition);
|
|
|
|
if (driveExists) {
|
|
|
|
//
|
|
// There is. Now, see if it is one that we care about.
|
|
//
|
|
*rootPath = bitPosition + TEXT('A');
|
|
type = GetDriveType(rootPath);
|
|
|
|
if (type == DRIVE_FIXED ||
|
|
type == DRIVE_REMOVABLE ||
|
|
type == DRIVE_CDROM) {
|
|
|
|
//
|
|
// This is a drive that we are interested in.
|
|
//
|
|
g_DriveLetters.ExistsOnSystem[bitPosition] = driveExists;
|
|
g_DriveLetters.Type[bitPosition] = type;
|
|
|
|
//
|
|
// Identifier String is not filled in this function.
|
|
//
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return rf;
|
|
}
|
|
|
|
VOID
|
|
CleanUpHardDriveTags (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// User cancelled. We need to clean up the tag files
|
|
// that were created for drive migration.
|
|
//
|
|
UINT i;
|
|
TCHAR path[MAX_PATH];
|
|
|
|
lstrcpy(path,TEXT("*:\\"));
|
|
lstrcat(path,TEXT(WINNT_WIN95UPG_DRVLTR_A));
|
|
|
|
|
|
for (i = 0; i < NUMDRIVELETTERS; i++) {
|
|
|
|
if (g_DriveLetters.ExistsOnSystem[i] &&
|
|
g_DriveLetters.Type[i] == DRIVE_FIXED) {
|
|
|
|
*path = (TCHAR) i + TEXT('A');
|
|
DeleteFile (path);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
GatherHardDriveInformation (
|
|
VOID
|
|
)
|
|
{
|
|
BOOL rf = TRUE;
|
|
DWORD index;
|
|
HANDLE signatureFile;
|
|
TCHAR signatureFilePath[sizeof (WINNT_WIN95UPG_DRVLTR_A) + 3];
|
|
DWORD signatureFilePathLength;
|
|
DWORD bytesWritten;
|
|
|
|
//
|
|
// Hard drive information is actually written to a special signature file
|
|
// on the root directory of each fixed hard drive. The information is nothing special --
|
|
// just the drive number (0 = A, etc.)
|
|
//
|
|
|
|
lstrcpy(signatureFilePath,TEXT("*:\\"));
|
|
lstrcat(signatureFilePath,TEXT(WINNT_WIN95UPG_DRVLTR_A));
|
|
signatureFilePathLength = lstrlen(signatureFilePath);
|
|
|
|
|
|
|
|
for (index = 0; index < NUMDRIVELETTERS; index++) {
|
|
|
|
if (g_DriveLetters.ExistsOnSystem[index] &&
|
|
g_DriveLetters.Type[index] == DRIVE_FIXED) {
|
|
|
|
*signatureFilePath = (TCHAR) index + TEXT('A');
|
|
|
|
signatureFile = CreateFile(
|
|
signatureFilePath,
|
|
GENERIC_WRITE | GENERIC_READ,
|
|
0,
|
|
NULL,
|
|
CREATE_ALWAYS,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL
|
|
);
|
|
|
|
if (signatureFile != INVALID_HANDLE_VALUE) {
|
|
|
|
WriteFile (signatureFile, &index, sizeof(DWORD), &bytesWritten, NULL);
|
|
|
|
|
|
|
|
CloseHandle (signatureFile);
|
|
SetFileAttributes (signatureFilePath, FILE_ATTRIBUTE_HIDDEN);
|
|
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return rf;
|
|
}
|
|
|
|
/*BOOL
|
|
GatherCdRomDriveInformation (
|
|
VOID
|
|
)
|
|
|
|
{
|
|
BOOL rf = TRUE;
|
|
HKEY scsiKey = NULL;
|
|
HKEY deviceKey = NULL;
|
|
|
|
TCHAR classData[25];
|
|
DWORD classDataSize = 25;
|
|
|
|
TCHAR targetData[5];
|
|
DWORD targetDataSize = 5;
|
|
|
|
TCHAR lunData[5];
|
|
DWORD lunDataSize = 5;
|
|
|
|
TCHAR driveLetterData[5];
|
|
DWORD driveLetterSize = 5;
|
|
|
|
TCHAR buffer [4096];
|
|
DWORD subKeyLength;
|
|
DWORD tempLength;
|
|
|
|
HKEY locationKey = NULL;
|
|
PTSTR locationName;
|
|
|
|
DWORD outerIndex;
|
|
DWORD enumReturn;
|
|
|
|
DWORD port;
|
|
DWORD unusedType;
|
|
DWORD error;
|
|
|
|
|
|
//
|
|
// Walk the SCSI tree looking for CD rom devices.
|
|
//
|
|
error = RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT("ENUM\\SCSI"), 0, KEY_READ, &scsiKey);
|
|
|
|
if (error) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Gather information about the key in preparation for enumerating
|
|
// it.
|
|
//
|
|
error = RegQueryInfoKey (
|
|
scsiKey,
|
|
NULL, // Don't care about the class.
|
|
NULL, // class size.
|
|
NULL, // reserved.
|
|
NULL, // Don't care about the number of subkeys.
|
|
&subKeyLength,
|
|
NULL, // Don't care about subclasses.
|
|
NULL, // Don't care about values.
|
|
NULL, // Don't care about max value name length.
|
|
NULL, // Don't care about max component.
|
|
NULL, // Don't care about the security descriptor.
|
|
NULL // Don't care about the last write time.
|
|
);
|
|
|
|
if (error) {
|
|
//
|
|
// This should really not happen.
|
|
//
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Succssesfully opened a key to HKLM\Enum\SCSI. Enumerate it.
|
|
//
|
|
outerIndex = 0;
|
|
do {
|
|
|
|
if (locationKey) {
|
|
|
|
RegCloseKey (locationKey);
|
|
locationKey = NULL;
|
|
}
|
|
if (deviceKey) {
|
|
|
|
RegCloseKey (deviceKey);
|
|
deviceKey = NULL;
|
|
}
|
|
|
|
|
|
tempLength = sizeof(buffer) / sizeof(TCHAR);
|
|
|
|
enumReturn = RegEnumKeyEx (
|
|
scsiKey,
|
|
outerIndex,
|
|
buffer,
|
|
&tempLength,
|
|
0, // Reserved
|
|
NULL, // Class name - not necessary.
|
|
NULL, // size of class name buffer.
|
|
NULL
|
|
);
|
|
|
|
outerIndex++;
|
|
|
|
//
|
|
// For each returned key, look up the "Class" value.
|
|
//
|
|
error = RegOpenKeyEx (scsiKey,buffer,0,KEY_READ,&deviceKey);
|
|
if (error) {
|
|
|
|
//
|
|
// Something is hosed. Give up on collecting SCSI data.
|
|
//
|
|
rf = FALSE;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// The port has to be decoded from the key one level
|
|
// below.
|
|
//
|
|
tempLength = sizeof (buffer) / sizeof(TCHAR);
|
|
|
|
error = RegEnumKeyEx (
|
|
deviceKey,
|
|
0,
|
|
buffer,
|
|
&tempLength,
|
|
0, // Reserved
|
|
NULL, // Class name - not necessary.
|
|
NULL, // size of class name buffer.
|
|
NULL
|
|
);
|
|
|
|
error = RegOpenKeyEx (deviceKey, buffer, 0, KEY_READ, &locationKey);
|
|
|
|
if (error) {
|
|
|
|
//
|
|
// This should really never happen. However, guard against it.
|
|
// Its not serious enough to abort the search. Just skip this
|
|
// particular key and continue.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
|
|
|
|
tempLength = classDataSize;
|
|
error = RegQueryValueEx(
|
|
locationKey,
|
|
TEXT("CLASS"),
|
|
0,
|
|
&unusedType,
|
|
(PBYTE) classData,
|
|
&tempLength
|
|
);
|
|
|
|
if (error) {
|
|
|
|
//
|
|
// This isn't a serious enough error to bring down the whole
|
|
// enumeration. Just note it in the logs and continue to the
|
|
// next key.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (!lstrcmpi(classData, TEXT("CDROM"))) {
|
|
|
|
|
|
lstrcpy (targetData, TEXT("-1"));
|
|
lstrcpy (lunData, TEXT("-1"));
|
|
lstrcpy (driveLetterData, TEXT("%"));
|
|
|
|
//
|
|
// Found a CdRom. Get the information that will be used in
|
|
// textmode setup to identify the drive.
|
|
//
|
|
tempLength = targetDataSize;
|
|
RegQueryValueEx(
|
|
locationKey,
|
|
TEXT("ScsiTargetId"),
|
|
0,
|
|
&unusedType,
|
|
(PBYTE) targetData,
|
|
&tempLength
|
|
);
|
|
|
|
tempLength = lunDataSize;
|
|
RegQueryValueEx(
|
|
locationKey,
|
|
TEXT("ScsiLun"),
|
|
0,
|
|
&unusedType,
|
|
(PBYTE) lunData,
|
|
&tempLength
|
|
);
|
|
|
|
tempLength = driveLetterSize;
|
|
RegQueryValueEx(
|
|
locationKey,
|
|
TEXT("CurrentDriveLetterAssignment"),
|
|
0,
|
|
&unusedType,
|
|
(PBYTE) driveLetterData,
|
|
&tempLength
|
|
);
|
|
|
|
|
|
|
|
|
|
if (*driveLetterData != TEXT('%')) {
|
|
|
|
//
|
|
// At this point, we have all of the information
|
|
// necessary to write a SCSI CdRom identifier
|
|
// string.
|
|
//
|
|
|
|
wsprintf(g_DriveLetters.IdentifierString[*driveLetterData - TEXT('A')], TEXT("%u^%s^%s"), 1, targetData, lunData);
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (locationKey) {
|
|
|
|
RegCloseKey (locationKey);
|
|
locationKey = NULL;
|
|
}
|
|
if (deviceKey) {
|
|
|
|
RegCloseKey (deviceKey);
|
|
deviceKey = NULL;
|
|
}
|
|
|
|
|
|
|
|
} while (rf && enumReturn == ERROR_SUCCESS);
|
|
|
|
if (locationKey) {
|
|
RegCloseKey(locationKey);
|
|
locationKey = NULL;
|
|
}
|
|
if (deviceKey) {
|
|
RegCloseKey(deviceKey);
|
|
deviceKey = NULL;
|
|
}
|
|
if (scsiKey) {
|
|
RegCloseKey(scsiKey);
|
|
scsiKey = NULL;
|
|
}
|
|
|
|
|
|
|
|
return rf;
|
|
}*/
|
|
|
|
BOOL pCDROMDeviceEnumCallback(
|
|
IN HKEY hDevice,
|
|
IN PCONTROLLERS_COLLECTION ControllersCollection,
|
|
IN UINT ControllerIndex,
|
|
IN PVOID CallbackData
|
|
)
|
|
{
|
|
DRIVE_SCSI_ADDRESS scsiAddress;
|
|
BOOL bResult;
|
|
|
|
MYASSERT(hDevice && ControllersCollection);
|
|
|
|
bResult = GetSCSIAddressFromPnPId(ControllersCollection,
|
|
hDevice,
|
|
ControllersCollection->ControllersInfo[ControllerIndex].PNPID,
|
|
&scsiAddress);
|
|
|
|
MYASSERT(bResult);
|
|
|
|
if(bResult &&
|
|
((UCHAR)INVALID_SCSI_PORT) != scsiAddress.PortNumber &&
|
|
DRIVE_CDROM == scsiAddress.DriveType){
|
|
wsprintf(g_DriveLetters.IdentifierString[scsiAddress.DriveLetter - TEXT('A')],
|
|
TEXT("%u^%u^%u"),
|
|
(UINT)scsiAddress.PortNumber,
|
|
(UINT)scsiAddress.TargetId,
|
|
(UINT)scsiAddress.Lun);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GatherCdRomDriveInformation (
|
|
VOID
|
|
)
|
|
{
|
|
PCONTROLLERS_COLLECTION ControllersCollection;
|
|
UINT i;
|
|
BOOL bResult;
|
|
BOOL bDetectedExtraIDEController = FALSE;
|
|
UINT numberOfSCSIController = 0;
|
|
|
|
//
|
|
// Collect all active IDE and SCSI controllers
|
|
//
|
|
bResult = GatherControllersInfo(&ControllersCollection);
|
|
if(!bResult){
|
|
MYASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
MYASSERT(ControllersCollection->ControllersInfo);
|
|
for(i = 0; i < ControllersCollection->NumberOfControllers; i++){
|
|
switch(ControllersCollection->ControllersInfo[i].ControllerType){
|
|
case CONTROLLER_EXTRA_IDE:
|
|
bDetectedExtraIDEController = TRUE;
|
|
break;
|
|
case CONTROLLER_SCSI:
|
|
numberOfSCSIController++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(bDetectedExtraIDEController){
|
|
DebugLog(Winnt32LogWarning, TEXT("Setup has detected that machine have extra IDE controller(s). Setup may not preserve drive letters."), 0);
|
|
}
|
|
|
|
if(numberOfSCSIController > 1){
|
|
DebugLog(Winnt32LogWarning, TEXT("Setup has detected that machine have more than one SCSI controllers. Setup may not preserve drive letters only for SCSI devices."), 0);
|
|
}
|
|
|
|
//
|
|
// If we found extra IDE controller(s) we can't ensure rigth device detection in this case.
|
|
// If we found more than one SCSI controllers without extra IDE controller(s),
|
|
// at least we can guarantee correct IDE devices detection.
|
|
//
|
|
bResult = DeviceEnum(ControllersCollection,
|
|
TEXT("SCSI"),
|
|
(PDEVICE_ENUM_CALLBACK_FUNCTION)pCDROMDeviceEnumCallback,
|
|
NULL);
|
|
MYASSERT(bResult);
|
|
|
|
ReleaseControllersInfo(ControllersCollection);
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
WriteInfoToSifFile (
|
|
IN PCTSTR FileName
|
|
)
|
|
{
|
|
BOOL rSuccess = TRUE;
|
|
DWORD index;
|
|
TCHAR dataString[MAX_PATH * 2]; // Well over the size needed.
|
|
TCHAR driveString[20]; // Well over the size needed.
|
|
PCTSTR sectionString = WINNT_D_WIN9XDRIVES;
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < NUMDRIVELETTERS; index++) {
|
|
|
|
if (g_DriveLetters.ExistsOnSystem[index]) {
|
|
|
|
wsprintf(
|
|
driveString,
|
|
TEXT("%u"),
|
|
index
|
|
);
|
|
|
|
wsprintf(
|
|
dataString,
|
|
TEXT("%u,%s"),
|
|
g_DriveLetters.Type[index],
|
|
g_DriveLetters.IdentifierString[index]
|
|
);
|
|
|
|
//
|
|
// Ending string looks like <drive num>,<drive type>,<identifier string>
|
|
//
|
|
|
|
WritePrivateProfileString (sectionString, driveString, dataString, FileName);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
return rSuccess;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
SaveDriveLetterInformation (
|
|
IN PCTSTR FileName
|
|
)
|
|
{
|
|
BOOL rf = TRUE;
|
|
|
|
if (InitializeDriveLetterStructure ()) {
|
|
|
|
GatherHardDriveInformation ();
|
|
GatherCdRomDriveInformation ();
|
|
WriteInfoToSifFile (FileName);
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|