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.

1579 lines
32 KiB

  1. /*++
  2. Copyright (c) 1990-1993 Microsoft Corporation
  3. Module Name:
  4. fdmisc.c
  5. Abstract:
  6. Miscellaneous routines for NT fdisk.
  7. Author:
  8. Ted Miller (tedm) 7-Jan-1992
  9. Modifications:
  10. 13-Dec-1993 (bobri) CdRom initialization support.
  11. --*/
  12. #include "fdisk.h"
  13. #include <process.h>
  14. extern HWND InitDlg;
  15. extern BOOLEAN StartedAsIcon;
  16. BOOL
  17. AllDisksOffLine(
  18. VOID
  19. )
  20. /*++
  21. Routine Description:
  22. Determine whether all hard disks are off line.
  23. Arguments:
  24. None.
  25. Return Value:
  26. TRUE if all disks off-line, false otherwise.
  27. --*/
  28. {
  29. ULONG i;
  30. FDASSERT(DiskCount);
  31. for (i=0; i<DiskCount; i++) {
  32. if (!IsDiskOffLine(i)) {
  33. return FALSE;
  34. }
  35. }
  36. return TRUE;
  37. }
  38. VOID
  39. FdShutdownTheSystem(
  40. VOID
  41. )
  42. /*++
  43. Routine Description:
  44. This routine attempts to update the caller privilege, then shutdown the
  45. Windows NT system. If it fails it prints a warning dialog. If it
  46. succeeds then it doesn't return to the caller.
  47. Arguments:
  48. None
  49. Return Value:
  50. None
  51. --*/
  52. {
  53. NTSTATUS Status;
  54. BOOLEAN PreviousPriv;
  55. InfoDialog(MSG_MUST_REBOOT);
  56. SetCursor(hcurWait);
  57. WriteProfile();
  58. // Enable shutdown privilege
  59. Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
  60. TRUE,
  61. FALSE,
  62. &PreviousPriv);
  63. #if DBG
  64. if (Status) {
  65. DbgPrint("DISKMAN: Status %lx attempting to enable shutdown privilege\n",Status);
  66. }
  67. #endif
  68. Sleep(3000);
  69. if (!ExitWindowsEx(EWX_REBOOT,(DWORD)(-1))) {
  70. WarningDialog(MSG_COULDNT_REBOOT);
  71. }
  72. }
  73. LPTSTR
  74. LoadAString(
  75. IN DWORD StringID
  76. )
  77. /*++
  78. Routine Description:
  79. Loads a string from the resource file and allocates a buffer of exactly
  80. the right size to hold it.
  81. Arguments:
  82. StringID - resource ID of string to load
  83. Return Value:
  84. pointer to buffer. If string is not found, the first
  85. (and only) char in the returned buffer will be 0.
  86. --*/
  87. {
  88. TCHAR text[500];
  89. LPTSTR buffer;
  90. text[0] = 0;
  91. LoadString(hModule, StringID, text, sizeof(text)/sizeof(TCHAR));
  92. buffer = Malloc((lstrlen(text)+1)*sizeof(TCHAR));
  93. lstrcpy(buffer, text);
  94. return buffer;
  95. }
  96. PWSTR
  97. LoadWString(
  98. IN DWORD StringID
  99. )
  100. /*++
  101. Routine Description:
  102. Loads a wide-char string from the resource file and allocates a
  103. buffer of exactly the right size to hold it.
  104. Arguments:
  105. StringID - resource ID of string to load
  106. Return Value:
  107. pointer to buffer. If string is not found, the first
  108. (and only) char in the returned buffer will be 0.
  109. --*/
  110. {
  111. WCHAR text[500];
  112. PWSTR buffer;
  113. text[0] = 0;
  114. LoadStringW(hModule, StringID, text, sizeof(text)/sizeof(WCHAR));
  115. buffer = Malloc((lstrlenW(text)+1)*sizeof(WCHAR));
  116. lstrcpyW(buffer, text);
  117. return buffer;
  118. }
  119. int
  120. GetHeightFromPoints(
  121. IN int Points
  122. )
  123. /*++
  124. Routine Description:
  125. This routine calculates the height of a font given a point value.
  126. The calculation is based on 72 points per inch and the display's
  127. pixels/inch device capability.
  128. Arguments:
  129. Points - number of points
  130. Return Value:
  131. pixel count (negative and therefore suitable for passing to
  132. CreateFont())
  133. --*/
  134. {
  135. HDC hdc = GetDC(NULL);
  136. int height = MulDiv(-Points, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  137. ReleaseDC(NULL, hdc);
  138. return height;
  139. }
  140. VOID
  141. UnicodeHack(
  142. IN PCHAR Source,
  143. OUT LPTSTR Dest
  144. )
  145. /*++
  146. Routine Description:
  147. Given a non-Unicode ASCII string, this routine will either convert it
  148. to Unicode or copy it, depending on the current definition of TCHAR.
  149. The 'conversion' is a simple hack that casts to TCHAR.
  150. Arguments:
  151. Source - source (ansi ascii) string
  152. Dest - destination string or wide string
  153. Return Value:
  154. None.
  155. --*/
  156. {
  157. int i;
  158. int j = lstrlen(Source);
  159. for (i=0; i<=j; i++) {
  160. Dest[i] = (TCHAR)(UCHAR)Source[i];
  161. }
  162. }
  163. VOID
  164. _RetreiveAndFormatMessage(
  165. IN DWORD Msg,
  166. OUT LPTSTR Buffer,
  167. IN DWORD BufferSize,
  168. IN va_list arglist
  169. )
  170. /*++
  171. Routine Description:
  172. Arguments:
  173. Return Value:
  174. --*/
  175. {
  176. DWORD x;
  177. TCHAR text[500];
  178. // get message from system or app msg file.
  179. x = FormatMessage( Msg >= MSG_FIRST_FDISK_MSG
  180. ? FORMAT_MESSAGE_FROM_HMODULE
  181. : FORMAT_MESSAGE_FROM_SYSTEM,
  182. NULL,
  183. Msg,
  184. 0,
  185. Buffer,
  186. BufferSize,
  187. &arglist);
  188. if (!x) { // couldn't find message
  189. LoadString(hModule,
  190. Msg >= MSG_FIRST_FDISK_MSG ? IDS_NOT_IN_APP_MSG_FILE : IDS_NOT_IN_SYS_MSG_FILE,
  191. text,
  192. sizeof(text)/sizeof(TCHAR));
  193. wsprintf(Buffer, text, Msg);
  194. }
  195. }
  196. DWORD
  197. CommonDialog(
  198. IN DWORD MsgCode,
  199. IN LPTSTR Caption,
  200. IN DWORD Flags,
  201. IN va_list arglist
  202. )
  203. /*++
  204. Routine Description:
  205. Simple dialog routine to get dialogs out of the resource
  206. for the program and run them as a message box.
  207. Arguments:
  208. MsgCode - dialog message code
  209. Caption - message box caption
  210. Flags - standard message box flags
  211. arglist - list to be given when pulling the message text
  212. Return Value:
  213. The MessageBox() return value
  214. --*/
  215. {
  216. TCHAR MsgBuf[MESSAGE_BUFFER_SIZE];
  217. if (!StartedAsIcon) {
  218. // Flags |= MB_SETFOREGROUND;
  219. }
  220. if (InitDlg) {
  221. PostMessage(InitDlg,
  222. (WM_USER + 1),
  223. 0,
  224. 0);
  225. InitDlg = (HWND) 0;
  226. }
  227. _RetreiveAndFormatMessage(MsgCode, MsgBuf, sizeof(MsgBuf), arglist);
  228. return MessageBox(GetActiveWindow(), MsgBuf, Caption, Flags);
  229. }
  230. VOID
  231. ErrorDialog(
  232. IN DWORD ErrorCode,
  233. ...
  234. )
  235. /*++
  236. -Routine Description:
  237. This routine retreives a message from the app or system message file
  238. and displays it in a message box.
  239. Arguments:
  240. ErrorCode - number of message
  241. ... - strings for insertion into message
  242. Return Value:
  243. None.
  244. --*/
  245. {
  246. va_list arglist;
  247. va_start(arglist, ErrorCode);
  248. CommonDialog(ErrorCode, NULL, MB_ICONHAND | MB_OK | MB_SYSTEMMODAL, arglist);
  249. va_end(arglist);
  250. }
  251. VOID
  252. WarningDialog(
  253. IN DWORD MsgCode,
  254. ...
  255. )
  256. /*++
  257. Routine Description:
  258. This routine retreives a message from the app or system message file
  259. and displays it in a message box.
  260. Arguments:
  261. MsgCode - number of message
  262. ... - strings for insertion into message
  263. Return Value:
  264. None.
  265. --*/
  266. {
  267. TCHAR Caption[100];
  268. va_list arglist;
  269. va_start(arglist, MsgCode);
  270. LoadString(hModule, IDS_APPNAME, Caption, sizeof(Caption)/sizeof(TCHAR));
  271. CommonDialog(MsgCode, Caption, MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL, arglist);
  272. va_end(arglist);
  273. }
  274. DWORD
  275. ConfirmationDialog(
  276. IN DWORD MsgCode,
  277. IN DWORD Flags,
  278. ...
  279. )
  280. /*++
  281. Routine Description:
  282. Support for a simple confirmation dialog
  283. Arguments:
  284. MsgCode - resource code for message
  285. Flags - dialog flags
  286. Return Value:
  287. Result from the CommonDialog() performed.
  288. --*/
  289. {
  290. TCHAR Caption[100];
  291. DWORD x;
  292. va_list arglist;
  293. va_start(arglist, Flags);
  294. LoadString(hModule, IDS_CONFIRM, Caption, sizeof(Caption)/sizeof(TCHAR));
  295. x = CommonDialog(MsgCode, Caption, Flags | MB_TASKMODAL, arglist);
  296. va_end(arglist);
  297. return x;
  298. }
  299. VOID
  300. InfoDialog(
  301. IN DWORD MsgCode,
  302. ...
  303. )
  304. /*++
  305. Routine Description:
  306. This routine retreives a message from the app or system message file
  307. and displays it in a message box.
  308. Arguments:
  309. MsgCode - number of message
  310. ... - strings for insertion into message
  311. Return Value:
  312. None.
  313. --*/
  314. {
  315. TCHAR Caption[100];
  316. va_list arglist;
  317. va_start(arglist, MsgCode);
  318. LoadString(hModule, IDS_APPNAME, Caption, sizeof(Caption)/sizeof(TCHAR));
  319. CommonDialog(MsgCode, Caption, MB_ICONINFORMATION | MB_OK | MB_TASKMODAL, arglist);
  320. va_end(arglist);
  321. }
  322. PREGION_DESCRIPTOR
  323. LocateRegionForFtObject(
  324. IN PFT_OBJECT FtObject
  325. )
  326. /*++
  327. Routine Description:
  328. Given an FtObject, find the associated region descriptor
  329. Arguments:
  330. FtObject - the ft object to search for.
  331. Return Value:
  332. NULL - no descriptor found
  333. !NULL - a pointer to the region descriptor for the FT object
  334. ++*/
  335. {
  336. PDISKSTATE diskState;
  337. PREGION_DESCRIPTOR regionDescriptor;
  338. DWORD disk,
  339. region;
  340. PPERSISTENT_REGION_DATA regionData;
  341. for (disk = 0; disk < DiskCount; disk++) {
  342. diskState = Disks[disk];
  343. for (region = 0; region < diskState->RegionCount; region++) {
  344. regionDescriptor = &diskState->RegionArray[region];
  345. regionData = PERSISTENT_DATA(regionDescriptor);
  346. if (regionData) {
  347. if (regionData->FtObject == FtObject) {
  348. return regionDescriptor;
  349. }
  350. }
  351. }
  352. }
  353. return NULL;
  354. }
  355. VOID
  356. InitVolumeLabelsAndTypeNames(
  357. VOID
  358. )
  359. /*++
  360. Routine Description:
  361. Determine the volume label and type name for each significant
  362. (non-extended, non-free, recognized) partition.
  363. Assumes that persistent data has already been set up, and drive letters
  364. determined.
  365. Arguments:
  366. None.
  367. Return Value:
  368. None.
  369. --*/
  370. {
  371. DWORD disk,
  372. region;
  373. PDISKSTATE ds;
  374. PREGION_DESCRIPTOR rd;
  375. PPERSISTENT_REGION_DATA regionData;
  376. WCHAR diskName[4];
  377. WCHAR volumeLabel[100];
  378. WCHAR typeName[100];
  379. UINT errorMode;
  380. lstrcpyW(diskName, L"x:\\");
  381. for (disk=0; disk<DiskCount; disk++) {
  382. ds = Disks[disk];
  383. for (region=0; region<ds->RegionCount; region++) {
  384. rd = &ds->RegionArray[region];
  385. if (DmSignificantRegion(rd)) {
  386. // If the region has a drive letter, use the drive letter
  387. // to get the info via the Windows API. Otherwise we'll
  388. // have to use the NT API.
  389. regionData = PERSISTENT_DATA(rd);
  390. if (!regionData) {
  391. continue;
  392. }
  393. if ((regionData->DriveLetter == NO_DRIVE_LETTER_YET)
  394. || (regionData->DriveLetter == NO_DRIVE_LETTER_EVER)) {
  395. PWSTR tempLabel,
  396. tempName;
  397. // No drive letter. Use NT API.
  398. // If this is an FT set use the zero member disk for the
  399. // call so all members get the right type and label
  400. if (regionData->FtObject) {
  401. PFT_OBJECT searchFtObject;
  402. // Want to get rd pointing to the zeroth member
  403. searchFtObject = regionData->FtObject->Set->Member0;
  404. // Now search regions for this match
  405. rd = LocateRegionForFtObject(searchFtObject);
  406. if (!rd) {
  407. continue;
  408. }
  409. }
  410. if (GetVolumeLabel(rd->Disk, rd->PartitionNumber, &tempLabel) == NO_ERROR) {
  411. lstrcpyW(volumeLabel, tempLabel);
  412. Free(tempLabel);
  413. } else {
  414. *volumeLabel = 0;
  415. }
  416. if (GetTypeName(rd->Disk, rd->PartitionNumber, &tempName) == NO_ERROR) {
  417. lstrcpyW(typeName, tempName);
  418. Free(tempName);
  419. } else {
  420. lstrcpyW(typeName, wszUnknown);
  421. }
  422. } else {
  423. // Use Windows API.
  424. diskName[0] = (WCHAR)(UCHAR)regionData->DriveLetter;
  425. errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  426. if (!GetVolumeInformationW(diskName, volumeLabel, sizeof(volumeLabel)/2, NULL, NULL, NULL, typeName, sizeof(typeName)/2)) {
  427. lstrcpyW(typeName, wszUnknown);
  428. *volumeLabel = 0;
  429. }
  430. SetErrorMode(errorMode);
  431. }
  432. if (!lstrcmpiW(typeName, L"raw")) {
  433. lstrcpyW(typeName, wszUnknown);
  434. }
  435. regionData->TypeName = Malloc((lstrlenW(typeName) + 1) * sizeof(WCHAR));
  436. regionData->VolumeLabel = Malloc((lstrlenW(volumeLabel) + 1) * sizeof(WCHAR));
  437. lstrcpyW(regionData->TypeName, typeName);
  438. lstrcpyW(regionData->VolumeLabel, volumeLabel);
  439. }
  440. }
  441. }
  442. }
  443. VOID
  444. DetermineRegionInfo(
  445. IN PREGION_DESCRIPTOR Region,
  446. OUT PWSTR *TypeName,
  447. OUT PWSTR *VolumeLabel,
  448. OUT PWCH DriveLetter
  449. )
  450. /*++
  451. Routine Description:
  452. For a given region, fetch the persistent data, appropriately modified
  453. depending on whether the region is used or free, recognized, etc.
  454. Arguments:
  455. Region - supplies a pointer to the region whose data is to be fetched.
  456. TypeName - receives a pointer to the type name. If the region is
  457. unrecognized, the type is determined based on the system id of
  458. the partition.
  459. VolumeLabel - receives a pointer to the volume label. If the region is
  460. free space or unrecognized, the volume label is "".
  461. DriveLetter - receices the drive letter. If the region is free space
  462. or unrecognized, the drive letter is ' ' (space).
  463. Return Value:
  464. None.
  465. --*/
  466. {
  467. PWSTR typeName,
  468. volumeLabel;
  469. WCHAR driveLetter;
  470. PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
  471. if (DmSignificantRegion(Region)) {
  472. typeName = regionData->TypeName;
  473. volumeLabel = regionData->VolumeLabel;
  474. driveLetter = (WCHAR)(UCHAR)regionData->DriveLetter;
  475. if ((driveLetter == NO_DRIVE_LETTER_YET) || (driveLetter == NO_DRIVE_LETTER_EVER)) {
  476. driveLetter = L' ';
  477. }
  478. } else {
  479. typeName = GetWideSysIDName(Region->SysID);
  480. volumeLabel = L"";
  481. driveLetter = L' ';
  482. }
  483. *TypeName = typeName;
  484. *VolumeLabel = volumeLabel;
  485. *DriveLetter = driveLetter;
  486. }
  487. PREGION_DESCRIPTOR
  488. RegionFromFtObject(
  489. IN PFT_OBJECT FtObject
  490. )
  491. /*++
  492. Routine Description:
  493. Given an ft object, determine which region it belongs to. The algorithm
  494. is brute force -- look at each region on each disk until a match is found.
  495. Arguments:
  496. FtObject - ft member whose region is to be located.
  497. Return Value:
  498. pointer to region descriptor
  499. --*/
  500. {
  501. PREGION_DESCRIPTOR reg;
  502. DWORD region,
  503. disk;
  504. PDISKSTATE ds;
  505. for (disk=0; disk<DiskCount; disk++) {
  506. ds = Disks[disk];
  507. for (region=0; region<ds->RegionCount; region++) {
  508. reg = &ds->RegionArray[region];
  509. if (DmSignificantRegion(reg) && (GET_FT_OBJECT(reg) == FtObject)) {
  510. return reg;
  511. }
  512. }
  513. }
  514. return NULL;
  515. }
  516. //
  517. // For each drive letter, these arrays hold the disk and partition number
  518. // the the drive letter is linked to.
  519. //
  520. #define M1 ((unsigned)(-1))
  521. unsigned
  522. DriveLetterDiskNumbers[26] = { M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,
  523. M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1
  524. },
  525. DriveLetterPartitionNumbers[24] = { M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,
  526. M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1
  527. };
  528. #undef M1
  529. //
  530. // Drive letter usage map. Bit n set means that drive letter 'C'+n is in use.
  531. //
  532. ULONG DriveLetterUsageMap = 0;
  533. #define DRIVELETTERBIT(letter) (1 << (unsigned)((UCHAR)letter-(UCHAR)'C'))
  534. #define SetDriveLetterUsed(letter) DriveLetterUsageMap |= DRIVELETTERBIT(letter)
  535. #define SetDriveLetterFree(letter) DriveLetterUsageMap &= (~DRIVELETTERBIT(letter))
  536. #define IsDriveLetterUsed(letter) (DriveLetterUsageMap & DRIVELETTERBIT(letter))
  537. CHAR
  538. GetAvailableDriveLetter(
  539. VOID
  540. )
  541. /*++
  542. Routine Description:
  543. Scan the drive letter usage bitmap and return the next available
  544. drive letter. May also mark the drivee letter used.
  545. Arguments:
  546. None.
  547. Return Value:
  548. The next available drive letter, or 0 if all are used.
  549. --*/
  550. {
  551. CHAR driveLetter;
  552. FDASSERT(!(DriveLetterUsageMap & 0xff000000));
  553. for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
  554. if (!IsDriveLetterUsed(driveLetter)) {
  555. return driveLetter;
  556. }
  557. }
  558. return 0;
  559. }
  560. VOID
  561. MarkDriveLetterUsed(
  562. IN CHAR DriveLetter
  563. )
  564. /*++
  565. Routine Description:
  566. Given an ASCII drive letter, mark it in the usage map as being used.
  567. Arguments:
  568. DriveLetter - the letter to mark
  569. Return Value:
  570. None
  571. --*/
  572. {
  573. FDASSERT(!(DriveLetterUsageMap & 0xff000000));
  574. if ((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER)) {
  575. SetDriveLetterUsed(DriveLetter);
  576. }
  577. }
  578. VOID
  579. MarkDriveLetterFree(
  580. IN CHAR DriveLetter
  581. )
  582. /*++
  583. Routine Description:
  584. Given a drive letter, remove it from the usage map, thereby making it available
  585. for reuse.
  586. Arguments:
  587. Drive Letter - the letter to free
  588. Return Value:
  589. None
  590. --*/
  591. {
  592. FDASSERT(!(DriveLetterUsageMap & 0xff000000));
  593. if ((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER)) {
  594. SetDriveLetterFree(DriveLetter);
  595. }
  596. }
  597. BOOL
  598. DriveLetterIsAvailable(
  599. IN CHAR DriveLetter
  600. )
  601. /*++
  602. Routine Description:
  603. Determine if the drive letter given is available for use.
  604. Arguments:
  605. DriveLetter - the letter to check in the usage map
  606. Return Value:
  607. TRUE if it is free and can be used.
  608. FALSE if it is currently in use.
  609. --*/
  610. {
  611. FDASSERT(!(DriveLetterUsageMap & 0xff000000));
  612. FDASSERT((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER));
  613. return !IsDriveLetterUsed(DriveLetter);
  614. }
  615. BOOL
  616. AllDriveLettersAreUsed(
  617. VOID
  618. )
  619. /*++
  620. Routine Description:
  621. Determine if all possible drive letters are in use.
  622. Arguments:
  623. None
  624. Return Value:
  625. TRUE if all letters are in use - FALSE otherwise
  626. --*/
  627. {
  628. FDASSERT(!(DriveLetterUsageMap & 0xff000000));
  629. return(DriveLetterUsageMap == 0x00ffffff);
  630. }
  631. ULONG
  632. GetDiskNumberFromDriveLetter(
  633. IN CHAR DriveLetter
  634. )
  635. /*++
  636. Routine Description:
  637. Given a drive letter return the disk number that contains the partition
  638. that is the drive letter.
  639. Arguments:
  640. DriveLetter - the drive letter to check.
  641. Return Value:
  642. -1 if the letter is invalid.
  643. The disk number for the drive letter if it is valid.
  644. --*/
  645. {
  646. DriveLetter = toupper( DriveLetter );
  647. if (DriveLetter >= 'C' && DriveLetter <= 'Z') {
  648. return DriveLetterDiskNumbers[ DriveLetter - 'C' ];
  649. } else {
  650. return (ULONG)(-1);
  651. }
  652. }
  653. ULONG
  654. GetPartitionNumberFromDriveLetter(
  655. IN CHAR DriveLetter
  656. )
  657. /*++
  658. Routine Description:
  659. Given a drive letter return the numeric value for the partition that
  660. the letter is associated with.
  661. Arguments:
  662. DriveLetter - the letter in question.
  663. Return Value:
  664. -1 if letter is invalid
  665. Partition number for partition that is the drive letter
  666. --*/
  667. {
  668. DriveLetter = toupper( DriveLetter );
  669. if (DriveLetter >= 'C' && DriveLetter <= 'Z') {
  670. return DriveLetterPartitionNumbers[ DriveLetter - 'C' ];
  671. } else {
  672. return (ULONG)(-1);
  673. }
  674. }
  675. CHAR
  676. LocateDriveLetterFromDiskAndPartition(
  677. IN ULONG Disk,
  678. IN ULONG Partition
  679. )
  680. /*++
  681. Routine Description:
  682. Given a disk and partition number return the drive letter assigned to it.
  683. Arguments:
  684. Disk - the disk index
  685. Partition - the partition index
  686. Return Value:
  687. The drive letter for the specific partition or
  688. NO_DRIVE_LETTER_YET if it is not assigned a letter.
  689. --*/
  690. {
  691. unsigned i;
  692. for (i=0; i<24; i++) {
  693. if (Disk == DriveLetterDiskNumbers[i] &&
  694. Partition == DriveLetterPartitionNumbers[i]) {
  695. return((CHAR)(i+(unsigned)(UCHAR)'C'));
  696. }
  697. }
  698. return NO_DRIVE_LETTER_YET;
  699. }
  700. CHAR
  701. LocateDriveLetter(
  702. IN PREGION_DESCRIPTOR Region
  703. )
  704. /*++
  705. Routine Description:
  706. Return the drive letter associated to a region.
  707. Arguments:
  708. Region - the region wanted.
  709. Return Value:
  710. The drive letter or NO_DRIVE_LETTER_YET
  711. --*/
  712. {
  713. PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
  714. if (regionData) {
  715. if (regionData->FtObject) {
  716. if (regionData->DriveLetter) {
  717. return regionData->DriveLetter;
  718. }
  719. }
  720. }
  721. return LocateDriveLetterFromDiskAndPartition(Region->Disk,
  722. Region->OriginalPartitionNumber);
  723. }
  724. #define IsDigitW(digit) (((digit) >= L'0') && ((digit) <= L'9'))
  725. VOID
  726. InitializeDriveLetterInfo(
  727. VOID
  728. )
  729. /*++
  730. Routine Description:
  731. Initialze all of the external support structures for drive letter maintainence.
  732. Arguments:
  733. None
  734. Return Value:
  735. None
  736. --*/
  737. {
  738. WCHAR DriveLetterW;
  739. CHAR DriveLetter = '\0';
  740. PWSTR LinkTarget;
  741. WCHAR DosDevicesName[sizeof(L"\\DosDevices\\A:")];
  742. int DiskNo,
  743. PartNo;
  744. PWSTR Pattern,
  745. String;
  746. DWORD x,
  747. ec;
  748. PFT_OBJECT FtObject;
  749. PFT_OBJECT_SET FtSet;
  750. PREGION_DESCRIPTOR Region;
  751. // Construct list of drives with pagefiles
  752. LoadExistingPageFileInfo();
  753. // Initialize network information.
  754. NetworkInitialize();
  755. // For each drive letter c-z, query the symbolic link.
  756. for (DriveLetterW=L'C'; DriveLetterW<=L'Z'; DriveLetterW++) {
  757. wsprintfW(DosDevicesName, L"%ws%wc:", L"\\DosDevices\\", DriveLetterW);
  758. if ((ec = GetDriveLetterLinkTarget(DosDevicesName, &LinkTarget)) == NO_ERROR) {
  759. // Check if it is a Cdrom
  760. if (_wcsnicmp(LinkTarget, L"\\Device\\CdRom", 13) == 0) {
  761. // Save the information on this CdRom away
  762. CdRomAddDevice(LinkTarget, DriveLetterW);
  763. }
  764. // The drive letter is used because it is linked to something,
  765. // even if we can't figure out what. So mark it used here.
  766. SetDriveLetterUsed(DriveLetterW);
  767. CharUpperW(LinkTarget);
  768. Pattern = L"\\DEVICE\\HARDDISK";
  769. String = LinkTarget;
  770. // Attempt to match the '\device\harddisk' part
  771. for (x=0; x < (sizeof(L"\\DEVICE\\HARDDISK") / sizeof(WCHAR)) - 1; x++) {
  772. if (*Pattern++ != *String++) {
  773. goto next_letter;
  774. }
  775. }
  776. // Now get the hard disk #
  777. if (!IsDigitW(*String)) {
  778. continue;
  779. }
  780. DiskNo = 0;
  781. while (IsDigitW(*String)) {
  782. DiskNo = (DiskNo * 10) + (*String - L'0');
  783. *String++;
  784. }
  785. // Attempt to match the '\partition' part
  786. Pattern = L"\\PARTITION";
  787. for (x=0; x < (sizeof(L"\\PARTITION") / sizeof(WCHAR)) - 1; x++) {
  788. if (*Pattern++ != *String++) {
  789. goto next_letter;
  790. }
  791. }
  792. // Now get the partition #, which cannot be 0
  793. PartNo = 0;
  794. while (IsDigitW(*String)) {
  795. PartNo = (PartNo * 10) + (*String - L'0');
  796. *String++;
  797. }
  798. if (!PartNo) {
  799. continue;
  800. }
  801. // Make sure there is nothing left in the link target's name
  802. if (*String) {
  803. continue;
  804. }
  805. // We understand the link target. Store the disk and partition.
  806. DriveLetterDiskNumbers[DriveLetterW-L'C'] = DiskNo;
  807. DriveLetterPartitionNumbers[DriveLetterW-L'C'] = PartNo;
  808. } else {
  809. if (ec == ERROR_ACCESS_DENIED) {
  810. ErrorDialog(MSG_ACCESS_DENIED);
  811. // BUGBUG When system and workstation manager are the same
  812. // thing, then we'd never have gotten here. We can't just
  813. // send a WM_DESTROY message to hwndFrame because we're not
  814. // in the message loop here -- we end up doing a bunch of
  815. // processing before the quit message is pulled our of the
  816. // queue. So just exit.
  817. SendMessage(hwndFrame,WM_DESTROY,0,0);
  818. exit(1);
  819. }
  820. }
  821. next_letter:
  822. {}
  823. }
  824. // Now for each non-ft, significant region on each disk, figure out its
  825. // drive letter.
  826. for (x=0; x<DiskCount; x++) {
  827. PDISKSTATE ds = Disks[x];
  828. unsigned reg;
  829. for (reg=0; reg<ds->RegionCount; reg++) {
  830. PREGION_DESCRIPTOR region = &ds->RegionArray[reg];
  831. if (DmSignificantRegion(region)) {
  832. // Handle drive letters for FT sets specially.
  833. if (!GET_FT_OBJECT(region)) {
  834. PERSISTENT_DATA(region)->DriveLetter = LocateDriveLetter(region);
  835. }
  836. }
  837. }
  838. // If this is a removable disk, record the reserved drive
  839. // letter for that disk.
  840. if (IsDiskRemovable[x]) {
  841. RemovableDiskReservedDriveLetters[x] = LocateDriveLetterFromDiskAndPartition(x, 1);
  842. } else {
  843. RemovableDiskReservedDriveLetters[x] = NO_DRIVE_LETTER_YET;
  844. }
  845. }
  846. // Now handle ft sets. For each set, loop through the objects twice.
  847. // On the first pass, figure out which object actually is linked to the
  848. // drive letter. On the second pass, assign the drive letter found to
  849. // each of the objects in the set.
  850. for (FtSet = FtObjects; FtSet; FtSet = FtSet->Next) {
  851. for (FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next) {
  852. Region = RegionFromFtObject(FtObject);
  853. if (Region) {
  854. if ((DriveLetter = LocateDriveLetter(Region)) != NO_DRIVE_LETTER_YET) {
  855. break;
  856. }
  857. }
  858. }
  859. for (FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next) {
  860. Region = RegionFromFtObject(FtObject);
  861. if (Region) {
  862. PERSISTENT_DATA(Region)->DriveLetter = DriveLetter;
  863. }
  864. }
  865. }
  866. }
  867. #if DBG
  868. VOID
  869. FdiskAssertFailedRoutine(
  870. IN char *Expression,
  871. IN char *FileName,
  872. IN int LineNumber
  873. )
  874. /*++
  875. Routine Description:
  876. Routine that is called when an assertion fails in the debug version.
  877. Throw up a list box giving appriopriate information and terminate
  878. the program.
  879. Arguments:
  880. Source - source (ansi ascii) string
  881. Dest - destination string or wide string
  882. Return Value:
  883. None.
  884. --*/
  885. {
  886. char text[500];
  887. wsprintf(text,
  888. "Line #%u in File '%s'\n[%s]\n\nClick OK to exit.",
  889. LineNumber,
  890. FileName,
  891. Expression
  892. );
  893. MessageBoxA(NULL,text,"Assertion Failure",MB_TASKMODAL | MB_OK);
  894. exit(1);
  895. }
  896. #include <stdio.h>
  897. PVOID LogFile;
  898. int LoggingLevel = 1000;
  899. VOID
  900. InitLogging(
  901. VOID
  902. )
  903. /*++
  904. Routine Description:
  905. Open the log file for debug logging.
  906. Arguments:
  907. None
  908. Return Value:
  909. None
  910. --*/
  911. {
  912. LogFile = (PVOID)fopen("c:\\fdisk.log","wt");
  913. if(LogFile == NULL) {
  914. MessageBox(GetActiveWindow(),"Can't open log file; logging turned off","DEBUG",MB_SYSTEMMODAL|MB_OK);
  915. LoggingLevel = -1;
  916. }
  917. }
  918. VOID
  919. FdLog(
  920. IN int Level,
  921. IN PCHAR FormatString,
  922. ...
  923. )
  924. /*++
  925. Routine Description:
  926. Write a line into the log file for debugging.
  927. Arguments:
  928. Debug level and "printf" like argument string.
  929. Return Value:
  930. None
  931. --*/
  932. {
  933. va_list arglist;
  934. if(Level <= LoggingLevel) {
  935. va_start(arglist,FormatString);
  936. if(vfprintf((FILE *)LogFile,FormatString,arglist) < 0) {
  937. LoggingLevel = -1;
  938. MessageBox(GetActiveWindow(),"Error writing to log file; logging turned off","DEBUG",MB_SYSTEMMODAL|MB_OK);
  939. fclose((FILE *)LogFile);
  940. } else {
  941. fflush((FILE *)LogFile);
  942. }
  943. va_end(arglist);
  944. }
  945. }
  946. VOID
  947. LOG_DISK_REGISTRY(
  948. IN PCHAR RoutineName,
  949. IN PDISK_REGISTRY DiskRegistry
  950. )
  951. /*++
  952. Routine Description:
  953. Log what was in the disk registry into the debugging log file.
  954. Arguments:
  955. RoutineName - calling routines name
  956. DiskRegistry - registry information for disks
  957. Return Value:
  958. None
  959. --*/
  960. {
  961. ULONG i;
  962. PDISK_DESCRIPTION diskDesc;
  963. FDLOG((2,"%s: %u disks; registry info follows:\n",RoutineName,DiskRegistry->NumberOfDisks));
  964. diskDesc = DiskRegistry->Disks;
  965. for(i=0; i<DiskRegistry->NumberOfDisks; i++) {
  966. LOG_ONE_DISK_REGISTRY_DISK_ENTRY(NULL,diskDesc);
  967. diskDesc = (PDISK_DESCRIPTION)&diskDesc->Partitions[diskDesc->NumberOfPartitions];
  968. }
  969. }
  970. VOID
  971. LOG_ONE_DISK_REGISTRY_DISK_ENTRY(
  972. IN PCHAR RoutineName OPTIONAL,
  973. IN PDISK_DESCRIPTION DiskDescription
  974. )
  975. /*++
  976. Routine Description:
  977. This routine walks through the partition information from
  978. the registry for a single disk and writes lines in the
  979. debugging log file.
  980. Arguments:
  981. RoutineName - the name of the calling routine
  982. DiskDescription - the disk description portion of the registry
  983. Return Value:
  984. None
  985. --*/
  986. {
  987. USHORT j;
  988. PDISK_PARTITION partDesc;
  989. PDISK_DESCRIPTION diskDesc = DiskDescription;
  990. if(ARGUMENT_PRESENT(RoutineName)) {
  991. FDLOG((2,"%s: disk registry entry follows:\n",RoutineName));
  992. }
  993. FDLOG((2," Disk signature : %08lx\n",diskDesc->Signature));
  994. FDLOG((2," Partition count: %u\n",diskDesc->NumberOfPartitions));
  995. if(diskDesc->NumberOfPartitions) {
  996. FDLOG((2," # Dr FtTyp FtGrp FtMem Start Length\n"));
  997. }
  998. for(j=0; j<diskDesc->NumberOfPartitions; j++) {
  999. CHAR dr1,dr2;
  1000. partDesc = &diskDesc->Partitions[j];
  1001. if(partDesc->AssignDriveLetter) {
  1002. if(partDesc->DriveLetter) {
  1003. dr1 = partDesc->DriveLetter;
  1004. dr2 = ':';
  1005. } else {
  1006. dr1 = dr2 = ' ';
  1007. }
  1008. } else {
  1009. dr1 = 'n';
  1010. dr2 = 'o';
  1011. }
  1012. FDLOG((2,
  1013. " %02u %c%c %-5u %-5u %-5u %08lx:%08lx %08lx:%08lx\n",
  1014. partDesc->LogicalNumber,
  1015. dr1,dr2,
  1016. partDesc->FtType,
  1017. partDesc->FtGroup,
  1018. partDesc->FtMember,
  1019. partDesc->StartingOffset.HighPart,
  1020. partDesc->StartingOffset.LowPart,
  1021. partDesc->Length.HighPart,
  1022. partDesc->Length.LowPart
  1023. ));
  1024. }
  1025. }
  1026. VOID
  1027. LOG_DRIVE_LAYOUT(
  1028. IN PDRIVE_LAYOUT_INFORMATION DriveLayout
  1029. )
  1030. /*++
  1031. Routine Description:
  1032. Write the drive layout into the debugging log file.
  1033. Arguments:
  1034. DriveLayout - the layout to write
  1035. Return Value:
  1036. None
  1037. --*/
  1038. {
  1039. ULONG i;
  1040. FDLOG((2," Disk signature : %08lx\n",DriveLayout->Signature));
  1041. FDLOG((2," Partition count: %u\n",DriveLayout->PartitionCount));
  1042. for(i=0; i<DriveLayout->PartitionCount; i++) {
  1043. if(!i) {
  1044. FDLOG((2," ID Active Recog Start Size Hidden\n"));
  1045. }
  1046. FDLOG((2,
  1047. " %02x %s %s %08lx:%08lx %08lx:%08lx %08lx\n",
  1048. DriveLayout->PartitionEntry[i].PartitionType,
  1049. DriveLayout->PartitionEntry[i].BootIndicator ? "yes" : "no ",
  1050. DriveLayout->PartitionEntry[i].RecognizedPartition ? "yes" : "no ",
  1051. DriveLayout->PartitionEntry[i].StartingOffset.HighPart,
  1052. DriveLayout->PartitionEntry[i].StartingOffset.LowPart,
  1053. DriveLayout->PartitionEntry[i].PartitionLength.HighPart,
  1054. DriveLayout->PartitionEntry[i].PartitionLength.LowPart,
  1055. DriveLayout->PartitionEntry[i].HiddenSectors
  1056. ));
  1057. }
  1058. }
  1059. #endif