#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 ,, // WritePrivateProfileString (sectionString, driveString, dataString, FileName); } } return rSuccess; } DWORD SaveDriveLetterInformation ( IN PCTSTR FileName ) { BOOL rf = TRUE; if (InitializeDriveLetterStructure ()) { GatherHardDriveInformation (); GatherCdRomDriveInformation (); WriteInfoToSifFile (FileName); } return ERROR_SUCCESS; }