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.

522 lines
15 KiB

  1. /*++
  2. Copyright (c) 1993-1994 Microsoft Corporation
  3. Module Name:
  4. cdrom.c
  5. Abstract:
  6. This module contains the set of routines that display and control the
  7. drive letters for CdRom devices.
  8. Author:
  9. Bob Rinne (bobri) 12/9/93
  10. Environment:
  11. User process.
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "fdisk.h"
  16. #include "shellapi.h"
  17. #include <string.h>
  18. #include <stdio.h>
  19. #include <wchar.h>
  20. #include <malloc.h>
  21. PCDROM_DESCRIPTOR CdRomChainBase = NULL;
  22. PCDROM_DESCRIPTOR CdRomChainLast = NULL;
  23. PCDROM_DESCRIPTOR CdRomChanged = NULL;
  24. static BOOLEAN CdRomFirstCall = TRUE;
  25. static TCHAR SourcePathLetter = (TCHAR) '\0';
  26. static TCHAR SourcePathKeyName[80];
  27. static TCHAR SourcePathValueName[30];
  28. VOID
  29. CdRomAddDevice(
  30. IN PWSTR NtName,
  31. IN WCHAR DriveLetter
  32. )
  33. /*++
  34. Routine Description:
  35. Build a cdrom description structure for this and fill it in.
  36. Arguments:
  37. NtName - The unicode name for the device.
  38. DriveLetter - The DosDevice name.
  39. Return Value:
  40. None
  41. --*/
  42. {
  43. PCDROM_DESCRIPTOR cdrom;
  44. PWCHAR cp;
  45. LONG error;
  46. HKEY keyHandle;
  47. DWORD valueType;
  48. ULONG size;
  49. TCHAR *string;
  50. if (CdRomFirstCall) {
  51. CdRomFirstCall = FALSE;
  52. // Get the registry path and value name.
  53. LoadString(hModule,
  54. IDS_SOURCE_PATH,
  55. SourcePathKeyName,
  56. sizeof(SourcePathKeyName)/sizeof(TCHAR));
  57. LoadString(hModule,
  58. IDS_SOURCE_PATH_NAME,
  59. SourcePathValueName,
  60. sizeof(SourcePathValueName)/sizeof(TCHAR));
  61. error = RegOpenKey(HKEY_LOCAL_MACHINE,
  62. SourcePathKeyName,
  63. &keyHandle);
  64. if (error == NO_ERROR) {
  65. error = RegQueryValueEx(keyHandle,
  66. SourcePathValueName,
  67. NULL,
  68. &valueType,
  69. (PUCHAR)NULL,
  70. &size);
  71. if (error == NO_ERROR) {
  72. string = (PUCHAR) LocalAlloc(LMEM_FIXED, size);
  73. if (string) {
  74. error = RegQueryValueEx(keyHandle,
  75. SourcePathValueName,
  76. NULL,
  77. &valueType,
  78. string,
  79. &size);
  80. if (error == NO_ERROR) {
  81. SourcePathLetter = *string;
  82. }
  83. }
  84. LocalFree(string);
  85. }
  86. RegCloseKey(keyHandle);
  87. }
  88. }
  89. cdrom = (PCDROM_DESCRIPTOR) malloc(sizeof(CDROM_DESCRIPTOR));
  90. if (cdrom) {
  91. cdrom->DeviceName = (PWSTR) malloc((wcslen(NtName)+1)*sizeof(WCHAR));
  92. if (cdrom->DeviceName) {
  93. wcscpy(cdrom->DeviceName, NtName);
  94. cp = cdrom->DeviceName;
  95. while (*cp) {
  96. if (iswdigit(*cp)) {
  97. break;
  98. }
  99. cp++;
  100. }
  101. if (*cp) {
  102. cdrom->DeviceNumber = wcstoul(cp, (WCHAR) 0, 10);
  103. }
  104. cdrom->DriveLetter = DriveLetter;
  105. cdrom->Next = NULL;
  106. cdrom->NewDriveLetter = (WCHAR) 0;
  107. if (CdRomChainBase) {
  108. CdRomChainLast->Next = cdrom;
  109. } else {
  110. AllowCdRom = TRUE;
  111. CdRomChainBase = cdrom;
  112. }
  113. CdRomChainLast = cdrom;
  114. } else {
  115. free(cdrom);
  116. }
  117. }
  118. }
  119. INT
  120. CdRomDlgProc(
  121. IN HWND hDlg,
  122. IN UINT wMsg,
  123. IN DWORD wParam,
  124. IN LONG lParam
  125. )
  126. /*++
  127. Routine Description:
  128. Handle the dialog for CD-ROMS
  129. Arguments:
  130. Standard Windows dialog procedure
  131. Return Value:
  132. TRUE if something was deleted.
  133. FALSE otherwise.
  134. --*/
  135. {
  136. HWND hwndCombo;
  137. DWORD selection;
  138. DWORD index;
  139. CHAR driveLetter;
  140. TCHAR string[40];
  141. PCDROM_DESCRIPTOR cdrom;
  142. static PCDROM_DESCRIPTOR currentCdrom;
  143. static CHAR currentSelectionLetter;
  144. switch (wMsg) {
  145. case WM_INITDIALOG:
  146. // Store all device strings into the selection area.
  147. hwndCombo = GetDlgItem(hDlg, IDC_CDROM_NAMES);
  148. cdrom = currentCdrom = CdRomChainBase;
  149. currentSelectionLetter = (CHAR) cdrom->DriveLetter;
  150. while (cdrom) {
  151. sprintf(string, "CdRom%d", cdrom->DeviceNumber);
  152. SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string);
  153. cdrom = cdrom->Next;
  154. }
  155. SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
  156. // Update the drive letter selections.
  157. selection = index = 0;
  158. hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
  159. string[1] = TEXT(':');
  160. string[2] = 0;
  161. for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
  162. if ((DriveLetterIsAvailable((CHAR)driveLetter)) ||
  163. (driveLetter == currentSelectionLetter)) {
  164. *string = driveLetter;
  165. SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string);
  166. if (driveLetter == currentSelectionLetter) {
  167. selection = index;
  168. }
  169. index++;
  170. }
  171. }
  172. // set the current selection to the appropriate index
  173. SendMessage(hwndCombo, CB_SETCURSEL, selection, 0);
  174. return TRUE;
  175. case WM_COMMAND:
  176. switch (wParam) {
  177. case FD_IDHELP:
  178. DialogHelp(HC_DM_DLG_CDROM);
  179. break;
  180. case IDCANCEL:
  181. EndDialog(hDlg, FALSE);
  182. break;
  183. case IDOK:
  184. // User has selected the drive letter and wants the mount to occur.
  185. hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
  186. selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
  187. SendMessage(hwndCombo,
  188. CB_GETLBTEXT,
  189. selection,
  190. (LONG)string);
  191. currentCdrom->NewDriveLetter = (WCHAR) string[0];
  192. CdRomChanged = currentCdrom;
  193. EndDialog(hDlg, TRUE);
  194. break;
  195. default:
  196. if (HIWORD(wParam) == LBN_SELCHANGE) {
  197. TCHAR *cp;
  198. if (LOWORD(wParam) != IDC_CDROM_NAMES) {
  199. break;
  200. }
  201. // The state of something in the dialog changed.
  202. hwndCombo = GetDlgItem(hDlg, IDC_CDROM_NAMES);
  203. selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
  204. SendMessage(hwndCombo,
  205. CB_GETLBTEXT,
  206. selection,
  207. (LONG)string);
  208. // The format of the string returned is "cdrom#". Parse the
  209. // value of # in order to find the selection.
  210. cp = string;
  211. while (*cp) {
  212. cp++;
  213. }
  214. cp--;
  215. while ((*cp >= (TCHAR) '0') && (*cp <= (TCHAR) '9')) {
  216. cp--;
  217. }
  218. cp++;
  219. selection = 0;
  220. while (*cp) {
  221. selection = (selection * 10) + (*cp - (TCHAR) '0');
  222. cp++;
  223. }
  224. // Find the matching device name.
  225. for (cdrom = CdRomChainBase; cdrom; cdrom = cdrom->Next) {
  226. if (selection == cdrom->DeviceNumber) {
  227. // found the match
  228. currentSelectionLetter = (CHAR) cdrom->DriveLetter;
  229. currentCdrom = cdrom;
  230. break;
  231. }
  232. }
  233. // The only thing that is important is to track the cdrom
  234. // device name selected and update the drive letter list.
  235. selection = index = 0;
  236. hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
  237. SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
  238. string[1] = TEXT(':');
  239. string[2] = 0;
  240. for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
  241. if ((DriveLetterIsAvailable((CHAR)driveLetter)) ||
  242. (driveLetter == currentSelectionLetter)) {
  243. *string = driveLetter;
  244. SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string);
  245. if (driveLetter == currentSelectionLetter) {
  246. selection = index;
  247. }
  248. index++;
  249. }
  250. }
  251. // set the current selection to the appropriate index
  252. SendMessage(hwndCombo, CB_SETCURSEL, selection, 0);
  253. }
  254. break;
  255. }
  256. }
  257. return FALSE;
  258. }
  259. VOID
  260. CdRom(
  261. IN HWND Dialog,
  262. IN PVOID Param
  263. )
  264. /*++
  265. Routine Description:
  266. Start the CdRom dialogs.
  267. Arguments:
  268. None
  269. Return Value:
  270. None
  271. --*/
  272. {
  273. BOOLEAN result = 0;
  274. DWORD action,
  275. ec;
  276. TCHAR name[40];
  277. TCHAR letter[10];
  278. PWSTR linkTarget;
  279. OBJECT_ATTRIBUTES oa;
  280. WCHAR dosName[20];
  281. HANDLE handle;
  282. NTSTATUS status;
  283. IO_STATUS_BLOCK statusBlock;
  284. ANSI_STRING ansiName;
  285. UNICODE_STRING unicodeName;
  286. UINT errorMode;
  287. result = DialogBoxParam(hModule,
  288. MAKEINTRESOURCE(IDD_CDROM),
  289. Dialog,
  290. (DLGPROC) CdRomDlgProc,
  291. (ULONG) NULL);
  292. if (result) {
  293. action = ConfirmationDialog(MSG_DRIVE_RENAME_WARNING, MB_ICONQUESTION | MB_YESNOCANCEL);
  294. if (!action) {
  295. return;
  296. }
  297. // Attempt to open and lock the cdrom.
  298. sprintf(name, "\\Device\\CdRom%d", CdRomChanged->DeviceNumber);
  299. RtlInitAnsiString(&ansiName, name);
  300. status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
  301. if (!NT_SUCCESS(status)) {
  302. ErrorDialog(MSG_CDROM_LETTER_ERROR);
  303. return;
  304. }
  305. memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
  306. oa.Length = sizeof(OBJECT_ATTRIBUTES);
  307. oa.ObjectName = &unicodeName;
  308. oa.Attributes = OBJ_CASE_INSENSITIVE;
  309. errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  310. status = NtOpenFile(&handle,
  311. SYNCHRONIZE | FILE_READ_DATA,
  312. &oa,
  313. &statusBlock,
  314. FILE_SHARE_READ,
  315. FILE_SYNCHRONOUS_IO_ALERT);
  316. RtlFreeUnicodeString(&unicodeName);
  317. SetErrorMode(errorMode);
  318. if (!NT_SUCCESS(status)) {
  319. ErrorDialog(MSG_CANNOT_LOCK_CDROM);
  320. return;
  321. }
  322. // Lock the drive to insure that no other access is occurring
  323. // to the volume. This is done via the "Low" routine for
  324. // convenience
  325. status = LowLockDrive(handle);
  326. if (!NT_SUCCESS(status)) {
  327. LowCloseDisk(handle);
  328. ErrorDialog(MSG_CANNOT_LOCK_CDROM);
  329. return;
  330. }
  331. // Before attempting to move the name, see if the letter
  332. // is currently in use - could be a new network connection
  333. // or a partition that is scheduled for deletion.
  334. wsprintfW(dosName, L"\\DosDevices\\%wc:", (WCHAR) CdRomChanged->NewDriveLetter);
  335. ec = GetDriveLetterLinkTarget(dosName, &linkTarget);
  336. if (ec == NO_ERROR) {
  337. // Something is using this letter.
  338. LowCloseDisk(handle);
  339. ErrorDialog(MSG_CANNOT_MOVE_CDROM);
  340. return;
  341. }
  342. // remove existing definition - if this fails don't continue.
  343. sprintf(letter, "%c:", (UCHAR) CdRomChanged->DriveLetter);
  344. if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) letter, (LPCTSTR) NULL)) {
  345. LowCloseDisk(handle);
  346. ErrorDialog(MSG_CDROM_LETTER_ERROR);
  347. return;
  348. }
  349. status = DiskRegistryAssignCdRomLetter(CdRomChanged->DeviceName,
  350. CdRomChanged->NewDriveLetter);
  351. MarkDriveLetterFree((UCHAR)CdRomChanged->DriveLetter);
  352. // See if this was the device used to install NT
  353. if (SourcePathLetter) {
  354. if (SourcePathLetter == CdRomChanged->DriveLetter) {
  355. LONG error;
  356. HKEY keyHandle;
  357. DWORD valueType;
  358. ULONG size;
  359. TCHAR *string;
  360. // Update the source path
  361. error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  362. SourcePathKeyName,
  363. 0,
  364. KEY_ALL_ACCESS,
  365. &keyHandle);
  366. if (error == NO_ERROR) {
  367. error = RegQueryValueEx(keyHandle,
  368. SourcePathValueName,
  369. NULL,
  370. &valueType,
  371. (PUCHAR)NULL,
  372. &size);
  373. if (error == NO_ERROR) {
  374. string = (PUCHAR) LocalAlloc(LMEM_FIXED, size);
  375. if (string) {
  376. error = RegQueryValueEx(keyHandle,
  377. SourcePathValueName,
  378. NULL,
  379. &valueType,
  380. string,
  381. &size);
  382. if (error == NO_ERROR) {
  383. *string = SourcePathLetter = (UCHAR) CdRomChanged->NewDriveLetter;
  384. RegSetValueEx(keyHandle,
  385. SourcePathValueName,
  386. 0,
  387. REG_SZ,
  388. string,
  389. size);
  390. }
  391. }
  392. LocalFree(string);
  393. }
  394. RegCloseKey(keyHandle);
  395. }
  396. }
  397. }
  398. // set up new device letter - name is already set up
  399. sprintf(letter, "%c:", (UCHAR) CdRomChanged->NewDriveLetter);
  400. if (DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) letter, (LPCTSTR) name)) {
  401. CdRomChanged->DriveLetter = CdRomChanged->NewDriveLetter;
  402. MarkDriveLetterUsed((UCHAR)CdRomChanged->DriveLetter);
  403. } else {
  404. RegistryChanged = TRUE;
  405. }
  406. LowCloseDisk(handle);
  407. }
  408. }