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.

5549 lines
153 KiB

  1. /*++
  2. Copyright (c) 1991-1994 Microsoft Corporation
  3. Module Name:
  4. windisk.c
  5. Abstract:
  6. This module contains the main dialog and support routines for
  7. Disk Administrator.
  8. Author:
  9. Edward (Ted) Miller (TedM) 11/15/91
  10. Environment:
  11. User process.
  12. Notes:
  13. Revision History:
  14. 11-Nov-93 (bobri) added doublespace and commit support.
  15. --*/
  16. #include "fdisk.h"
  17. #include "shellapi.h"
  18. #include <string.h>
  19. #include <stdio.h>
  20. #if DBG && DEVL
  21. // stuff used in debug version
  22. BOOL AllowAllDeletes = FALSE; // whether to allow deleting boot/sys parts
  23. #endif
  24. // External from fdinit.
  25. extern HWND InitDlg;
  26. extern BOOLEAN InitDlgComplete;
  27. extern BOOLEAN StartedAsIcon;
  28. HANDLE hAccelerator;
  29. // This is the maximum number of members that WinDisk will support
  30. // in an FT Set.
  31. #define MaxMembersInFtSet 32
  32. // The following vars keep track of the currently selected regions.
  33. DWORD SelectionCount = 0;
  34. PDISKSTATE SelectedDS[MaxMembersInFtSet];
  35. ULONG SelectedRG[MaxMembersInFtSet];
  36. #define SELECTED_REGION(i) (SelectedDS[i]->RegionArray[SelectedRG[i]])
  37. FT_TYPE FtSelectionType;
  38. // This variable tracks whether the system partition is secure.
  39. BOOL SystemPartitionIsSecure = FALSE;
  40. // Deleted a partition with no drive letter
  41. BOOLEAN CommitDueToDelete = FALSE;
  42. BOOLEAN CommitDueToMirror = FALSE;
  43. BOOLEAN CommitDueToExtended = FALSE;
  44. // If a mirror is made of the boot partition, this will become
  45. // non-zero and indicate which disk should get some boot code in
  46. // the MBR.
  47. ULONG UpdateMbrOnDisk = 0;
  48. #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
  49. // If FmIfs.dll doesn't have double space routines this
  50. // flag will reflect that fact.
  51. extern BOOLEAN DoubleSpaceSupported;
  52. BOOLEAN DoubleSpaceAutomount;
  53. #endif
  54. VOID
  55. FrameCommandHandler(
  56. IN HWND hwnd,
  57. IN DWORD wParam,
  58. IN LONG lParam
  59. );
  60. DWORD
  61. SetUpMenu(
  62. IN PDISKSTATE *SinglySelectedDisk,
  63. IN DWORD *SinglySelectedRegion
  64. );
  65. BOOL
  66. AssignDriveLetter(
  67. IN BOOL WarnIfNoLetter,
  68. IN DWORD StringId,
  69. OUT PCHAR DriveLetter
  70. );
  71. VOID
  72. AdjustOptionsMenu(
  73. VOID
  74. );
  75. ULONG
  76. PartitionCount(
  77. IN ULONG Disk
  78. );
  79. VOID
  80. CheckForBootNumberChange(
  81. IN ULONG Disk
  82. )
  83. /*++
  84. Routine Description:
  85. Determine if the disk that has just changed is the boot disk.
  86. If so, determine if the boot partition number changed. If it
  87. did, warn the user.
  88. Arguments:
  89. RegionDescriptor - the region that has just changed.
  90. Return Value:
  91. None
  92. --*/
  93. {
  94. ULONG newPart;
  95. CHAR oldNumberString[8],
  96. newNumberString[8];
  97. DWORD msgCode;
  98. if (Disk == BootDiskNumber) {
  99. // Pass a pointer to Disk even though this is just to get the
  100. // old partition number back.
  101. if (BootPartitionNumberChanged(&Disk, &newPart)) {
  102. #if i386
  103. msgCode = MSG_CHANGED_BOOT_PARTITION_X86;
  104. #else
  105. msgCode = MSG_CHANGED_BOOT_PARTITION_ARC;
  106. #endif
  107. sprintf(oldNumberString, "%d", Disk);
  108. sprintf(newNumberString, "%d", newPart);
  109. InfoDialog(msgCode, oldNumberString, newNumberString);
  110. }
  111. }
  112. }
  113. BOOL
  114. IsSystemPartitionSecure(
  115. )
  116. /*++
  117. Routine Description:
  118. This routine knows where to go in the Registry to determine
  119. if the system partition for this boot is to be protected from
  120. modification.
  121. Arguments:
  122. None
  123. Return Value:
  124. TRUE if the system partition is secure
  125. FALSE otherwise.
  126. --*/
  127. {
  128. LONG ec;
  129. HKEY hkey;
  130. DWORD type;
  131. DWORD size;
  132. ULONG value;
  133. value = FALSE;
  134. ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  135. TEXT("System\\CurrentControlSet\\Control\\Lsa"),
  136. 0,
  137. KEY_QUERY_VALUE,
  138. &hkey);
  139. if (ec == NO_ERROR) {
  140. size = sizeof(ULONG);
  141. ec = RegQueryValueExA(hkey,
  142. TEXT("Protect System Partition"),
  143. NULL,
  144. &type,
  145. (PBYTE)&value,
  146. &size);
  147. if ((ec != NO_ERROR) || (type != REG_DWORD)) {
  148. value = FALSE;
  149. }
  150. RegCloseKey(hkey);
  151. }
  152. return value;
  153. }
  154. VOID __cdecl
  155. main(
  156. IN int argc,
  157. IN char *argv[],
  158. IN char *envp[]
  159. )
  160. /*++
  161. Routine Description:
  162. This is were control is given to Disk Administrator when it
  163. is started. This routine initializes the application and
  164. contains the control loop for getting and processing Windows
  165. messages.
  166. Arguments:
  167. Standard "main" entry
  168. Return Value:
  169. Standard "main" entry
  170. --*/
  171. {
  172. MSG msg;
  173. NTSTATUS status;
  174. HANDLE mutex;
  175. hModule = GetModuleHandle(NULL);
  176. mutex = CreateMutex(NULL,FALSE,"Disk Administrator Is Running");
  177. if (mutex == NULL) {
  178. // An error (like out of memory) has occurred.
  179. return;
  180. }
  181. // Make sure we are the only process with a handle to our named mutex.
  182. if (GetLastError() == ERROR_ALREADY_EXISTS) {
  183. CloseHandle(mutex);
  184. InfoDialog(MSG_ALREADY_RUNNING);
  185. return;
  186. } else {
  187. DisplayInitializationMessage();
  188. }
  189. // Determine whether this is LanmanNt or Windows NT by looking at
  190. // HKEY_LOCAL_MACHINE,System\CurrentControlSet\Control\ProductOptions.
  191. // If the ProductType value therein is "LanmanNt" then this is LanmanNt.
  192. {
  193. LONG ec;
  194. HKEY hkey;
  195. DWORD type;
  196. DWORD size;
  197. UCHAR buf[100];
  198. IsLanmanNt = FALSE;
  199. #if DBG
  200. // The code below will allow users to run WinDisk in Lanman
  201. // mode on WinNt. It should never be enabled in a released
  202. // build, but is very useful for internal users.
  203. if (argc >= 2 && !_stricmp(argv[1], "-p:lanman")) {
  204. IsLanmanNt = TRUE;
  205. }
  206. #endif
  207. ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  208. TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
  209. 0,
  210. KEY_QUERY_VALUE,
  211. &hkey);
  212. if (ec == NO_ERROR) {
  213. size = sizeof(buf);
  214. ec = RegQueryValueExA(hkey,
  215. TEXT("ProductType"),
  216. NULL,
  217. &type,
  218. buf,
  219. &size);
  220. if ((ec == NO_ERROR) && (type == REG_SZ)) {
  221. if (!lstrcmpiA(buf,"lanmannt")) {
  222. IsLanmanNt = TRUE;
  223. }
  224. if (!lstrcmpiA(buf,"servernt")) {
  225. IsLanmanNt = TRUE;
  226. }
  227. }
  228. RegCloseKey(hkey);
  229. }
  230. }
  231. // Set the Help file name to the file appropriate to
  232. // the product.
  233. HelpFile = IsLanmanNt ? LanmanHelpFile : WinHelpFile;
  234. // Determine whether the system partition is protected:
  235. SystemPartitionIsSecure = IsSystemPartitionSecure();
  236. try {
  237. #if DBG
  238. InitLogging();
  239. #endif
  240. // Insure that all drives are present before looking.
  241. RescanDevices();
  242. if (!NT_SUCCESS(status = FdiskInitialize())) {
  243. ErrorDialog(status == STATUS_ACCESS_DENIED ? MSG_ACCESS_DENIED : EC(status));
  244. goto xx1;
  245. }
  246. if (((DiskCount = GetDiskCount()) == 0) || AllDisksOffLine()) {
  247. ErrorDialog(MSG_NO_DISKS);
  248. goto xx2;
  249. }
  250. if (!InitializeApp()) {
  251. ErrorDialog(MSG_CANT_CREATE_WINDOWS);
  252. goto xx2;
  253. }
  254. InitRectControl();
  255. SetUpMenu(&SingleSel,&SingleSelIndex);
  256. AdjustOptionsMenu();
  257. InitHelp();
  258. hAccelerator = LoadAccelerators(hModule, TEXT("MainAcc"));
  259. if (InitDlg) {
  260. PostMessage(InitDlg,
  261. (WM_USER + 1),
  262. 0,
  263. 0);
  264. InitDlg = (HWND) 0;
  265. }
  266. while (GetMessage(&msg,NULL,0,0)) {
  267. if (!TranslateAccelerator(hwndFrame, hAccelerator, &msg)) {
  268. TranslateMessage(&msg);
  269. DispatchMessage(&msg);
  270. }
  271. }
  272. TermHelp();
  273. UnloadIfsDll();
  274. xx2:
  275. FdiskCleanUp();
  276. xx1:
  277. ;
  278. } finally {
  279. // Destroy the mutex.
  280. CloseHandle(mutex);
  281. }
  282. }
  283. LONG
  284. MyFrameWndProc(
  285. IN HWND hwnd,
  286. IN UINT msg,
  287. IN UINT wParam,
  288. IN LONG lParam
  289. )
  290. /*++
  291. Routine Description:
  292. This is the window handler for the main display of Disk Administrator.
  293. Arguments:
  294. Standard window handler procedure
  295. Return Value:
  296. Standard window handler procedure
  297. --*/
  298. {
  299. static BOOLEAN oneTime = TRUE;
  300. PMEASUREITEMSTRUCT pMeasureItem;
  301. DWORD ec;
  302. DWORD action;
  303. DWORD temp;
  304. RECT rc;
  305. BOOL profileWritten,
  306. changesMade,
  307. mustReboot,
  308. configureFt;
  309. HMENU hMenu;
  310. switch (msg) {
  311. case WM_CREATE:
  312. // create the listbox
  313. if (!StartedAsIcon) {
  314. StartedAsIcon = IsIconic(hwnd);
  315. }
  316. GetClientRect(hwnd,&rc);
  317. #if 1
  318. hwndList = CreateWindow(TEXT("listbox"),
  319. NULL,
  320. WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | LBS_NOTIFY |
  321. LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED,
  322. 0,
  323. dyLegend,
  324. rc.right - rc.left,
  325. rc.bottom - rc.top - (StatusBar ? dyStatus : 0) - (Legend ? dyLegend : 0),
  326. hwnd,
  327. (HMENU)ID_LISTBOX,
  328. hModule,
  329. NULL);
  330. #else
  331. hwndList = CreateWindow(TEXT("listbox"),
  332. NULL,
  333. WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | LBS_NOTIFY |
  334. LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED,
  335. 0,
  336. dyLegend,
  337. CW_USEDEFAULT,
  338. CW_USEDEFAULT,
  339. hwnd,
  340. (HMENU)ID_LISTBOX,
  341. hModule,
  342. NULL);
  343. #endif
  344. if (hwndList) {
  345. SetFocus(hwndList);
  346. // subclass the listbox so we can handle keyboard
  347. // input our way.
  348. SubclassListBox(hwndList);
  349. }
  350. // If we are not running the LanmanNt version of
  351. // Windisk, remove the Fault-Tolerance menu item.
  352. if (!IsLanmanNt && (hMenu = GetMenu( hwnd )) != NULL ) {
  353. DeleteMenu( hMenu, 1, MF_BYPOSITION );
  354. DrawMenuBar( hwnd );
  355. }
  356. StatusTextDrlt[0] = 0;
  357. StatusTextStat[0] = StatusTextSize[0] = 0;
  358. StatusTextType[0] = StatusTextVoll[0] = 0;
  359. break;
  360. case WM_SETFOCUS:
  361. SetFocus(hwndList);
  362. break;
  363. case WM_WININICHANGE:
  364. if ((lParam == (LONG)NULL) || !lstrcmpi((LPTSTR)lParam,TEXT("colors"))) {
  365. TotalRedrawAndRepaint();
  366. InvalidateRect(hwnd,NULL,FALSE);
  367. }
  368. break;
  369. case WM_SIZE:
  370. // resize the listbox
  371. GetClientRect(hwnd,&rc);
  372. #if 0
  373. temp = rc.right - rc.left;
  374. if (GraphWidth != temp) {
  375. GraphWidth = temp;
  376. BarWidth = GraphWidth - dxBarTextMargin;
  377. }
  378. #endif
  379. MoveWindow(hwndList,
  380. rc.left,
  381. rc.top,
  382. rc.right - rc.left,
  383. rc.bottom - rc.top - (StatusBar ? dyStatus : 0) - (Legend ? dyLegend : 0),
  384. TRUE);
  385. // invalidate status/legend area so that the clipping
  386. // rectangle is right for redraws
  387. rc.top = rc.bottom;
  388. if (StatusBar) {
  389. rc.top -= dyStatus;
  390. }
  391. if (Legend) {
  392. rc.top -= dyLegend;
  393. }
  394. if (rc.top != rc.bottom) {
  395. InvalidateRect(hwnd,&rc,FALSE);
  396. }
  397. // FALL THROUGH
  398. case WM_MOVE:
  399. // if not iconic or minimized, save new position for profile
  400. if (!IsZoomed(hwndFrame) && !IsIconic(hwndFrame)) {
  401. GetWindowRect(hwndFrame,&rc);
  402. ProfileWindowX = rc.left;
  403. ProfileWindowY = rc.top;
  404. ProfileWindowW = rc.right - rc.left;
  405. ProfileWindowH = rc.bottom - rc.top;
  406. }
  407. break;
  408. case WM_ENTERIDLE:
  409. if (ConfigurationSearchIdleTrigger == TRUE && wParam == MSGF_DIALOGBOX) {
  410. PostMessage((HWND)lParam,WM_ENTERIDLE,wParam,lParam);
  411. } else {
  412. // If we're coming from a dialog box and the F1 key is down,
  413. // kick the dialog box and make it spit out help.
  414. if ((wParam == MSGF_DIALOGBOX) &&
  415. (GetKeyState(VK_F1) & 0x8000) &&
  416. GetDlgItem((HANDLE) lParam, FD_IDHELP)) {
  417. PostMessage((HANDLE) lParam, WM_COMMAND, FD_IDHELP, 0L);
  418. }
  419. }
  420. return 1; // indicate we did not process the message
  421. case WM_PAINT:
  422. #if 1
  423. if ((!IsIconic(hwnd)) && !(InitDlg && StartedAsIcon)) {
  424. #else
  425. if (!StartedAsIcon) {
  426. #endif
  427. HDC hdcTemp,hdcScr;
  428. HBITMAP hbmTemp;
  429. PAINTSTRUCT ps;
  430. HBRUSH hBrush;
  431. HFONT hFontOld;
  432. RECT rcTemp,rcTemp2;
  433. DWORD ClientRight;
  434. BeginPaint(hwnd,&ps);
  435. hdcScr = ps.hdc;
  436. GetClientRect(hwnd,&rc);
  437. rcTemp2 = rc;
  438. ClientRight = rc.right;
  439. rc.top = rc.bottom - dyStatus + dyBorder;
  440. if (StatusBar) {
  441. hdcTemp = CreateCompatibleDC(hdcScr);
  442. hbmTemp = CreateCompatibleBitmap(hdcScr,rc.right-rc.left+1,rc.bottom-rc.top+1);
  443. SelectObject(hdcTemp,hbmTemp);
  444. // adjust position for off-screen bitmap
  445. rcTemp = rc;
  446. rc.bottom -= rc.top;
  447. rc.top = 0;
  448. hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  449. if (hBrush) {
  450. FillRect(hdcTemp,&rc,hBrush);
  451. DeleteObject(hBrush);
  452. }
  453. // draw the status bar at the bottom of the window
  454. hFontOld = SelectObject(hdcTemp,hFontStatus);
  455. // Status text
  456. rc.left = 8 * dyBorder;
  457. rc.right = 2 * GraphWidth / 5;
  458. DrawStatusAreaItem(&rc,hdcTemp,StatusTextStat,FALSE);
  459. // size
  460. rc.left = rc.right + (8*dyBorder);
  461. rc.right = rc.left + (GraphWidth / 9);
  462. DrawStatusAreaItem(&rc,hdcTemp,StatusTextSize,FALSE);
  463. // type
  464. rc.left = rc.right + (8*dyBorder);
  465. rc.right = rc.left + (GraphWidth / 5);
  466. DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextType,TRUE);
  467. // drive letter
  468. rc.left = rc.right + (8*dyBorder);
  469. rc.right = rc.left + (8*dyBorder) + dxDriveLetterStatusArea;
  470. DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextDrlt,TRUE);
  471. // vol label
  472. rc.left = rc.right + (8*dyBorder);
  473. rc.right = GraphWidth - (8*dyBorder);
  474. DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextVoll,TRUE);
  475. BitBlt(hdcScr,
  476. rcTemp.left,
  477. rcTemp.top,
  478. rcTemp.right-rcTemp.left+1,
  479. rcTemp.bottom-rcTemp.top+1,
  480. hdcTemp,
  481. 0,
  482. 0,
  483. SRCCOPY);
  484. if (hFontOld) {
  485. SelectObject(hdcTemp,hFontOld);
  486. }
  487. DeleteObject(hbmTemp);
  488. DeleteDC(hdcTemp);
  489. } else {
  490. rcTemp = rcTemp2;
  491. rcTemp.top = rcTemp.bottom;
  492. }
  493. if (Legend) {
  494. // draw the legend onto the screen
  495. if (StatusBar) {
  496. rcTemp2.bottom -= dyStatus;
  497. }
  498. rcTemp2.top = rcTemp2.bottom - dyLegend + (2*dyBorder);
  499. if (StatusBar) {
  500. rcTemp2.top += dyBorder;
  501. }
  502. rcTemp2.right = GraphWidth;
  503. DrawLegend(hdcScr,&rcTemp2);
  504. }
  505. // dark line across top of status/legend area
  506. if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNTEXT))) {
  507. if (StatusBar || Legend) {
  508. rcTemp.bottom = rcTemp.top;
  509. if (Legend) {
  510. rcTemp.bottom -= dyLegend - 1;
  511. rcTemp.top -= dyLegend - 1;
  512. }
  513. rcTemp.top -= dyBorder;
  514. FillRect(hdcScr,&rcTemp,hBrush);
  515. }
  516. DeleteObject(hBrush);
  517. }
  518. EndPaint(hwnd,&ps);
  519. }
  520. if (InitDlg) {
  521. if (InitDlgComplete) {
  522. PostMessage(InitDlg,
  523. (WM_USER + 1),
  524. 0,
  525. 0);
  526. InitDlg = (HWND) 0;
  527. }
  528. }
  529. if (oneTime) {
  530. if (!StartedAsIcon) {
  531. SetForegroundWindow(hwnd);
  532. }
  533. oneTime = FALSE;
  534. }
  535. break;
  536. case WM_COMMAND:
  537. FrameCommandHandler(hwnd,wParam,lParam);
  538. break;
  539. case WM_MEASUREITEM:
  540. pMeasureItem = (PMEASUREITEMSTRUCT)lParam;
  541. pMeasureItem->itemHeight = GraphHeight;
  542. break;
  543. case WM_DRAWITEM:
  544. WMDrawItem((PDRAWITEMSTRUCT)lParam);
  545. break;
  546. case WM_CTLCOLORLISTBOX:
  547. if (lParam == (LONG)hwndList) {
  548. return (LONG)GetStockObject(LTGRAY_BRUSH);
  549. } else {
  550. return DefWindowProc(hwnd,msg,wParam,lParam);
  551. }
  552. case WM_CLOSE:
  553. // Determine whether any disks have been changed, and whether
  554. // the system must be rebooted. The system must be rebooted
  555. // if the registry has changed, if any non-removable disk has
  556. // changed, or if any removable disk that was not originally
  557. // unpartitioned has changed.
  558. changesMade = FALSE;
  559. configureFt = FALSE;
  560. mustReboot = RestartRequired;
  561. for (temp=0; temp<DiskCount; temp++) {
  562. if (HavePartitionsBeenChanged(temp)) {
  563. changesMade = TRUE;
  564. break;
  565. }
  566. }
  567. profileWritten = FALSE;
  568. // Determine if the commit can be done without a reboot.
  569. // If FT is in the system then it must be notified to
  570. // reconfigure if a reboot is not performed. If it is
  571. // not in the system, but the new disk information requires
  572. // it, then a reboot must be forced.
  573. if (FtInstalled()) {
  574. configureFt = TRUE;
  575. }
  576. if (NewConfigurationRequiresFt()) {
  577. if (!configureFt) {
  578. // The FT driver is not loaded currently.
  579. mustReboot = TRUE;
  580. } else {
  581. // If the system is going to be rebooted, don't
  582. // have FT reconfigure prior to shutdown.
  583. if (mustReboot) {
  584. configureFt = FALSE;
  585. }
  586. }
  587. }
  588. if (RegistryChanged | changesMade | RestartRequired) {
  589. if (RestartRequired) {
  590. action = IDYES;
  591. } else {
  592. action = ConfirmationDialog(MSG_CONFIRM_EXIT, MB_ICONQUESTION | MB_YESNOCANCEL);
  593. }
  594. if (action == IDYES) {
  595. ec = CommitLockVolumes(0);
  596. if (ec) {
  597. // could not lock all volumes
  598. ErrorDialog(MSG_CANNOT_LOCK_FOR_COMMIT);
  599. CommitUnlockVolumes(DiskCount, FALSE);
  600. break;
  601. }
  602. if (mustReboot) {
  603. if (RestartRequired) {
  604. action = IDYES;
  605. } else {
  606. action = ConfirmationDialog(MSG_REQUIRE_REBOOT, MB_ICONQUESTION | MB_YESNO);
  607. }
  608. if (action != IDYES) {
  609. CommitUnlockVolumes(DiskCount, FALSE);
  610. break;
  611. }
  612. }
  613. SetCursor(hcurWait);
  614. ec = CommitChanges();
  615. SetCursor(hcurNormal);
  616. CommitUnlockVolumes(DiskCount, TRUE);
  617. if (ec != NO_ERROR) {
  618. ErrorDialog(MSG_BAD_CONFIG_SET);
  619. } else {
  620. ULONG oldBootPartitionNumber,
  621. newBootPartitionNumber;
  622. CHAR oldNumberString[8],
  623. newNumberString[8];
  624. DWORD msgCode;
  625. // Update the configuration registry
  626. ec = SaveFt();
  627. if (configureFt) {
  628. // Issue device control to ftdisk driver to reconfigure.
  629. FtConfigure();
  630. }
  631. // Register autochk to fix up file systems
  632. // in newly extended volume sets, if necessary
  633. if (RegisterFileSystemExtend()) {
  634. mustReboot = TRUE;
  635. }
  636. // Determine if the FT driver must be enabled.
  637. if (DiskRegistryRequiresFt() == TRUE) {
  638. if (!FtInstalled()) {
  639. mustReboot = TRUE;
  640. }
  641. DiskRegistryEnableFt();
  642. } else {
  643. DiskRegistryDisableFt();
  644. }
  645. if (ec == NO_ERROR) {
  646. InfoDialog(MSG_OK_COMMIT);
  647. } else {
  648. ErrorDialog(MSG_BAD_CONFIG_SET);
  649. }
  650. // Has the partition number of the boot
  651. // partition changed?
  652. if (BootPartitionNumberChanged(&oldBootPartitionNumber, &newBootPartitionNumber)) {
  653. #if i386
  654. msgCode = MSG_BOOT_PARTITION_CHANGED_X86;
  655. #else
  656. msgCode = MSG_BOOT_PARTITION_CHANGED_ARC;
  657. #endif
  658. sprintf(oldNumberString, "%d", oldBootPartitionNumber);
  659. sprintf(newNumberString, "%d", newBootPartitionNumber);
  660. InfoDialog(msgCode, oldNumberString, newNumberString);
  661. }
  662. ClearCommittedDiskInformation();
  663. if (UpdateMbrOnDisk) {
  664. UpdateMasterBootCode(UpdateMbrOnDisk);
  665. UpdateMbrOnDisk = 0;
  666. }
  667. // Reboot if necessary.
  668. if (mustReboot) {
  669. SetCursor(hcurWait);
  670. Sleep(5000);
  671. SetCursor(hcurNormal);
  672. FdShutdownTheSystem();
  673. profileWritten = TRUE;
  674. }
  675. CommitDueToDelete = CommitDueToMirror = FALSE;
  676. CommitAssignLetterList();
  677. }
  678. } else if (action == IDCANCEL) {
  679. return 0; // don't exit
  680. } else {
  681. FDASSERT(action == IDNO);
  682. }
  683. }
  684. if (!profileWritten) {
  685. WriteProfile();
  686. }
  687. DestroyWindow(hwnd);
  688. break;
  689. case WM_DESTROY:
  690. // BUGBUG clean up here -- release dc's, free DiskStates, etc.
  691. WinHelp(hwndFrame,HelpFile,HELP_QUIT,0);
  692. PostQuitMessage(0);
  693. break;
  694. case WM_MENUSELECT:
  695. SetMenuItemHelpContext(wParam,lParam);
  696. break;
  697. case WM_F1DOWN:
  698. Help(wParam);
  699. break;
  700. default:
  701. return DefWindowProc(hwnd, msg, wParam, lParam);
  702. }
  703. return 0;
  704. }
  705. #if i386
  706. VOID
  707. SetUpMenui386(
  708. HMENU hMenu,
  709. DWORD SelectionCount
  710. )
  711. /*++
  712. Routine Description:
  713. X86 SPECIFIC
  714. This routine understands the X86 specific feature of
  715. "Active Partition". It determines if the "set partition
  716. active" menu item should be enabled.
  717. Arguments:
  718. hMenu - menu handle
  719. SelectionCount - number of items currently selected.
  720. Return Value:
  721. None
  722. --*/
  723. {
  724. BOOL allowActive = FALSE;
  725. PREGION_DESCRIPTOR regionDescriptor;
  726. if ((SelectionCount == 1) && (FtSelectionType == -1)) {
  727. regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
  728. // allow it to be made active if
  729. // - it is not free space
  730. // - it is a primary partition
  731. // - it is on disk 0
  732. // - it is not already active
  733. // - it is not part of an ft set
  734. if ((regionDescriptor->SysID != SYSID_UNUSED)
  735. && (regionDescriptor->RegionType == REGION_PRIMARY)
  736. && !regionDescriptor->Active
  737. && (GET_FT_OBJECT(regionDescriptor) == NULL)) {
  738. allowActive = TRUE;
  739. }
  740. }
  741. EnableMenuItem(hMenu,
  742. IDM_PARTITIONACTIVE,
  743. allowActive ? MF_ENABLED : MF_GRAYED);
  744. }
  745. #endif
  746. DWORD
  747. SetUpMenu(
  748. IN PDISKSTATE *SinglySelectedDisk,
  749. IN DWORD *SinglySelectedRegion
  750. )
  751. /*++
  752. Routine Description:
  753. This routine sets up the menu bar based on the state of the app and
  754. the disks.
  755. If multiple items are selected, allow neither create nor delete.
  756. If a single partition is selected, allow delete.
  757. If a single free space is selected, allow create.
  758. If the free space is the only free space in the extended partitions,
  759. also allow delete. (This is how to delete the extended partition).
  760. Arguments:
  761. SinglySelectedDisk -- if there is only one selected item, the PDISKSTATE
  762. pointed to by this paramater will get a pointer
  763. to the selected region's disk structure. If there are
  764. multiple selected items (or none), then the value
  765. will be set to NULL.
  766. SinglySelectedRegion -- if there is only one selected item, the DWORD
  767. pointed to by this paramater will get the selected
  768. region #. Otherwise the DWORD gets -1.
  769. Return Value:
  770. Count of selected regions.
  771. --*/
  772. {
  773. BOOL allowCreate = FALSE,
  774. allowCreateEx = FALSE,
  775. allowDelete = FALSE,
  776. allowFormat = FALSE,
  777. allowLabel = FALSE,
  778. allowBreakMirror = FALSE,
  779. allowCreateMirror = FALSE,
  780. allowCreateStripe = FALSE,
  781. allowCreateVolumeSet = FALSE,
  782. allowExtendVolumeSet = FALSE,
  783. allowCreatePStripe = FALSE,
  784. allowDriveLetter = FALSE,
  785. allowRecoverParity = FALSE,
  786. ftSetSelected = FALSE,
  787. nonFtItemSelected = FALSE,
  788. multipleItemsSelected = FALSE,
  789. volumeSetAndFreeSpaceSelected = FALSE,
  790. onDifferentDisks,
  791. possibleRecover;
  792. BOOL allowCommit = CommitAllowed();
  793. WCHAR driveLetter = L' ';
  794. PWSTR typeName = NULL,
  795. volumeLabel = NULL;
  796. PDISKSTATE diskState,
  797. selDiskState = NULL;
  798. DWORD i,
  799. j,
  800. selectedRegion = 0;
  801. ULONG ordinal = 0,
  802. selectedFreeSpaces = 0,
  803. freeSpaceIndex = 0,
  804. componentsInFtSet = 0,
  805. selectedNonFtPartitions = 0;
  806. HMENU hMenu = GetMenu(hwndFrame);
  807. FT_TYPE type = (FT_TYPE) 0;
  808. PULONG diskSeenCounts;
  809. PFT_OBJECT_SET ftSet = NULL;
  810. PFT_OBJECT ftObject = NULL;
  811. PREGION_DESCRIPTOR regionDescriptor;
  812. PPERSISTENT_REGION_DATA regionData;
  813. diskSeenCounts = Malloc(DiskCount * sizeof(ULONG));
  814. RtlZeroMemory(diskSeenCounts,DiskCount * sizeof(ULONG));
  815. SelectionCount = 0;
  816. for (i=0; i<DiskCount; i++) {
  817. diskState = Disks[i];
  818. for (j=0; j<diskState->RegionCount; j++) {
  819. if (diskState->Selected[j]) {
  820. selDiskState = diskState;
  821. selectedRegion = j;
  822. SelectionCount++;
  823. if (SelectionCount <= MaxMembersInFtSet) {
  824. SelectedDS[SelectionCount-1] = diskState;
  825. SelectedRG[SelectionCount-1] = j;
  826. }
  827. diskSeenCounts[diskState->Disk]++;
  828. if (ftObject = GET_FT_OBJECT(&diskState->RegionArray[j])) {
  829. ftSet = ftObject->Set;
  830. if (componentsInFtSet == 0) {
  831. ordinal = ftSet->Ordinal;
  832. type = ftSet->Type;
  833. ftSetSelected = TRUE;
  834. componentsInFtSet = 1;
  835. } else if ((ftSet->Ordinal == ordinal) && (ftSet->Type == type)) {
  836. componentsInFtSet++;
  837. } else {
  838. ftSetSelected = FALSE;
  839. }
  840. } else {
  841. nonFtItemSelected = TRUE;
  842. if (IsRecognizedPartition(diskState->RegionArray[j].SysID) ) {
  843. selectedNonFtPartitions += 1;
  844. }
  845. }
  846. }
  847. }
  848. }
  849. // Determine the number of free-space regions selected:
  850. selectedFreeSpaces = 0;
  851. for (i=0; i<SelectionCount && i < MaxMembersInFtSet; i++) {
  852. if (SELECTED_REGION(i).SysID == SYSID_UNUSED) {
  853. freeSpaceIndex = i;
  854. selectedFreeSpaces++;
  855. }
  856. }
  857. FtSelectionType = -1;
  858. possibleRecover = FALSE;
  859. if (nonFtItemSelected && ftSetSelected) {
  860. // Both FT and Non-FT items have been selected. First,
  861. // check to see if a volume set and free space have been
  862. // selected; then reset the state to indicate that the
  863. // selection does not consists of a mix of FT and non-FT
  864. // objects.
  865. if (type == VolumeSet && selectedFreeSpaces + componentsInFtSet == SelectionCount ) {
  866. volumeSetAndFreeSpaceSelected = TRUE;
  867. }
  868. possibleRecover = TRUE;
  869. ftSetSelected = FALSE;
  870. nonFtItemSelected = FALSE;
  871. multipleItemsSelected = TRUE;
  872. }
  873. if ((SelectionCount == 1) && !ftSetSelected) {
  874. *SinglySelectedDisk = selDiskState;
  875. *SinglySelectedRegion = selectedRegion;
  876. regionDescriptor = &selDiskState->RegionArray[selectedRegion];
  877. if (regionDescriptor->SysID == SYSID_UNUSED) {
  878. // Free region. Always allow create; let DoCreate() sort out
  879. // details about whether partition table is full, etc.
  880. allowCreate = TRUE;
  881. if (regionDescriptor->RegionType == REGION_PRIMARY) {
  882. allowCreateEx = TRUE;
  883. }
  884. // special case -- allow deletion of the extended partition if
  885. // there are no logicals in it.
  886. if ((regionDescriptor->RegionType == REGION_LOGICAL)
  887. && selDiskState->ExistExtended
  888. && !selDiskState->ExistLogical) {
  889. FDASSERT(regionDescriptor->SysID == SYSID_UNUSED);
  890. allowDelete = TRUE;
  891. }
  892. } else {
  893. // used region. Delete always allowed.
  894. allowDelete = TRUE;
  895. regionData = (PPERSISTENT_REGION_DATA)(PERSISTENT_DATA(regionDescriptor));
  896. if (regionData) {
  897. if (regionData->VolumeExists) {
  898. if ((regionData->DriveLetter != NO_DRIVE_LETTER_YET) && (regionData->DriveLetter != NO_DRIVE_LETTER_EVER)) {
  899. allowFormat = TRUE;
  900. }
  901. }
  902. }
  903. // If the region is recognized, then also allow drive letter
  904. // manipulation.
  905. if (IsRecognizedPartition(regionDescriptor->SysID)) {
  906. allowDriveLetter = TRUE;
  907. // DblSpace volumes are allowed on non-FT, FAT volumes only
  908. DetermineRegionInfo(regionDescriptor,
  909. &typeName,
  910. &volumeLabel,
  911. &driveLetter);
  912. if ((driveLetter != NO_DRIVE_LETTER_YET) && (driveLetter != NO_DRIVE_LETTER_EVER)) {
  913. if (wcscmp(typeName, L"FAT") == 0) {
  914. allowLabel = allowFormat;
  915. #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
  916. allowDblSpace = allowFormat;
  917. #endif
  918. // Force the dll in now to know if Double Space
  919. // support is offerred by the dll.
  920. LoadIfsDll();
  921. }
  922. if ((wcscmp(typeName, L"NTFS") == 0) ||
  923. (wcscmp(typeName, L"HPFS") == 0)) {
  924. allowLabel = allowFormat;
  925. }
  926. }
  927. }
  928. }
  929. } else {
  930. if (SelectionCount) {
  931. *SinglySelectedDisk = NULL;
  932. *SinglySelectedRegion = (DWORD)(-1);
  933. // Multiple regions are selected. This might be an existing ft set,
  934. // a set of regions that allow creation of an ft set, or just plain
  935. // old multiple items.
  936. //
  937. // First deal with a selected ft set.
  938. if (ftSetSelected) {
  939. regionDescriptor = &SELECTED_REGION(0);
  940. regionData = (PPERSISTENT_REGION_DATA)(PERSISTENT_DATA(regionDescriptor));
  941. // RDR - should locate member zero of the set since it
  942. // may not be committed yet.
  943. if (regionData) {
  944. if (regionData->VolumeExists) {
  945. if ((regionData->DriveLetter != NO_DRIVE_LETTER_YET) && (regionData->DriveLetter != NO_DRIVE_LETTER_EVER)) {
  946. // Now check for special cases on FT sets
  947. ftObject = regionData->FtObject;
  948. if (ftObject) {
  949. ftSet = ftObject->Set;
  950. if (ftSet) {
  951. FT_SET_STATUS setState = ftSet->Status;
  952. ULONG numberOfMembers;
  953. LowFtVolumeStatus(regionDescriptor->Disk,
  954. regionDescriptor->PartitionNumber,
  955. &setState,
  956. &numberOfMembers);
  957. if ((ftSet->Status != FtSetDisabled) &&
  958. (setState != FtSetDisabled)) {
  959. allowFormat = TRUE;
  960. }
  961. }
  962. }
  963. }
  964. if (regionData->TypeName) {
  965. typeName = regionData->TypeName;
  966. } else {
  967. typeName = NULL;
  968. DetermineRegionInfo(regionDescriptor,
  969. &typeName,
  970. &volumeLabel,
  971. &driveLetter);
  972. if (!typeName) {
  973. if (SelectionCount > 1) {
  974. // it is an FT set - try the next member.
  975. regionDescriptor = &SELECTED_REGION(1);
  976. DetermineRegionInfo(regionDescriptor,
  977. &typeName,
  978. &volumeLabel,
  979. &driveLetter);
  980. regionDescriptor = &SELECTED_REGION(0);
  981. }
  982. }
  983. }
  984. if (typeName) {
  985. if ((wcscmp(typeName, L"NTFS") == 0) ||
  986. (wcscmp(typeName, L"HPFS") == 0) ||
  987. (wcscmp(typeName, L"FAT") == 0)) {
  988. allowLabel = allowFormat;
  989. }
  990. }
  991. }
  992. }
  993. // Allow the correct type of ft-related delete.
  994. switch (type) {
  995. case Mirror:
  996. allowBreakMirror = TRUE;
  997. allowDelete = TRUE;
  998. break;
  999. case StripeWithParity:
  1000. if ((SelectionCount == ftSet->NumberOfMembers) &&
  1001. (ftSet->Status == FtSetRecoverable)) {
  1002. allowRecoverParity = TRUE;
  1003. }
  1004. allowDelete = TRUE;
  1005. break;
  1006. case Stripe:
  1007. case VolumeSet:
  1008. allowDelete = TRUE;
  1009. break;
  1010. default:
  1011. FDASSERT(FALSE);
  1012. }
  1013. FtSelectionType = type;
  1014. if (type == StripeWithParity) {
  1015. // If the set is disabled. Do not allow drive
  1016. // letter changes - This is done because there are
  1017. // conditions whereby the drive letter code will
  1018. // access violate if this is done.
  1019. if (ftSet->Status != FtSetDisabled) {
  1020. // Must have either member 0 or member 1 for access
  1021. for (ftObject = ftSet->Members; ftObject; ftObject = ftObject->Next) {
  1022. if ((ftObject->MemberIndex == 0) ||
  1023. (ftObject->MemberIndex == 1)) {
  1024. allowDriveLetter = TRUE;
  1025. break;
  1026. }
  1027. }
  1028. // if the drive letter cannot be done, then no live
  1029. // action can be done.
  1030. if (!allowDriveLetter) {
  1031. ftSet->Status = FtSetDisabled;
  1032. allowFormat = FALSE;
  1033. allowLabel = FALSE;
  1034. }
  1035. }
  1036. } else {
  1037. allowDriveLetter = TRUE;
  1038. }
  1039. } else {
  1040. // Next figure out whether some sort of ft object set could
  1041. // be created out of the selected regions.
  1042. if (SelectionCount <= MaxMembersInFtSet) {
  1043. // Determine whether the selected regions are all on
  1044. // different disks.
  1045. onDifferentDisks = TRUE;
  1046. for (i=0; i<DiskCount; i++) {
  1047. if (diskSeenCounts[i] > 1) {
  1048. onDifferentDisks = FALSE;
  1049. break;
  1050. }
  1051. }
  1052. // Check for allowing mirror creation. User must have selected
  1053. // two regions -- one a recognized partition, the other a free space.
  1054. if (onDifferentDisks && (SelectionCount == 2)
  1055. &&((SELECTED_REGION(0).SysID == SYSID_UNUSED) != (SELECTED_REGION(1).SysID == SYSID_UNUSED))
  1056. &&( IsRecognizedPartition(SELECTED_REGION(0).SysID) ||
  1057. IsRecognizedPartition(SELECTED_REGION(1).SysID))
  1058. &&!GET_FT_OBJECT(&(SELECTED_REGION(0)))
  1059. &&!GET_FT_OBJECT(&(SELECTED_REGION(1))))
  1060. {
  1061. allowCreateMirror = TRUE;
  1062. }
  1063. // Check for allowing volume set or stripe set
  1064. if (selectedFreeSpaces == SelectionCount) {
  1065. allowCreateVolumeSet = TRUE;
  1066. if (onDifferentDisks) {
  1067. allowCreateStripe = TRUE;
  1068. if (selectedFreeSpaces > 2) {
  1069. allowCreatePStripe = TRUE;
  1070. }
  1071. }
  1072. }
  1073. // Check for allowing volume set expansion. If
  1074. // the selected regions consist of one volume set
  1075. // and free space, then that volume set can be
  1076. // extended. If the selection consists of one
  1077. // recognized non-FT partition and free space,
  1078. // then we can convert those regions into a
  1079. // volume set.
  1080. if (volumeSetAndFreeSpaceSelected ||
  1081. (SelectionCount > 1 &&
  1082. selectedFreeSpaces == SelectionCount - 1 &&
  1083. selectedNonFtPartitions == 1) ) {
  1084. allowExtendVolumeSet = TRUE;
  1085. }
  1086. // Check for allowing non-in-place FT recover
  1087. if ((SelectionCount > 1)
  1088. && (selectedFreeSpaces == 1)
  1089. && possibleRecover
  1090. && (type == StripeWithParity)
  1091. && (ftSet->Status == FtSetRecoverable)) {
  1092. BOOL OrphanOnSameDiskAsFreeSpace = FALSE;
  1093. if (!onDifferentDisks) {
  1094. // Determine whether the orphan is on the same
  1095. // disk as the free space. First find the orphan.
  1096. for (i=0; i<SelectionCount; i++) {
  1097. PREGION_DESCRIPTOR reg = &SELECTED_REGION(i);
  1098. if ((i != freeSpaceIndex)
  1099. && (GET_FT_OBJECT(reg)->State == Orphaned))
  1100. {
  1101. if (SELECTED_REGION(freeSpaceIndex).Disk == reg->Disk) {
  1102. OrphanOnSameDiskAsFreeSpace = TRUE;
  1103. }
  1104. break;
  1105. }
  1106. }
  1107. }
  1108. if (onDifferentDisks || OrphanOnSameDiskAsFreeSpace) {
  1109. allowRecoverParity = TRUE;
  1110. }
  1111. }
  1112. }
  1113. }
  1114. }
  1115. }
  1116. EnableMenuItem(hMenu,
  1117. IDM_PARTITIONCREATE,
  1118. allowCreate ? MF_ENABLED : MF_GRAYED);
  1119. EnableMenuItem(hMenu,
  1120. IDM_PARTITIONCREATEEX,
  1121. allowCreateEx ? MF_ENABLED : MF_GRAYED);
  1122. EnableMenuItem(hMenu,
  1123. IDM_PARTITIONDELETE,
  1124. allowDelete ? MF_ENABLED : MF_GRAYED);
  1125. EnableMenuItem(hMenu,
  1126. IDM_PARTITIONFORMAT,
  1127. allowFormat ? MF_ENABLED : MF_GRAYED);
  1128. EnableMenuItem(hMenu,
  1129. IDM_PARTITIONLABEL,
  1130. allowLabel ? MF_ENABLED : MF_GRAYED);
  1131. #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
  1132. EnableMenuItem(hMenu,
  1133. IDM_DBLSPACE,
  1134. (allowDblSpace & DoubleSpaceSupported) ? MF_ENABLED : MF_GRAYED);
  1135. if (DoubleSpaceAutomount = DiskRegistryAutomountCurrentState()) {
  1136. CheckMenuItem(hMenu, IDM_AUTOMOUNT, MF_BYCOMMAND | MF_CHECKED);
  1137. }
  1138. EnableMenuItem(hMenu,
  1139. IDM_AUTOMOUNT,
  1140. MF_ENABLED);
  1141. #endif
  1142. EnableMenuItem(hMenu,
  1143. IDM_CDROM,
  1144. AllowCdRom ? MF_ENABLED : MF_GRAYED);
  1145. #if i386
  1146. SetUpMenui386(hMenu,SelectionCount);
  1147. #else
  1148. EnableMenuItem(hMenu,
  1149. IDM_SECURESYSTEM,
  1150. MF_ENABLED);
  1151. CheckMenuItem(hMenu,
  1152. IDM_SECURESYSTEM,
  1153. SystemPartitionIsSecure ? MF_CHECKED : MF_UNCHECKED);
  1154. #endif
  1155. EnableMenuItem(hMenu,
  1156. IDM_FTBREAKMIRROR,
  1157. allowBreakMirror ? MF_ENABLED : MF_GRAYED);
  1158. EnableMenuItem(hMenu,
  1159. IDM_FTESTABLISHMIRROR,
  1160. IsLanmanNt &&
  1161. allowCreateMirror ? MF_ENABLED : MF_GRAYED);
  1162. EnableMenuItem(hMenu,
  1163. IDM_FTCREATESTRIPE,
  1164. allowCreateStripe ? MF_ENABLED : MF_GRAYED);
  1165. EnableMenuItem(hMenu,
  1166. IDM_FTCREATEPSTRIPE,
  1167. allowCreatePStripe ? MF_ENABLED : MF_GRAYED);
  1168. EnableMenuItem(hMenu,
  1169. IDM_FTCREATEVOLUMESET,
  1170. allowCreateVolumeSet ? MF_ENABLED : MF_GRAYED);
  1171. EnableMenuItem(hMenu,
  1172. IDM_FTEXTENDVOLUMESET,
  1173. allowExtendVolumeSet ? MF_ENABLED : MF_GRAYED);
  1174. EnableMenuItem(hMenu,
  1175. IDM_PARTITIONLETTER,
  1176. allowDriveLetter ? MF_ENABLED : MF_GRAYED);
  1177. EnableMenuItem(hMenu,
  1178. IDM_FTRECOVERSTRIPE,
  1179. IsLanmanNt &&
  1180. allowRecoverParity ? MF_ENABLED : MF_GRAYED);
  1181. // If the registry has change allow commit.
  1182. if (RegistryChanged) {
  1183. allowCommit = TRUE;
  1184. }
  1185. EnableMenuItem(hMenu,
  1186. IDM_COMMIT,
  1187. allowCommit ? MF_ENABLED : MF_GRAYED);
  1188. return SelectionCount;
  1189. }
  1190. VOID
  1191. CompleteSingleRegionOperation(
  1192. IN PDISKSTATE DiskState
  1193. )
  1194. /*++
  1195. Routine Description:
  1196. Redraw the disk bar for the DiskState given and cause the
  1197. display to refresh.
  1198. Arguments:
  1199. DiskState - the disk involved.
  1200. Return Value:
  1201. None
  1202. --*/
  1203. {
  1204. RECT rc;
  1205. signed displayOffset;
  1206. EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
  1207. DeterminePartitioningState(DiskState);
  1208. DrawDiskBar(DiskState);
  1209. SetUpMenu(&SingleSel, &SingleSelIndex);
  1210. // BUGBUG use of disk# as offset in listbox
  1211. displayOffset = (signed)DiskState->Disk
  1212. - (signed)SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);
  1213. if (displayOffset > 0) { // otherwise it's not visible
  1214. // make a thin rectangle to force update
  1215. rc.left = BarLeftX + 5;
  1216. rc.right = rc.left + 5;
  1217. rc.top = (displayOffset * GraphHeight) + BarTopYOffset;
  1218. rc.bottom = rc.top + 5;
  1219. InvalidateRect(hwndList, &rc, FALSE);
  1220. }
  1221. ClearStatusArea();
  1222. ResetLBCursorRegion();
  1223. ForceLBRedraw();
  1224. }
  1225. VOID
  1226. TotalRedrawAndRepaint(
  1227. VOID
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. Invalidate the display and cause all disk bars to be redrawn.
  1232. Arguments:
  1233. None
  1234. Return Value:
  1235. None
  1236. --*/
  1237. {
  1238. unsigned i;
  1239. for (i=0; i<DiskCount; i++) {
  1240. DrawDiskBar(Disks[i]);
  1241. }
  1242. ForceLBRedraw();
  1243. }
  1244. VOID
  1245. CompleteMultiRegionOperation(
  1246. VOID
  1247. )
  1248. /*++
  1249. Routine Description:
  1250. This routine will cause the display to be updated
  1251. after a multi-region action has been completed.
  1252. Arguments:
  1253. None
  1254. Return Value:
  1255. None
  1256. --*/
  1257. {
  1258. unsigned i;
  1259. EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
  1260. for (i=0; i<DiskCount; i++) {
  1261. DeterminePartitioningState(Disks[i]);
  1262. }
  1263. TotalRedrawAndRepaint();
  1264. SetUpMenu(&SingleSel, &SingleSelIndex);
  1265. ClearStatusArea();
  1266. ResetLBCursorRegion();
  1267. }
  1268. PPERSISTENT_REGION_DATA
  1269. DmAllocatePersistentData(
  1270. IN PWSTR VolumeLabel,
  1271. IN PWSTR TypeName,
  1272. IN CHAR DriveLetter
  1273. )
  1274. /*++
  1275. Routine Description:
  1276. Allocate a structure to hold persistent region data. Fill in the volume
  1277. label, type name, and drive letter. The volume label and type name are
  1278. duplicated.
  1279. Arguments:
  1280. VolumeLabel - volume label to be stored in the the persistent data.
  1281. The string will be duplicated first and a pointer to the duplicate
  1282. copy is what is stored in the persistent data. May be NULL.
  1283. TypeName - name of type of region, ie unformatted, FAT, etc. May be NULL.
  1284. DriveLetter - drive letter to be stored in persistent data
  1285. Return Value:
  1286. pointer to newly allocated persistent data structure. The structure
  1287. may be freed via DmFreePersistentData(), below.
  1288. --*/
  1289. {
  1290. PPERSISTENT_REGION_DATA regionData = NULL;
  1291. PWSTR volumeLabel = NULL,
  1292. typeName = NULL;
  1293. if (VolumeLabel) {
  1294. volumeLabel = Malloc((lstrlenW(VolumeLabel)+1)*sizeof(WCHAR));
  1295. lstrcpyW(volumeLabel,VolumeLabel);
  1296. }
  1297. if (TypeName) {
  1298. typeName = Malloc((lstrlenW(TypeName)+1)*sizeof(WCHAR));
  1299. lstrcpyW(typeName,TypeName);
  1300. }
  1301. regionData = Malloc(sizeof(PERSISTENT_REGION_DATA));
  1302. DmInitPersistentRegionData(regionData, NULL, volumeLabel, typeName, DriveLetter);
  1303. return regionData;
  1304. }
  1305. VOID
  1306. DmFreePersistentData(
  1307. IN OUT PPERSISTENT_REGION_DATA RegionData
  1308. )
  1309. /*++
  1310. Routine Description:
  1311. Free a persistent data structure and storage used for volume label
  1312. and type name (does not free ft objects).
  1313. Arguments:
  1314. RegionData - structure to be freed.
  1315. Return Value:
  1316. None.
  1317. --*/
  1318. {
  1319. if (RegionData->VolumeLabel) {
  1320. Free(RegionData->VolumeLabel);
  1321. }
  1322. if (RegionData->TypeName) {
  1323. Free(RegionData->TypeName);
  1324. }
  1325. Free(RegionData);
  1326. }
  1327. VOID
  1328. DoCreate(
  1329. IN DWORD CreationType // REGION_EXTENDED or REGION_PRIMARY
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. This routine creates a new partition.
  1334. Arguments:
  1335. CreationType - indicator of partition type (extended or primary).
  1336. Return Value:
  1337. None
  1338. --*/
  1339. {
  1340. PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
  1341. ULONG diskNumber = regionDescriptor->Disk;
  1342. MINMAXDLG_PARAMS dlgParams;
  1343. DWORD creationSize;
  1344. DWORD ec;
  1345. PPERSISTENT_REGION_DATA regionData;
  1346. BOOLEAN isRemovable;
  1347. CHAR driveLetter;
  1348. FDASSERT(SingleSel);
  1349. FDASSERT(regionDescriptor->SysID == SYSID_UNUSED);
  1350. // WinDisk can only create a single partition on a removable
  1351. // disk--no extended partitions and only one primary.
  1352. isRemovable = IsDiskRemovable[diskNumber];
  1353. if (isRemovable) {
  1354. if (CreationType == REGION_EXTENDED) {
  1355. ErrorDialog(MSG_NO_EXTENDED_ON_REMOVABLE);
  1356. return;
  1357. }
  1358. if (Disks[diskNumber]->ExistAny) {
  1359. ErrorDialog(MSG_ONLY_ONE_PARTITION_ON_REMOVABLE);
  1360. return;
  1361. }
  1362. }
  1363. // Make sure the partition table is not full, and that we are allowed to
  1364. // create the type of partition to be created.
  1365. if (regionDescriptor->RegionType == REGION_PRIMARY) {
  1366. if (!SingleSel->CreatePrimary) {
  1367. ErrorDialog(MSG_PART_TABLE_FULL);
  1368. return;
  1369. }
  1370. if ((CreationType == REGION_EXTENDED) && !SingleSel->CreateExtended) {
  1371. ErrorDialog(MSG_EXTENDED_ALREADY_EXISTS);
  1372. return;
  1373. }
  1374. }
  1375. // If not creating an extended partition, allocate a drive letter.
  1376. // If no drive letter is available, warn the user and allow him to cancel.
  1377. // If the new partition is on a removable disk, use the reserved
  1378. // drive letter for that removable disk.
  1379. if (CreationType != REGION_EXTENDED) {
  1380. CreationType = regionDescriptor->RegionType; // primary or logical
  1381. if (isRemovable) {
  1382. driveLetter = RemovableDiskReservedDriveLetters[diskNumber];
  1383. } else {
  1384. if (!AssignDriveLetter(TRUE, CreationType == REGION_LOGICAL ? IDS_LOGICALVOLUME : IDS_PARTITION, &driveLetter)) {
  1385. return;
  1386. }
  1387. }
  1388. } else {
  1389. CommitDueToExtended = TRUE;
  1390. }
  1391. #if i386
  1392. // if the user is creating a primary partition and there are already
  1393. // primary partitions, warn him that the scheme he will create may
  1394. // not be DOS compatible.
  1395. if ((CreationType == REGION_PRIMARY) && SingleSel->ExistPrimary) {
  1396. if (ConfirmationDialog(MSG_CREATE_NOT_COMPAT, MB_ICONQUESTION | MB_YESNO) != IDYES) {
  1397. return;
  1398. }
  1399. }
  1400. #endif
  1401. // now get the size.
  1402. dlgParams.MinSizeMB = FdGetMinimumSizeMB(diskNumber);
  1403. dlgParams.MaxSizeMB = FdGetMaximumSizeMB(regionDescriptor, CreationType);
  1404. switch (CreationType) {
  1405. case REGION_PRIMARY:
  1406. dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_P;
  1407. dlgParams.MinimumStringID = IDS_CRTPART_MIN_P;
  1408. dlgParams.MaximumStringID = IDS_CRTPART_MAX_P;
  1409. dlgParams.SizeStringID = IDS_CRTPART_SIZE_P;
  1410. dlgParams.HelpContextId = HC_DM_DLG_CREATEPRIMARY;
  1411. break;
  1412. case REGION_EXTENDED:
  1413. dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_E;
  1414. dlgParams.MinimumStringID = IDS_CRTPART_MIN_P;
  1415. dlgParams.MaximumStringID = IDS_CRTPART_MAX_P;
  1416. dlgParams.SizeStringID = IDS_CRTPART_SIZE_P;
  1417. dlgParams.HelpContextId = HC_DM_DLG_CREATEEXTENDED;
  1418. break;
  1419. case REGION_LOGICAL:
  1420. dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_L;
  1421. dlgParams.MinimumStringID = IDS_CRTPART_MIN_L;
  1422. dlgParams.MaximumStringID = IDS_CRTPART_MAX_L;
  1423. dlgParams.SizeStringID = IDS_CRTPART_SIZE_L;
  1424. dlgParams.HelpContextId = HC_DM_DLG_CREATELOGICAL;
  1425. break;
  1426. default:
  1427. FDASSERT(FALSE);
  1428. }
  1429. creationSize = DialogBoxParam(hModule,
  1430. MAKEINTRESOURCE(IDD_MINMAX),
  1431. hwndFrame,
  1432. (DLGPROC)MinMaxDlgProc,
  1433. (LONG)&dlgParams);
  1434. if (!creationSize) { // user cancelled
  1435. return;
  1436. }
  1437. // Since the WinDisk can only create one partition on a removable
  1438. // disk, if the user requests a size smaller than the maximum
  1439. // on a removable disk, prompt to confirm:
  1440. if (isRemovable && creationSize != FdGetMaximumSizeMB(regionDescriptor, CreationType)) {
  1441. if (ConfirmationDialog(MSG_REMOVABLE_PARTITION_NOT_FULL_SIZE,MB_ICONQUESTION | MB_YESNO) != IDYES) {
  1442. return;
  1443. }
  1444. }
  1445. #if i386
  1446. // See whether the partition will cross over the 1024 cylinder boundary
  1447. // and warn the user if it will.
  1448. //
  1449. // If the extended partition crosses the boundary and the user is creating
  1450. // a logical drive, warn him even though the logical drive itself may not
  1451. // cross the boundary -- he still won't be able to access it.
  1452. {
  1453. DWORD i,
  1454. msgId = (DWORD)(-1);
  1455. if (CreationType == REGION_LOGICAL) {
  1456. PREGION_DESCRIPTOR extReg;
  1457. //
  1458. // Find the extended partition
  1459. //
  1460. for (i=0; i<Disks[diskNumber]->RegionCount; i++) {
  1461. extReg = &Disks[diskNumber]->RegionArray[i];
  1462. if (IsExtended(extReg->SysID)) {
  1463. break;
  1464. }
  1465. extReg = NULL;
  1466. }
  1467. FDASSERT(extReg);
  1468. if (extReg && FdCrosses1024Cylinder(extReg, 0, REGION_LOGICAL)) {
  1469. msgId = MSG_LOG_1024_CYL;
  1470. }
  1471. } else {
  1472. if (FdCrosses1024Cylinder(regionDescriptor, creationSize, CreationType)) {
  1473. msgId = (CreationType == REGION_PRIMARY) ? MSG_PRI_1024_CYL : MSG_EXT_1024_CYL;
  1474. }
  1475. }
  1476. if ((msgId != (ULONG)(-1)) && (ConfirmationDialog(msgId, MB_ICONQUESTION | MB_YESNO) != IDYES)) {
  1477. return;
  1478. }
  1479. }
  1480. #endif
  1481. // If not creating an extended partition, we need to create a new
  1482. // persistent region data structure to associate with the new
  1483. // partition.
  1484. if (CreationType == REGION_EXTENDED) {
  1485. regionData = NULL;
  1486. } else {
  1487. regionData = DmAllocatePersistentData(L"", wszNewUnformatted, driveLetter);
  1488. }
  1489. SetCursor(hcurWait);
  1490. ec = CreatePartition(regionDescriptor,
  1491. creationSize,
  1492. CreationType);
  1493. if (ec != NO_ERROR) {
  1494. SetCursor(hcurNormal);
  1495. ErrorDialog(ec);
  1496. }
  1497. DmSetPersistentRegionData(regionDescriptor, regionData);
  1498. if (CreationType != REGION_EXTENDED) {
  1499. if (!isRemovable) {
  1500. MarkDriveLetterUsed(driveLetter);
  1501. CommitToAssignLetterList(regionDescriptor, FALSE);
  1502. }
  1503. }
  1504. // this clears all selections on the disk
  1505. CompleteSingleRegionOperation(SingleSel);
  1506. SetCursor(hcurNormal);
  1507. }
  1508. VOID
  1509. DoDelete(
  1510. VOID
  1511. )
  1512. /*++
  1513. Routine Description:
  1514. Using the global selection information, delete the partition.
  1515. Arguments:
  1516. None
  1517. Return Value:
  1518. None
  1519. --*/
  1520. {
  1521. PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
  1522. ULONG diskNumber = regionDescriptor->Disk;
  1523. DWORD actualIndex = SingleSelIndex;
  1524. DWORD i,
  1525. ec;
  1526. PPERSISTENT_REGION_DATA regionData;
  1527. BOOL deletingExtended;
  1528. FDASSERT(SingleSel);
  1529. // if deleting a free space in the extended partition, then delete the
  1530. // extended partition itself.
  1531. if ((regionDescriptor->RegionType == REGION_LOGICAL) && !SingleSel->ExistLogical) {
  1532. FDASSERT(SingleSel->ExistExtended);
  1533. // find the extended partition
  1534. for (i=0; i<SingleSel->RegionCount; i++) {
  1535. if (IsExtended(SingleSel->RegionArray[i].SysID)) {
  1536. actualIndex = i;
  1537. break;
  1538. }
  1539. }
  1540. deletingExtended = TRUE;
  1541. FDASSERT(actualIndex != SingleSelIndex);
  1542. } else {
  1543. deletingExtended = FALSE;
  1544. // Make sure deletion of this partition is allowed. It is not allowed
  1545. // if it is the boot partition (or sys partition on x86).
  1546. if ((ec = DeletionIsAllowed(&SingleSel->RegionArray[actualIndex])) != NO_ERROR) {
  1547. ErrorDialog(ec);
  1548. return;
  1549. }
  1550. }
  1551. // If this is a partition that will become the result of a
  1552. // mirror break, insure that the break has occurred. Otherwise
  1553. // this delete will have bad results.
  1554. regionDescriptor = &SingleSel->RegionArray[actualIndex];
  1555. if (regionDescriptor->Reserved) {
  1556. if (regionDescriptor->Reserved->Partition) {
  1557. if (regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded) {
  1558. ErrorDialog(MSG_MUST_COMMIT_BREAK);
  1559. return;
  1560. }
  1561. }
  1562. }
  1563. if (!deletingExtended && (ConfirmationDialog(MSG_CONFIRM_DELETE, MB_ICONQUESTION | MB_YESNO) != IDYES)) {
  1564. return;
  1565. }
  1566. // actualIndex is the thing to delete.
  1567. FDASSERT(regionDescriptor->SysID != SYSID_UNUSED);
  1568. regionData = PERSISTENT_DATA(regionDescriptor);
  1569. if (regionData) {
  1570. // Remember drive letter if there is one in order to lock it for delete.
  1571. if (CommitToLockList(regionDescriptor, !IsDiskRemovable[diskNumber], TRUE, FALSE)) {
  1572. // Could not lock exclusively - do not allow delete.
  1573. if (IsPagefileOnDrive(regionData->DriveLetter)) {
  1574. ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE);
  1575. return;
  1576. } else {
  1577. if (CommitToLockList(regionDescriptor, !IsDiskRemovable[diskNumber], TRUE, FALSE)) {
  1578. FDLOG((1,"DoDelete: Couldn't lock 2 times - popup shown\n"));
  1579. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
  1580. return;
  1581. }
  1582. }
  1583. }
  1584. } else {
  1585. // Deleting an extended partition - enable commit.
  1586. CommitDueToDelete = TRUE;
  1587. }
  1588. SetCursor(hcurWait);
  1589. // Perform the "delete" of internal structures.
  1590. ec = DeletePartition(regionDescriptor);
  1591. if (ec != NO_ERROR) {
  1592. SetCursor(hcurNormal);
  1593. ErrorDialog(ec);
  1594. }
  1595. if (regionData) {
  1596. // Make the letter available for reuse.
  1597. if (!IsDiskRemovable[diskNumber]) {
  1598. MarkDriveLetterFree(regionData->DriveLetter);
  1599. }
  1600. // Free the persistent data associated with the region.
  1601. DmFreePersistentData(regionData);
  1602. DmSetPersistentRegionData(regionDescriptor,NULL);
  1603. }
  1604. // this clears all selections on the disk
  1605. CompleteSingleRegionOperation(SingleSel);
  1606. SetCursor(hcurNormal);
  1607. }
  1608. #if i386
  1609. VOID
  1610. DoMakeActive(
  1611. VOID
  1612. )
  1613. /*++
  1614. Routine Description:
  1615. This routine sets that active partition bit on for the selected partition.
  1616. This code is x86 specific.
  1617. Arguments:
  1618. None
  1619. Return Value:
  1620. None
  1621. --*/
  1622. {
  1623. SetCursor(hcurWait);
  1624. FDASSERT(SingleSel);
  1625. FDASSERT(!SingleSel->RegionArray[SingleSelIndex].Active);
  1626. FDASSERT(SingleSel->RegionArray[SingleSelIndex].RegionType == REGION_PRIMARY);
  1627. FDASSERT(SingleSel->RegionArray[SingleSelIndex].SysID != SYSID_UNUSED);
  1628. MakePartitionActive(SingleSel->RegionArray,
  1629. SingleSel->RegionCount,
  1630. SingleSelIndex);
  1631. SetCursor(hcurNormal);
  1632. InfoDialog(MSG_DISK0_ACTIVE);
  1633. SetCursor(hcurWait);
  1634. CompleteSingleRegionOperation(SingleSel);
  1635. SetCursor(hcurNormal);
  1636. }
  1637. #endif
  1638. VOID
  1639. DoProtectSystemPartition(
  1640. VOID
  1641. )
  1642. /*++
  1643. Routine Description:
  1644. This function toggles the state of the system partition security:
  1645. if the system partition is secure, it makes it non-secure; if the
  1646. system partition is not secure, it makes it secure.
  1647. Arguments:
  1648. None.
  1649. Return Value:
  1650. None.
  1651. --*/
  1652. {
  1653. LONG ec;
  1654. HKEY hkey;
  1655. DWORD value;
  1656. DWORD MessageId;
  1657. SetCursor(hcurWait);
  1658. MessageId = SystemPartitionIsSecure ? MSG_CONFIRM_UNPROTECT_SYSTEM :
  1659. MSG_CONFIRM_PROTECT_SYSTEM;
  1660. if (ConfirmationDialog(MessageId, MB_ICONEXCLAMATION | MB_YESNO) != IDYES) {
  1661. return;
  1662. }
  1663. ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1664. TEXT("System\\CurrentControlSet\\Control\\Lsa"),
  1665. 0,
  1666. KEY_SET_VALUE,
  1667. &hkey);
  1668. if (ec != ERROR_SUCCESS) {
  1669. MessageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM :
  1670. MSG_CANT_PROTECT_SYSTEM;
  1671. ErrorDialog(MessageId);
  1672. return;
  1673. }
  1674. // If the system partition is currently secure, change it
  1675. // to not secure; if it is not secure, make it secure.
  1676. value = SystemPartitionIsSecure ? 0 : 1;
  1677. ec = RegSetValueEx(hkey,
  1678. TEXT("Protect System Partition"),
  1679. 0,
  1680. REG_DWORD,
  1681. (PBYTE)&value,
  1682. sizeof(DWORD));
  1683. RegCloseKey(hkey);
  1684. if (ec != ERROR_SUCCESS) {
  1685. MessageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM :
  1686. MSG_CANT_PROTECT_SYSTEM;
  1687. ErrorDialog(MessageId);
  1688. return;
  1689. }
  1690. SystemPartitionIsSecure = !SystemPartitionIsSecure;
  1691. SetUpMenu(&SingleSel,&SingleSelIndex);
  1692. RestartRequired = TRUE;
  1693. SetCursor(hcurNormal);
  1694. }
  1695. VOID
  1696. DoEstablishMirror(
  1697. VOID
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. Using the global selection values, this routine will associate
  1702. freespace with an existing partition in order to construct a
  1703. mirror.
  1704. Arguments:
  1705. None
  1706. Return Value:
  1707. None
  1708. --*/
  1709. {
  1710. LARGE_INTEGER partitionSize,
  1711. freeSpaceSize;
  1712. DWORD i,
  1713. part,
  1714. free = 0;
  1715. PREGION_DESCRIPTOR regionDescriptor,
  1716. freeSpace = NULL,
  1717. existingPartition = NULL;
  1718. PREGION_DESCRIPTOR regionArray[MaxMembersInFtSet];
  1719. UCHAR newSysID;
  1720. PPERSISTENT_REGION_DATA regionData;
  1721. HMENU hMenu = GetMenu(hwndFrame);
  1722. FDASSERT(SelectionCount == 2);
  1723. // Make sure that the mirror pair does not include any
  1724. // partitions on removable media.
  1725. for (i=0; i<SelectionCount; i++) {
  1726. if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
  1727. ErrorDialog(MSG_NO_REMOVABLE_IN_MIRROR);
  1728. return;
  1729. }
  1730. }
  1731. for (i=0; i<2; i++) {
  1732. regionDescriptor = &SELECTED_REGION(i);
  1733. if (regionDescriptor->SysID == SYSID_UNUSED) {
  1734. free = i;
  1735. freeSpace = regionDescriptor;
  1736. } else {
  1737. part = i;
  1738. existingPartition = regionDescriptor;
  1739. }
  1740. }
  1741. FDASSERT((freeSpace != NULL) && (existingPartition != NULL));
  1742. // Make sure that we are allowed to create a partition in the free space.
  1743. if (!( ((freeSpace->RegionType == REGION_LOGICAL) && SelectedDS[free]->CreateLogical)
  1744. || ((freeSpace->RegionType == REGION_PRIMARY) && SelectedDS[free]->CreatePrimary))) {
  1745. ErrorDialog(MSG_CRTSTRP_FULL);
  1746. return;
  1747. }
  1748. // Make sure that the free space is large enough to hold a mirror of
  1749. // the existing partition. Do this by getting the EXACT size of
  1750. // the existing partition and the free space.
  1751. partitionSize = FdGetExactSize(existingPartition, FALSE);
  1752. freeSpaceSize = FdGetExactSize(freeSpace, FALSE);
  1753. if (freeSpaceSize.QuadPart < partitionSize.QuadPart) {
  1754. ErrorDialog(MSG_CRTMIRROR_BADFREE);
  1755. return;
  1756. }
  1757. if (BootDiskNumber != (ULONG)-1) {
  1758. // If the disk number and original partition number of this
  1759. // region match the recorded disk number and partition number
  1760. // of the boot partition warn the user about mirroring the boot
  1761. // drive.
  1762. if (existingPartition->Disk == BootDiskNumber &&
  1763. existingPartition->OriginalPartitionNumber == BootPartitionNumber) {
  1764. WarningDialog(MSG_MIRROR_OF_BOOT);
  1765. // Set up to write the boot code to the MBR of the mirror.
  1766. UpdateMbrOnDisk = freeSpace->Disk;
  1767. }
  1768. }
  1769. SetCursor(hcurWait);
  1770. regionData = DmAllocatePersistentData(PERSISTENT_DATA(existingPartition)->VolumeLabel,
  1771. PERSISTENT_DATA(existingPartition)->TypeName,
  1772. PERSISTENT_DATA(existingPartition)->DriveLetter);
  1773. // Finally, create the new partition.
  1774. newSysID = (UCHAR)(existingPartition->SysID | (UCHAR)SYSID_FT);
  1775. CreatePartitionEx(freeSpace,
  1776. partitionSize,
  1777. 0,
  1778. freeSpace->RegionType,
  1779. newSysID);
  1780. DmSetPersistentRegionData(freeSpace, regionData);
  1781. // Set the partition type of the existing partition.
  1782. SetSysID2(existingPartition, newSysID);
  1783. regionArray[0] = existingPartition;
  1784. regionArray[1] = freeSpace;
  1785. FdftCreateFtObjectSet(Mirror,
  1786. regionArray,
  1787. 2,
  1788. FtSetNewNeedsInitialization);
  1789. CompleteMultiRegionOperation();
  1790. SetCursor(hcurNormal);
  1791. CommitDueToMirror = TRUE;
  1792. EnableMenuItem(hMenu,
  1793. IDM_COMMIT,
  1794. MF_ENABLED);
  1795. }
  1796. VOID
  1797. DoBreakMirror(
  1798. VOID
  1799. )
  1800. /*++
  1801. Routine Description:
  1802. Using the global selection variables, this routine will break
  1803. the mirror relationship and modify their region descriptors to
  1804. describe two non-ft partitions giving either the primary member
  1805. of the mirror the drive letter for the mirror, or the only healthy
  1806. member of the mirror the drive letter. The remaining "new" partition
  1807. will receive the next available drive letter.
  1808. Arguments:
  1809. None
  1810. Return Value:
  1811. None
  1812. --*/
  1813. {
  1814. DWORD i;
  1815. PFT_OBJECT_SET ftSet;
  1816. PFT_OBJECT ftObject0,
  1817. ftObject1;
  1818. PREGION_DESCRIPTOR regionDescriptor;
  1819. PPERSISTENT_REGION_DATA regionData;
  1820. ULONG newDriveLetterRegion;
  1821. CHAR driveLetter;
  1822. HMENU hMenu = GetMenu(hwndFrame);
  1823. FDASSERT((SelectionCount) == 1 || (SelectionCount == 2));
  1824. ftObject0 = GET_FT_OBJECT(&SELECTED_REGION(0));
  1825. if (SelectionCount == 2) {
  1826. ftObject1 = GET_FT_OBJECT(&SELECTED_REGION(1));
  1827. } else {
  1828. ftObject1 = NULL;
  1829. }
  1830. ftSet = ftObject0->Set;
  1831. // Determine if the action is allowed.
  1832. switch (ftSet->Status) {
  1833. case FtSetInitializing:
  1834. case FtSetRegenerating:
  1835. ErrorDialog(MSG_CANT_BREAK_INITIALIZING_SET);
  1836. return;
  1837. break;
  1838. default:
  1839. break;
  1840. }
  1841. if (ConfirmationDialog(MSG_CONFIRM_BRK_MIRROR,MB_ICONQUESTION | MB_YESNO) != IDYES) {
  1842. return;
  1843. }
  1844. SetCursor(hcurWait);
  1845. // Figure out which region gets the new drive letter. A complication is
  1846. // that selection 0 is not necessarily member 0.
  1847. //
  1848. // If there is only one selection, then only one part of the mirror set
  1849. // is present -- no new drive letters are assigned.
  1850. // Otherwise, if one of the members is orphaned, it gets the new
  1851. // drive letter. Else the secondary member gets the new drive letter.
  1852. if (SelectionCount == 2) {
  1853. if (ftObject0->State == Orphaned) {
  1854. newDriveLetterRegion = 0;
  1855. } else {
  1856. if (ftObject1->State == Orphaned) {
  1857. newDriveLetterRegion = 1;
  1858. } else {
  1859. // Neither member is orphaned; determine which is
  1860. // member 0 and give the other one the new drive letter.
  1861. if (ftObject0->MemberIndex) { // secondary member ?
  1862. newDriveLetterRegion = 0;
  1863. } else {
  1864. newDriveLetterRegion = 1;
  1865. }
  1866. }
  1867. }
  1868. } else {
  1869. // The one remaining member could be the shadow.
  1870. // The drive letter must move to locate this partition
  1871. regionDescriptor = &SELECTED_REGION(0);
  1872. regionData = PERSISTENT_DATA(regionDescriptor);
  1873. if (!regionData->FtObject->MemberIndex) {
  1874. // The shadow has become the valid partition.
  1875. // move the current letter there.
  1876. CommitToAssignLetterList(regionDescriptor, TRUE);
  1877. }
  1878. newDriveLetterRegion = (ULONG)(-1);
  1879. }
  1880. // if newDriveLetterRegion is -1 this will still work and
  1881. // select the 0 selected region.
  1882. if (CommitToLockList(&SELECTED_REGION(newDriveLetterRegion ? 0 : 1), FALSE, TRUE, FALSE)) {
  1883. if (ConfirmationDialog(MSG_CONFIRM_SHUTDOWN_FOR_MIRROR, MB_ICONQUESTION | MB_YESNO) != IDYES) {
  1884. return;
  1885. }
  1886. RestartRequired = TRUE;
  1887. }
  1888. if (newDriveLetterRegion != (ULONG)(-1)) {
  1889. if (AssignDriveLetter(FALSE, 0, &driveLetter)) {
  1890. // Got a valid drive letter
  1891. MarkDriveLetterUsed(driveLetter);
  1892. } else {
  1893. // didn't get a letter. Instead the magic value
  1894. // for no drive letter assigned has been returned
  1895. }
  1896. regionDescriptor = &SELECTED_REGION(newDriveLetterRegion);
  1897. regionData = PERSISTENT_DATA(regionDescriptor);
  1898. regionData->DriveLetter = driveLetter;
  1899. CommitToAssignLetterList(regionDescriptor, FALSE);
  1900. if (!regionData->FtObject->MemberIndex) {
  1901. // The shadow has become the valid partition.
  1902. // move the current letter there.
  1903. CommitToAssignLetterList(&SELECTED_REGION(newDriveLetterRegion ? 0 : 1), TRUE);
  1904. }
  1905. } else {
  1906. regionDescriptor = &SELECTED_REGION(0);
  1907. regionData = PERSISTENT_DATA(regionDescriptor);
  1908. if (regionData->FtObject->MemberIndex) {
  1909. // The shadow is all that is left.
  1910. CommitToAssignLetterList(regionDescriptor, TRUE);
  1911. }
  1912. }
  1913. FdftDeleteFtObjectSet(ftSet, FALSE);
  1914. for (i=0; i<SelectionCount; i++) {
  1915. regionDescriptor = &SELECTED_REGION(i);
  1916. if (regionDescriptor->Reserved) {
  1917. if (regionDescriptor->Reserved->Partition) {
  1918. regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded = TRUE;
  1919. }
  1920. }
  1921. SET_FT_OBJECT(regionDescriptor, 0);
  1922. SetSysID2(regionDescriptor, (UCHAR)(regionDescriptor->SysID & ~VALID_NTFT));
  1923. }
  1924. CompleteMultiRegionOperation();
  1925. SetCursor(hcurNormal);
  1926. CommitDueToMirror = TRUE;
  1927. EnableMenuItem(hMenu,
  1928. IDM_COMMIT,
  1929. MF_ENABLED);
  1930. }
  1931. VOID
  1932. DoBreakAndDeleteMirror(
  1933. VOID
  1934. )
  1935. /*++
  1936. Routine Description:
  1937. This routine will delete the mirror relationship information
  1938. and the member partitions of the mirror.
  1939. Arguments:
  1940. None
  1941. Return Value:
  1942. None
  1943. --*/
  1944. {
  1945. PFT_OBJECT_SET ftSet;
  1946. DWORD i;
  1947. PREGION_DESCRIPTOR regionDescriptor;
  1948. CHAR driveLetter = '\0';
  1949. FDASSERT( SelectionCount == 1 || SelectionCount == 2 );
  1950. // Attempt to lock this before continuing.
  1951. regionDescriptor = &SELECTED_REGION(0);
  1952. if (CommitToLockList(regionDescriptor, TRUE, TRUE, FALSE)) {
  1953. // Could not lock the volume - do not allow delete.
  1954. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
  1955. return;
  1956. }
  1957. ftSet = (GET_FT_OBJECT(regionDescriptor))->Set;
  1958. // Determine if the action is allowed.
  1959. switch (ftSet->Status) {
  1960. case FtSetInitializing:
  1961. case FtSetRegenerating:
  1962. ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET);
  1963. return;
  1964. break;
  1965. default:
  1966. break;
  1967. }
  1968. if (ConfirmationDialog(MSG_CONFIRM_BRKANDDEL_MIRROR, MB_ICONQUESTION | MB_YESNO) != IDYES) {
  1969. return;
  1970. }
  1971. SetCursor(hcurWait);
  1972. FdftDeleteFtObjectSet(ftSet, FALSE);
  1973. for (i = 0; i < SelectionCount; i++) {
  1974. regionDescriptor = &SELECTED_REGION(i);
  1975. if (i) {
  1976. FDASSERT(PERSISTENT_DATA(regionDescriptor)->DriveLetter == driveLetter);
  1977. } else {
  1978. driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
  1979. }
  1980. // Free the pieces of the set.
  1981. DmFreePersistentData(PERSISTENT_DATA(regionDescriptor));
  1982. DmSetPersistentRegionData(regionDescriptor, NULL);
  1983. DeletePartition(regionDescriptor);
  1984. }
  1985. MarkDriveLetterFree(driveLetter);
  1986. // Remember drive letter if there is one in order to lock it for delete.
  1987. CompleteMultiRegionOperation();
  1988. SetCursor(hcurNormal);
  1989. }
  1990. VOID
  1991. DoCreateStripe(
  1992. IN BOOL Parity
  1993. )
  1994. /*++
  1995. Routine Description:
  1996. This routine starts the dialog with the user to determine
  1997. the parameters of the creation of a stripe or stripe set
  1998. with parity. Based on the user response it creates the
  1999. internal structures necessary for the creation of a stripe
  2000. or stripe set with parity.
  2001. The regions involved in the stripe creation are located via
  2002. the global parameters for multiple selections.
  2003. Arguments:
  2004. Parity - boolean to indicate the presence of parity in the stripe.
  2005. Return Value
  2006. None
  2007. --*/
  2008. {
  2009. MINMAXDLG_PARAMS params;
  2010. DWORD smallestSize = (DWORD)(-1);
  2011. DWORD creationSize;
  2012. unsigned i;
  2013. PREGION_DESCRIPTOR regionDescriptor,
  2014. regionArray[MaxMembersInFtSet];
  2015. PPERSISTENT_REGION_DATA regionData;
  2016. CHAR DriveLetter;
  2017. // Make sure that the volume set does not include any
  2018. // partitions on removable media.
  2019. for (i=0; i<SelectionCount; i++) {
  2020. if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
  2021. ErrorDialog(MSG_NO_REMOVABLE_IN_STRIPE);
  2022. return;
  2023. }
  2024. }
  2025. // Scan the disks to determine the maximum size, which is
  2026. // the size of the smallest partition times the number of
  2027. // partitions.
  2028. for (i=0; i<SelectionCount; i++) {
  2029. FDASSERT(SELECTED_REGION(i).SysID == SYSID_UNUSED);
  2030. if (SELECTED_REGION(i).SizeMB < smallestSize) {
  2031. smallestSize = SELECTED_REGION(i).SizeMB;
  2032. }
  2033. }
  2034. // Figure out a drive letter.
  2035. if (!AssignDriveLetter(TRUE, IDS_STRIPESET, &DriveLetter)) {
  2036. return;
  2037. }
  2038. params.CaptionStringID = Parity ? IDS_CRTPSTRP_CAPTION : IDS_CRTSTRP_CAPTION;
  2039. params.MinimumStringID = IDS_CRTSTRP_MIN;
  2040. params.MaximumStringID = IDS_CRTSTRP_MAX;
  2041. params.SizeStringID = IDS_CRTSTRP_SIZE;
  2042. params.MinSizeMB = SelectionCount;
  2043. params.MaxSizeMB = smallestSize * SelectionCount;
  2044. if (Parity) {
  2045. params.HelpContextId = HC_DM_DLG_CREATEPARITYSTRIPE;
  2046. } else {
  2047. params.HelpContextId = HC_DM_DLG_CREATESTRIPESET;
  2048. }
  2049. creationSize = DialogBoxParam(hModule,
  2050. MAKEINTRESOURCE(IDD_MINMAX),
  2051. hwndFrame,
  2052. (DLGPROC)MinMaxDlgProc,
  2053. (LONG)&params);
  2054. if (!creationSize) { // user cancelled
  2055. return;
  2056. }
  2057. // Determine how large we have to make each member of the stripe set.
  2058. creationSize = (creationSize / SelectionCount);
  2059. FDASSERT(creationSize <= smallestSize);
  2060. if (creationSize % SelectionCount) {
  2061. creationSize++; // round up.
  2062. }
  2063. SetCursor(hcurWait);
  2064. // Make sure we are allowed to create all the partitions
  2065. for (i=0; i<SelectionCount; i++) {
  2066. regionDescriptor = &SELECTED_REGION(i);
  2067. FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
  2068. if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical)
  2069. || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) {
  2070. SetCursor(hcurNormal);
  2071. ErrorDialog(MSG_CRTSTRP_FULL);
  2072. return;
  2073. }
  2074. }
  2075. // Now actually perform the creation.
  2076. for (i=0; i<SelectionCount; i++) {
  2077. regionDescriptor = &SELECTED_REGION(i);
  2078. CreatePartitionEx(regionDescriptor,
  2079. RtlConvertLongToLargeInteger(0L),
  2080. creationSize,
  2081. regionDescriptor->RegionType,
  2082. (UCHAR)(SYSID_BIGFAT | SYSID_FT));
  2083. // Finish setting up the FT set
  2084. regionData = DmAllocatePersistentData(L"", wszNewUnformatted, DriveLetter);
  2085. DmSetPersistentRegionData(regionDescriptor, regionData);
  2086. regionArray[i] = regionDescriptor;
  2087. }
  2088. // The zeroth element is the one to assign the drive letter to.
  2089. CommitToAssignLetterList(&SELECTED_REGION(0), FALSE);
  2090. FdftCreateFtObjectSet(Parity ? StripeWithParity : Stripe,
  2091. regionArray,
  2092. SelectionCount,
  2093. Parity ? FtSetNewNeedsInitialization : FtSetNew);
  2094. MarkDriveLetterUsed(DriveLetter);
  2095. CompleteMultiRegionOperation();
  2096. SetCursor(hcurNormal);
  2097. }
  2098. VOID
  2099. DoDeleteStripeOrVolumeSet(
  2100. IN DWORD ConfirmationMsg
  2101. )
  2102. /*++
  2103. Routine Description:
  2104. Common code for the deletion of a stripe or volume set.
  2105. This routine will display a message giving the user a 2nd
  2106. chance to change their mind, then based on the answer perform
  2107. the work of deleting the item. This consists of removing
  2108. the region descriptors (and related information) from the
  2109. collection of Disk structures.
  2110. Arguments:
  2111. ConfirmationMsg - text for comfirming what is being deleted.
  2112. Return Value:
  2113. None
  2114. --*/
  2115. {
  2116. DWORD i;
  2117. PFT_OBJECT_SET ftSet;
  2118. PFT_OBJECT ftObject;
  2119. PREGION_DESCRIPTOR regionDescriptor;
  2120. FT_SET_STATUS setState;
  2121. ULONG numberOfMembers;
  2122. CHAR driveLetter = '\0';
  2123. BOOL setIsHealthy = TRUE;
  2124. regionDescriptor = &SELECTED_REGION(0);
  2125. // Determine if the action is allowed.
  2126. ftObject = GET_FT_OBJECT(regionDescriptor);
  2127. ftSet = ftObject->Set;
  2128. LowFtVolumeStatus(regionDescriptor->Disk,
  2129. regionDescriptor->PartitionNumber,
  2130. &setState,
  2131. &numberOfMembers);
  2132. if (ftSet->Status != setState) {
  2133. ftSet->Status = setState;
  2134. }
  2135. switch (ftSet->Status) {
  2136. case FtSetDisabled:
  2137. setIsHealthy = FALSE;
  2138. break;
  2139. case FtSetInitializing:
  2140. case FtSetRegenerating:
  2141. ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET);
  2142. return;
  2143. break;
  2144. default:
  2145. break;
  2146. }
  2147. // Attempt to lock this before continuing.
  2148. if (CommitToLockList(regionDescriptor, TRUE, setIsHealthy, TRUE)) {
  2149. // Could not lock the volume - try again, the file systems appear
  2150. // to be confused.
  2151. if (CommitToLockList(regionDescriptor, TRUE, setIsHealthy, TRUE)) {
  2152. // Don't allow the delete.
  2153. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
  2154. return;
  2155. }
  2156. }
  2157. if (ConfirmationDialog(ConfirmationMsg,MB_ICONQUESTION | MB_YESNO) != IDYES) {
  2158. return;
  2159. }
  2160. // Delete all partitions that are part of the stripe set
  2161. SetCursor(hcurWait);
  2162. FdftDeleteFtObjectSet(ftSet,FALSE);
  2163. for (i=0; i<SelectionCount; i++) {
  2164. ULONG diskNumber;
  2165. regionDescriptor = &SELECTED_REGION(i);
  2166. if (i) {
  2167. FDASSERT(PERSISTENT_DATA(regionDescriptor)->DriveLetter == driveLetter);
  2168. } else {
  2169. driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
  2170. }
  2171. diskNumber = regionDescriptor->Disk;
  2172. DmFreePersistentData(PERSISTENT_DATA(regionDescriptor));
  2173. DmSetPersistentRegionData(regionDescriptor, NULL);
  2174. DeletePartition(regionDescriptor);
  2175. }
  2176. // Mark the drive letter that was being used by the stripe or volume
  2177. // set free.
  2178. MarkDriveLetterFree(driveLetter);
  2179. // Remember drive letter if there is one in order to lock it for delete.
  2180. CompleteMultiRegionOperation();
  2181. SetCursor(hcurNormal);
  2182. }
  2183. VOID
  2184. DoDeleteStripe(
  2185. VOID
  2186. )
  2187. /*++
  2188. Routine Description:
  2189. Routine is called to delete a stripe. It calls a general
  2190. routine for stripe and volume set deletion.
  2191. Arguments:
  2192. None
  2193. Return Value:
  2194. None
  2195. --*/
  2196. {
  2197. DoDeleteStripeOrVolumeSet(MSG_CONFIRM_DEL_STRP);
  2198. }
  2199. VOID
  2200. DoCreateVolumeSet(
  2201. VOID
  2202. )
  2203. /*++
  2204. Routine Description:
  2205. This routine uses the global selection information to collect
  2206. a group of freespace regions on the disks and organize them into
  2207. a volume set.
  2208. Arguments:
  2209. None
  2210. Return Value:
  2211. None
  2212. --*/
  2213. {
  2214. MINMAXDLG_PARAMS params;
  2215. DWORD creationSize,
  2216. size,
  2217. maxTotalSize=0,
  2218. totalSizeUsed;
  2219. DWORD sizes[MaxMembersInFtSet];
  2220. PULONG primarySpacesToUseOnDisk;
  2221. CHAR driveLetter;
  2222. unsigned i;
  2223. PREGION_DESCRIPTOR regionDescriptor,
  2224. regionArray[MaxMembersInFtSet];
  2225. PPERSISTENT_REGION_DATA regionData;
  2226. // Make sure that the volume set does not include any
  2227. // partitions on removable media.
  2228. for (i=0; i<SelectionCount; i++) {
  2229. if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
  2230. ErrorDialog(MSG_NO_REMOVABLE_IN_VOLUMESET);
  2231. return;
  2232. }
  2233. }
  2234. for (i=0; i<SelectionCount; i++) {
  2235. FDASSERT(SELECTED_REGION(i).SysID == SYSID_UNUSED);
  2236. size = SELECTED_REGION(i).SizeMB;
  2237. sizes[i] = size;
  2238. maxTotalSize += size;
  2239. }
  2240. // Figure out a drive letter.
  2241. if (!AssignDriveLetter(TRUE, IDS_VOLUMESET, &driveLetter)) {
  2242. return;
  2243. }
  2244. params.CaptionStringID = IDS_CRTVSET_CAPTION;
  2245. params.MinimumStringID = IDS_CRTVSET_MIN;
  2246. params.MaximumStringID = IDS_CRTVSET_MAX;
  2247. params.SizeStringID = IDS_CRTVSET_SIZE;
  2248. params.MinSizeMB = SelectionCount;
  2249. params.MaxSizeMB = maxTotalSize;
  2250. params.HelpContextId = HC_DM_DLG_CREATEVOLUMESET;
  2251. creationSize = DialogBoxParam(hModule,
  2252. MAKEINTRESOURCE(IDD_MINMAX),
  2253. hwndFrame,
  2254. (DLGPROC)MinMaxDlgProc,
  2255. (LONG)&params);
  2256. if (!creationSize) { // user cancelled
  2257. return;
  2258. }
  2259. // Determine how large we have to make each member of the volume set.
  2260. // The percentage of each free space that will be used is the ratio
  2261. // of the total space he chose to the total free space.
  2262. //
  2263. // Example: 2 75 meg free spaces for a total set size of 150 MB.
  2264. // User chooses a set size of 100 MB. Use 50 MB of each space.
  2265. totalSizeUsed = 0;
  2266. for (i=0; i<SelectionCount; i++) {
  2267. sizes[i] = sizes[i] * creationSize / maxTotalSize;
  2268. if ((sizes[i] * creationSize) % maxTotalSize) {
  2269. sizes[i]++;
  2270. }
  2271. if (sizes[i] == 0) {
  2272. sizes[i]++;
  2273. }
  2274. totalSizeUsed += sizes[i];
  2275. }
  2276. // Make sure that the total amount used is not greater than the
  2277. // maximum amount available. Note that this loop is certain
  2278. // to terminate because maxTotalSize >= SelectionCount; if
  2279. // each of the sizes goes down to one, we will exit the loop
  2280. while (totalSizeUsed > maxTotalSize) {
  2281. for (i=0; (i<SelectionCount) && (totalSizeUsed > maxTotalSize); i++) {
  2282. if (sizes[i] > 1) {
  2283. sizes[i]--;
  2284. totalSizeUsed--;
  2285. }
  2286. }
  2287. }
  2288. SetCursor(hcurWait);
  2289. // Make sure that we are allowed to create a partition in the space.
  2290. // This is tricky because a volume set could contain more than one
  2291. // primary partition on a disk -- which means that if we're not careful
  2292. // we could create a disk with more than 4 primary partitions!
  2293. primarySpacesToUseOnDisk = Malloc(DiskCount * sizeof(ULONG));
  2294. RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG));
  2295. for (i=0; i<SelectionCount; i++) {
  2296. regionDescriptor = &SELECTED_REGION(i);
  2297. FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
  2298. if (regionDescriptor->RegionType == REGION_PRIMARY) {
  2299. primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++;
  2300. }
  2301. if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical)
  2302. || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary)))
  2303. {
  2304. SetCursor(hcurNormal);
  2305. Free(primarySpacesToUseOnDisk);
  2306. ErrorDialog(MSG_CRTSTRP_FULL);
  2307. return;
  2308. }
  2309. }
  2310. // Look through the array we built to see whether we are supposed to use
  2311. // more than one primary partition on a given disk. For each such disk,
  2312. // make sure that we can actually create that many primary partitions.
  2313. for (i=0; i<DiskCount; i++) {
  2314. // If there are not enough primary partition slots, fail.
  2315. if ((primarySpacesToUseOnDisk[i] > 1)
  2316. && (4 - PartitionCount(i) < primarySpacesToUseOnDisk[i]))
  2317. {
  2318. SetCursor(hcurNormal);
  2319. Free(primarySpacesToUseOnDisk);
  2320. ErrorDialog(MSG_CRTSTRP_FULL);
  2321. return;
  2322. }
  2323. }
  2324. Free(primarySpacesToUseOnDisk);
  2325. // Now actually perform the creation.
  2326. for (i=0; i<SelectionCount; i++) {
  2327. regionDescriptor = &SELECTED_REGION(i);
  2328. FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
  2329. CreatePartitionEx(regionDescriptor,
  2330. RtlConvertLongToLargeInteger(0L),
  2331. sizes[i],
  2332. regionDescriptor->RegionType,
  2333. (UCHAR)(SYSID_BIGFAT | SYSID_FT));
  2334. regionData = DmAllocatePersistentData(L"", wszNewUnformatted, driveLetter);
  2335. DmSetPersistentRegionData(regionDescriptor, regionData);
  2336. regionArray[i] = regionDescriptor;
  2337. }
  2338. // The zeroth element is the one to assign the drive letter to.
  2339. FdftCreateFtObjectSet(VolumeSet, regionArray, SelectionCount, FtSetNew);
  2340. MarkDriveLetterUsed(driveLetter);
  2341. CommitToAssignLetterList(&SELECTED_REGION(0), FALSE);
  2342. CompleteMultiRegionOperation();
  2343. SetCursor(hcurNormal);
  2344. }
  2345. VOID
  2346. DoExtendVolumeSet(
  2347. VOID
  2348. )
  2349. /*++
  2350. Routine Description:
  2351. This routine uses the global selection item information to
  2352. add additional freespace to an existing volume set or partition.
  2353. Arguments:
  2354. None
  2355. Return Value:
  2356. None
  2357. --*/
  2358. {
  2359. MINMAXDLG_PARAMS params;
  2360. DWORD currentSize = 0,
  2361. freeSize = 0,
  2362. maxTotalSize = 0,
  2363. newSize = 0,
  2364. totalFreeSpaceUsed,
  2365. freeSpaceUsed,
  2366. Size;
  2367. DWORD Sizes[MaxMembersInFtSet];
  2368. ULONG nonFtPartitions = 0,
  2369. numberOfFreeRegions = 0;
  2370. PULONG primarySpacesToUseOnDisk;
  2371. WCHAR driveLetter = L' ';
  2372. PWSTR typeName = NULL,
  2373. volumeLabel = NULL;
  2374. PREGION_DESCRIPTOR regionDescriptor;
  2375. PREGION_DESCRIPTOR newRegions[MaxMembersInFtSet];
  2376. PREGION_DESCRIPTOR convertedRegion;
  2377. PFT_OBJECT_SET ftSet = NULL;
  2378. PPERSISTENT_REGION_DATA regionData;
  2379. unsigned i;
  2380. DWORD ec;
  2381. // Make sure that the volume set does not include any
  2382. // partitions on removable media.
  2383. for (i=0; i<SelectionCount; i++) {
  2384. if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
  2385. ErrorDialog(MSG_NO_REMOVABLE_IN_VOLUMESET);
  2386. return;
  2387. }
  2388. }
  2389. // First, determine the current size of the volume set,
  2390. // it's file system type and associated drive letter,
  2391. // and the size of the selected free space
  2392. for (i = 0; i < SelectionCount; i++) {
  2393. regionDescriptor = &(SELECTED_REGION(i));
  2394. Size = regionDescriptor->SizeMB;
  2395. Sizes[i] = Size;
  2396. maxTotalSize += Size;
  2397. if (regionDescriptor->SysID == SYSID_UNUSED) {
  2398. // This region is a chunk of free space; include it
  2399. // in the free space tallies.
  2400. newRegions[numberOfFreeRegions] = regionDescriptor;
  2401. Sizes[numberOfFreeRegions] = Size;
  2402. numberOfFreeRegions++;
  2403. freeSize += Size;
  2404. } else if (GET_FT_OBJECT(regionDescriptor)) {
  2405. // This is an element of an existing volume set.
  2406. currentSize += Size;
  2407. if ( ftSet == NULL ) {
  2408. DetermineRegionInfo(regionDescriptor,
  2409. &typeName,
  2410. &volumeLabel,
  2411. &driveLetter);
  2412. ftSet = GET_FT_OBJECT(regionDescriptor)->Set;
  2413. }
  2414. } else {
  2415. // This is a non-FT partition.
  2416. nonFtPartitions++;
  2417. DetermineRegionInfo(regionDescriptor,
  2418. &typeName,
  2419. &volumeLabel,
  2420. &driveLetter);
  2421. currentSize = Size;
  2422. convertedRegion = regionDescriptor;
  2423. }
  2424. }
  2425. // Check for consistency: the selection must have either a volume
  2426. // set or a partition, but not both, and cannot have more than
  2427. // one non-FT partition.
  2428. if (nonFtPartitions > 1 ||
  2429. (ftSet != NULL && nonFtPartitions != 0) ||
  2430. (ftSet == NULL && nonFtPartitions == 0)) {
  2431. return;
  2432. }
  2433. if (nonFtPartitions != 0 &&
  2434. (ec = DeletionIsAllowed(convertedRegion)) != NO_ERROR) {
  2435. // If the error-message is delete-specific, remap it.
  2436. //
  2437. switch( ec ) {
  2438. #if i386
  2439. case MSG_CANT_DELETE_ACTIVE0: ec = MSG_CANT_EXTEND_ACTIVE0;
  2440. break;
  2441. #endif
  2442. case MSG_CANT_DELETE_WINNT: ec = MSG_CANT_EXTEND_WINNT;
  2443. break;
  2444. default: break;
  2445. }
  2446. ErrorDialog(ec);
  2447. return;
  2448. }
  2449. if (wcscmp(typeName, L"NTFS") != 0) {
  2450. ErrorDialog(MSG_EXTEND_VOLSET_MUST_BE_NTFS);
  2451. return;
  2452. }
  2453. params.CaptionStringID = IDS_EXPVSET_CAPTION;
  2454. params.MinimumStringID = IDS_CRTVSET_MIN;
  2455. params.MaximumStringID = IDS_CRTVSET_MAX;
  2456. params.SizeStringID = IDS_CRTVSET_SIZE;
  2457. params.MinSizeMB = currentSize + numberOfFreeRegions;
  2458. params.MaxSizeMB = maxTotalSize;
  2459. params.HelpContextId = HC_DM_DLG_EXTENDVOLUMESET;
  2460. newSize = DialogBoxParam(hModule,
  2461. MAKEINTRESOURCE(IDD_MINMAX),
  2462. hwndFrame,
  2463. (DLGPROC)MinMaxDlgProc,
  2464. (LONG)&params);
  2465. if (!newSize) { // user cancelled
  2466. return;
  2467. }
  2468. // Determine how large to make each new member of the volume
  2469. // set. The percentage of free space to use is the ratio of
  2470. // the amount by which the volume set will grow to the total
  2471. // free space.
  2472. freeSpaceUsed = newSize - currentSize;
  2473. totalFreeSpaceUsed = 0;
  2474. for ( i = 0; i < numberOfFreeRegions; i++ ) {
  2475. Sizes[i] = Sizes[i] * freeSpaceUsed / freeSize;
  2476. if ((Sizes[i] * freeSpaceUsed) % freeSize) {
  2477. Sizes[i]++;
  2478. }
  2479. if (Sizes[i] == 0) {
  2480. Sizes[i]++;
  2481. }
  2482. totalFreeSpaceUsed += Sizes[i];
  2483. }
  2484. // Make sure that the total amount of free space used is not
  2485. // greater than the amount available. Note that this loop is
  2486. // certain to terminate because the amount of free space used
  2487. // is >= the number of free regions, so this loop will exit
  2488. // if one megabyte is used in each free region (the degenerate
  2489. // case).
  2490. while (totalFreeSpaceUsed > freeSize) {
  2491. for (i = 0;
  2492. (i < numberOfFreeRegions) && (totalFreeSpaceUsed > freeSize);
  2493. i++) {
  2494. if ( Sizes[i] > 1 ) {
  2495. Sizes[i]--;
  2496. totalFreeSpaceUsed--;
  2497. }
  2498. }
  2499. }
  2500. SetCursor(hcurWait);
  2501. // Make sure that we are allowed to create a partition in the space.
  2502. //
  2503. // This is tricky because a volume set could contain more than one
  2504. // primary partition on a disk -- which means that if we're not careful
  2505. // we could create a disk with more than 4 primary partitions!
  2506. primarySpacesToUseOnDisk = Malloc(DiskCount * sizeof(ULONG));
  2507. RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG));
  2508. for (i=0; i<SelectionCount; i++) {
  2509. regionDescriptor = &SELECTED_REGION(i);
  2510. if (regionDescriptor->SysID == SYSID_UNUSED) {
  2511. FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
  2512. if (regionDescriptor->RegionType == REGION_PRIMARY) {
  2513. primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++;
  2514. }
  2515. if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical)
  2516. || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) {
  2517. SetCursor(hcurNormal);
  2518. Free(primarySpacesToUseOnDisk);
  2519. ErrorDialog(MSG_CRTSTRP_FULL);
  2520. return;
  2521. }
  2522. }
  2523. }
  2524. // Look through the array we built to see whether we are supposed to use
  2525. // more than one primary partition on a given disk. For each such disk,
  2526. // make sure that we can actually create that many primary partitions.
  2527. for (i=0; i<DiskCount; i++) {
  2528. // If there are not enough primary partition slots, fail.
  2529. if ((primarySpacesToUseOnDisk[i] > 1)
  2530. && (4 - PartitionCount(i) < primarySpacesToUseOnDisk[i])) {
  2531. SetCursor(hcurNormal);
  2532. Free(primarySpacesToUseOnDisk);
  2533. ErrorDialog(MSG_CRTSTRP_FULL);
  2534. return;
  2535. }
  2536. }
  2537. // Now actually perform the creation.
  2538. for (i=0; i<numberOfFreeRegions; i++) {
  2539. regionDescriptor = newRegions[i];
  2540. FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
  2541. CreatePartitionEx(regionDescriptor,
  2542. RtlConvertLongToLargeInteger(0L),
  2543. Sizes[i],
  2544. regionDescriptor->RegionType,
  2545. (UCHAR)(SYSID_IFS | SYSID_FT));
  2546. regionData = DmAllocatePersistentData(volumeLabel, typeName, (CHAR)driveLetter);
  2547. DmSetPersistentRegionData(regionDescriptor, regionData);
  2548. }
  2549. if (nonFtPartitions != 0) {
  2550. // Create the volume set so we can extend it
  2551. FdftCreateFtObjectSet(VolumeSet, &convertedRegion, 1, FtSetExtended);
  2552. ftSet = GET_FT_OBJECT(convertedRegion)->Set;
  2553. // Set the converted region's partition System Id to indicate
  2554. // that it is now part of a volume set.
  2555. SetSysID2(convertedRegion, (UCHAR)(convertedRegion->SysID | SYSID_FT));
  2556. }
  2557. FdftExtendFtObjectSet(ftSet, newRegions, numberOfFreeRegions);
  2558. CompleteMultiRegionOperation();
  2559. SetCursor(hcurNormal);
  2560. }
  2561. VOID
  2562. DoDeleteVolumeSet(
  2563. VOID
  2564. )
  2565. /*++
  2566. Routine Description:
  2567. Routine is called to delete a volume set. It calls a general
  2568. routine for stripe and volume set deletion.
  2569. Arguments:
  2570. None
  2571. Return Value:
  2572. None
  2573. --*/
  2574. {
  2575. DoDeleteStripeOrVolumeSet(MSG_CONFIRM_DEL_VSET);
  2576. }
  2577. extern ULONG OrdinalToAllocate[];
  2578. VOID
  2579. DoRecoverStripe(
  2580. VOID
  2581. )
  2582. /*++
  2583. Routine Description:
  2584. Using the global selection information this routine will
  2585. set up a stripe with parity such that a problem member is
  2586. regenerated. This new member may either be the problem member
  2587. (i.e. regeneration is "in place") or new free space on a
  2588. different disk.
  2589. Arguments:
  2590. None
  2591. Return Value:
  2592. None
  2593. --*/
  2594. {
  2595. PREGION_DESCRIPTOR freeSpace = NULL;
  2596. PREGION_DESCRIPTOR unhealthy = NULL;
  2597. ULONG freeSpaceI = 0;
  2598. ULONG i;
  2599. PREGION_DESCRIPTOR regionArray[MaxMembersInFtSet];
  2600. LARGE_INTEGER minimumSize;
  2601. PFT_OBJECT ftObject;
  2602. // Initialize minimumSize to the maximum possible positive value
  2603. minimumSize.HighPart = 0x7FFFFFFF;
  2604. minimumSize.LowPart = 0xFFFFFFFF;
  2605. if ((!IsRegionCommitted(&SELECTED_REGION(0))) &&
  2606. (!IsRegionCommitted(&SELECTED_REGION(1)))) {
  2607. ErrorDialog(MSG_NOT_COMMITTED);
  2608. return;
  2609. }
  2610. FDASSERT(SelectionCount > 1);
  2611. FDASSERT(SelectionCount <= MaxMembersInFtSet);
  2612. SetCursor(hcurWait);
  2613. // Determine the exact size of the smallest member of the stripe set.
  2614. // If the user is regenerating using an additional free space, this
  2615. // will be the size requirement for the free space.
  2616. // Also find the free space (if any).
  2617. // If there is no free space, then we're doing an 'in-place' recover
  2618. // (ie regnerating into the unhealthy member). If there is a free space,
  2619. // make sure we are allowed to create a partition or logical drive in it.
  2620. for (i=0; i<SelectionCount; i++) {
  2621. regionArray[i] = &SELECTED_REGION(i);
  2622. FDASSERT(!IsExtended(regionArray[i]->SysID));
  2623. if (regionArray[i]->SysID == SYSID_UNUSED) {
  2624. PDISKSTATE ds;
  2625. FDASSERT(freeSpace == NULL);
  2626. freeSpace = regionArray[i];
  2627. freeSpaceI = i;
  2628. // Make sure we are allowed to create a partition or logical
  2629. // drive in the selected free space.
  2630. ds = SelectedDS[freeSpaceI];
  2631. if (!( ((freeSpace->RegionType == REGION_LOGICAL) && ds->CreateLogical)
  2632. || ((freeSpace->RegionType == REGION_PRIMARY) && ds->CreatePrimary))) {
  2633. SetCursor(hcurNormal);
  2634. ErrorDialog(MSG_CRTSTRP_FULL);
  2635. return;
  2636. }
  2637. } else {
  2638. LARGE_INTEGER largeTemp;
  2639. largeTemp = FdGetExactSize(regionArray[i], FALSE);
  2640. if (largeTemp.QuadPart < minimumSize.QuadPart) {
  2641. minimumSize = largeTemp;
  2642. }
  2643. if (GET_FT_OBJECT(regionArray[i])->State != Healthy) {
  2644. FDASSERT(unhealthy == NULL);
  2645. unhealthy = regionArray[i];
  2646. }
  2647. }
  2648. }
  2649. // If there is a free space, place it at item 0 of the regionArray
  2650. // to simplify processing later.
  2651. if (freeSpace) {
  2652. PREGION_DESCRIPTOR tempRegion = regionArray[0];
  2653. regionArray[0] = regionArray[freeSpaceI];
  2654. regionArray[freeSpaceI] = tempRegion;
  2655. i = 1;
  2656. } else {
  2657. i = 0;
  2658. }
  2659. // Get a pointer to the FT object for the broken member. Can't do this
  2660. // in the loop above because the broken member might be on an off-line
  2661. // disk.
  2662. for (ftObject=GET_FT_OBJECT(regionArray[i])->Set->Members; ftObject; ftObject = ftObject->Next) {
  2663. if (ftObject->State != Healthy) {
  2664. break;
  2665. }
  2666. }
  2667. FDASSERT(ftObject);
  2668. // Determine if the action is allowed.
  2669. if (ftObject->Set) {
  2670. switch (ftObject->Set->Status) {
  2671. case FtSetInitializing:
  2672. case FtSetRegenerating:
  2673. ErrorDialog(MSG_CANT_REGEN_INITIALIZING_SET);
  2674. return;
  2675. break;
  2676. default:
  2677. break;
  2678. }
  2679. }
  2680. // Must lock the volume to perform this operation.
  2681. if (CommitToLockList(regionArray[i], FALSE, TRUE, FALSE)) {
  2682. // Could not lock the volume - try again, the file systems appear
  2683. // to be confused.
  2684. if (CommitToLockList(regionArray[i], FALSE, TRUE, FALSE)) {
  2685. // Don't allow the delete.
  2686. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
  2687. return;
  2688. }
  2689. }
  2690. if (freeSpace) {
  2691. LARGE_INTEGER temp;
  2692. PPERSISTENT_REGION_DATA regionData,
  2693. regionDataTemp;
  2694. // Make sure the free space region is large enough.
  2695. temp = FdGetExactSize(freeSpace, FALSE);
  2696. if (temp.QuadPart < minimumSize.QuadPart) {
  2697. SetCursor(hcurNormal);
  2698. ErrorDialog(MSG_NOT_LARGE_ENOUGH_FOR_STRIPE);
  2699. return;
  2700. }
  2701. // Create the new partition.
  2702. CreatePartitionEx(freeSpace,
  2703. minimumSize,
  2704. 0,
  2705. freeSpace->RegionType,
  2706. regionArray[1]->SysID);
  2707. // Set up the new partition's persistent data
  2708. regionDataTemp = PERSISTENT_DATA(regionArray[1]);
  2709. regionData = DmAllocatePersistentData(regionDataTemp->VolumeLabel,
  2710. regionDataTemp->TypeName,
  2711. regionDataTemp->DriveLetter);
  2712. regionData->FtObject = ftObject;
  2713. DmSetPersistentRegionData(freeSpace, regionData);
  2714. // Check to see if member zero of the set changed and
  2715. // the drive letter needs to move.
  2716. if (!ftObject->MemberIndex) {
  2717. // This is member zero. Move the drive letter to the
  2718. // new region descriptor.
  2719. CommitToAssignLetterList(freeSpace, TRUE);
  2720. }
  2721. // If the unhealthy member is on-line, delete it.
  2722. // Otherwise remove it from the off-line disk.
  2723. if (unhealthy) {
  2724. DmFreePersistentData(PERSISTENT_DATA(unhealthy));
  2725. DmSetPersistentRegionData(unhealthy, NULL);
  2726. DeletePartition(unhealthy);
  2727. }
  2728. // Remove any offline disks - this doesn't really
  2729. // delete the set.
  2730. FdftDeleteFtObjectSet(ftObject->Set, TRUE);
  2731. }
  2732. ftObject->Set->Ordinal = FdftNextOrdinal(StripeWithParity);
  2733. ftObject->State = Regenerating;
  2734. ftObject->Set->Status = FtSetRecovered;
  2735. RegistryChanged = TRUE;
  2736. CompleteMultiRegionOperation();
  2737. SetCursor(hcurNormal);
  2738. }
  2739. VOID
  2740. AdjustOptionsMenu(
  2741. VOID
  2742. )
  2743. /*++
  2744. Routine Description:
  2745. This routine updates the options menu (i.e. maintains
  2746. the state of the menu items for whether the status bar
  2747. or legend are displayed).
  2748. Arguments:
  2749. None
  2750. Return Value:
  2751. None
  2752. --*/
  2753. {
  2754. RECT rc;
  2755. CheckMenuItem(GetMenu(hwndFrame),
  2756. IDM_OPTIONSSTATUS,
  2757. MF_BYCOMMAND | (StatusBar ? MF_CHECKED : MF_UNCHECKED));
  2758. CheckMenuItem(GetMenu(hwndFrame),
  2759. IDM_OPTIONSLEGEND,
  2760. MF_BYCOMMAND | (Legend ? MF_CHECKED : MF_UNCHECKED));
  2761. GetClientRect(hwndFrame, &rc);
  2762. SendMessage(hwndFrame, WM_SIZE, SIZENORMAL, MAKELONG(rc.right, rc.bottom));
  2763. InvalidateRect(hwndFrame, NULL, TRUE);
  2764. }
  2765. VOID
  2766. FrameCommandHandler(
  2767. IN HWND hwnd,
  2768. IN DWORD wParam,
  2769. IN LONG lParam
  2770. )
  2771. /*++
  2772. Routine Description:
  2773. This routine handles WM_COMMAND messages for the frame window.
  2774. Arguments:
  2775. None.
  2776. Return Value:
  2777. None.
  2778. --*/
  2779. {
  2780. DWORD i,
  2781. pos;
  2782. DWORD HelpFlag;
  2783. POINT point;
  2784. switch (LOWORD(wParam)) {
  2785. case IDM_PARTITIONCREATE:
  2786. DoCreate(REGION_PRIMARY);
  2787. break;
  2788. case IDM_PARTITIONCREATEEX:
  2789. DoCreate(REGION_EXTENDED);
  2790. break;
  2791. case IDM_PARTITIONDELETE:
  2792. switch (FtSelectionType) {
  2793. case Mirror:
  2794. DoBreakAndDeleteMirror();
  2795. break;
  2796. case Stripe:
  2797. case StripeWithParity:
  2798. DoDeleteStripe();
  2799. break;
  2800. case VolumeSet:
  2801. DoDeleteVolumeSet();
  2802. break;
  2803. default:
  2804. DoDelete();
  2805. break;
  2806. }
  2807. break;
  2808. #if i386
  2809. case IDM_PARTITIONACTIVE:
  2810. DoMakeActive();
  2811. break;
  2812. #endif
  2813. case IDM_SECURESYSTEM:
  2814. DoProtectSystemPartition();
  2815. break;
  2816. case IDM_PARTITIONLETTER:
  2817. {
  2818. int driveLetterIn,
  2819. driveLetterOut;
  2820. PREGION_DESCRIPTOR regionDescriptor;
  2821. PPERSISTENT_REGION_DATA regionData;
  2822. PFT_OBJECT ftObject;
  2823. ULONG index;
  2824. regionDescriptor = &SELECTED_REGION(0);
  2825. FDASSERT(regionDescriptor);
  2826. regionData = PERSISTENT_DATA(regionDescriptor);
  2827. FDASSERT(regionData);
  2828. if (ftObject = regionData->FtObject) {
  2829. // Must find the zero member of this set for the
  2830. // drive letter assignment. Search all of the selected
  2831. // regions
  2832. index = 0;
  2833. while (ftObject->MemberIndex) {
  2834. // search the next selected item if there is one
  2835. index++;
  2836. if (index >= SelectionCount) {
  2837. ftObject = NULL;
  2838. break;
  2839. }
  2840. regionDescriptor = &SELECTED_REGION(index);
  2841. FDASSERT(regionDescriptor);
  2842. regionData = PERSISTENT_DATA(regionDescriptor);
  2843. FDASSERT(regionData);
  2844. ftObject = regionData->FtObject;
  2845. // must have an FtObject to continue
  2846. if (!ftObject) {
  2847. break;
  2848. }
  2849. }
  2850. if (!ftObject) {
  2851. // This is really an internal error.
  2852. }
  2853. // regionDescriptor locates the zero element now.
  2854. }
  2855. driveLetterIn = (int)(UCHAR)regionData->DriveLetter;
  2856. if (IsDiskRemovable[regionDescriptor->Disk]) {
  2857. ErrorDialog(MSG_CANT_ASSIGN_LETTER_TO_REMOVABLE);
  2858. } else if (AllDriveLettersAreUsed() && ((driveLetterIn == NO_DRIVE_LETTER_YET) || (driveLetterIn == NO_DRIVE_LETTER_EVER))) {
  2859. ErrorDialog(MSG_ALL_DRIVE_LETTERS_USED);
  2860. } else {
  2861. driveLetterOut = DialogBoxParam(hModule,
  2862. MAKEINTRESOURCE(IDD_DRIVELET),
  2863. hwndFrame,
  2864. (DLGPROC)DriveLetterDlgProc,
  2865. (LONG)regionDescriptor);
  2866. if (driveLetterOut) {
  2867. LETTER_ASSIGNMENT_RESULT result;
  2868. if ((driveLetterIn == NO_DRIVE_LETTER_YET) || (driveLetterIn == NO_DRIVE_LETTER_EVER)) {
  2869. // Must insure that driveLetterIn maps to same things
  2870. // as is returned by the dialog when the user selects
  2871. // no letter.
  2872. driveLetterIn = NO_DRIVE_LETTER_EVER;
  2873. }
  2874. if (driveLetterOut != driveLetterIn) {
  2875. if (result = CommitDriveLetter(regionDescriptor, (CHAR) driveLetterIn, (CHAR)driveLetterOut)) {
  2876. // The following would be more rigorously correct:
  2877. // if non-ft, just set regionData->DriveLetter. If
  2878. // ft, scan all regions on all disks for members of
  2879. // ft set and set their drive letter fields.
  2880. //
  2881. // The below is probably correct, though.
  2882. for (i=0; i<SelectionCount; i++) {
  2883. PERSISTENT_DATA(&SELECTED_REGION(i))->DriveLetter = (CHAR)driveLetterOut;
  2884. }
  2885. // Don't allow the letter that is actually in use
  2886. // and will only change on a reboot to cycle back
  2887. // into the free list.
  2888. if (result != MustReboot) {
  2889. // Mark old letter free, new one used.
  2890. MarkDriveLetterFree((CHAR)driveLetterIn);
  2891. }
  2892. MarkDriveLetterUsed((CHAR)driveLetterOut);
  2893. // force status area and all disk bars to be redrawn
  2894. if (SelectionCount > 1) {
  2895. CompleteMultiRegionOperation();
  2896. } else {
  2897. CompleteSingleRegionOperation(SingleSel);
  2898. }
  2899. EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
  2900. }
  2901. }
  2902. }
  2903. }
  2904. break;
  2905. }
  2906. case IDM_PARTITIONFORMAT: {
  2907. PREGION_DESCRIPTOR regionDescriptor;
  2908. regionDescriptor = &SELECTED_REGION(0);
  2909. FDASSERT(regionDescriptor);
  2910. FormatPartition(regionDescriptor);
  2911. break;
  2912. }
  2913. case IDM_PARTITIONLABEL: {
  2914. PREGION_DESCRIPTOR regionDescriptor;
  2915. regionDescriptor = &SELECTED_REGION(0);
  2916. FDASSERT(regionDescriptor);
  2917. LabelPartition(regionDescriptor);
  2918. break;
  2919. }
  2920. case IDM_PARTITIONEXIT:
  2921. SendMessage(hwndFrame,WM_CLOSE,0,0);
  2922. break;
  2923. case IDM_CONFIGMIGRATE:
  2924. if (DoMigratePreviousFtConfig()) {
  2925. // Determine if the FT driver must be enabled.
  2926. SetCursor(hcurWait);
  2927. Sleep(2000);
  2928. if (DiskRegistryRequiresFt() == TRUE) {
  2929. DiskRegistryEnableFt();
  2930. } else {
  2931. DiskRegistryDisableFt();
  2932. }
  2933. // wait four seconds before shutdown
  2934. Sleep(4000);
  2935. SetCursor(hcurNormal);
  2936. FdShutdownTheSystem();
  2937. }
  2938. break;
  2939. case IDM_CONFIGSAVE:
  2940. DoSaveFtConfig();
  2941. break;
  2942. case IDM_CONFIGRESTORE:
  2943. if (DoRestoreFtConfig()) {
  2944. // Determine if the FT driver must be enabled.
  2945. if (DiskRegistryRequiresFt() == TRUE) {
  2946. DiskRegistryEnableFt();
  2947. } else {
  2948. DiskRegistryDisableFt();
  2949. }
  2950. // wait five seconds before shutdown
  2951. SetCursor(hcurWait);
  2952. Sleep(5000);
  2953. SetCursor(hcurNormal);
  2954. FdShutdownTheSystem();
  2955. }
  2956. break;
  2957. case IDM_FTESTABLISHMIRROR:
  2958. DoEstablishMirror();
  2959. break;
  2960. case IDM_FTBREAKMIRROR:
  2961. DoBreakMirror();
  2962. break;
  2963. case IDM_FTCREATESTRIPE:
  2964. DoCreateStripe(FALSE);
  2965. break;
  2966. case IDM_FTCREATEPSTRIPE:
  2967. DoCreateStripe(TRUE);
  2968. break;
  2969. case IDM_FTCREATEVOLUMESET:
  2970. DoCreateVolumeSet();
  2971. break;
  2972. case IDM_FTEXTENDVOLUMESET:
  2973. DoExtendVolumeSet();
  2974. break;
  2975. case IDM_FTRECOVERSTRIPE:
  2976. DoRecoverStripe();
  2977. break;
  2978. #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
  2979. case IDM_DBLSPACE:
  2980. DblSpace(hwndFrame, NULL);
  2981. break;
  2982. case IDM_AUTOMOUNT: {
  2983. HMENU hMenu;
  2984. if (DoubleSpaceAutomount) {
  2985. DoubleSpaceAutomount = FALSE;
  2986. } else {
  2987. DoubleSpaceAutomount = TRUE;
  2988. }
  2989. DiskRegistryDblSpaceRemovable(DoubleSpaceAutomount);
  2990. hMenu = GetMenu(hwndFrame);
  2991. CheckMenuItem(hMenu,
  2992. IDM_AUTOMOUNT,
  2993. (DoubleSpaceAutomount) ? MF_CHECKED : MF_UNCHECKED);
  2994. break;
  2995. }
  2996. #endif
  2997. case IDM_CDROM:
  2998. CdRom(hwndFrame, NULL);
  2999. break;
  3000. case IDM_COMMIT:
  3001. CommitAllChanges(NULL);
  3002. EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_ENABLED);
  3003. break;
  3004. case IDM_OPTIONSSTATUS:
  3005. StatusBar = !StatusBar;
  3006. AdjustOptionsMenu();
  3007. break;
  3008. case IDM_OPTIONSLEGEND:
  3009. Legend = !Legend;
  3010. AdjustOptionsMenu();
  3011. break;
  3012. case IDM_OPTIONSCOLORS:
  3013. switch(DialogBox(hModule, MAKEINTRESOURCE(IDD_COLORS), hwnd, (DLGPROC)ColorDlgProc)) {
  3014. case IDOK:
  3015. for (i=0; i<BRUSH_ARRAY_SIZE; i++) {
  3016. DeleteObject(Brushes[i]);
  3017. Brushes[i] = CreateHatchBrush(AvailableHatches[BrushHatches[i] = SelectedHatch[i]],
  3018. AvailableColors[BrushColors[i] = SelectedColor[i]]);
  3019. }
  3020. SetCursor(hcurWait);
  3021. TotalRedrawAndRepaint();
  3022. if (Legend) {
  3023. InvalidateRect(hwndFrame, NULL, FALSE);
  3024. }
  3025. SetCursor(hcurNormal);
  3026. break;
  3027. case IDCANCEL:
  3028. break;
  3029. case -1:
  3030. ErrorDialog(ERROR_NOT_ENOUGH_MEMORY);
  3031. break;
  3032. default:
  3033. FDASSERT(0);
  3034. }
  3035. break;
  3036. case IDM_OPTIONSDISPLAY: {
  3037. PBAR_TYPE newBarTypes = Malloc(DiskCount * sizeof(BAR_TYPE));
  3038. for (i=0; i<DiskCount; i++) {
  3039. newBarTypes[i] = Disks[i]->BarType;
  3040. }
  3041. switch (DialogBoxParam(hModule,
  3042. MAKEINTRESOURCE(IDD_DISPLAYOPTIONS),
  3043. hwnd,
  3044. (DLGPROC)DisplayOptionsDlgProc,
  3045. (DWORD)newBarTypes)) {
  3046. case IDOK:
  3047. SetCursor(hcurWait);
  3048. for (i=0; i<DiskCount; i++) {
  3049. Disks[i]->BarType = newBarTypes[i];
  3050. }
  3051. TotalRedrawAndRepaint();
  3052. SetCursor(hcurNormal);
  3053. break;
  3054. case IDCANCEL:
  3055. break;
  3056. default:
  3057. FDASSERT(0);
  3058. }
  3059. Free(newBarTypes);
  3060. break;
  3061. }
  3062. case IDM_HELPCONTENTS:
  3063. case IDM_HELP:
  3064. HelpFlag = HELP_INDEX;
  3065. goto CallWinHelp;
  3066. break;
  3067. case IDM_HELPSEARCH:
  3068. HelpFlag = HELP_PARTIALKEY;
  3069. goto CallWinHelp;
  3070. break;
  3071. case IDM_HELPHELP:
  3072. HelpFlag = HELP_HELPONHELP;
  3073. goto CallWinHelp;
  3074. break;
  3075. case IDM_HELPABOUT: {
  3076. TCHAR title[100];
  3077. LoadString(hModule, IDS_APPNAME, title, sizeof(title)/sizeof(TCHAR));
  3078. ShellAbout(hwndFrame, title, NULL, (HICON)GetClassLong(hwndFrame, GCL_HICON));
  3079. break;
  3080. }
  3081. #if DBG && DEVL
  3082. case IDM_DEBUGALLOWDELETES:
  3083. AllowAllDeletes = !AllowAllDeletes;
  3084. CheckMenuItem(GetMenu(hwndFrame),
  3085. IDM_DEBUGALLOWDELETES,
  3086. AllowAllDeletes ? MF_CHECKED : MF_UNCHECKED);
  3087. break;
  3088. #endif
  3089. case ID_LISTBOX:
  3090. switch (HIWORD(wParam)) {
  3091. case LBN_SELCHANGE:
  3092. point.x = LOWORD(pos = GetMessagePos());
  3093. point.y = HIWORD(pos);
  3094. MouseSelection(GetKeyState(VK_CONTROL) & ~1, // strip toggle bit
  3095. &point);
  3096. return;
  3097. default:
  3098. DefWindowProc(hwnd, WM_COMMAND, wParam, lParam);
  3099. return;
  3100. }
  3101. break;
  3102. default:
  3103. DefWindowProc(hwnd, WM_COMMAND, wParam, lParam);
  3104. }
  3105. return;
  3106. CallWinHelp:
  3107. if (!WinHelp(hwndFrame, HelpFile, HelpFlag, (LONG)"")) {
  3108. WarningDialog(MSG_HELP_ERROR);
  3109. }
  3110. }
  3111. DWORD
  3112. DeletionIsAllowed(
  3113. IN PREGION_DESCRIPTOR Region
  3114. )
  3115. /*++
  3116. Routine Description:
  3117. This routine makes sure deletion of the partition is allowed. We do not
  3118. allow the user to delete the Windows NT boot partition or the active
  3119. partition on disk 0 (x86 only).
  3120. Note that this routine is also used to determine whether an existing
  3121. single-partition volume can be extended into a volume set, since the
  3122. criteria are the same.
  3123. Arguments:
  3124. Region - points to region descriptor for the region which the user would
  3125. like to delete.
  3126. Return Value:
  3127. NO_ERROR if deletion is allowed; error number for message to display
  3128. if not.
  3129. --*/
  3130. {
  3131. ULONG ec;
  3132. PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
  3133. FDASSERT(!IsExtended(Region->SysID)); // can't be extended partition
  3134. FDASSERT(Region->SysID != SYSID_UNUSED); // can't be free space
  3135. #if DBG && DEVL
  3136. if (AllowAllDeletes) {
  3137. return NO_ERROR;
  3138. }
  3139. #endif
  3140. // if this is not an original region, deletion is allowed.
  3141. if (!Region->OriginalPartitionNumber) {
  3142. return NO_ERROR;
  3143. }
  3144. // if there is no persistent data for this region, allow deletion.
  3145. if (regionData == NULL) {
  3146. return NO_ERROR;
  3147. }
  3148. ec = NO_ERROR;
  3149. // Determine the Windows NT drive by determining the windows directory
  3150. // and pulling out the first letter.
  3151. if (BootDiskNumber != (ULONG)-1) {
  3152. // If the disk number and original partition number of this
  3153. // region match the recorded disk number and partition number
  3154. // of the boot partition, don't allow deletion.
  3155. if (Region->Disk == BootDiskNumber &&
  3156. Region->OriginalPartitionNumber == BootPartitionNumber) {
  3157. ec = MSG_CANT_DELETE_WINNT;
  3158. }
  3159. }
  3160. #if i386
  3161. if (ec == NO_ERROR) {
  3162. if (!Region->Disk && Region->Active) {
  3163. ec = MSG_CANT_DELETE_ACTIVE0;
  3164. }
  3165. }
  3166. #endif
  3167. return ec;
  3168. }
  3169. BOOLEAN
  3170. BootPartitionNumberChanged(
  3171. PULONG OldNumber,
  3172. PULONG NewNumber
  3173. )
  3174. /*++
  3175. Routine Description
  3176. This function determines whether the partition number of
  3177. the boot partition has changed during this invocation of
  3178. Windisk. With dynamic partitioning enabled, the work of
  3179. this routine increases. This routine must guess what the
  3180. partition numbers will be when the system is rebooted to
  3181. determine if the partition number for the boot partition
  3182. has changed. It does this via the following algorithm:
  3183. 1. Count all primary partitions - These get numbers first
  3184. starting from 1.
  3185. 2. Count all logical drives - These get numbers second starting
  3186. from the count of primary partitions plus 1.
  3187. The partition numbers located in the region structures cannot
  3188. be assumed to be valid. This work must be done from the
  3189. region array located in the disk state structure for the
  3190. disk.
  3191. Arguments:
  3192. None.
  3193. Return Value:
  3194. TRUE if the boot partition's partition number has changed.
  3195. --*/
  3196. {
  3197. PDISKSTATE bootDisk;
  3198. PREGION_DESCRIPTOR regionDescriptor,
  3199. bootDescriptor = NULL;
  3200. ULONG i,
  3201. partitionNumber = 0;
  3202. if (BootDiskNumber == (ULONG)(-1) || BootDiskNumber > DiskCount) {
  3203. // Can't tell--assume it hasn't.
  3204. return FALSE;
  3205. }
  3206. if (!ChangeCommittedOnDisk(BootDiskNumber)) {
  3207. // disk wasn't changed - no possibility for a problem.
  3208. return FALSE;
  3209. }
  3210. bootDisk = Disks[BootDiskNumber];
  3211. // Find the region descriptor for the boot partition
  3212. for (i = 0; i < bootDisk->RegionCount; i++) {
  3213. regionDescriptor = &bootDisk->RegionArray[i];
  3214. if (regionDescriptor->OriginalPartitionNumber == BootPartitionNumber) {
  3215. bootDescriptor = regionDescriptor;
  3216. break;
  3217. }
  3218. }
  3219. if (!bootDescriptor) {
  3220. // Can't find boot partition - assume no change
  3221. return FALSE;
  3222. }
  3223. // No go through the region descriptors and count the partition
  3224. // numbers as they will be counted during system boot.
  3225. //
  3226. // If the boot region is located determine if the partition
  3227. // number changed.
  3228. for (i = 0; i < bootDisk->RegionCount; i++) {
  3229. regionDescriptor = &bootDisk->RegionArray[i];
  3230. if ((regionDescriptor->RegionType == REGION_PRIMARY) &&
  3231. (!IsExtended(regionDescriptor->SysID) &&
  3232. (regionDescriptor->SysID != SYSID_UNUSED))) {
  3233. partitionNumber++;
  3234. if (regionDescriptor == bootDescriptor) {
  3235. if (partitionNumber != regionDescriptor->OriginalPartitionNumber) {
  3236. *OldNumber = regionDescriptor->OriginalPartitionNumber;
  3237. *NewNumber = partitionNumber;
  3238. return TRUE;
  3239. } else {
  3240. // Numbers match, no problem.
  3241. return FALSE;
  3242. }
  3243. }
  3244. }
  3245. }
  3246. // Check the logical drives as well.
  3247. for (i = 0; i < bootDisk->RegionCount; i++) {
  3248. regionDescriptor = &bootDisk->RegionArray[i];
  3249. if (regionDescriptor->RegionType == REGION_LOGICAL) {
  3250. partitionNumber++;
  3251. if (regionDescriptor == bootDescriptor) {
  3252. if (partitionNumber != regionDescriptor->OriginalPartitionNumber) {
  3253. *OldNumber = regionDescriptor->OriginalPartitionNumber;
  3254. *NewNumber = partitionNumber;
  3255. return TRUE;
  3256. } else {
  3257. return FALSE;
  3258. }
  3259. }
  3260. }
  3261. }
  3262. return FALSE;
  3263. }
  3264. DWORD
  3265. CommitChanges(
  3266. VOID
  3267. )
  3268. /*++
  3269. Routine Description:
  3270. This routine updates the disks to reflect changes made by the user
  3271. the partitioning scheme, or to stamp signatures on disks.
  3272. If the partitioning scheme on a disk has changed at all, a check will
  3273. first be made for a valid signature on the mbr in sector 0. If the
  3274. signature is not valid, x86 boot code will be written to the sector.
  3275. Arguments:
  3276. None.
  3277. Return Value:
  3278. Windows error code.
  3279. --*/
  3280. {
  3281. unsigned i;
  3282. DWORD ec,
  3283. rc = NO_ERROR;
  3284. for (i=0; i<DiskCount; i++) {
  3285. if (HavePartitionsBeenChanged(i)) {
  3286. ec = MasterBootCode(i, 0, TRUE, FALSE);
  3287. // MasterBootCode has already translated the NT error
  3288. // status into a Windows error status.
  3289. if (rc == NO_ERROR) {
  3290. rc = ec; // save first non-success return code
  3291. }
  3292. ec = CommitPartitionChanges(i);
  3293. // CommitPartitionChanges returns a native NT error, it
  3294. // must be translated before it can be saved.
  3295. if (ec != NO_ERROR) {
  3296. ec = RtlNtStatusToDosError(ec);
  3297. }
  3298. if (rc == NO_ERROR) { // save first non-success return code
  3299. rc = ec;
  3300. }
  3301. }
  3302. }
  3303. if (rc != NO_ERROR) {
  3304. // If CommitPartitionChanges returns an error, it will be
  3305. // an NT status, which needs to be converted to a DOS status.
  3306. if (rc == ERROR_MR_MID_NOT_FOUND) {
  3307. ErrorDialog(MSG_ERROR_DURING_COMMIT);
  3308. } else {
  3309. ErrorDialog(rc);
  3310. }
  3311. }
  3312. return rc;
  3313. }
  3314. BOOL
  3315. AssignDriveLetter(
  3316. IN BOOL WarnIfNoLetter,
  3317. IN DWORD StringId,
  3318. OUT PCHAR DriveLetter
  3319. )
  3320. /*++
  3321. Routine Description:
  3322. Determine the next available drive letter. If no drive letters are
  3323. available, optionally warn the user and allow him to cancel the
  3324. operation.
  3325. Arguments:
  3326. WarnIfNoLetter - whether to warn the user if no drive letters are
  3327. available and allow him to cancel the operation.
  3328. StringId - resource containing the name of the object being created
  3329. that will need a drive letter (ie, partition, logical drive, stripe
  3330. set, volume set).
  3331. DriveLetter - receives the drive letter to assign, or NO_DRIVE_LETTER_YET
  3332. if no more left.
  3333. Return Value:
  3334. If there were no more drive letters, returns TRUE if the user wants
  3335. to create anyway, FALSE if he canceled. If there were drive letters
  3336. available, the return value is undefined.
  3337. --*/
  3338. {
  3339. CHAR driveLetter;
  3340. TCHAR name[256];
  3341. driveLetter = GetAvailableDriveLetter();
  3342. if (WarnIfNoLetter && !driveLetter) {
  3343. LoadString(hModule, StringId, name, sizeof(name)/sizeof(TCHAR));
  3344. if (ConfirmationDialog(MSG_NO_AVAIL_LETTER, MB_ICONQUESTION | MB_YESNO, name) != IDYES) {
  3345. return FALSE;
  3346. }
  3347. }
  3348. if (!driveLetter) {
  3349. driveLetter = NO_DRIVE_LETTER_YET;
  3350. }
  3351. *DriveLetter = driveLetter;
  3352. return TRUE;
  3353. }
  3354. VOID
  3355. DeterminePartitioningState(
  3356. IN OUT PDISKSTATE DiskState
  3357. )
  3358. /*++
  3359. Routine Description:
  3360. This routine determines the disk's partitioning state (ie, what types
  3361. of partitions exist and may be created), filling out a DISKSTATE
  3362. structure with the info. It also allocates the array for the
  3363. left/right position pairs for each region's on-screen square.
  3364. Arguments:
  3365. DiskState - the CreateXXX and ExistXXX fields will be filled in for the
  3366. disk in the Disk field
  3367. Return Value:
  3368. None.
  3369. --*/
  3370. {
  3371. DWORD i;
  3372. // If there's an existing region array there, free it.
  3373. if (DiskState->RegionArray) {
  3374. FreeRegionArray(DiskState->RegionArray, DiskState->RegionCount);
  3375. }
  3376. // get the region array for the disk in question
  3377. GetAllDiskRegions(DiskState->Disk,
  3378. &DiskState->RegionArray,
  3379. &DiskState->RegionCount);
  3380. // Allocate the array for the left/right coords for the graph.
  3381. // This may overallocate by one square (for extended partition).
  3382. DiskState->LeftRight = Realloc(DiskState->LeftRight,
  3383. DiskState->RegionCount * sizeof(LEFTRIGHT));
  3384. DiskState->Selected = Realloc(DiskState->Selected,
  3385. DiskState->RegionCount * sizeof(BOOLEAN));
  3386. for (i=0; i<DiskState->RegionCount; i++) {
  3387. DiskState->Selected[i] = FALSE;
  3388. }
  3389. // figure out whether various creations are allowed
  3390. IsAnyCreationAllowed(DiskState->Disk,
  3391. TRUE,
  3392. &DiskState->CreateAny,
  3393. &DiskState->CreatePrimary,
  3394. &DiskState->CreateExtended,
  3395. &DiskState->CreateLogical);
  3396. // figure out whether various partition types exist
  3397. DoesAnyPartitionExist(DiskState->Disk,
  3398. &DiskState->ExistAny,
  3399. &DiskState->ExistPrimary,
  3400. &DiskState->ExistExtended,
  3401. &DiskState->ExistLogical);
  3402. }
  3403. VOID
  3404. DrawDiskBar(
  3405. IN PDISKSTATE DiskState
  3406. )
  3407. /*++
  3408. Routine Description:
  3409. This routine will draw the disk bar into the window.
  3410. Arguments:
  3411. DiskState - current disk to draw.
  3412. Return Value:
  3413. None
  3414. --*/
  3415. {
  3416. PREGION_DESCRIPTOR regionDescriptor;
  3417. PDISKSTATE diskState;
  3418. LONGLONG temp1,
  3419. temp2;
  3420. HDC hDCMem = DiskState->hDCMem;
  3421. DWORD leftAdjust = BarLeftX,
  3422. xDiskText,
  3423. cx = 0,
  3424. brushIndex = 0;
  3425. HPEN hpenT;
  3426. char text[100],
  3427. textBold[5];
  3428. TCHAR uniText[100],
  3429. uniTextBold[5],
  3430. mbBuffer[16];
  3431. RECT rc;
  3432. HFONT hfontT;
  3433. COLORREF previousColor;
  3434. HBRUSH hbr;
  3435. BOOL isFree,
  3436. isLogical;
  3437. HDC hdcTemp;
  3438. HBITMAP hbmOld;
  3439. PWSTR typeName,
  3440. volumeLabel;
  3441. WCHAR driveLetter;
  3442. BAR_TYPE barType;
  3443. ULONG diskSize,
  3444. largestDiskSize;
  3445. unsigned i;
  3446. // If this is a removable. Update to whatever its current
  3447. // information may be.
  3448. if (IsDiskRemovable[DiskState->Disk]) {
  3449. PPERSISTENT_REGION_DATA regionData;
  3450. // Update the information on this disk.
  3451. regionDescriptor = &DiskState->RegionArray[0];
  3452. regionData = PERSISTENT_DATA(regionDescriptor);
  3453. if (GetVolumeTypeAndSize(DiskState->Disk,
  3454. regionDescriptor->PartitionNumber,
  3455. &volumeLabel,
  3456. &typeName,
  3457. &diskSize)) {
  3458. // Update the values for the removable.
  3459. if (regionData) {
  3460. // Always want RAW file systems to display as "Unknown"
  3461. if (!lstrcmpiW(typeName, L"raw")) {
  3462. Free(typeName);
  3463. typeName = Malloc((wcslen(wszUnknown) * sizeof(WCHAR)) + sizeof(WCHAR));
  3464. lstrcpyW(typeName, wszUnknown);
  3465. }
  3466. if (regionData->VolumeLabel) {
  3467. Free(regionData->VolumeLabel);
  3468. }
  3469. regionData->VolumeLabel = volumeLabel;
  3470. if (regionData->TypeName) {
  3471. Free(regionData->TypeName);
  3472. }
  3473. regionData->TypeName = typeName;
  3474. }
  3475. DiskState->DiskSizeMB = diskSize;
  3476. }
  3477. }
  3478. // figure out largest disk's size
  3479. for (largestDiskSize = i = 0, diskState = Disks[0];
  3480. i < DiskCount;
  3481. diskState = Disks[++i]) {
  3482. if (diskState->DiskSizeMB > largestDiskSize) {
  3483. largestDiskSize = diskState->DiskSizeMB;
  3484. }
  3485. }
  3486. // erase the graph background
  3487. rc.left = rc.top = 0;
  3488. rc.right = GraphWidth + 1;
  3489. rc.bottom = GraphHeight + 1;
  3490. FillRect(hDCMem, &rc, GetStockObject(LTGRAY_BRUSH));
  3491. hpenT = SelectObject(hDCMem,hPenThinSolid);
  3492. // Draw the disk info area: small disk bitmap, some text, and a
  3493. // line across the top.
  3494. //
  3495. // First draw the bitmap.
  3496. hdcTemp = CreateCompatibleDC(hDCMem);
  3497. if (IsDiskRemovable[DiskState->Disk]) {
  3498. hbmOld = SelectObject(hdcTemp, hBitmapRemovableDisk);
  3499. BitBlt(hDCMem,
  3500. xRemovableDisk,
  3501. yRemovableDisk,
  3502. dxRemovableDisk,
  3503. dyRemovableDisk,
  3504. hdcTemp,
  3505. 0,
  3506. 0,
  3507. SRCCOPY);
  3508. } else {
  3509. hbmOld = SelectObject(hdcTemp, hBitmapSmallDisk);
  3510. BitBlt(hDCMem,
  3511. xSmallDisk,
  3512. ySmallDisk,
  3513. dxSmallDisk,
  3514. dySmallDisk,
  3515. hdcTemp,
  3516. 0,
  3517. 0,
  3518. SRCCOPY);
  3519. }
  3520. if (hbmOld) {
  3521. SelectObject(hdcTemp, hbmOld);
  3522. }
  3523. DeleteDC(hdcTemp);
  3524. // Now draw the line.
  3525. if (IsDiskRemovable[DiskState->Disk]) {
  3526. MoveToEx(hDCMem, xRemovableDisk, BarTopYOffset, NULL);
  3527. LineTo(hDCMem, BarLeftX - xRemovableDisk, BarTopYOffset);
  3528. xDiskText = 2 * dxRemovableDisk;
  3529. } else {
  3530. MoveToEx(hDCMem, xSmallDisk, BarTopYOffset, NULL);
  3531. LineTo(hDCMem, BarLeftX - xSmallDisk, BarTopYOffset);
  3532. xDiskText = 2 * dxSmallDisk;
  3533. }
  3534. // Now draw the text.
  3535. hfontT = SelectObject(hDCMem, hFontGraphBold);
  3536. SetTextColor(hDCMem, RGB(0, 0, 0));
  3537. SetBkColor(hDCMem, RGB(192, 192, 192));
  3538. wsprintf(uniText, DiskN, DiskState->Disk);
  3539. TextOut(hDCMem,
  3540. xDiskText,
  3541. BarTopYOffset + dyBarTextLine,
  3542. uniText,
  3543. lstrlen(uniText));
  3544. SelectObject(hDCMem, hFontGraph);
  3545. if (DiskState->OffLine) {
  3546. LoadString(hModule, IDS_OFFLINE, uniText, sizeof(uniText)/sizeof(TCHAR));
  3547. } else {
  3548. LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
  3549. wsprintf(uniText, TEXT("%u %s"), DiskState->DiskSizeMB, mbBuffer);
  3550. }
  3551. TextOut(hDCMem,
  3552. xDiskText,
  3553. BarTopYOffset + (4*dyBarTextLine),
  3554. uniText,
  3555. lstrlen(uniText));
  3556. if (DiskState->OffLine) {
  3557. SelectObject(hDCMem, GetStockObject(LTGRAY_BRUSH));
  3558. Rectangle(hDCMem,
  3559. BarLeftX,
  3560. BarTopYOffset,
  3561. BarLeftX + BarWidth,
  3562. BarBottomYOffset);
  3563. LoadString(hModule, IDS_NO_CONFIG_INFO, uniText, sizeof(uniText)/sizeof(TCHAR));
  3564. TextOut(hDCMem,
  3565. BarLeftX + dxBarTextMargin,
  3566. BarTopYOffset + (4*dyBarTextLine),
  3567. uniText,
  3568. lstrlen(uniText));
  3569. } else {
  3570. // Account for extreme differences in largest to smallest disk
  3571. // by insuring that a disk is always 1/4 the size of the
  3572. // largest disk.
  3573. diskSize = DiskState->DiskSizeMB;
  3574. if (diskSize < largestDiskSize / 4) {
  3575. diskSize = largestDiskSize / 4;
  3576. }
  3577. #if 0
  3578. // manage the horizontal size of the list box in order
  3579. // to get a scroll bar. Perhaps this only needs to be done
  3580. // once. BUGBUG: This will cause a horizontal scroll bar
  3581. // that works correctly, but the region selection code is
  3582. // not prepared for this, so selection of regions doesn't
  3583. // operate correctly.
  3584. largestExtent = (WPARAM)(BarWidth + BarLeftX + 2);
  3585. SendMessage(hwndList, LB_SETHORIZONTALEXTENT, largestExtent, 0);
  3586. #endif
  3587. // If user wants WinDisk to decide which type of view to use, do that
  3588. // here. We'll use a proportional view unless any single region would
  3589. // have a width less than the size of a drive letter.
  3590. if ((barType = DiskState->BarType) == BarAuto) {
  3591. ULONG regionSize;
  3592. barType = BarProportional;
  3593. for (i=0; i<DiskState->RegionCount; i++) {
  3594. regionDescriptor = &DiskState->RegionArray[i];
  3595. if (IsExtended(regionDescriptor->SysID)) {
  3596. continue;
  3597. }
  3598. temp1 = UInt32x32To64(BarWidth, diskSize);
  3599. temp1 *= regionDescriptor->SizeMB;
  3600. temp2 = UInt32x32To64(largestDiskSize, DiskState->DiskSizeMB);
  3601. regionSize = (ULONG) (temp1 / temp2);
  3602. if (regionSize < 12*SELECTION_THICKNESS) {
  3603. barType = BarEqual;
  3604. break;
  3605. }
  3606. }
  3607. }
  3608. if (barType == BarEqual) {
  3609. temp1 = UInt32x32To64(BarWidth, diskSize);
  3610. temp2 = UInt32x32To64((DiskState->RegionCount -
  3611. (DiskState->ExistExtended ? 1 : 0)), largestDiskSize);
  3612. cx = (ULONG) (temp1 / temp2);
  3613. }
  3614. for (i=0; i<DiskState->RegionCount; i++) {
  3615. PFT_OBJECT ftObject = NULL;
  3616. regionDescriptor = &DiskState->RegionArray[i];
  3617. if (!IsExtended(regionDescriptor->SysID)) {
  3618. if (barType == BarProportional) {
  3619. temp1 = UInt32x32To64(BarWidth, diskSize);
  3620. temp1 *= regionDescriptor->SizeMB;
  3621. temp2 = UInt32x32To64(largestDiskSize, DiskState->DiskSizeMB);
  3622. cx = (ULONG) (temp1 / temp2);
  3623. }
  3624. isFree = (regionDescriptor->SysID == SYSID_UNUSED);
  3625. isLogical = (regionDescriptor->RegionType == REGION_LOGICAL);
  3626. if (!isFree) {
  3627. // If we've got a mirror or stripe set, use special colors.
  3628. ftObject = GET_FT_OBJECT(regionDescriptor);
  3629. switch(ftObject ? ftObject->Set->Type : -1) {
  3630. case Mirror:
  3631. brushIndex = BRUSH_MIRROR;
  3632. break;
  3633. case Stripe:
  3634. case StripeWithParity:
  3635. brushIndex = BRUSH_STRIPESET;
  3636. break;
  3637. case VolumeSet:
  3638. brushIndex = BRUSH_VOLUMESET;
  3639. break;
  3640. default:
  3641. brushIndex = isLogical ? BRUSH_USEDLOGICAL : BRUSH_USEDPRIMARY;
  3642. } // end the switch
  3643. }
  3644. previousColor = SetBkColor(hDCMem, RGB(255, 255, 255));
  3645. SetBkMode(hDCMem, OPAQUE);
  3646. if (isFree) {
  3647. // Free space -- cross hatch the whole block.
  3648. hbr = SelectObject(hDCMem,isLogical ? hBrushFreeLogical : hBrushFreePrimary);
  3649. Rectangle(hDCMem,
  3650. leftAdjust,
  3651. BarTopYOffset,
  3652. leftAdjust + cx,
  3653. BarBottomYOffset);
  3654. } else {
  3655. // Used space -- make most of the block white except for
  3656. // a small strip at the top, which gets an identifying color.
  3657. // If the partition is not recognized, leave it all white.
  3658. hbr = SelectObject(hDCMem, GetStockObject(WHITE_BRUSH));
  3659. Rectangle(hDCMem, leftAdjust, BarTopYOffset, leftAdjust + cx, BarBottomYOffset);
  3660. if (IsRecognizedPartition(regionDescriptor->SysID)) {
  3661. SelectObject(hDCMem, Brushes[brushIndex]);
  3662. Rectangle(hDCMem,
  3663. leftAdjust,
  3664. BarTopYOffset,
  3665. leftAdjust + cx,
  3666. BarTopYOffset + (4 * dyBarTextLine / 5) + 1);
  3667. }
  3668. }
  3669. if (hbr) {
  3670. SelectObject(hDCMem, hbr);
  3671. }
  3672. DiskState->LeftRight[i].Left = leftAdjust;
  3673. DiskState->LeftRight[i].Right = leftAdjust + cx - 1;
  3674. // Figure out the type name (ie, unformatted, fat, etc) and
  3675. // volume label.
  3676. typeName = NULL;
  3677. volumeLabel = NULL;
  3678. DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter);
  3679. LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
  3680. if (!typeName) {
  3681. typeName = wszUnknown;
  3682. }
  3683. if (!volumeLabel) {
  3684. volumeLabel = L"";
  3685. }
  3686. wsprintf(text,
  3687. "\n%ws\n%ws\n%u %s",
  3688. volumeLabel,
  3689. typeName,
  3690. regionDescriptor->SizeMB,
  3691. mbBuffer);
  3692. *textBold = 0;
  3693. if (driveLetter != L' ') {
  3694. wsprintf(textBold, "%wc:", driveLetter);
  3695. }
  3696. UnicodeHack(text, uniText);
  3697. UnicodeHack(textBold, uniTextBold);
  3698. // output the text
  3699. rc.left = leftAdjust + dxBarTextMargin;
  3700. rc.right = leftAdjust + cx - dxBarTextMargin;
  3701. rc.top = BarTopYOffset + dyBarTextLine;
  3702. rc.bottom = BarBottomYOffset;
  3703. SetBkMode(hDCMem, TRANSPARENT);
  3704. SelectObject(hDCMem, hFontGraphBold);
  3705. // If this is an unhealthy ft set member, draw the text in red.
  3706. if (!isFree && ftObject
  3707. && (ftObject->State != Healthy)
  3708. && (ftObject->State != Initializing)) {
  3709. SetTextColor(hDCMem, RGB(192, 0, 0));
  3710. } else {
  3711. SetTextColor(hDCMem, RGB(0, 0, 0));
  3712. }
  3713. DrawText(hDCMem, uniTextBold, -1, &rc, DT_LEFT | DT_NOPREFIX);
  3714. SelectObject(hDCMem, hFontGraph);
  3715. DrawText(hDCMem, uniText, -1, &rc, DT_LEFT | DT_NOPREFIX);
  3716. #if i386
  3717. // if this guy is active make a mark in the upper left
  3718. // corner of his rectangle.
  3719. if ((regionDescriptor->SysID != SYSID_UNUSED)
  3720. && (regionDescriptor->Disk == 0)
  3721. && (regionDescriptor->RegionType == REGION_PRIMARY)
  3722. && regionDescriptor->Active) {
  3723. TextOut(hDCMem,
  3724. leftAdjust + dxBarTextMargin,
  3725. BarTopYOffset + 2,
  3726. TEXT("*"),
  3727. 1);
  3728. }
  3729. #endif
  3730. #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
  3731. // Check for DoubleSpace volumes and update display accordingly
  3732. dblSpaceIndex = 0;
  3733. dblSpace = NULL;
  3734. while (dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace)) {
  3735. if (dblSpace->Mounted) {
  3736. SetTextColor(hDCMem, RGB(192,0,0));
  3737. } else {
  3738. SetTextColor(hDCMem, RGB(0,0,0));
  3739. }
  3740. wsprintf(uniText,
  3741. TEXT("%c: %s"),
  3742. dblSpace->DriveLetter,
  3743. dblSpace->FileName);
  3744. rc.left = leftAdjust + dxBarTextMargin + 60;
  3745. rc.right = leftAdjust + cx - dxBarTextMargin;
  3746. rc.top = BarTopYOffset + dyBarTextLine + (dblSpaceIndex * 15);
  3747. rc.bottom = BarBottomYOffset;
  3748. DrawText(hDCMem, uniText, -1, &rc, DT_LEFT | DT_NOPREFIX);
  3749. dblSpaceIndex++;
  3750. }
  3751. #endif
  3752. SetBkColor(hDCMem, previousColor);
  3753. leftAdjust += cx - 1;
  3754. } else {
  3755. DiskState->LeftRight[i].Left = DiskState->LeftRight[i].Right = 0;
  3756. }
  3757. }
  3758. }
  3759. SelectObject(hDCMem, hpenT);
  3760. SelectObject(hDCMem, hfontT);
  3761. }
  3762. VOID
  3763. AdjustMenuAndStatus(
  3764. VOID
  3765. )
  3766. /*++
  3767. Routine Description:
  3768. This routine updates the information in the Status bar
  3769. if something is selected and if the status bar is to be
  3770. displayed.
  3771. Arguments"
  3772. None
  3773. Return Value:
  3774. None
  3775. --*/
  3776. {
  3777. TCHAR mbBuffer[16],
  3778. statusBarPartitionString[200],
  3779. dblSpaceString[200];
  3780. DWORD selectionCount,
  3781. msg,
  3782. regionIndex;
  3783. PDISKSTATE diskState;
  3784. PWSTR volumeLabel,
  3785. typeName;
  3786. WCHAR driveLetter;
  3787. switch (selectionCount = SetUpMenu(&SingleSel,&SingleSelIndex)) {
  3788. case 0:
  3789. StatusTextDrlt[0] = 0;
  3790. StatusTextSize[0] = StatusTextStat[0] = 0;
  3791. StatusTextVoll[0] = StatusTextType[0] = 0;
  3792. break;
  3793. case 1:
  3794. // Might be part of a partial FT set.
  3795. if (FtSelectionType != -1) {
  3796. goto FtSet;
  3797. }
  3798. diskState = SingleSel;
  3799. regionIndex = SingleSelIndex;
  3800. DetermineRegionInfo(&diskState->RegionArray[regionIndex],
  3801. &typeName,
  3802. &volumeLabel,
  3803. &driveLetter);
  3804. lstrcpyW(StatusTextType,typeName);
  3805. lstrcpyW(StatusTextVoll,volumeLabel);
  3806. if (diskState->RegionArray[regionIndex].SysID == SYSID_UNUSED) {
  3807. if (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL) {
  3808. if (diskState->ExistLogical) {
  3809. msg = IDS_FREEEXT;
  3810. } else {
  3811. msg = IDS_EXTENDEDPARTITION;
  3812. }
  3813. } else {
  3814. msg = IDS_FREESPACE;
  3815. }
  3816. driveLetter = L' ';
  3817. StatusTextType[0] = 0;
  3818. } else {
  3819. msg = (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL)
  3820. ? IDS_LOGICALVOLUME
  3821. : IDS_PARTITION;
  3822. #if i386
  3823. if ((msg == IDS_PARTITION) && (diskState->Disk == 0) && diskState->RegionArray[regionIndex].Active) {
  3824. msg = IDS_ACTIVEPARTITION;
  3825. }
  3826. #endif
  3827. }
  3828. LoadString(hModule, msg, statusBarPartitionString, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0]));
  3829. if (DblSpaceVolumeExists(&diskState->RegionArray[regionIndex])) {
  3830. LoadString(hModule, IDS_WITH_DBLSPACE, dblSpaceString, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0]));
  3831. } else {
  3832. dblSpaceString[0] = dblSpaceString[1] = 0;
  3833. }
  3834. wsprintf(StatusTextStat,
  3835. "%s %s",
  3836. statusBarPartitionString,
  3837. dblSpaceString);
  3838. LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
  3839. wsprintf(StatusTextSize,
  3840. "%u %s",
  3841. diskState->RegionArray[regionIndex].SizeMB,
  3842. mbBuffer);
  3843. StatusTextDrlt[0] = driveLetter;
  3844. StatusTextDrlt[1] = (WCHAR)((driveLetter == L' ') ? 0 : L':');
  3845. break;
  3846. default:
  3847. FtSet:
  3848. // Might be an ft set, might be multiple items
  3849. if (FtSelectionType == -1) {
  3850. LoadString(hModule, IDS_MULTIPLEITEMS, StatusTextStat, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0]));
  3851. StatusTextDrlt[0] = 0;
  3852. StatusTextSize[0] = 0;
  3853. StatusTextType[0] = StatusTextVoll[0] = 0;
  3854. } else {
  3855. PREGION_DESCRIPTOR regionDescriptor;
  3856. DWORD resid = 0,
  3857. i;
  3858. DWORD Size = 0;
  3859. TCHAR textbuf[STATUS_TEXT_SIZE];
  3860. PFT_OBJECT_SET ftSet;
  3861. PFT_OBJECT ftObject;
  3862. FT_SET_STATUS setState;
  3863. ULONG numberOfMembers;
  3864. WCHAR ftstat[65];
  3865. STATUS_CODE status;
  3866. typeName = NULL;
  3867. DetermineRegionInfo(&SELECTED_REGION(0),
  3868. &typeName,
  3869. &volumeLabel,
  3870. &driveLetter);
  3871. if (!typeName) {
  3872. if (SelectionCount > 1) {
  3873. DetermineRegionInfo(&SELECTED_REGION(0),
  3874. &typeName,
  3875. &volumeLabel,
  3876. &driveLetter);
  3877. }
  3878. }
  3879. if (!typeName) {
  3880. typeName = wszUnknown;
  3881. volumeLabel = L"";
  3882. }
  3883. lstrcpyW(StatusTextType, typeName);
  3884. lstrcpyW(StatusTextVoll, volumeLabel);
  3885. switch (FtSelectionType) {
  3886. case Mirror:
  3887. resid = IDS_STATUS_MIRROR;
  3888. Size = SELECTED_REGION(0).SizeMB;
  3889. break;
  3890. case Stripe:
  3891. resid = IDS_STATUS_STRIPESET;
  3892. goto CalcSize;
  3893. case StripeWithParity:
  3894. resid = IDS_STATUS_PARITY;
  3895. goto CalcSize;
  3896. case VolumeSet:
  3897. resid = IDS_STATUS_VOLUMESET;
  3898. goto CalcSize;
  3899. CalcSize:
  3900. for (i=0; i<selectionCount; i++) {
  3901. Size += SELECTED_REGION(i).SizeMB;
  3902. }
  3903. break;
  3904. default:
  3905. FDASSERT(FALSE);
  3906. }
  3907. ftObject = GET_FT_OBJECT(&SELECTED_REGION(0));
  3908. ftSet = ftObject->Set;
  3909. if (FtSelectionType != VolumeSet) {
  3910. regionDescriptor = LocateRegionForFtObject(ftSet->Member0);
  3911. if (!regionDescriptor) {
  3912. // The zeroth member is off line
  3913. ftObject = ftSet->Members;
  3914. while (ftObject) {
  3915. // Find member 1
  3916. if (ftObject->MemberIndex == 1) {
  3917. regionDescriptor = LocateRegionForFtObject(ftObject);
  3918. break;
  3919. }
  3920. ftObject = ftObject->Next;
  3921. }
  3922. }
  3923. // If the partition number is zero, then this set has
  3924. // not been committed to the disk yet.
  3925. if ((regionDescriptor) && (regionDescriptor->PartitionNumber)) {
  3926. status = LowFtVolumeStatus(regionDescriptor->Disk,
  3927. regionDescriptor->PartitionNumber,
  3928. &setState,
  3929. &numberOfMembers);
  3930. if (status == OK_STATUS) {
  3931. if ((ftSet->Status != FtSetNewNeedsInitialization) &&
  3932. (ftSet->Status != FtSetNew)) {
  3933. if (ftSet->Status != setState) {
  3934. PFT_OBJECT tempFtObjectPtr;
  3935. ftSet->Status = setState;
  3936. // Determine if each object should be updated.
  3937. switch (setState) {
  3938. case FtSetHealthy:
  3939. // Each object in the set should have
  3940. // the partition state updated. Determine
  3941. // the value for the update and walk
  3942. // the chain to perform the update.
  3943. for (tempFtObjectPtr = ftSet->Members;
  3944. tempFtObjectPtr;
  3945. tempFtObjectPtr = tempFtObjectPtr->Next) {
  3946. tempFtObjectPtr->State = Healthy;
  3947. }
  3948. TotalRedrawAndRepaint();
  3949. break;
  3950. case FtSetInitializing:
  3951. case FtSetRegenerating:
  3952. case FtSetDisabled:
  3953. FdftUpdateFtObjectSet(ftSet, setState);
  3954. TotalRedrawAndRepaint();
  3955. break;
  3956. default:
  3957. break;
  3958. }
  3959. }
  3960. }
  3961. }
  3962. }
  3963. }
  3964. LoadString(hModule, resid, textbuf, sizeof(textbuf)/sizeof(TCHAR));
  3965. switch (resid) {
  3966. case IDS_STATUS_STRIPESET:
  3967. case IDS_STATUS_VOLUMESET:
  3968. wsprintf(StatusTextStat, textbuf, ftSet->Ordinal);
  3969. break;
  3970. case IDS_STATUS_PARITY:
  3971. case IDS_STATUS_MIRROR:
  3972. switch(ftSet->Status) {
  3973. case FtSetHealthy:
  3974. resid = IDS_HEALTHY;
  3975. break;
  3976. case FtSetNew:
  3977. case FtSetNewNeedsInitialization:
  3978. resid = IDS_NEW;
  3979. break;
  3980. case FtSetBroken:
  3981. resid = IDS_BROKEN;
  3982. break;
  3983. case FtSetRecoverable:
  3984. resid = IDS_RECOVERABLE;
  3985. break;
  3986. case FtSetRecovered:
  3987. resid = IDS_REGENERATED;
  3988. break;
  3989. case FtSetInitializing:
  3990. resid = IDS_INITIALIZING;
  3991. break;
  3992. case FtSetRegenerating:
  3993. resid = IDS_REGENERATING;
  3994. break;
  3995. case FtSetDisabled:
  3996. resid = IDS_DISABLED;
  3997. break;
  3998. case FtSetInitializationFailed:
  3999. resid = IDS_INIT_FAILED;
  4000. break;
  4001. default:
  4002. FDASSERT(FALSE);
  4003. }
  4004. LoadStringW(hModule, resid, ftstat, sizeof(ftstat)/sizeof(WCHAR));
  4005. wsprintf(StatusTextStat, textbuf, ftSet->Ordinal,ftstat);
  4006. break;
  4007. default:
  4008. FDASSERT(FALSE);
  4009. }
  4010. LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
  4011. wsprintf(StatusTextSize, "%u %s", Size, mbBuffer);
  4012. StatusTextDrlt[0] = driveLetter;
  4013. StatusTextDrlt[1] = (WCHAR)((driveLetter == L' ') ? 0 : L':');
  4014. }
  4015. }
  4016. UpdateStatusBarDisplay();
  4017. }
  4018. ULONG
  4019. PartitionCount(
  4020. IN ULONG Disk
  4021. )
  4022. /*++
  4023. Routine Description:
  4024. Given a disk index, this routine calculates the number of partitions the
  4025. disk contains.
  4026. Arguments:
  4027. Disk - This disk index for the count.
  4028. Return Value:
  4029. The number of partitions on the disk
  4030. --*/
  4031. {
  4032. unsigned i;
  4033. ULONG partitions = 0;
  4034. PREGION_DESCRIPTOR regionDescriptor;
  4035. for (i=0; i<Disks[Disk]->RegionCount; i++) {
  4036. regionDescriptor = &Disks[Disk]->RegionArray[i];
  4037. if ((regionDescriptor->RegionType != REGION_LOGICAL) && (regionDescriptor->SysID != SYSID_UNUSED)) {
  4038. partitions++;
  4039. }
  4040. }
  4041. return partitions;
  4042. }
  4043. BOOL
  4044. RegisterFileSystemExtend(
  4045. VOID
  4046. )
  4047. /*++
  4048. Routine Description:
  4049. This function adds registry entries to extend the file
  4050. system structures in volume sets that have been extended.
  4051. Arguments:
  4052. None.
  4053. Return Value:
  4054. non-zero if there was a file system that was extended.
  4055. --*/
  4056. {
  4057. BYTE buf[1024];
  4058. PSTR template = "autochk /x ";
  4059. CHAR extendedDrives[26];
  4060. PDISKSTATE diskState;
  4061. PREGION_DESCRIPTOR regionDescriptor;
  4062. PFT_OBJECT ftObject;
  4063. DWORD cExt = 0,
  4064. i,
  4065. j,
  4066. valueType,
  4067. size,
  4068. templateLength;
  4069. HKEY hkey;
  4070. LONG ec;
  4071. // Traverse the disks to find any volume sets that
  4072. // have been extended.
  4073. for (i = 0; i < DiskCount; i++) {
  4074. diskState = Disks[i];
  4075. for (j = 0; j < diskState->RegionCount; j++) {
  4076. regionDescriptor = &diskState->RegionArray[j];
  4077. if ((ftObject = GET_FT_OBJECT(regionDescriptor)) != NULL
  4078. && ftObject->MemberIndex == 0
  4079. && ftObject->Set->Type == VolumeSet
  4080. && ftObject->Set->Status == FtSetExtended) {
  4081. extendedDrives[cExt++] = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
  4082. }
  4083. }
  4084. }
  4085. if (cExt) {
  4086. // Fetch the BootExecute value of the Session Manager key.
  4087. ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4088. TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
  4089. 0,
  4090. KEY_QUERY_VALUE | KEY_SET_VALUE,
  4091. &hkey);
  4092. if (ec != NO_ERROR) {
  4093. return 0;
  4094. }
  4095. size = sizeof(buf);
  4096. ec = RegQueryValueExA(hkey,
  4097. TEXT("BootExecute"),
  4098. NULL,
  4099. &valueType,
  4100. buf,
  4101. &size);
  4102. if (ec != NO_ERROR || valueType != REG_MULTI_SZ) {
  4103. return 0;
  4104. }
  4105. // Decrement size to get rid of the extra trailing null
  4106. if (size) {
  4107. size--;
  4108. }
  4109. templateLength = strlen(template);
  4110. for (i = 0; i < cExt; i++) {
  4111. // Add an entry for this drive to the BootExecute value.
  4112. strncpy(buf+size, template, templateLength);
  4113. size += templateLength;
  4114. buf[size++] = extendedDrives[i];
  4115. buf[size++] = ':';
  4116. buf[size++] = 0;
  4117. }
  4118. // Add an additional trailing null at the end
  4119. buf[size++] = 0;
  4120. // Save the value.
  4121. ec = RegSetValueExA(hkey,
  4122. TEXT("BootExecute"),
  4123. 0,
  4124. REG_MULTI_SZ,
  4125. buf,
  4126. size);
  4127. RegCloseKey( hkey );
  4128. if (ec != NO_ERROR) {
  4129. return 0;
  4130. }
  4131. return 1;
  4132. }
  4133. return 0;
  4134. }