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

  1. #include "precomp.h"
  2. #include "devenum.h"
  3. #define NUMDRIVELETTERS 26
  4. // drvletter struct.
  5. typedef struct _DRIVELETTERS {
  6. BOOL ExistsOnSystem[NUMDRIVELETTERS];
  7. DWORD Type[NUMDRIVELETTERS]; // Returned from GetDriveType
  8. TCHAR IdentifierString[NUMDRIVELETTERS][MAX_PATH]; // Varies by Drive type.
  9. } DRIVELETTERS, *PDRIVELETTERS;
  10. DRIVELETTERS g_DriveLetters;
  11. PCTSTR DriveTypeAsString(
  12. IN UINT Type
  13. )
  14. {
  15. static PCTSTR driveTypeStrings[] = {
  16. TEXT("DRIVE_UNKNOWN"), //The drive type cannot be determined.
  17. TEXT("DRIVE_NO_ROOT_DIR"), //The root directory does not exist.
  18. TEXT("DRIVE_REMOVABLE"), //The disk can be removed from the drive.
  19. TEXT("DRIVE_FIXED"), //The disk cannot be removed from the drive.
  20. TEXT("DRIVE_REMOTE"), //The drive is a remote (network) drive.
  21. TEXT("DRIVE_CDROM"), //The drive is a CD-ROM drive.
  22. TEXT("DRIVE_RAMDISK"), //The drive is a RAM disk.
  23. };
  24. return driveTypeStrings[Type];
  25. }
  26. BOOL
  27. InitializeDriveLetterStructure (
  28. VOID
  29. )
  30. {
  31. DWORD DriveLettersOnSystem = GetLogicalDrives();
  32. BYTE bitPosition;
  33. DWORD maxBitPosition = NUMDRIVELETTERS;
  34. TCHAR rootPath[4];
  35. BOOL driveExists;
  36. UINT type;
  37. BOOL rf = TRUE;
  38. //
  39. //rootPath[0] will be set to the drive letter of interest.
  40. //
  41. rootPath[1] = TEXT(':');
  42. rootPath[2] = TEXT('\\');
  43. rootPath[3] = TEXT('\0');
  44. //
  45. // GetLogicalDrives returns a bitmask of all of the drive letters
  46. // in use on the system. (i.e. bit position 0 is turned on if there is
  47. // an 'A' drive, 1 is turned on if there is a 'B' drive, etc.
  48. // This loop will use this bitmask to fill in the global drive
  49. // letters structure with information about what drive letters
  50. // are available and what there drive types are.
  51. //
  52. for (bitPosition = 0; bitPosition < maxBitPosition; bitPosition++) {
  53. //
  54. // Initialize the entry to safe values.
  55. //
  56. g_DriveLetters.Type[bitPosition] = 0;
  57. g_DriveLetters.ExistsOnSystem[bitPosition] = FALSE;
  58. *g_DriveLetters.IdentifierString[bitPosition] = 0;
  59. //
  60. // Now, determine if there is a drive in this spot.
  61. //
  62. driveExists = DriveLettersOnSystem & (1 << bitPosition);
  63. if (driveExists) {
  64. //
  65. // There is. Now, see if it is one that we care about.
  66. //
  67. *rootPath = bitPosition + TEXT('A');
  68. type = GetDriveType(rootPath);
  69. if (type == DRIVE_FIXED ||
  70. type == DRIVE_REMOVABLE ||
  71. type == DRIVE_CDROM) {
  72. //
  73. // This is a drive that we are interested in.
  74. //
  75. g_DriveLetters.ExistsOnSystem[bitPosition] = driveExists;
  76. g_DriveLetters.Type[bitPosition] = type;
  77. //
  78. // Identifier String is not filled in this function.
  79. //
  80. }
  81. }
  82. }
  83. return rf;
  84. }
  85. VOID
  86. CleanUpHardDriveTags (
  87. VOID
  88. )
  89. {
  90. //
  91. // User cancelled. We need to clean up the tag files
  92. // that were created for drive migration.
  93. //
  94. UINT i;
  95. TCHAR path[MAX_PATH];
  96. lstrcpy(path,TEXT("*:\\"));
  97. lstrcat(path,TEXT(WINNT_WIN95UPG_DRVLTR_A));
  98. for (i = 0; i < NUMDRIVELETTERS; i++) {
  99. if (g_DriveLetters.ExistsOnSystem[i] &&
  100. g_DriveLetters.Type[i] == DRIVE_FIXED) {
  101. *path = (TCHAR) i + TEXT('A');
  102. DeleteFile (path);
  103. }
  104. }
  105. }
  106. BOOL
  107. GatherHardDriveInformation (
  108. VOID
  109. )
  110. {
  111. BOOL rf = TRUE;
  112. DWORD index;
  113. HANDLE signatureFile;
  114. TCHAR signatureFilePath[sizeof (WINNT_WIN95UPG_DRVLTR_A) + 3];
  115. DWORD signatureFilePathLength;
  116. DWORD bytesWritten;
  117. //
  118. // Hard drive information is actually written to a special signature file
  119. // on the root directory of each fixed hard drive. The information is nothing special --
  120. // just the drive number (0 = A, etc.)
  121. //
  122. lstrcpy(signatureFilePath,TEXT("*:\\"));
  123. lstrcat(signatureFilePath,TEXT(WINNT_WIN95UPG_DRVLTR_A));
  124. signatureFilePathLength = lstrlen(signatureFilePath);
  125. for (index = 0; index < NUMDRIVELETTERS; index++) {
  126. if (g_DriveLetters.ExistsOnSystem[index] &&
  127. g_DriveLetters.Type[index] == DRIVE_FIXED) {
  128. *signatureFilePath = (TCHAR) index + TEXT('A');
  129. signatureFile = CreateFile(
  130. signatureFilePath,
  131. GENERIC_WRITE | GENERIC_READ,
  132. 0,
  133. NULL,
  134. CREATE_ALWAYS,
  135. FILE_ATTRIBUTE_NORMAL,
  136. NULL
  137. );
  138. if (signatureFile != INVALID_HANDLE_VALUE) {
  139. WriteFile (signatureFile, &index, sizeof(DWORD), &bytesWritten, NULL);
  140. CloseHandle (signatureFile);
  141. SetFileAttributes (signatureFilePath, FILE_ATTRIBUTE_HIDDEN);
  142. }
  143. }
  144. }
  145. return rf;
  146. }
  147. /*BOOL
  148. GatherCdRomDriveInformation (
  149. VOID
  150. )
  151. {
  152. BOOL rf = TRUE;
  153. HKEY scsiKey = NULL;
  154. HKEY deviceKey = NULL;
  155. TCHAR classData[25];
  156. DWORD classDataSize = 25;
  157. TCHAR targetData[5];
  158. DWORD targetDataSize = 5;
  159. TCHAR lunData[5];
  160. DWORD lunDataSize = 5;
  161. TCHAR driveLetterData[5];
  162. DWORD driveLetterSize = 5;
  163. TCHAR buffer [4096];
  164. DWORD subKeyLength;
  165. DWORD tempLength;
  166. HKEY locationKey = NULL;
  167. PTSTR locationName;
  168. DWORD outerIndex;
  169. DWORD enumReturn;
  170. DWORD port;
  171. DWORD unusedType;
  172. DWORD error;
  173. //
  174. // Walk the SCSI tree looking for CD rom devices.
  175. //
  176. error = RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT("ENUM\\SCSI"), 0, KEY_READ, &scsiKey);
  177. if (error) {
  178. return TRUE;
  179. }
  180. //
  181. // Gather information about the key in preparation for enumerating
  182. // it.
  183. //
  184. error = RegQueryInfoKey (
  185. scsiKey,
  186. NULL, // Don't care about the class.
  187. NULL, // class size.
  188. NULL, // reserved.
  189. NULL, // Don't care about the number of subkeys.
  190. &subKeyLength,
  191. NULL, // Don't care about subclasses.
  192. NULL, // Don't care about values.
  193. NULL, // Don't care about max value name length.
  194. NULL, // Don't care about max component.
  195. NULL, // Don't care about the security descriptor.
  196. NULL // Don't care about the last write time.
  197. );
  198. if (error) {
  199. //
  200. // This should really not happen.
  201. //
  202. return FALSE;
  203. }
  204. //
  205. // Succssesfully opened a key to HKLM\Enum\SCSI. Enumerate it.
  206. //
  207. outerIndex = 0;
  208. do {
  209. if (locationKey) {
  210. RegCloseKey (locationKey);
  211. locationKey = NULL;
  212. }
  213. if (deviceKey) {
  214. RegCloseKey (deviceKey);
  215. deviceKey = NULL;
  216. }
  217. tempLength = sizeof(buffer) / sizeof(TCHAR);
  218. enumReturn = RegEnumKeyEx (
  219. scsiKey,
  220. outerIndex,
  221. buffer,
  222. &tempLength,
  223. 0, // Reserved
  224. NULL, // Class name - not necessary.
  225. NULL, // size of class name buffer.
  226. NULL
  227. );
  228. outerIndex++;
  229. //
  230. // For each returned key, look up the "Class" value.
  231. //
  232. error = RegOpenKeyEx (scsiKey,buffer,0,KEY_READ,&deviceKey);
  233. if (error) {
  234. //
  235. // Something is hosed. Give up on collecting SCSI data.
  236. //
  237. rf = FALSE;
  238. break;
  239. }
  240. //
  241. // The port has to be decoded from the key one level
  242. // below.
  243. //
  244. tempLength = sizeof (buffer) / sizeof(TCHAR);
  245. error = RegEnumKeyEx (
  246. deviceKey,
  247. 0,
  248. buffer,
  249. &tempLength,
  250. 0, // Reserved
  251. NULL, // Class name - not necessary.
  252. NULL, // size of class name buffer.
  253. NULL
  254. );
  255. error = RegOpenKeyEx (deviceKey, buffer, 0, KEY_READ, &locationKey);
  256. if (error) {
  257. //
  258. // This should really never happen. However, guard against it.
  259. // Its not serious enough to abort the search. Just skip this
  260. // particular key and continue.
  261. //
  262. continue;
  263. }
  264. tempLength = classDataSize;
  265. error = RegQueryValueEx(
  266. locationKey,
  267. TEXT("CLASS"),
  268. 0,
  269. &unusedType,
  270. (PBYTE) classData,
  271. &tempLength
  272. );
  273. if (error) {
  274. //
  275. // This isn't a serious enough error to bring down the whole
  276. // enumeration. Just note it in the logs and continue to the
  277. // next key.
  278. //
  279. continue;
  280. }
  281. if (!lstrcmpi(classData, TEXT("CDROM"))) {
  282. lstrcpy (targetData, TEXT("-1"));
  283. lstrcpy (lunData, TEXT("-1"));
  284. lstrcpy (driveLetterData, TEXT("%"));
  285. //
  286. // Found a CdRom. Get the information that will be used in
  287. // textmode setup to identify the drive.
  288. //
  289. tempLength = targetDataSize;
  290. RegQueryValueEx(
  291. locationKey,
  292. TEXT("ScsiTargetId"),
  293. 0,
  294. &unusedType,
  295. (PBYTE) targetData,
  296. &tempLength
  297. );
  298. tempLength = lunDataSize;
  299. RegQueryValueEx(
  300. locationKey,
  301. TEXT("ScsiLun"),
  302. 0,
  303. &unusedType,
  304. (PBYTE) lunData,
  305. &tempLength
  306. );
  307. tempLength = driveLetterSize;
  308. RegQueryValueEx(
  309. locationKey,
  310. TEXT("CurrentDriveLetterAssignment"),
  311. 0,
  312. &unusedType,
  313. (PBYTE) driveLetterData,
  314. &tempLength
  315. );
  316. if (*driveLetterData != TEXT('%')) {
  317. //
  318. // At this point, we have all of the information
  319. // necessary to write a SCSI CdRom identifier
  320. // string.
  321. //
  322. wsprintf(g_DriveLetters.IdentifierString[*driveLetterData - TEXT('A')], TEXT("%u^%s^%s"), 1, targetData, lunData);
  323. }
  324. }
  325. if (locationKey) {
  326. RegCloseKey (locationKey);
  327. locationKey = NULL;
  328. }
  329. if (deviceKey) {
  330. RegCloseKey (deviceKey);
  331. deviceKey = NULL;
  332. }
  333. } while (rf && enumReturn == ERROR_SUCCESS);
  334. if (locationKey) {
  335. RegCloseKey(locationKey);
  336. locationKey = NULL;
  337. }
  338. if (deviceKey) {
  339. RegCloseKey(deviceKey);
  340. deviceKey = NULL;
  341. }
  342. if (scsiKey) {
  343. RegCloseKey(scsiKey);
  344. scsiKey = NULL;
  345. }
  346. return rf;
  347. }*/
  348. BOOL pCDROMDeviceEnumCallback(
  349. IN HKEY hDevice,
  350. IN PCONTROLLERS_COLLECTION ControllersCollection,
  351. IN UINT ControllerIndex,
  352. IN PVOID CallbackData
  353. )
  354. {
  355. DRIVE_SCSI_ADDRESS scsiAddress;
  356. BOOL bResult;
  357. MYASSERT(hDevice && ControllersCollection);
  358. bResult = GetSCSIAddressFromPnPId(ControllersCollection,
  359. hDevice,
  360. ControllersCollection->ControllersInfo[ControllerIndex].PNPID,
  361. &scsiAddress);
  362. MYASSERT(bResult);
  363. if(bResult &&
  364. ((UCHAR)INVALID_SCSI_PORT) != scsiAddress.PortNumber &&
  365. DRIVE_CDROM == scsiAddress.DriveType){
  366. wsprintf(g_DriveLetters.IdentifierString[scsiAddress.DriveLetter - TEXT('A')],
  367. TEXT("%u^%u^%u"),
  368. (UINT)scsiAddress.PortNumber,
  369. (UINT)scsiAddress.TargetId,
  370. (UINT)scsiAddress.Lun);
  371. }
  372. return TRUE;
  373. }
  374. BOOL
  375. GatherCdRomDriveInformation (
  376. VOID
  377. )
  378. {
  379. PCONTROLLERS_COLLECTION ControllersCollection;
  380. UINT i;
  381. BOOL bResult;
  382. BOOL bDetectedExtraIDEController = FALSE;
  383. UINT numberOfSCSIController = 0;
  384. //
  385. // Collect all active IDE and SCSI controllers
  386. //
  387. bResult = GatherControllersInfo(&ControllersCollection);
  388. if(!bResult){
  389. MYASSERT(FALSE);
  390. return FALSE;
  391. }
  392. MYASSERT(ControllersCollection->ControllersInfo);
  393. for(i = 0; i < ControllersCollection->NumberOfControllers; i++){
  394. switch(ControllersCollection->ControllersInfo[i].ControllerType){
  395. case CONTROLLER_EXTRA_IDE:
  396. bDetectedExtraIDEController = TRUE;
  397. break;
  398. case CONTROLLER_SCSI:
  399. numberOfSCSIController++;
  400. break;
  401. }
  402. }
  403. if(bDetectedExtraIDEController){
  404. DebugLog(Winnt32LogWarning, TEXT("Setup has detected that machine have extra IDE controller(s). Setup may not preserve drive letters."), 0);
  405. }
  406. if(numberOfSCSIController > 1){
  407. 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);
  408. }
  409. //
  410. // If we found extra IDE controller(s) we can't ensure rigth device detection in this case.
  411. // If we found more than one SCSI controllers without extra IDE controller(s),
  412. // at least we can guarantee correct IDE devices detection.
  413. //
  414. bResult = DeviceEnum(ControllersCollection,
  415. TEXT("SCSI"),
  416. (PDEVICE_ENUM_CALLBACK_FUNCTION)pCDROMDeviceEnumCallback,
  417. NULL);
  418. MYASSERT(bResult);
  419. ReleaseControllersInfo(ControllersCollection);
  420. return bResult;
  421. }
  422. BOOL
  423. WriteInfoToSifFile (
  424. IN PCTSTR FileName
  425. )
  426. {
  427. BOOL rSuccess = TRUE;
  428. DWORD index;
  429. TCHAR dataString[MAX_PATH * 2]; // Well over the size needed.
  430. TCHAR driveString[20]; // Well over the size needed.
  431. PCTSTR sectionString = WINNT_D_WIN9XDRIVES;
  432. for (index = 0; index < NUMDRIVELETTERS; index++) {
  433. if (g_DriveLetters.ExistsOnSystem[index]) {
  434. wsprintf(
  435. driveString,
  436. TEXT("%u"),
  437. index
  438. );
  439. wsprintf(
  440. dataString,
  441. TEXT("%u,%s"),
  442. g_DriveLetters.Type[index],
  443. g_DriveLetters.IdentifierString[index]
  444. );
  445. //
  446. // Ending string looks like <drive num>,<drive type>,<identifier string>
  447. //
  448. WritePrivateProfileString (sectionString, driveString, dataString, FileName);
  449. }
  450. }
  451. return rSuccess;
  452. }
  453. DWORD
  454. SaveDriveLetterInformation (
  455. IN PCTSTR FileName
  456. )
  457. {
  458. BOOL rf = TRUE;
  459. if (InitializeDriveLetterStructure ()) {
  460. GatherHardDriveInformation ();
  461. GatherCdRomDriveInformation ();
  462. WriteInfoToSifFile (FileName);
  463. }
  464. return ERROR_SUCCESS;
  465. }