Source code of Windows XP (NT5)
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

#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;
}