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.

527 lines
12 KiB

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