/*++ Copyright (c) 1991-1994 Microsoft Corporation Module Name: windisk.c Abstract: This module contains the main dialog and support routines for Disk Administrator. Author: Edward (Ted) Miller (TedM) 11/15/91 Environment: User process. Notes: Revision History: 11-Nov-93 (bobri) added doublespace and commit support. --*/ #include "fdisk.h" #include "shellapi.h" #include #include #if DBG && DEVL // stuff used in debug version BOOL AllowAllDeletes = FALSE; // whether to allow deleting boot/sys parts #endif // External from fdinit. extern HWND InitDlg; extern BOOLEAN InitDlgComplete; extern BOOLEAN StartedAsIcon; HANDLE hAccelerator; // This is the maximum number of members that WinDisk will support // in an FT Set. #define MaxMembersInFtSet 32 // The following vars keep track of the currently selected regions. DWORD SelectionCount = 0; PDISKSTATE SelectedDS[MaxMembersInFtSet]; ULONG SelectedRG[MaxMembersInFtSet]; #define SELECTED_REGION(i) (SelectedDS[i]->RegionArray[SelectedRG[i]]) FT_TYPE FtSelectionType; // This variable tracks whether the system partition is secure. BOOL SystemPartitionIsSecure = FALSE; // Deleted a partition with no drive letter BOOLEAN CommitDueToDelete = FALSE; BOOLEAN CommitDueToMirror = FALSE; BOOLEAN CommitDueToExtended = FALSE; // If a mirror is made of the boot partition, this will become // non-zero and indicate which disk should get some boot code in // the MBR. ULONG UpdateMbrOnDisk = 0; #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED // If FmIfs.dll doesn't have double space routines this // flag will reflect that fact. extern BOOLEAN DoubleSpaceSupported; BOOLEAN DoubleSpaceAutomount; #endif VOID FrameCommandHandler( IN HWND hwnd, IN DWORD wParam, IN LONG lParam ); DWORD SetUpMenu( IN PDISKSTATE *SinglySelectedDisk, IN DWORD *SinglySelectedRegion ); BOOL AssignDriveLetter( IN BOOL WarnIfNoLetter, IN DWORD StringId, OUT PCHAR DriveLetter ); VOID AdjustOptionsMenu( VOID ); ULONG PartitionCount( IN ULONG Disk ); VOID CheckForBootNumberChange( IN ULONG Disk ) /*++ Routine Description: Determine if the disk that has just changed is the boot disk. If so, determine if the boot partition number changed. If it did, warn the user. Arguments: RegionDescriptor - the region that has just changed. Return Value: None --*/ { ULONG newPart; CHAR oldNumberString[8], newNumberString[8]; DWORD msgCode; if (Disk == BootDiskNumber) { // Pass a pointer to Disk even though this is just to get the // old partition number back. if (BootPartitionNumberChanged(&Disk, &newPart)) { #if i386 msgCode = MSG_CHANGED_BOOT_PARTITION_X86; #else msgCode = MSG_CHANGED_BOOT_PARTITION_ARC; #endif sprintf(oldNumberString, "%d", Disk); sprintf(newNumberString, "%d", newPart); InfoDialog(msgCode, oldNumberString, newNumberString); } } } BOOL IsSystemPartitionSecure( ) /*++ Routine Description: This routine knows where to go in the Registry to determine if the system partition for this boot is to be protected from modification. Arguments: None Return Value: TRUE if the system partition is secure FALSE otherwise. --*/ { LONG ec; HKEY hkey; DWORD type; DWORD size; ULONG value; value = FALSE; ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\Lsa"), 0, KEY_QUERY_VALUE, &hkey); if (ec == NO_ERROR) { size = sizeof(ULONG); ec = RegQueryValueExA(hkey, TEXT("Protect System Partition"), NULL, &type, (PBYTE)&value, &size); if ((ec != NO_ERROR) || (type != REG_DWORD)) { value = FALSE; } RegCloseKey(hkey); } return value; } VOID __cdecl main( IN int argc, IN char *argv[], IN char *envp[] ) /*++ Routine Description: This is were control is given to Disk Administrator when it is started. This routine initializes the application and contains the control loop for getting and processing Windows messages. Arguments: Standard "main" entry Return Value: Standard "main" entry --*/ { MSG msg; NTSTATUS status; HANDLE mutex; hModule = GetModuleHandle(NULL); mutex = CreateMutex(NULL,FALSE,"Disk Administrator Is Running"); if (mutex == NULL) { // An error (like out of memory) has occurred. return; } // Make sure we are the only process with a handle to our named mutex. if (GetLastError() == ERROR_ALREADY_EXISTS) { CloseHandle(mutex); InfoDialog(MSG_ALREADY_RUNNING); return; } else { DisplayInitializationMessage(); } // Determine whether this is LanmanNt or Windows NT by looking at // HKEY_LOCAL_MACHINE,System\CurrentControlSet\Control\ProductOptions. // If the ProductType value therein is "LanmanNt" then this is LanmanNt. { LONG ec; HKEY hkey; DWORD type; DWORD size; UCHAR buf[100]; IsLanmanNt = FALSE; #if DBG // The code below will allow users to run WinDisk in Lanman // mode on WinNt. It should never be enabled in a released // build, but is very useful for internal users. if (argc >= 2 && !_stricmp(argv[1], "-p:lanman")) { IsLanmanNt = TRUE; } #endif ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\ProductOptions"), 0, KEY_QUERY_VALUE, &hkey); if (ec == NO_ERROR) { size = sizeof(buf); ec = RegQueryValueExA(hkey, TEXT("ProductType"), NULL, &type, buf, &size); if ((ec == NO_ERROR) && (type == REG_SZ)) { if (!lstrcmpiA(buf,"lanmannt")) { IsLanmanNt = TRUE; } if (!lstrcmpiA(buf,"servernt")) { IsLanmanNt = TRUE; } } RegCloseKey(hkey); } } // Set the Help file name to the file appropriate to // the product. HelpFile = IsLanmanNt ? LanmanHelpFile : WinHelpFile; // Determine whether the system partition is protected: SystemPartitionIsSecure = IsSystemPartitionSecure(); try { #if DBG InitLogging(); #endif // Insure that all drives are present before looking. RescanDevices(); if (!NT_SUCCESS(status = FdiskInitialize())) { ErrorDialog(status == STATUS_ACCESS_DENIED ? MSG_ACCESS_DENIED : EC(status)); goto xx1; } if (((DiskCount = GetDiskCount()) == 0) || AllDisksOffLine()) { ErrorDialog(MSG_NO_DISKS); goto xx2; } if (!InitializeApp()) { ErrorDialog(MSG_CANT_CREATE_WINDOWS); goto xx2; } InitRectControl(); SetUpMenu(&SingleSel,&SingleSelIndex); AdjustOptionsMenu(); InitHelp(); hAccelerator = LoadAccelerators(hModule, TEXT("MainAcc")); if (InitDlg) { PostMessage(InitDlg, (WM_USER + 1), 0, 0); InitDlg = (HWND) 0; } while (GetMessage(&msg,NULL,0,0)) { if (!TranslateAccelerator(hwndFrame, hAccelerator, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } TermHelp(); UnloadIfsDll(); xx2: FdiskCleanUp(); xx1: ; } finally { // Destroy the mutex. CloseHandle(mutex); } } LONG MyFrameWndProc( IN HWND hwnd, IN UINT msg, IN UINT wParam, IN LONG lParam ) /*++ Routine Description: This is the window handler for the main display of Disk Administrator. Arguments: Standard window handler procedure Return Value: Standard window handler procedure --*/ { static BOOLEAN oneTime = TRUE; PMEASUREITEMSTRUCT pMeasureItem; DWORD ec; DWORD action; DWORD temp; RECT rc; BOOL profileWritten, changesMade, mustReboot, configureFt; HMENU hMenu; switch (msg) { case WM_CREATE: // create the listbox if (!StartedAsIcon) { StartedAsIcon = IsIconic(hwnd); } GetClientRect(hwnd,&rc); #if 1 hwndList = CreateWindow(TEXT("listbox"), NULL, WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED, 0, dyLegend, rc.right - rc.left, rc.bottom - rc.top - (StatusBar ? dyStatus : 0) - (Legend ? dyLegend : 0), hwnd, (HMENU)ID_LISTBOX, hModule, NULL); #else hwndList = CreateWindow(TEXT("listbox"), NULL, WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED, 0, dyLegend, CW_USEDEFAULT, CW_USEDEFAULT, hwnd, (HMENU)ID_LISTBOX, hModule, NULL); #endif if (hwndList) { SetFocus(hwndList); // subclass the listbox so we can handle keyboard // input our way. SubclassListBox(hwndList); } // If we are not running the LanmanNt version of // Windisk, remove the Fault-Tolerance menu item. if (!IsLanmanNt && (hMenu = GetMenu( hwnd )) != NULL ) { DeleteMenu( hMenu, 1, MF_BYPOSITION ); DrawMenuBar( hwnd ); } StatusTextDrlt[0] = 0; StatusTextStat[0] = StatusTextSize[0] = 0; StatusTextType[0] = StatusTextVoll[0] = 0; break; case WM_SETFOCUS: SetFocus(hwndList); break; case WM_WININICHANGE: if ((lParam == (LONG)NULL) || !lstrcmpi((LPTSTR)lParam,TEXT("colors"))) { TotalRedrawAndRepaint(); InvalidateRect(hwnd,NULL,FALSE); } break; case WM_SIZE: // resize the listbox GetClientRect(hwnd,&rc); #if 0 temp = rc.right - rc.left; if (GraphWidth != temp) { GraphWidth = temp; BarWidth = GraphWidth - dxBarTextMargin; } #endif MoveWindow(hwndList, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top - (StatusBar ? dyStatus : 0) - (Legend ? dyLegend : 0), TRUE); // invalidate status/legend area so that the clipping // rectangle is right for redraws rc.top = rc.bottom; if (StatusBar) { rc.top -= dyStatus; } if (Legend) { rc.top -= dyLegend; } if (rc.top != rc.bottom) { InvalidateRect(hwnd,&rc,FALSE); } // FALL THROUGH case WM_MOVE: // if not iconic or minimized, save new position for profile if (!IsZoomed(hwndFrame) && !IsIconic(hwndFrame)) { GetWindowRect(hwndFrame,&rc); ProfileWindowX = rc.left; ProfileWindowY = rc.top; ProfileWindowW = rc.right - rc.left; ProfileWindowH = rc.bottom - rc.top; } break; case WM_ENTERIDLE: if (ConfigurationSearchIdleTrigger == TRUE && wParam == MSGF_DIALOGBOX) { PostMessage((HWND)lParam,WM_ENTERIDLE,wParam,lParam); } else { // If we're coming from a dialog box and the F1 key is down, // kick the dialog box and make it spit out help. if ((wParam == MSGF_DIALOGBOX) && (GetKeyState(VK_F1) & 0x8000) && GetDlgItem((HANDLE) lParam, FD_IDHELP)) { PostMessage((HANDLE) lParam, WM_COMMAND, FD_IDHELP, 0L); } } return 1; // indicate we did not process the message case WM_PAINT: #if 1 if ((!IsIconic(hwnd)) && !(InitDlg && StartedAsIcon)) { #else if (!StartedAsIcon) { #endif HDC hdcTemp,hdcScr; HBITMAP hbmTemp; PAINTSTRUCT ps; HBRUSH hBrush; HFONT hFontOld; RECT rcTemp,rcTemp2; DWORD ClientRight; BeginPaint(hwnd,&ps); hdcScr = ps.hdc; GetClientRect(hwnd,&rc); rcTemp2 = rc; ClientRight = rc.right; rc.top = rc.bottom - dyStatus + dyBorder; if (StatusBar) { hdcTemp = CreateCompatibleDC(hdcScr); hbmTemp = CreateCompatibleBitmap(hdcScr,rc.right-rc.left+1,rc.bottom-rc.top+1); SelectObject(hdcTemp,hbmTemp); // adjust position for off-screen bitmap rcTemp = rc; rc.bottom -= rc.top; rc.top = 0; hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); if (hBrush) { FillRect(hdcTemp,&rc,hBrush); DeleteObject(hBrush); } // draw the status bar at the bottom of the window hFontOld = SelectObject(hdcTemp,hFontStatus); // Status text rc.left = 8 * dyBorder; rc.right = 2 * GraphWidth / 5; DrawStatusAreaItem(&rc,hdcTemp,StatusTextStat,FALSE); // size rc.left = rc.right + (8*dyBorder); rc.right = rc.left + (GraphWidth / 9); DrawStatusAreaItem(&rc,hdcTemp,StatusTextSize,FALSE); // type rc.left = rc.right + (8*dyBorder); rc.right = rc.left + (GraphWidth / 5); DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextType,TRUE); // drive letter rc.left = rc.right + (8*dyBorder); rc.right = rc.left + (8*dyBorder) + dxDriveLetterStatusArea; DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextDrlt,TRUE); // vol label rc.left = rc.right + (8*dyBorder); rc.right = GraphWidth - (8*dyBorder); DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextVoll,TRUE); BitBlt(hdcScr, rcTemp.left, rcTemp.top, rcTemp.right-rcTemp.left+1, rcTemp.bottom-rcTemp.top+1, hdcTemp, 0, 0, SRCCOPY); if (hFontOld) { SelectObject(hdcTemp,hFontOld); } DeleteObject(hbmTemp); DeleteDC(hdcTemp); } else { rcTemp = rcTemp2; rcTemp.top = rcTemp.bottom; } if (Legend) { // draw the legend onto the screen if (StatusBar) { rcTemp2.bottom -= dyStatus; } rcTemp2.top = rcTemp2.bottom - dyLegend + (2*dyBorder); if (StatusBar) { rcTemp2.top += dyBorder; } rcTemp2.right = GraphWidth; DrawLegend(hdcScr,&rcTemp2); } // dark line across top of status/legend area if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNTEXT))) { if (StatusBar || Legend) { rcTemp.bottom = rcTemp.top; if (Legend) { rcTemp.bottom -= dyLegend - 1; rcTemp.top -= dyLegend - 1; } rcTemp.top -= dyBorder; FillRect(hdcScr,&rcTemp,hBrush); } DeleteObject(hBrush); } EndPaint(hwnd,&ps); } if (InitDlg) { if (InitDlgComplete) { PostMessage(InitDlg, (WM_USER + 1), 0, 0); InitDlg = (HWND) 0; } } if (oneTime) { if (!StartedAsIcon) { SetForegroundWindow(hwnd); } oneTime = FALSE; } break; case WM_COMMAND: FrameCommandHandler(hwnd,wParam,lParam); break; case WM_MEASUREITEM: pMeasureItem = (PMEASUREITEMSTRUCT)lParam; pMeasureItem->itemHeight = GraphHeight; break; case WM_DRAWITEM: WMDrawItem((PDRAWITEMSTRUCT)lParam); break; case WM_CTLCOLORLISTBOX: if (lParam == (LONG)hwndList) { return (LONG)GetStockObject(LTGRAY_BRUSH); } else { return DefWindowProc(hwnd,msg,wParam,lParam); } case WM_CLOSE: // Determine whether any disks have been changed, and whether // the system must be rebooted. The system must be rebooted // if the registry has changed, if any non-removable disk has // changed, or if any removable disk that was not originally // unpartitioned has changed. changesMade = FALSE; configureFt = FALSE; mustReboot = RestartRequired; for (temp=0; tempRegionArray[SingleSelIndex]; // allow it to be made active if // - it is not free space // - it is a primary partition // - it is on disk 0 // - it is not already active // - it is not part of an ft set if ((regionDescriptor->SysID != SYSID_UNUSED) && (regionDescriptor->RegionType == REGION_PRIMARY) && !regionDescriptor->Active && (GET_FT_OBJECT(regionDescriptor) == NULL)) { allowActive = TRUE; } } EnableMenuItem(hMenu, IDM_PARTITIONACTIVE, allowActive ? MF_ENABLED : MF_GRAYED); } #endif DWORD SetUpMenu( IN PDISKSTATE *SinglySelectedDisk, IN DWORD *SinglySelectedRegion ) /*++ Routine Description: This routine sets up the menu bar based on the state of the app and the disks. If multiple items are selected, allow neither create nor delete. If a single partition is selected, allow delete. If a single free space is selected, allow create. If the free space is the only free space in the extended partitions, also allow delete. (This is how to delete the extended partition). Arguments: SinglySelectedDisk -- if there is only one selected item, the PDISKSTATE pointed to by this paramater will get a pointer to the selected region's disk structure. If there are multiple selected items (or none), then the value will be set to NULL. SinglySelectedRegion -- if there is only one selected item, the DWORD pointed to by this paramater will get the selected region #. Otherwise the DWORD gets -1. Return Value: Count of selected regions. --*/ { BOOL allowCreate = FALSE, allowCreateEx = FALSE, allowDelete = FALSE, allowFormat = FALSE, allowLabel = FALSE, allowBreakMirror = FALSE, allowCreateMirror = FALSE, allowCreateStripe = FALSE, allowCreateVolumeSet = FALSE, allowExtendVolumeSet = FALSE, allowCreatePStripe = FALSE, allowDriveLetter = FALSE, allowRecoverParity = FALSE, ftSetSelected = FALSE, nonFtItemSelected = FALSE, multipleItemsSelected = FALSE, volumeSetAndFreeSpaceSelected = FALSE, onDifferentDisks, possibleRecover; BOOL allowCommit = CommitAllowed(); WCHAR driveLetter = L' '; PWSTR typeName = NULL, volumeLabel = NULL; PDISKSTATE diskState, selDiskState = NULL; DWORD i, j, selectedRegion = 0; ULONG ordinal = 0, selectedFreeSpaces = 0, freeSpaceIndex = 0, componentsInFtSet = 0, selectedNonFtPartitions = 0; HMENU hMenu = GetMenu(hwndFrame); FT_TYPE type = (FT_TYPE) 0; PULONG diskSeenCounts; PFT_OBJECT_SET ftSet = NULL; PFT_OBJECT ftObject = NULL; PREGION_DESCRIPTOR regionDescriptor; PPERSISTENT_REGION_DATA regionData; diskSeenCounts = Malloc(DiskCount * sizeof(ULONG)); RtlZeroMemory(diskSeenCounts,DiskCount * sizeof(ULONG)); SelectionCount = 0; for (i=0; iRegionCount; j++) { if (diskState->Selected[j]) { selDiskState = diskState; selectedRegion = j; SelectionCount++; if (SelectionCount <= MaxMembersInFtSet) { SelectedDS[SelectionCount-1] = diskState; SelectedRG[SelectionCount-1] = j; } diskSeenCounts[diskState->Disk]++; if (ftObject = GET_FT_OBJECT(&diskState->RegionArray[j])) { ftSet = ftObject->Set; if (componentsInFtSet == 0) { ordinal = ftSet->Ordinal; type = ftSet->Type; ftSetSelected = TRUE; componentsInFtSet = 1; } else if ((ftSet->Ordinal == ordinal) && (ftSet->Type == type)) { componentsInFtSet++; } else { ftSetSelected = FALSE; } } else { nonFtItemSelected = TRUE; if (IsRecognizedPartition(diskState->RegionArray[j].SysID) ) { selectedNonFtPartitions += 1; } } } } } // Determine the number of free-space regions selected: selectedFreeSpaces = 0; for (i=0; iRegionArray[selectedRegion]; if (regionDescriptor->SysID == SYSID_UNUSED) { // Free region. Always allow create; let DoCreate() sort out // details about whether partition table is full, etc. allowCreate = TRUE; if (regionDescriptor->RegionType == REGION_PRIMARY) { allowCreateEx = TRUE; } // special case -- allow deletion of the extended partition if // there are no logicals in it. if ((regionDescriptor->RegionType == REGION_LOGICAL) && selDiskState->ExistExtended && !selDiskState->ExistLogical) { FDASSERT(regionDescriptor->SysID == SYSID_UNUSED); allowDelete = TRUE; } } else { // used region. Delete always allowed. allowDelete = TRUE; regionData = (PPERSISTENT_REGION_DATA)(PERSISTENT_DATA(regionDescriptor)); if (regionData) { if (regionData->VolumeExists) { if ((regionData->DriveLetter != NO_DRIVE_LETTER_YET) && (regionData->DriveLetter != NO_DRIVE_LETTER_EVER)) { allowFormat = TRUE; } } } // If the region is recognized, then also allow drive letter // manipulation. if (IsRecognizedPartition(regionDescriptor->SysID)) { allowDriveLetter = TRUE; // DblSpace volumes are allowed on non-FT, FAT volumes only DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter); if ((driveLetter != NO_DRIVE_LETTER_YET) && (driveLetter != NO_DRIVE_LETTER_EVER)) { if (wcscmp(typeName, L"FAT") == 0) { allowLabel = allowFormat; #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED allowDblSpace = allowFormat; #endif // Force the dll in now to know if Double Space // support is offerred by the dll. LoadIfsDll(); } if ((wcscmp(typeName, L"NTFS") == 0) || (wcscmp(typeName, L"HPFS") == 0)) { allowLabel = allowFormat; } } } } } else { if (SelectionCount) { *SinglySelectedDisk = NULL; *SinglySelectedRegion = (DWORD)(-1); // Multiple regions are selected. This might be an existing ft set, // a set of regions that allow creation of an ft set, or just plain // old multiple items. // // First deal with a selected ft set. if (ftSetSelected) { regionDescriptor = &SELECTED_REGION(0); regionData = (PPERSISTENT_REGION_DATA)(PERSISTENT_DATA(regionDescriptor)); // RDR - should locate member zero of the set since it // may not be committed yet. if (regionData) { if (regionData->VolumeExists) { if ((regionData->DriveLetter != NO_DRIVE_LETTER_YET) && (regionData->DriveLetter != NO_DRIVE_LETTER_EVER)) { // Now check for special cases on FT sets ftObject = regionData->FtObject; if (ftObject) { ftSet = ftObject->Set; if (ftSet) { FT_SET_STATUS setState = ftSet->Status; ULONG numberOfMembers; LowFtVolumeStatus(regionDescriptor->Disk, regionDescriptor->PartitionNumber, &setState, &numberOfMembers); if ((ftSet->Status != FtSetDisabled) && (setState != FtSetDisabled)) { allowFormat = TRUE; } } } } if (regionData->TypeName) { typeName = regionData->TypeName; } else { typeName = NULL; DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter); if (!typeName) { if (SelectionCount > 1) { // it is an FT set - try the next member. regionDescriptor = &SELECTED_REGION(1); DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter); regionDescriptor = &SELECTED_REGION(0); } } } if (typeName) { if ((wcscmp(typeName, L"NTFS") == 0) || (wcscmp(typeName, L"HPFS") == 0) || (wcscmp(typeName, L"FAT") == 0)) { allowLabel = allowFormat; } } } } // Allow the correct type of ft-related delete. switch (type) { case Mirror: allowBreakMirror = TRUE; allowDelete = TRUE; break; case StripeWithParity: if ((SelectionCount == ftSet->NumberOfMembers) && (ftSet->Status == FtSetRecoverable)) { allowRecoverParity = TRUE; } allowDelete = TRUE; break; case Stripe: case VolumeSet: allowDelete = TRUE; break; default: FDASSERT(FALSE); } FtSelectionType = type; if (type == StripeWithParity) { // If the set is disabled. Do not allow drive // letter changes - This is done because there are // conditions whereby the drive letter code will // access violate if this is done. if (ftSet->Status != FtSetDisabled) { // Must have either member 0 or member 1 for access for (ftObject = ftSet->Members; ftObject; ftObject = ftObject->Next) { if ((ftObject->MemberIndex == 0) || (ftObject->MemberIndex == 1)) { allowDriveLetter = TRUE; break; } } // if the drive letter cannot be done, then no live // action can be done. if (!allowDriveLetter) { ftSet->Status = FtSetDisabled; allowFormat = FALSE; allowLabel = FALSE; } } } else { allowDriveLetter = TRUE; } } else { // Next figure out whether some sort of ft object set could // be created out of the selected regions. if (SelectionCount <= MaxMembersInFtSet) { // Determine whether the selected regions are all on // different disks. onDifferentDisks = TRUE; for (i=0; i 1) { onDifferentDisks = FALSE; break; } } // Check for allowing mirror creation. User must have selected // two regions -- one a recognized partition, the other a free space. if (onDifferentDisks && (SelectionCount == 2) &&((SELECTED_REGION(0).SysID == SYSID_UNUSED) != (SELECTED_REGION(1).SysID == SYSID_UNUSED)) &&( IsRecognizedPartition(SELECTED_REGION(0).SysID) || IsRecognizedPartition(SELECTED_REGION(1).SysID)) &&!GET_FT_OBJECT(&(SELECTED_REGION(0))) &&!GET_FT_OBJECT(&(SELECTED_REGION(1)))) { allowCreateMirror = TRUE; } // Check for allowing volume set or stripe set if (selectedFreeSpaces == SelectionCount) { allowCreateVolumeSet = TRUE; if (onDifferentDisks) { allowCreateStripe = TRUE; if (selectedFreeSpaces > 2) { allowCreatePStripe = TRUE; } } } // Check for allowing volume set expansion. If // the selected regions consist of one volume set // and free space, then that volume set can be // extended. If the selection consists of one // recognized non-FT partition and free space, // then we can convert those regions into a // volume set. if (volumeSetAndFreeSpaceSelected || (SelectionCount > 1 && selectedFreeSpaces == SelectionCount - 1 && selectedNonFtPartitions == 1) ) { allowExtendVolumeSet = TRUE; } // Check for allowing non-in-place FT recover if ((SelectionCount > 1) && (selectedFreeSpaces == 1) && possibleRecover && (type == StripeWithParity) && (ftSet->Status == FtSetRecoverable)) { BOOL OrphanOnSameDiskAsFreeSpace = FALSE; if (!onDifferentDisks) { // Determine whether the orphan is on the same // disk as the free space. First find the orphan. for (i=0; iState == Orphaned)) { if (SELECTED_REGION(freeSpaceIndex).Disk == reg->Disk) { OrphanOnSameDiskAsFreeSpace = TRUE; } break; } } } if (onDifferentDisks || OrphanOnSameDiskAsFreeSpace) { allowRecoverParity = TRUE; } } } } } } EnableMenuItem(hMenu, IDM_PARTITIONCREATE, allowCreate ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_PARTITIONCREATEEX, allowCreateEx ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_PARTITIONDELETE, allowDelete ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_PARTITIONFORMAT, allowFormat ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_PARTITIONLABEL, allowLabel ? MF_ENABLED : MF_GRAYED); #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED EnableMenuItem(hMenu, IDM_DBLSPACE, (allowDblSpace & DoubleSpaceSupported) ? MF_ENABLED : MF_GRAYED); if (DoubleSpaceAutomount = DiskRegistryAutomountCurrentState()) { CheckMenuItem(hMenu, IDM_AUTOMOUNT, MF_BYCOMMAND | MF_CHECKED); } EnableMenuItem(hMenu, IDM_AUTOMOUNT, MF_ENABLED); #endif EnableMenuItem(hMenu, IDM_CDROM, AllowCdRom ? MF_ENABLED : MF_GRAYED); #if i386 SetUpMenui386(hMenu,SelectionCount); #else EnableMenuItem(hMenu, IDM_SECURESYSTEM, MF_ENABLED); CheckMenuItem(hMenu, IDM_SECURESYSTEM, SystemPartitionIsSecure ? MF_CHECKED : MF_UNCHECKED); #endif EnableMenuItem(hMenu, IDM_FTBREAKMIRROR, allowBreakMirror ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_FTESTABLISHMIRROR, IsLanmanNt && allowCreateMirror ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_FTCREATESTRIPE, allowCreateStripe ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_FTCREATEPSTRIPE, allowCreatePStripe ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_FTCREATEVOLUMESET, allowCreateVolumeSet ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_FTEXTENDVOLUMESET, allowExtendVolumeSet ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_PARTITIONLETTER, allowDriveLetter ? MF_ENABLED : MF_GRAYED); EnableMenuItem(hMenu, IDM_FTRECOVERSTRIPE, IsLanmanNt && allowRecoverParity ? MF_ENABLED : MF_GRAYED); // If the registry has change allow commit. if (RegistryChanged) { allowCommit = TRUE; } EnableMenuItem(hMenu, IDM_COMMIT, allowCommit ? MF_ENABLED : MF_GRAYED); return SelectionCount; } VOID CompleteSingleRegionOperation( IN PDISKSTATE DiskState ) /*++ Routine Description: Redraw the disk bar for the DiskState given and cause the display to refresh. Arguments: DiskState - the disk involved. Return Value: None --*/ { RECT rc; signed displayOffset; EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED); DeterminePartitioningState(DiskState); DrawDiskBar(DiskState); SetUpMenu(&SingleSel, &SingleSelIndex); // BUGBUG use of disk# as offset in listbox displayOffset = (signed)DiskState->Disk - (signed)SendMessage(hwndList, LB_GETTOPINDEX, 0, 0); if (displayOffset > 0) { // otherwise it's not visible // make a thin rectangle to force update rc.left = BarLeftX + 5; rc.right = rc.left + 5; rc.top = (displayOffset * GraphHeight) + BarTopYOffset; rc.bottom = rc.top + 5; InvalidateRect(hwndList, &rc, FALSE); } ClearStatusArea(); ResetLBCursorRegion(); ForceLBRedraw(); } VOID TotalRedrawAndRepaint( VOID ) /*++ Routine Description: Invalidate the display and cause all disk bars to be redrawn. Arguments: None Return Value: None --*/ { unsigned i; for (i=0; iVolumeLabel) { Free(RegionData->VolumeLabel); } if (RegionData->TypeName) { Free(RegionData->TypeName); } Free(RegionData); } VOID DoCreate( IN DWORD CreationType // REGION_EXTENDED or REGION_PRIMARY ) /*++ Routine Description: This routine creates a new partition. Arguments: CreationType - indicator of partition type (extended or primary). Return Value: None --*/ { PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex]; ULONG diskNumber = regionDescriptor->Disk; MINMAXDLG_PARAMS dlgParams; DWORD creationSize; DWORD ec; PPERSISTENT_REGION_DATA regionData; BOOLEAN isRemovable; CHAR driveLetter; FDASSERT(SingleSel); FDASSERT(regionDescriptor->SysID == SYSID_UNUSED); // WinDisk can only create a single partition on a removable // disk--no extended partitions and only one primary. isRemovable = IsDiskRemovable[diskNumber]; if (isRemovable) { if (CreationType == REGION_EXTENDED) { ErrorDialog(MSG_NO_EXTENDED_ON_REMOVABLE); return; } if (Disks[diskNumber]->ExistAny) { ErrorDialog(MSG_ONLY_ONE_PARTITION_ON_REMOVABLE); return; } } // Make sure the partition table is not full, and that we are allowed to // create the type of partition to be created. if (regionDescriptor->RegionType == REGION_PRIMARY) { if (!SingleSel->CreatePrimary) { ErrorDialog(MSG_PART_TABLE_FULL); return; } if ((CreationType == REGION_EXTENDED) && !SingleSel->CreateExtended) { ErrorDialog(MSG_EXTENDED_ALREADY_EXISTS); return; } } // If not creating an extended partition, allocate a drive letter. // If no drive letter is available, warn the user and allow him to cancel. // If the new partition is on a removable disk, use the reserved // drive letter for that removable disk. if (CreationType != REGION_EXTENDED) { CreationType = regionDescriptor->RegionType; // primary or logical if (isRemovable) { driveLetter = RemovableDiskReservedDriveLetters[diskNumber]; } else { if (!AssignDriveLetter(TRUE, CreationType == REGION_LOGICAL ? IDS_LOGICALVOLUME : IDS_PARTITION, &driveLetter)) { return; } } } else { CommitDueToExtended = TRUE; } #if i386 // if the user is creating a primary partition and there are already // primary partitions, warn him that the scheme he will create may // not be DOS compatible. if ((CreationType == REGION_PRIMARY) && SingleSel->ExistPrimary) { if (ConfirmationDialog(MSG_CREATE_NOT_COMPAT, MB_ICONQUESTION | MB_YESNO) != IDYES) { return; } } #endif // now get the size. dlgParams.MinSizeMB = FdGetMinimumSizeMB(diskNumber); dlgParams.MaxSizeMB = FdGetMaximumSizeMB(regionDescriptor, CreationType); switch (CreationType) { case REGION_PRIMARY: dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_P; dlgParams.MinimumStringID = IDS_CRTPART_MIN_P; dlgParams.MaximumStringID = IDS_CRTPART_MAX_P; dlgParams.SizeStringID = IDS_CRTPART_SIZE_P; dlgParams.HelpContextId = HC_DM_DLG_CREATEPRIMARY; break; case REGION_EXTENDED: dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_E; dlgParams.MinimumStringID = IDS_CRTPART_MIN_P; dlgParams.MaximumStringID = IDS_CRTPART_MAX_P; dlgParams.SizeStringID = IDS_CRTPART_SIZE_P; dlgParams.HelpContextId = HC_DM_DLG_CREATEEXTENDED; break; case REGION_LOGICAL: dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_L; dlgParams.MinimumStringID = IDS_CRTPART_MIN_L; dlgParams.MaximumStringID = IDS_CRTPART_MAX_L; dlgParams.SizeStringID = IDS_CRTPART_SIZE_L; dlgParams.HelpContextId = HC_DM_DLG_CREATELOGICAL; break; default: FDASSERT(FALSE); } creationSize = DialogBoxParam(hModule, MAKEINTRESOURCE(IDD_MINMAX), hwndFrame, MinMaxDlgProc, (LONG)&dlgParams); if (!creationSize) { // user cancelled return; } // Since the WinDisk can only create one partition on a removable // disk, if the user requests a size smaller than the maximum // on a removable disk, prompt to confirm: if (isRemovable && creationSize != FdGetMaximumSizeMB(regionDescriptor, CreationType)) { if (ConfirmationDialog(MSG_REMOVABLE_PARTITION_NOT_FULL_SIZE,MB_ICONQUESTION | MB_YESNO) != IDYES) { return; } } #if i386 // See whether the partition will cross over the 1024 cylinder boundary // and warn the user if it will. // // If the extended partition crosses the boundary and the user is creating // a logical drive, warn him even though the logical drive itself may not // cross the boundary -- he still won't be able to access it. { DWORD i, msgId = (DWORD)(-1); if (CreationType == REGION_LOGICAL) { PREGION_DESCRIPTOR extReg; // // Find the extended partition // for (i=0; iRegionCount; i++) { extReg = &Disks[diskNumber]->RegionArray[i]; if (IsExtended(extReg->SysID)) { break; } extReg = NULL; } FDASSERT(extReg); if (extReg && FdCrosses1024Cylinder(extReg, 0, REGION_LOGICAL)) { msgId = MSG_LOG_1024_CYL; } } else { if (FdCrosses1024Cylinder(regionDescriptor, creationSize, CreationType)) { msgId = (CreationType == REGION_PRIMARY) ? MSG_PRI_1024_CYL : MSG_EXT_1024_CYL; } } if ((msgId != (ULONG)(-1)) && (ConfirmationDialog(msgId, MB_ICONQUESTION | MB_YESNO) != IDYES)) { return; } } #endif // If not creating an extended partition, we need to create a new // persistent region data structure to associate with the new // partition. if (CreationType == REGION_EXTENDED) { regionData = NULL; } else { regionData = DmAllocatePersistentData(L"", wszNewUnformatted, driveLetter); } SetCursor(hcurWait); ec = CreatePartition(regionDescriptor, creationSize, CreationType); if (ec != NO_ERROR) { SetCursor(hcurNormal); ErrorDialog(ec); } DmSetPersistentRegionData(regionDescriptor, regionData); if (CreationType != REGION_EXTENDED) { if (!isRemovable) { MarkDriveLetterUsed(driveLetter); CommitToAssignLetterList(regionDescriptor, FALSE); } } // this clears all selections on the disk CompleteSingleRegionOperation(SingleSel); SetCursor(hcurNormal); } VOID DoDelete( VOID ) /*++ Routine Description: Using the global selection information, delete the partition. Arguments: None Return Value: None --*/ { PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex]; ULONG diskNumber = regionDescriptor->Disk; DWORD actualIndex = SingleSelIndex; DWORD i, ec; PPERSISTENT_REGION_DATA regionData; BOOL deletingExtended; FDASSERT(SingleSel); // if deleting a free space in the extended partition, then delete the // extended partition itself. if ((regionDescriptor->RegionType == REGION_LOGICAL) && !SingleSel->ExistLogical) { FDASSERT(SingleSel->ExistExtended); // find the extended partition for (i=0; iRegionCount; i++) { if (IsExtended(SingleSel->RegionArray[i].SysID)) { actualIndex = i; break; } } deletingExtended = TRUE; FDASSERT(actualIndex != SingleSelIndex); } else { deletingExtended = FALSE; // Make sure deletion of this partition is allowed. It is not allowed // if it is the boot partition (or sys partition on x86). if ((ec = DeletionIsAllowed(&SingleSel->RegionArray[actualIndex])) != NO_ERROR) { ErrorDialog(ec); return; } } // If this is a partition that will become the result of a // mirror break, insure that the break has occurred. Otherwise // this delete will have bad results. regionDescriptor = &SingleSel->RegionArray[actualIndex]; if (regionDescriptor->Reserved) { if (regionDescriptor->Reserved->Partition) { if (regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded) { ErrorDialog(MSG_MUST_COMMIT_BREAK); return; } } } if (!deletingExtended && (ConfirmationDialog(MSG_CONFIRM_DELETE, MB_ICONQUESTION | MB_YESNO) != IDYES)) { return; } // actualIndex is the thing to delete. FDASSERT(regionDescriptor->SysID != SYSID_UNUSED); regionData = PERSISTENT_DATA(regionDescriptor); if (regionData) { // Remember drive letter if there is one in order to lock it for delete. if (CommitToLockList(regionDescriptor, !IsDiskRemovable[diskNumber], TRUE, FALSE)) { // Could not lock exclusively - do not allow delete. if (IsPagefileOnDrive(regionData->DriveLetter)) { ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE); return; } else { if (CommitToLockList(regionDescriptor, !IsDiskRemovable[diskNumber], TRUE, FALSE)) { FDLOG((1,"DoDelete: Couldn't lock 2 times - popup shown\n")); ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN); return; } } } } else { // Deleting an extended partition - enable commit. CommitDueToDelete = TRUE; } SetCursor(hcurWait); // Perform the "delete" of internal structures. ec = DeletePartition(regionDescriptor); if (ec != NO_ERROR) { SetCursor(hcurNormal); ErrorDialog(ec); } if (regionData) { // Make the letter available for reuse. if (!IsDiskRemovable[diskNumber]) { MarkDriveLetterFree(regionData->DriveLetter); } // Free the persistent data associated with the region. DmFreePersistentData(regionData); DmSetPersistentRegionData(regionDescriptor,NULL); } // this clears all selections on the disk CompleteSingleRegionOperation(SingleSel); SetCursor(hcurNormal); } #if i386 VOID DoMakeActive( VOID ) /*++ Routine Description: This routine sets that active partition bit on for the selected partition. This code is x86 specific. Arguments: None Return Value: None --*/ { SetCursor(hcurWait); FDASSERT(SingleSel); FDASSERT(!SingleSel->RegionArray[SingleSelIndex].Active); FDASSERT(SingleSel->RegionArray[SingleSelIndex].RegionType == REGION_PRIMARY); FDASSERT(SingleSel->RegionArray[SingleSelIndex].SysID != SYSID_UNUSED); MakePartitionActive(SingleSel->RegionArray, SingleSel->RegionCount, SingleSelIndex); SetCursor(hcurNormal); InfoDialog(MSG_DISK0_ACTIVE); SetCursor(hcurWait); CompleteSingleRegionOperation(SingleSel); SetCursor(hcurNormal); } #endif VOID DoProtectSystemPartition( VOID ) /*++ Routine Description: This function toggles the state of the system partition security: if the system partition is secure, it makes it non-secure; if the system partition is not secure, it makes it secure. Arguments: None. Return Value: None. --*/ { LONG ec; HKEY hkey; DWORD value; DWORD MessageId; SetCursor(hcurWait); MessageId = SystemPartitionIsSecure ? MSG_CONFIRM_UNPROTECT_SYSTEM : MSG_CONFIRM_PROTECT_SYSTEM; if (ConfirmationDialog(MessageId, MB_ICONEXCLAMATION | MB_YESNO) != IDYES) { return; } ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\Lsa"), 0, KEY_SET_VALUE, &hkey); if (ec != ERROR_SUCCESS) { MessageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM : MSG_CANT_PROTECT_SYSTEM; ErrorDialog(MessageId); return; } // If the system partition is currently secure, change it // to not secure; if it is not secure, make it secure. value = SystemPartitionIsSecure ? 0 : 1; ec = RegSetValueEx(hkey, TEXT("Protect System Partition"), 0, REG_DWORD, (PBYTE)&value, sizeof(DWORD)); RegCloseKey(hkey); if (ec != ERROR_SUCCESS) { MessageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM : MSG_CANT_PROTECT_SYSTEM; ErrorDialog(MessageId); return; } SystemPartitionIsSecure = !SystemPartitionIsSecure; SetUpMenu(&SingleSel,&SingleSelIndex); RestartRequired = TRUE; SetCursor(hcurNormal); } VOID DoEstablishMirror( VOID ) /*++ Routine Description: Using the global selection values, this routine will associate freespace with an existing partition in order to construct a mirror. Arguments: None Return Value: None --*/ { LARGE_INTEGER partitionSize, freeSpaceSize; DWORD i, part, free = 0; PREGION_DESCRIPTOR regionDescriptor, freeSpace = NULL, existingPartition = NULL; PREGION_DESCRIPTOR regionArray[MaxMembersInFtSet]; UCHAR newSysID; PPERSISTENT_REGION_DATA regionData; HMENU hMenu = GetMenu(hwndFrame); FDASSERT(SelectionCount == 2); // Make sure that the mirror pair does not include any // partitions on removable media. for (i=0; iSysID == SYSID_UNUSED) { free = i; freeSpace = regionDescriptor; } else { part = i; existingPartition = regionDescriptor; } } FDASSERT((freeSpace != NULL) && (existingPartition != NULL)); // Make sure that we are allowed to create a partition in the free space. if (!( ((freeSpace->RegionType == REGION_LOGICAL) && SelectedDS[free]->CreateLogical) || ((freeSpace->RegionType == REGION_PRIMARY) && SelectedDS[free]->CreatePrimary))) { ErrorDialog(MSG_CRTSTRP_FULL); return; } // Make sure that the free space is large enough to hold a mirror of // the existing partition. Do this by getting the EXACT size of // the existing partition and the free space. partitionSize = FdGetExactSize(existingPartition, FALSE); freeSpaceSize = FdGetExactSize(freeSpace, FALSE); if (freeSpaceSize.QuadPart < partitionSize.QuadPart) { ErrorDialog(MSG_CRTMIRROR_BADFREE); return; } if (BootDiskNumber != (ULONG)-1) { // If the disk number and original partition number of this // region match the recorded disk number and partition number // of the boot partition warn the user about mirroring the boot // drive. if (existingPartition->Disk == BootDiskNumber && existingPartition->OriginalPartitionNumber == BootPartitionNumber) { WarningDialog(MSG_MIRROR_OF_BOOT); // Set up to write the boot code to the MBR of the mirror. UpdateMbrOnDisk = freeSpace->Disk; } } SetCursor(hcurWait); regionData = DmAllocatePersistentData(PERSISTENT_DATA(existingPartition)->VolumeLabel, PERSISTENT_DATA(existingPartition)->TypeName, PERSISTENT_DATA(existingPartition)->DriveLetter); // Finally, create the new partition. newSysID = (UCHAR)(existingPartition->SysID | (UCHAR)SYSID_FT); CreatePartitionEx(freeSpace, partitionSize, 0, freeSpace->RegionType, newSysID); DmSetPersistentRegionData(freeSpace, regionData); // Set the partition type of the existing partition. SetSysID2(existingPartition, newSysID); regionArray[0] = existingPartition; regionArray[1] = freeSpace; FdftCreateFtObjectSet(Mirror, regionArray, 2, FtSetNewNeedsInitialization); CompleteMultiRegionOperation(); SetCursor(hcurNormal); CommitDueToMirror = TRUE; EnableMenuItem(hMenu, IDM_COMMIT, MF_ENABLED); } VOID DoBreakMirror( VOID ) /*++ Routine Description: Using the global selection variables, this routine will break the mirror relationship and modify their region descriptors to describe two non-ft partitions giving either the primary member of the mirror the drive letter for the mirror, or the only healthy member of the mirror the drive letter. The remaining "new" partition will receive the next available drive letter. Arguments: None Return Value: None --*/ { DWORD i; PFT_OBJECT_SET ftSet; PFT_OBJECT ftObject0, ftObject1; PREGION_DESCRIPTOR regionDescriptor; PPERSISTENT_REGION_DATA regionData; ULONG newDriveLetterRegion; CHAR driveLetter; HMENU hMenu = GetMenu(hwndFrame); FDASSERT((SelectionCount) == 1 || (SelectionCount == 2)); ftObject0 = GET_FT_OBJECT(&SELECTED_REGION(0)); if (SelectionCount == 2) { ftObject1 = GET_FT_OBJECT(&SELECTED_REGION(1)); } else { ftObject1 = NULL; } ftSet = ftObject0->Set; // Determine if the action is allowed. switch (ftSet->Status) { case FtSetInitializing: case FtSetRegenerating: ErrorDialog(MSG_CANT_BREAK_INITIALIZING_SET); return; break; default: break; } if (ConfirmationDialog(MSG_CONFIRM_BRK_MIRROR,MB_ICONQUESTION | MB_YESNO) != IDYES) { return; } SetCursor(hcurWait); // Figure out which region gets the new drive letter. A complication is // that selection 0 is not necessarily member 0. // // If there is only one selection, then only one part of the mirror set // is present -- no new drive letters are assigned. // Otherwise, if one of the members is orphaned, it gets the new // drive letter. Else the secondary member gets the new drive letter. if (SelectionCount == 2) { if (ftObject0->State == Orphaned) { newDriveLetterRegion = 0; } else { if (ftObject1->State == Orphaned) { newDriveLetterRegion = 1; } else { // Neither member is orphaned; determine which is // member 0 and give the other one the new drive letter. if (ftObject0->MemberIndex) { // secondary member ? newDriveLetterRegion = 0; } else { newDriveLetterRegion = 1; } } } } else { // The one remaining member could be the shadow. // The drive letter must move to locate this partition regionDescriptor = &SELECTED_REGION(0); regionData = PERSISTENT_DATA(regionDescriptor); if (!regionData->FtObject->MemberIndex) { // The shadow has become the valid partition. // move the current letter there. CommitToAssignLetterList(regionDescriptor, TRUE); } newDriveLetterRegion = (ULONG)(-1); } // if newDriveLetterRegion is -1 this will still work and // select the 0 selected region. if (CommitToLockList(&SELECTED_REGION(newDriveLetterRegion ? 0 : 1), FALSE, TRUE, FALSE)) { if (ConfirmationDialog(MSG_CONFIRM_SHUTDOWN_FOR_MIRROR, MB_ICONQUESTION | MB_YESNO) != IDYES) { return; } RestartRequired = TRUE; } if (newDriveLetterRegion != (ULONG)(-1)) { if (AssignDriveLetter(FALSE, 0, &driveLetter)) { // Got a valid drive letter MarkDriveLetterUsed(driveLetter); } else { // didn't get a letter. Instead the magic value // for no drive letter assigned has been returned } regionDescriptor = &SELECTED_REGION(newDriveLetterRegion); regionData = PERSISTENT_DATA(regionDescriptor); regionData->DriveLetter = driveLetter; CommitToAssignLetterList(regionDescriptor, FALSE); if (!regionData->FtObject->MemberIndex) { // The shadow has become the valid partition. // move the current letter there. CommitToAssignLetterList(&SELECTED_REGION(newDriveLetterRegion ? 0 : 1), TRUE); } } else { regionDescriptor = &SELECTED_REGION(0); regionData = PERSISTENT_DATA(regionDescriptor); if (regionData->FtObject->MemberIndex) { // The shadow is all that is left. CommitToAssignLetterList(regionDescriptor, TRUE); } } FdftDeleteFtObjectSet(ftSet, FALSE); for (i=0; iReserved) { if (regionDescriptor->Reserved->Partition) { regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded = TRUE; } } SET_FT_OBJECT(regionDescriptor, 0); SetSysID2(regionDescriptor, (UCHAR)(regionDescriptor->SysID & ~VALID_NTFT)); } CompleteMultiRegionOperation(); SetCursor(hcurNormal); CommitDueToMirror = TRUE; EnableMenuItem(hMenu, IDM_COMMIT, MF_ENABLED); } VOID DoBreakAndDeleteMirror( VOID ) /*++ Routine Description: This routine will delete the mirror relationship information and the member partitions of the mirror. Arguments: None Return Value: None --*/ { PFT_OBJECT_SET ftSet; DWORD i; PREGION_DESCRIPTOR regionDescriptor; CHAR driveLetter = '\0'; FDASSERT( SelectionCount == 1 || SelectionCount == 2 ); // Attempt to lock this before continuing. regionDescriptor = &SELECTED_REGION(0); if (CommitToLockList(regionDescriptor, TRUE, TRUE, FALSE)) { // Could not lock the volume - do not allow delete. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN); return; } ftSet = (GET_FT_OBJECT(regionDescriptor))->Set; // Determine if the action is allowed. switch (ftSet->Status) { case FtSetInitializing: case FtSetRegenerating: ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET); return; break; default: break; } if (ConfirmationDialog(MSG_CONFIRM_BRKANDDEL_MIRROR, MB_ICONQUESTION | MB_YESNO) != IDYES) { return; } SetCursor(hcurWait); FdftDeleteFtObjectSet(ftSet, FALSE); for (i = 0; i < SelectionCount; i++) { regionDescriptor = &SELECTED_REGION(i); if (i) { FDASSERT(PERSISTENT_DATA(regionDescriptor)->DriveLetter == driveLetter); } else { driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter; } // Free the pieces of the set. DmFreePersistentData(PERSISTENT_DATA(regionDescriptor)); DmSetPersistentRegionData(regionDescriptor, NULL); DeletePartition(regionDescriptor); } MarkDriveLetterFree(driveLetter); // Remember drive letter if there is one in order to lock it for delete. CompleteMultiRegionOperation(); SetCursor(hcurNormal); } VOID DoCreateStripe( IN BOOL Parity ) /*++ Routine Description: This routine starts the dialog with the user to determine the parameters of the creation of a stripe or stripe set with parity. Based on the user response it creates the internal structures necessary for the creation of a stripe or stripe set with parity. The regions involved in the stripe creation are located via the global parameters for multiple selections. Arguments: Parity - boolean to indicate the presence of parity in the stripe. Return Value None --*/ { MINMAXDLG_PARAMS params; DWORD smallestSize = (DWORD)(-1); DWORD creationSize; unsigned i; PREGION_DESCRIPTOR regionDescriptor, regionArray[MaxMembersInFtSet]; PPERSISTENT_REGION_DATA regionData; CHAR DriveLetter; // Make sure that the volume set does not include any // partitions on removable media. for (i=0; iRegionType != REGION_EXTENDED); if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical) || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) { SetCursor(hcurNormal); ErrorDialog(MSG_CRTSTRP_FULL); return; } } // Now actually perform the creation. for (i=0; iRegionType, (UCHAR)(SYSID_BIGFAT | SYSID_FT)); // Finish setting up the FT set regionData = DmAllocatePersistentData(L"", wszNewUnformatted, DriveLetter); DmSetPersistentRegionData(regionDescriptor, regionData); regionArray[i] = regionDescriptor; } // The zeroth element is the one to assign the drive letter to. CommitToAssignLetterList(&SELECTED_REGION(0), FALSE); FdftCreateFtObjectSet(Parity ? StripeWithParity : Stripe, regionArray, SelectionCount, Parity ? FtSetNewNeedsInitialization : FtSetNew); MarkDriveLetterUsed(DriveLetter); CompleteMultiRegionOperation(); SetCursor(hcurNormal); } VOID DoDeleteStripeOrVolumeSet( IN DWORD ConfirmationMsg ) /*++ Routine Description: Common code for the deletion of a stripe or volume set. This routine will display a message giving the user a 2nd chance to change their mind, then based on the answer perform the work of deleting the item. This consists of removing the region descriptors (and related information) from the collection of Disk structures. Arguments: ConfirmationMsg - text for comfirming what is being deleted. Return Value: None --*/ { DWORD i; PFT_OBJECT_SET ftSet; PFT_OBJECT ftObject; PREGION_DESCRIPTOR regionDescriptor; FT_SET_STATUS setState; ULONG numberOfMembers; CHAR driveLetter = '\0'; BOOL setIsHealthy = TRUE; regionDescriptor = &SELECTED_REGION(0); // Determine if the action is allowed. ftObject = GET_FT_OBJECT(regionDescriptor); ftSet = ftObject->Set; LowFtVolumeStatus(regionDescriptor->Disk, regionDescriptor->PartitionNumber, &setState, &numberOfMembers); if (ftSet->Status != setState) { ftSet->Status = setState; } switch (ftSet->Status) { case FtSetDisabled: setIsHealthy = FALSE; break; case FtSetInitializing: case FtSetRegenerating: ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET); return; break; default: break; } // Attempt to lock this before continuing. if (CommitToLockList(regionDescriptor, TRUE, setIsHealthy, TRUE)) { // Could not lock the volume - try again, the file systems appear // to be confused. if (CommitToLockList(regionDescriptor, TRUE, setIsHealthy, TRUE)) { // Don't allow the delete. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN); return; } } if (ConfirmationDialog(ConfirmationMsg,MB_ICONQUESTION | MB_YESNO) != IDYES) { return; } // Delete all partitions that are part of the stripe set SetCursor(hcurWait); FdftDeleteFtObjectSet(ftSet,FALSE); for (i=0; iDriveLetter == driveLetter); } else { driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter; } diskNumber = regionDescriptor->Disk; DmFreePersistentData(PERSISTENT_DATA(regionDescriptor)); DmSetPersistentRegionData(regionDescriptor, NULL); DeletePartition(regionDescriptor); } // Mark the drive letter that was being used by the stripe or volume // set free. MarkDriveLetterFree(driveLetter); // Remember drive letter if there is one in order to lock it for delete. CompleteMultiRegionOperation(); SetCursor(hcurNormal); } VOID DoDeleteStripe( VOID ) /*++ Routine Description: Routine is called to delete a stripe. It calls a general routine for stripe and volume set deletion. Arguments: None Return Value: None --*/ { DoDeleteStripeOrVolumeSet(MSG_CONFIRM_DEL_STRP); } VOID DoCreateVolumeSet( VOID ) /*++ Routine Description: This routine uses the global selection information to collect a group of freespace regions on the disks and organize them into a volume set. Arguments: None Return Value: None --*/ { MINMAXDLG_PARAMS params; DWORD creationSize, size, maxTotalSize=0, totalSizeUsed; DWORD sizes[MaxMembersInFtSet]; PULONG primarySpacesToUseOnDisk; CHAR driveLetter; unsigned i; PREGION_DESCRIPTOR regionDescriptor, regionArray[MaxMembersInFtSet]; PPERSISTENT_REGION_DATA regionData; // Make sure that the volume set does not include any // partitions on removable media. for (i=0; i= SelectionCount; if // each of the sizes goes down to one, we will exit the loop while (totalSizeUsed > maxTotalSize) { for (i=0; (i maxTotalSize); i++) { if (sizes[i] > 1) { sizes[i]--; totalSizeUsed--; } } } SetCursor(hcurWait); // Make sure that we are allowed to create a partition in the space. // This is tricky because a volume set could contain more than one // primary partition on a disk -- which means that if we're not careful // we could create a disk with more than 4 primary partitions! primarySpacesToUseOnDisk = Malloc(DiskCount * sizeof(ULONG)); RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG)); for (i=0; iRegionType != REGION_EXTENDED); if (regionDescriptor->RegionType == REGION_PRIMARY) { primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++; } if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical) || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) { SetCursor(hcurNormal); Free(primarySpacesToUseOnDisk); ErrorDialog(MSG_CRTSTRP_FULL); return; } } // Look through the array we built to see whether we are supposed to use // more than one primary partition on a given disk. For each such disk, // make sure that we can actually create that many primary partitions. for (i=0; i 1) && (4 - PartitionCount(i) < primarySpacesToUseOnDisk[i])) { SetCursor(hcurNormal); Free(primarySpacesToUseOnDisk); ErrorDialog(MSG_CRTSTRP_FULL); return; } } Free(primarySpacesToUseOnDisk); // Now actually perform the creation. for (i=0; iRegionType != REGION_EXTENDED); CreatePartitionEx(regionDescriptor, RtlConvertLongToLargeInteger(0L), sizes[i], regionDescriptor->RegionType, (UCHAR)(SYSID_BIGFAT | SYSID_FT)); regionData = DmAllocatePersistentData(L"", wszNewUnformatted, driveLetter); DmSetPersistentRegionData(regionDescriptor, regionData); regionArray[i] = regionDescriptor; } // The zeroth element is the one to assign the drive letter to. FdftCreateFtObjectSet(VolumeSet, regionArray, SelectionCount, FtSetNew); MarkDriveLetterUsed(driveLetter); CommitToAssignLetterList(&SELECTED_REGION(0), FALSE); CompleteMultiRegionOperation(); SetCursor(hcurNormal); } VOID DoExtendVolumeSet( VOID ) /*++ Routine Description: This routine uses the global selection item information to add additional freespace to an existing volume set or partition. Arguments: None Return Value: None --*/ { MINMAXDLG_PARAMS params; DWORD currentSize = 0, freeSize = 0, maxTotalSize = 0, newSize = 0, totalFreeSpaceUsed, freeSpaceUsed, Size; DWORD Sizes[MaxMembersInFtSet]; ULONG nonFtPartitions = 0, numberOfFreeRegions = 0; PULONG primarySpacesToUseOnDisk; WCHAR driveLetter = L' '; PWSTR typeName = NULL, volumeLabel = NULL; PREGION_DESCRIPTOR regionDescriptor; PREGION_DESCRIPTOR newRegions[MaxMembersInFtSet]; PREGION_DESCRIPTOR convertedRegion; PFT_OBJECT_SET ftSet = NULL; PPERSISTENT_REGION_DATA regionData; unsigned i; DWORD ec; // Make sure that the volume set does not include any // partitions on removable media. for (i=0; iSizeMB; Sizes[i] = Size; maxTotalSize += Size; if (regionDescriptor->SysID == SYSID_UNUSED) { // This region is a chunk of free space; include it // in the free space tallies. newRegions[numberOfFreeRegions] = regionDescriptor; Sizes[numberOfFreeRegions] = Size; numberOfFreeRegions++; freeSize += Size; } else if (GET_FT_OBJECT(regionDescriptor)) { // This is an element of an existing volume set. currentSize += Size; if ( ftSet == NULL ) { DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter); ftSet = GET_FT_OBJECT(regionDescriptor)->Set; } } else { // This is a non-FT partition. nonFtPartitions++; DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter); currentSize = Size; convertedRegion = regionDescriptor; } } // Check for consistency: the selection must have either a volume // set or a partition, but not both, and cannot have more than // one non-FT partition. if (nonFtPartitions > 1 || (ftSet != NULL && nonFtPartitions != 0) || (ftSet == NULL && nonFtPartitions == 0)) { return; } if (nonFtPartitions != 0 && (ec = DeletionIsAllowed(convertedRegion)) != NO_ERROR) { // If the error-message is delete-specific, remap it. // switch( ec ) { #if i386 case MSG_CANT_DELETE_ACTIVE0: ec = MSG_CANT_EXTEND_ACTIVE0; break; #endif case MSG_CANT_DELETE_WINNT: ec = MSG_CANT_EXTEND_WINNT; break; default: break; } ErrorDialog(ec); return; } if (wcscmp(typeName, L"NTFS") != 0) { ErrorDialog(MSG_EXTEND_VOLSET_MUST_BE_NTFS); return; } params.CaptionStringID = IDS_EXPVSET_CAPTION; params.MinimumStringID = IDS_CRTVSET_MIN; params.MaximumStringID = IDS_CRTVSET_MAX; params.SizeStringID = IDS_CRTVSET_SIZE; params.MinSizeMB = currentSize + numberOfFreeRegions; params.MaxSizeMB = maxTotalSize; params.HelpContextId = HC_DM_DLG_EXTENDVOLUMESET; newSize = DialogBoxParam(hModule, MAKEINTRESOURCE(IDD_MINMAX), hwndFrame, MinMaxDlgProc, (LONG)¶ms); if (!newSize) { // user cancelled return; } // Determine how large to make each new member of the volume // set. The percentage of free space to use is the ratio of // the amount by which the volume set will grow to the total // free space. freeSpaceUsed = newSize - currentSize; totalFreeSpaceUsed = 0; for ( i = 0; i < numberOfFreeRegions; i++ ) { Sizes[i] = Sizes[i] * freeSpaceUsed / freeSize; if ((Sizes[i] * freeSpaceUsed) % freeSize) { Sizes[i]++; } if (Sizes[i] == 0) { Sizes[i]++; } totalFreeSpaceUsed += Sizes[i]; } // Make sure that the total amount of free space used is not // greater than the amount available. Note that this loop is // certain to terminate because the amount of free space used // is >= the number of free regions, so this loop will exit // if one megabyte is used in each free region (the degenerate // case). while (totalFreeSpaceUsed > freeSize) { for (i = 0; (i < numberOfFreeRegions) && (totalFreeSpaceUsed > freeSize); i++) { if ( Sizes[i] > 1 ) { Sizes[i]--; totalFreeSpaceUsed--; } } } SetCursor(hcurWait); // Make sure that we are allowed to create a partition in the space. // // This is tricky because a volume set could contain more than one // primary partition on a disk -- which means that if we're not careful // we could create a disk with more than 4 primary partitions! primarySpacesToUseOnDisk = Malloc(DiskCount * sizeof(ULONG)); RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG)); for (i=0; iSysID == SYSID_UNUSED) { FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED); if (regionDescriptor->RegionType == REGION_PRIMARY) { primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++; } if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical) || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) { SetCursor(hcurNormal); Free(primarySpacesToUseOnDisk); ErrorDialog(MSG_CRTSTRP_FULL); return; } } } // Look through the array we built to see whether we are supposed to use // more than one primary partition on a given disk. For each such disk, // make sure that we can actually create that many primary partitions. for (i=0; i 1) && (4 - PartitionCount(i) < primarySpacesToUseOnDisk[i])) { SetCursor(hcurNormal); Free(primarySpacesToUseOnDisk); ErrorDialog(MSG_CRTSTRP_FULL); return; } } // Now actually perform the creation. for (i=0; iRegionType != REGION_EXTENDED); CreatePartitionEx(regionDescriptor, RtlConvertLongToLargeInteger(0L), Sizes[i], regionDescriptor->RegionType, (UCHAR)(SYSID_IFS | SYSID_FT)); regionData = DmAllocatePersistentData(volumeLabel, typeName, (CHAR)driveLetter); DmSetPersistentRegionData(regionDescriptor, regionData); } if (nonFtPartitions != 0) { // Create the volume set so we can extend it FdftCreateFtObjectSet(VolumeSet, &convertedRegion, 1, FtSetExtended); ftSet = GET_FT_OBJECT(convertedRegion)->Set; // Set the converted region's partition System Id to indicate // that it is now part of a volume set. SetSysID2(convertedRegion, (UCHAR)(convertedRegion->SysID | SYSID_FT)); } FdftExtendFtObjectSet(ftSet, newRegions, numberOfFreeRegions); CompleteMultiRegionOperation(); SetCursor(hcurNormal); } VOID DoDeleteVolumeSet( VOID ) /*++ Routine Description: Routine is called to delete a volume set. It calls a general routine for stripe and volume set deletion. Arguments: None Return Value: None --*/ { DoDeleteStripeOrVolumeSet(MSG_CONFIRM_DEL_VSET); } extern ULONG OrdinalToAllocate[]; VOID DoRecoverStripe( VOID ) /*++ Routine Description: Using the global selection information this routine will set up a stripe with parity such that a problem member is regenerated. This new member may either be the problem member (i.e. regeneration is "in place") or new free space on a different disk. Arguments: None Return Value: None --*/ { PREGION_DESCRIPTOR freeSpace = NULL; PREGION_DESCRIPTOR unhealthy = NULL; ULONG freeSpaceI = 0; ULONG i; PREGION_DESCRIPTOR regionArray[MaxMembersInFtSet]; LARGE_INTEGER minimumSize; PFT_OBJECT ftObject; // Initialize minimumSize to the maximum possible positive value minimumSize.HighPart = 0x7FFFFFFF; minimumSize.LowPart = 0xFFFFFFFF; if ((!IsRegionCommitted(&SELECTED_REGION(0))) && (!IsRegionCommitted(&SELECTED_REGION(1)))) { ErrorDialog(MSG_NOT_COMMITTED); return; } FDASSERT(SelectionCount > 1); FDASSERT(SelectionCount <= MaxMembersInFtSet); SetCursor(hcurWait); // Determine the exact size of the smallest member of the stripe set. // If the user is regenerating using an additional free space, this // will be the size requirement for the free space. // Also find the free space (if any). // If there is no free space, then we're doing an 'in-place' recover // (ie regnerating into the unhealthy member). If there is a free space, // make sure we are allowed to create a partition or logical drive in it. for (i=0; iSysID)); if (regionArray[i]->SysID == SYSID_UNUSED) { PDISKSTATE ds; FDASSERT(freeSpace == NULL); freeSpace = regionArray[i]; freeSpaceI = i; // Make sure we are allowed to create a partition or logical // drive in the selected free space. ds = SelectedDS[freeSpaceI]; if (!( ((freeSpace->RegionType == REGION_LOGICAL) && ds->CreateLogical) || ((freeSpace->RegionType == REGION_PRIMARY) && ds->CreatePrimary))) { SetCursor(hcurNormal); ErrorDialog(MSG_CRTSTRP_FULL); return; } } else { LARGE_INTEGER largeTemp; largeTemp = FdGetExactSize(regionArray[i], FALSE); if (largeTemp.QuadPart < minimumSize.QuadPart) { minimumSize = largeTemp; } if (GET_FT_OBJECT(regionArray[i])->State != Healthy) { FDASSERT(unhealthy == NULL); unhealthy = regionArray[i]; } } } // If there is a free space, place it at item 0 of the regionArray // to simplify processing later. if (freeSpace) { PREGION_DESCRIPTOR tempRegion = regionArray[0]; regionArray[0] = regionArray[freeSpaceI]; regionArray[freeSpaceI] = tempRegion; i = 1; } else { i = 0; } // Get a pointer to the FT object for the broken member. Can't do this // in the loop above because the broken member might be on an off-line // disk. for (ftObject=GET_FT_OBJECT(regionArray[i])->Set->Members; ftObject; ftObject = ftObject->Next) { if (ftObject->State != Healthy) { break; } } FDASSERT(ftObject); // Determine if the action is allowed. if (ftObject->Set) { switch (ftObject->Set->Status) { case FtSetInitializing: case FtSetRegenerating: ErrorDialog(MSG_CANT_REGEN_INITIALIZING_SET); return; break; default: break; } } // Must lock the volume to perform this operation. if (CommitToLockList(regionArray[i], FALSE, TRUE, FALSE)) { // Could not lock the volume - try again, the file systems appear // to be confused. if (CommitToLockList(regionArray[i], FALSE, TRUE, FALSE)) { // Don't allow the delete. ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN); return; } } if (freeSpace) { LARGE_INTEGER temp; PPERSISTENT_REGION_DATA regionData, regionDataTemp; // Make sure the free space region is large enough. temp = FdGetExactSize(freeSpace, FALSE); if (temp.QuadPart < minimumSize.QuadPart) { SetCursor(hcurNormal); ErrorDialog(MSG_NOT_LARGE_ENOUGH_FOR_STRIPE); return; } // Create the new partition. CreatePartitionEx(freeSpace, minimumSize, 0, freeSpace->RegionType, regionArray[1]->SysID); // Set up the new partition's persistent data regionDataTemp = PERSISTENT_DATA(regionArray[1]); regionData = DmAllocatePersistentData(regionDataTemp->VolumeLabel, regionDataTemp->TypeName, regionDataTemp->DriveLetter); regionData->FtObject = ftObject; DmSetPersistentRegionData(freeSpace, regionData); // Check to see if member zero of the set changed and // the drive letter needs to move. if (!ftObject->MemberIndex) { // This is member zero. Move the drive letter to the // new region descriptor. CommitToAssignLetterList(freeSpace, TRUE); } // If the unhealthy member is on-line, delete it. // Otherwise remove it from the off-line disk. if (unhealthy) { DmFreePersistentData(PERSISTENT_DATA(unhealthy)); DmSetPersistentRegionData(unhealthy, NULL); DeletePartition(unhealthy); } // Remove any offline disks - this doesn't really // delete the set. FdftDeleteFtObjectSet(ftObject->Set, TRUE); } ftObject->Set->Ordinal = FdftNextOrdinal(StripeWithParity); ftObject->State = Regenerating; ftObject->Set->Status = FtSetRecovered; RegistryChanged = TRUE; CompleteMultiRegionOperation(); SetCursor(hcurNormal); } VOID AdjustOptionsMenu( VOID ) /*++ Routine Description: This routine updates the options menu (i.e. maintains the state of the menu items for whether the status bar or legend are displayed). Arguments: None Return Value: None --*/ { RECT rc; CheckMenuItem(GetMenu(hwndFrame), IDM_OPTIONSSTATUS, MF_BYCOMMAND | (StatusBar ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(GetMenu(hwndFrame), IDM_OPTIONSLEGEND, MF_BYCOMMAND | (Legend ? MF_CHECKED : MF_UNCHECKED)); GetClientRect(hwndFrame, &rc); SendMessage(hwndFrame, WM_SIZE, SIZENORMAL, MAKELONG(rc.right, rc.bottom)); InvalidateRect(hwndFrame, NULL, TRUE); } VOID FrameCommandHandler( IN HWND hwnd, IN DWORD wParam, IN LONG lParam ) /*++ Routine Description: This routine handles WM_COMMAND messages for the frame window. Arguments: None. Return Value: None. --*/ { DWORD i, pos; DWORD HelpFlag; POINT point; switch (LOWORD(wParam)) { case IDM_PARTITIONCREATE: DoCreate(REGION_PRIMARY); break; case IDM_PARTITIONCREATEEX: DoCreate(REGION_EXTENDED); break; case IDM_PARTITIONDELETE: switch (FtSelectionType) { case Mirror: DoBreakAndDeleteMirror(); break; case Stripe: case StripeWithParity: DoDeleteStripe(); break; case VolumeSet: DoDeleteVolumeSet(); break; default: DoDelete(); break; } break; #if i386 case IDM_PARTITIONACTIVE: DoMakeActive(); break; #endif case IDM_SECURESYSTEM: DoProtectSystemPartition(); break; case IDM_PARTITIONLETTER: { int driveLetterIn, driveLetterOut; PREGION_DESCRIPTOR regionDescriptor; PPERSISTENT_REGION_DATA regionData; PFT_OBJECT ftObject; ULONG index; regionDescriptor = &SELECTED_REGION(0); FDASSERT(regionDescriptor); regionData = PERSISTENT_DATA(regionDescriptor); FDASSERT(regionData); if (ftObject = regionData->FtObject) { // Must find the zero member of this set for the // drive letter assignment. Search all of the selected // regions index = 0; while (ftObject->MemberIndex) { // search the next selected item if there is one index++; if (index >= SelectionCount) { ftObject = NULL; break; } regionDescriptor = &SELECTED_REGION(index); FDASSERT(regionDescriptor); regionData = PERSISTENT_DATA(regionDescriptor); FDASSERT(regionData); ftObject = regionData->FtObject; // must have an FtObject to continue if (!ftObject) { break; } } if (!ftObject) { // This is really an internal error. } // regionDescriptor locates the zero element now. } driveLetterIn = (int)(UCHAR)regionData->DriveLetter; if (IsDiskRemovable[regionDescriptor->Disk]) { ErrorDialog(MSG_CANT_ASSIGN_LETTER_TO_REMOVABLE); } else if (AllDriveLettersAreUsed() && ((driveLetterIn == NO_DRIVE_LETTER_YET) || (driveLetterIn == NO_DRIVE_LETTER_EVER))) { ErrorDialog(MSG_ALL_DRIVE_LETTERS_USED); } else { driveLetterOut = DialogBoxParam(hModule, MAKEINTRESOURCE(IDD_DRIVELET), hwndFrame, DriveLetterDlgProc, (LONG)regionDescriptor); if (driveLetterOut) { LETTER_ASSIGNMENT_RESULT result; if ((driveLetterIn == NO_DRIVE_LETTER_YET) || (driveLetterIn == NO_DRIVE_LETTER_EVER)) { // Must insure that driveLetterIn maps to same things // as is returned by the dialog when the user selects // no letter. driveLetterIn = NO_DRIVE_LETTER_EVER; } if (driveLetterOut != driveLetterIn) { if (result = CommitDriveLetter(regionDescriptor, (CHAR) driveLetterIn, (CHAR)driveLetterOut)) { // The following would be more rigorously correct: // if non-ft, just set regionData->DriveLetter. If // ft, scan all regions on all disks for members of // ft set and set their drive letter fields. // // The below is probably correct, though. for (i=0; iDriveLetter = (CHAR)driveLetterOut; } // Don't allow the letter that is actually in use // and will only change on a reboot to cycle back // into the free list. if (result != MustReboot) { // Mark old letter free, new one used. MarkDriveLetterFree((CHAR)driveLetterIn); } MarkDriveLetterUsed((CHAR)driveLetterOut); // force status area and all disk bars to be redrawn if (SelectionCount > 1) { CompleteMultiRegionOperation(); } else { CompleteSingleRegionOperation(SingleSel); } EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED); } } } } break; } case IDM_PARTITIONFORMAT: { PREGION_DESCRIPTOR regionDescriptor; regionDescriptor = &SELECTED_REGION(0); FDASSERT(regionDescriptor); FormatPartition(regionDescriptor); break; } case IDM_PARTITIONLABEL: { PREGION_DESCRIPTOR regionDescriptor; regionDescriptor = &SELECTED_REGION(0); FDASSERT(regionDescriptor); LabelPartition(regionDescriptor); break; } case IDM_PARTITIONEXIT: SendMessage(hwndFrame,WM_CLOSE,0,0); break; case IDM_CONFIGMIGRATE: if (DoMigratePreviousFtConfig()) { // Determine if the FT driver must be enabled. SetCursor(hcurWait); Sleep(2000); if (DiskRegistryRequiresFt() == TRUE) { DiskRegistryEnableFt(); } else { DiskRegistryDisableFt(); } // wait four seconds before shutdown Sleep(4000); SetCursor(hcurNormal); FdShutdownTheSystem(); } break; case IDM_CONFIGSAVE: DoSaveFtConfig(); break; case IDM_CONFIGRESTORE: if (DoRestoreFtConfig()) { // Determine if the FT driver must be enabled. if (DiskRegistryRequiresFt() == TRUE) { DiskRegistryEnableFt(); } else { DiskRegistryDisableFt(); } // wait five seconds before shutdown SetCursor(hcurWait); Sleep(5000); SetCursor(hcurNormal); FdShutdownTheSystem(); } break; case IDM_FTESTABLISHMIRROR: DoEstablishMirror(); break; case IDM_FTBREAKMIRROR: DoBreakMirror(); break; case IDM_FTCREATESTRIPE: DoCreateStripe(FALSE); break; case IDM_FTCREATEPSTRIPE: DoCreateStripe(TRUE); break; case IDM_FTCREATEVOLUMESET: DoCreateVolumeSet(); break; case IDM_FTEXTENDVOLUMESET: DoExtendVolumeSet(); break; case IDM_FTRECOVERSTRIPE: DoRecoverStripe(); break; #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED case IDM_DBLSPACE: DblSpace(hwndFrame, NULL); break; case IDM_AUTOMOUNT: { HMENU hMenu; if (DoubleSpaceAutomount) { DoubleSpaceAutomount = FALSE; } else { DoubleSpaceAutomount = TRUE; } DiskRegistryDblSpaceRemovable(DoubleSpaceAutomount); hMenu = GetMenu(hwndFrame); CheckMenuItem(hMenu, IDM_AUTOMOUNT, (DoubleSpaceAutomount) ? MF_CHECKED : MF_UNCHECKED); break; } #endif case IDM_CDROM: CdRom(hwndFrame, NULL); break; case IDM_COMMIT: CommitAllChanges(NULL); EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_ENABLED); break; case IDM_OPTIONSSTATUS: StatusBar = !StatusBar; AdjustOptionsMenu(); break; case IDM_OPTIONSLEGEND: Legend = !Legend; AdjustOptionsMenu(); break; case IDM_OPTIONSCOLORS: switch(DialogBox(hModule, MAKEINTRESOURCE(IDD_COLORS), hwnd, ColorDlgProc)) { case IDOK: for (i=0; iBarType; } switch (DialogBoxParam(hModule, MAKEINTRESOURCE(IDD_DISPLAYOPTIONS), hwnd, DisplayOptionsDlgProc, (DWORD)newBarTypes)) { case IDOK: SetCursor(hcurWait); for (i=0; iBarType = newBarTypes[i]; } TotalRedrawAndRepaint(); SetCursor(hcurNormal); break; case IDCANCEL: break; default: FDASSERT(0); } Free(newBarTypes); break; } case IDM_HELPCONTENTS: case IDM_HELP: HelpFlag = HELP_INDEX; goto CallWinHelp; break; case IDM_HELPSEARCH: HelpFlag = HELP_PARTIALKEY; goto CallWinHelp; break; case IDM_HELPHELP: HelpFlag = HELP_HELPONHELP; goto CallWinHelp; break; case IDM_HELPABOUT: { TCHAR title[100]; LoadString(hModule, IDS_APPNAME, title, sizeof(title)/sizeof(TCHAR)); ShellAbout(hwndFrame, title, NULL, (HICON)GetClassLong(hwndFrame, GCL_HICON)); break; } #if DBG && DEVL case IDM_DEBUGALLOWDELETES: AllowAllDeletes = !AllowAllDeletes; CheckMenuItem(GetMenu(hwndFrame), IDM_DEBUGALLOWDELETES, AllowAllDeletes ? MF_CHECKED : MF_UNCHECKED); break; #endif case ID_LISTBOX: switch (HIWORD(wParam)) { case LBN_SELCHANGE: point.x = LOWORD(pos = GetMessagePos()); point.y = HIWORD(pos); MouseSelection(GetKeyState(VK_CONTROL) & ~1, // strip toggle bit &point); return; default: DefWindowProc(hwnd, WM_COMMAND, wParam, lParam); return; } break; default: DefWindowProc(hwnd, WM_COMMAND, wParam, lParam); } return; CallWinHelp: if (!WinHelp(hwndFrame, HelpFile, HelpFlag, (LONG)"")) { WarningDialog(MSG_HELP_ERROR); } } DWORD DeletionIsAllowed( IN PREGION_DESCRIPTOR Region ) /*++ Routine Description: This routine makes sure deletion of the partition is allowed. We do not allow the user to delete the Windows NT boot partition or the active partition on disk 0 (x86 only). Note that this routine is also used to determine whether an existing single-partition volume can be extended into a volume set, since the criteria are the same. Arguments: Region - points to region descriptor for the region which the user would like to delete. Return Value: NO_ERROR if deletion is allowed; error number for message to display if not. --*/ { ULONG ec; PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region); FDASSERT(!IsExtended(Region->SysID)); // can't be extended partition FDASSERT(Region->SysID != SYSID_UNUSED); // can't be free space #if DBG && DEVL if (AllowAllDeletes) { return NO_ERROR; } #endif // if this is not an original region, deletion is allowed. if (!Region->OriginalPartitionNumber) { return NO_ERROR; } // if there is no persistent data for this region, allow deletion. if (regionData == NULL) { return NO_ERROR; } ec = NO_ERROR; // Determine the Windows NT drive by determining the windows directory // and pulling out the first letter. if (BootDiskNumber != (ULONG)-1) { // If the disk number and original partition number of this // region match the recorded disk number and partition number // of the boot partition, don't allow deletion. if (Region->Disk == BootDiskNumber && Region->OriginalPartitionNumber == BootPartitionNumber) { ec = MSG_CANT_DELETE_WINNT; } } #if i386 if (ec == NO_ERROR) { if (!Region->Disk && Region->Active) { ec = MSG_CANT_DELETE_ACTIVE0; } } #endif return ec; } BOOLEAN BootPartitionNumberChanged( PULONG OldNumber, PULONG NewNumber ) /*++ Routine Description This function determines whether the partition number of the boot partition has changed during this invocation of Windisk. With dynamic partitioning enabled, the work of this routine increases. This routine must guess what the partition numbers will be when the system is rebooted to determine if the partition number for the boot partition has changed. It does this via the following algorithm: 1. Count all primary partitions - These get numbers first starting from 1. 2. Count all logical drives - These get numbers second starting from the count of primary partitions plus 1. The partition numbers located in the region structures cannot be assumed to be valid. This work must be done from the region array located in the disk state structure for the disk. Arguments: None. Return Value: TRUE if the boot partition's partition number has changed. --*/ { PDISKSTATE bootDisk; PREGION_DESCRIPTOR regionDescriptor, bootDescriptor = NULL; ULONG i, partitionNumber = 0; if (BootDiskNumber == (ULONG)(-1) || BootDiskNumber > DiskCount) { // Can't tell--assume it hasn't. return FALSE; } if (!ChangeCommittedOnDisk(BootDiskNumber)) { // disk wasn't changed - no possibility for a problem. return FALSE; } bootDisk = Disks[BootDiskNumber]; // Find the region descriptor for the boot partition for (i = 0; i < bootDisk->RegionCount; i++) { regionDescriptor = &bootDisk->RegionArray[i]; if (regionDescriptor->OriginalPartitionNumber == BootPartitionNumber) { bootDescriptor = regionDescriptor; break; } } if (!bootDescriptor) { // Can't find boot partition - assume no change return FALSE; } // No go through the region descriptors and count the partition // numbers as they will be counted during system boot. // // If the boot region is located determine if the partition // number changed. for (i = 0; i < bootDisk->RegionCount; i++) { regionDescriptor = &bootDisk->RegionArray[i]; if ((regionDescriptor->RegionType == REGION_PRIMARY) && (!IsExtended(regionDescriptor->SysID) && (regionDescriptor->SysID != SYSID_UNUSED))) { partitionNumber++; if (regionDescriptor == bootDescriptor) { if (partitionNumber != regionDescriptor->OriginalPartitionNumber) { *OldNumber = regionDescriptor->OriginalPartitionNumber; *NewNumber = partitionNumber; return TRUE; } else { // Numbers match, no problem. return FALSE; } } } } // Check the logical drives as well. for (i = 0; i < bootDisk->RegionCount; i++) { regionDescriptor = &bootDisk->RegionArray[i]; if (regionDescriptor->RegionType == REGION_LOGICAL) { partitionNumber++; if (regionDescriptor == bootDescriptor) { if (partitionNumber != regionDescriptor->OriginalPartitionNumber) { *OldNumber = regionDescriptor->OriginalPartitionNumber; *NewNumber = partitionNumber; return TRUE; } else { return FALSE; } } } } return FALSE; } DWORD CommitChanges( VOID ) /*++ Routine Description: This routine updates the disks to reflect changes made by the user the partitioning scheme, or to stamp signatures on disks. If the partitioning scheme on a disk has changed at all, a check will first be made for a valid signature on the mbr in sector 0. If the signature is not valid, x86 boot code will be written to the sector. Arguments: None. Return Value: Windows error code. --*/ { unsigned i; DWORD ec, rc = NO_ERROR; for (i=0; iRegionArray) { FreeRegionArray(DiskState->RegionArray, DiskState->RegionCount); } // get the region array for the disk in question GetAllDiskRegions(DiskState->Disk, &DiskState->RegionArray, &DiskState->RegionCount); // Allocate the array for the left/right coords for the graph. // This may overallocate by one square (for extended partition). DiskState->LeftRight = Realloc(DiskState->LeftRight, DiskState->RegionCount * sizeof(LEFTRIGHT)); DiskState->Selected = Realloc(DiskState->Selected, DiskState->RegionCount * sizeof(BOOLEAN)); for (i=0; iRegionCount; i++) { DiskState->Selected[i] = FALSE; } // figure out whether various creations are allowed IsAnyCreationAllowed(DiskState->Disk, TRUE, &DiskState->CreateAny, &DiskState->CreatePrimary, &DiskState->CreateExtended, &DiskState->CreateLogical); // figure out whether various partition types exist DoesAnyPartitionExist(DiskState->Disk, &DiskState->ExistAny, &DiskState->ExistPrimary, &DiskState->ExistExtended, &DiskState->ExistLogical); } VOID DrawDiskBar( IN PDISKSTATE DiskState ) /*++ Routine Description: This routine will draw the disk bar into the window. Arguments: DiskState - current disk to draw. Return Value: None --*/ { PREGION_DESCRIPTOR regionDescriptor; PDISKSTATE diskState; LONGLONG temp1, temp2; HDC hDCMem = DiskState->hDCMem; DWORD leftAdjust = BarLeftX, xDiskText, cx = 0, brushIndex = 0; HPEN hpenT; char text[100], textBold[5]; TCHAR uniText[100], uniTextBold[5], mbBuffer[16]; RECT rc; HFONT hfontT; COLORREF previousColor; HBRUSH hbr; BOOL isFree, isLogical; HDC hdcTemp; HBITMAP hbmOld; PWSTR typeName, volumeLabel; WCHAR driveLetter; BAR_TYPE barType; ULONG diskSize, largestDiskSize; unsigned i; // If this is a removable. Update to whatever its current // information may be. if (IsDiskRemovable[DiskState->Disk]) { PPERSISTENT_REGION_DATA regionData; // Update the information on this disk. regionDescriptor = &DiskState->RegionArray[0]; regionData = PERSISTENT_DATA(regionDescriptor); if (GetVolumeTypeAndSize(DiskState->Disk, regionDescriptor->PartitionNumber, &volumeLabel, &typeName, &diskSize)) { // Update the values for the removable. if (regionData) { // Always want RAW file systems to display as "Unknown" if (!lstrcmpiW(typeName, L"raw")) { Free(typeName); typeName = Malloc((wcslen(wszUnknown) * sizeof(WCHAR)) + sizeof(WCHAR)); lstrcpyW(typeName, wszUnknown); } if (regionData->VolumeLabel) { Free(regionData->VolumeLabel); } regionData->VolumeLabel = volumeLabel; if (regionData->TypeName) { Free(regionData->TypeName); } regionData->TypeName = typeName; } DiskState->DiskSizeMB = diskSize; } } // figure out largest disk's size for (largestDiskSize = i = 0, diskState = Disks[0]; i < DiskCount; diskState = Disks[++i]) { if (diskState->DiskSizeMB > largestDiskSize) { largestDiskSize = diskState->DiskSizeMB; } } // erase the graph background rc.left = rc.top = 0; rc.right = GraphWidth + 1; rc.bottom = GraphHeight + 1; FillRect(hDCMem, &rc, GetStockObject(LTGRAY_BRUSH)); hpenT = SelectObject(hDCMem,hPenThinSolid); // Draw the disk info area: small disk bitmap, some text, and a // line across the top. // // First draw the bitmap. hdcTemp = CreateCompatibleDC(hDCMem); if (IsDiskRemovable[DiskState->Disk]) { hbmOld = SelectObject(hdcTemp, hBitmapRemovableDisk); BitBlt(hDCMem, xRemovableDisk, yRemovableDisk, dxRemovableDisk, dyRemovableDisk, hdcTemp, 0, 0, SRCCOPY); } else { hbmOld = SelectObject(hdcTemp, hBitmapSmallDisk); BitBlt(hDCMem, xSmallDisk, ySmallDisk, dxSmallDisk, dySmallDisk, hdcTemp, 0, 0, SRCCOPY); } if (hbmOld) { SelectObject(hdcTemp, hbmOld); } DeleteDC(hdcTemp); // Now draw the line. if (IsDiskRemovable[DiskState->Disk]) { MoveToEx(hDCMem, xRemovableDisk, BarTopYOffset, NULL); LineTo(hDCMem, BarLeftX - xRemovableDisk, BarTopYOffset); xDiskText = 2 * dxRemovableDisk; } else { MoveToEx(hDCMem, xSmallDisk, BarTopYOffset, NULL); LineTo(hDCMem, BarLeftX - xSmallDisk, BarTopYOffset); xDiskText = 2 * dxSmallDisk; } // Now draw the text. hfontT = SelectObject(hDCMem, hFontGraphBold); SetTextColor(hDCMem, RGB(0, 0, 0)); SetBkColor(hDCMem, RGB(192, 192, 192)); wsprintf(uniText, DiskN, DiskState->Disk); TextOut(hDCMem, xDiskText, BarTopYOffset + dyBarTextLine, uniText, lstrlen(uniText)); SelectObject(hDCMem, hFontGraph); if (DiskState->OffLine) { LoadString(hModule, IDS_OFFLINE, uniText, sizeof(uniText)/sizeof(TCHAR)); } else { LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR)); wsprintf(uniText, TEXT("%u %s"), DiskState->DiskSizeMB, mbBuffer); } TextOut(hDCMem, xDiskText, BarTopYOffset + (4*dyBarTextLine), uniText, lstrlen(uniText)); if (DiskState->OffLine) { SelectObject(hDCMem, GetStockObject(LTGRAY_BRUSH)); Rectangle(hDCMem, BarLeftX, BarTopYOffset, BarLeftX + BarWidth, BarBottomYOffset); LoadString(hModule, IDS_NO_CONFIG_INFO, uniText, sizeof(uniText)/sizeof(TCHAR)); TextOut(hDCMem, BarLeftX + dxBarTextMargin, BarTopYOffset + (4*dyBarTextLine), uniText, lstrlen(uniText)); } else { // Account for extreme differences in largest to smallest disk // by insuring that a disk is always 1/4 the size of the // largest disk. diskSize = DiskState->DiskSizeMB; if (diskSize < largestDiskSize / 4) { diskSize = largestDiskSize / 4; } #if 0 // manage the horizontal size of the list box in order // to get a scroll bar. Perhaps this only needs to be done // once. BUGBUG: This will cause a horizontal scroll bar // that works correctly, but the region selection code is // not prepared for this, so selection of regions doesn't // operate correctly. largestExtent = (WPARAM)(BarWidth + BarLeftX + 2); SendMessage(hwndList, LB_SETHORIZONTALEXTENT, largestExtent, 0); #endif // If user wants WinDisk to decide which type of view to use, do that // here. We'll use a proportional view unless any single region would // have a width less than the size of a drive letter. if ((barType = DiskState->BarType) == BarAuto) { ULONG regionSize; barType = BarProportional; for (i=0; iRegionCount; i++) { regionDescriptor = &DiskState->RegionArray[i]; if (IsExtended(regionDescriptor->SysID)) { continue; } temp1 = UInt32x32To64(BarWidth, diskSize); temp1 *= regionDescriptor->SizeMB; temp2 = UInt32x32To64(largestDiskSize, DiskState->DiskSizeMB); regionSize = (ULONG) (temp1 / temp2); if (regionSize < 12*SELECTION_THICKNESS) { barType = BarEqual; break; } } } if (barType == BarEqual) { temp1 = UInt32x32To64(BarWidth, diskSize); temp2 = UInt32x32To64((DiskState->RegionCount - (DiskState->ExistExtended ? 1 : 0)), largestDiskSize); cx = (ULONG) (temp1 / temp2); } for (i=0; iRegionCount; i++) { PFT_OBJECT ftObject = NULL; regionDescriptor = &DiskState->RegionArray[i]; if (!IsExtended(regionDescriptor->SysID)) { if (barType == BarProportional) { temp1 = UInt32x32To64(BarWidth, diskSize); temp1 *= regionDescriptor->SizeMB; temp2 = UInt32x32To64(largestDiskSize, DiskState->DiskSizeMB); cx = (ULONG) (temp1 / temp2); } isFree = (regionDescriptor->SysID == SYSID_UNUSED); isLogical = (regionDescriptor->RegionType == REGION_LOGICAL); if (!isFree) { // If we've got a mirror or stripe set, use special colors. ftObject = GET_FT_OBJECT(regionDescriptor); switch(ftObject ? ftObject->Set->Type : -1) { case Mirror: brushIndex = BRUSH_MIRROR; break; case Stripe: case StripeWithParity: brushIndex = BRUSH_STRIPESET; break; case VolumeSet: brushIndex = BRUSH_VOLUMESET; break; default: brushIndex = isLogical ? BRUSH_USEDLOGICAL : BRUSH_USEDPRIMARY; } // end the switch } previousColor = SetBkColor(hDCMem, RGB(255, 255, 255)); SetBkMode(hDCMem, OPAQUE); if (isFree) { // Free space -- cross hatch the whole block. hbr = SelectObject(hDCMem,isLogical ? hBrushFreeLogical : hBrushFreePrimary); Rectangle(hDCMem, leftAdjust, BarTopYOffset, leftAdjust + cx, BarBottomYOffset); } else { // Used space -- make most of the block white except for // a small strip at the top, which gets an identifying color. // If the partition is not recognized, leave it all white. hbr = SelectObject(hDCMem, GetStockObject(WHITE_BRUSH)); Rectangle(hDCMem, leftAdjust, BarTopYOffset, leftAdjust + cx, BarBottomYOffset); if (IsRecognizedPartition(regionDescriptor->SysID)) { SelectObject(hDCMem, Brushes[brushIndex]); Rectangle(hDCMem, leftAdjust, BarTopYOffset, leftAdjust + cx, BarTopYOffset + (4 * dyBarTextLine / 5) + 1); } } if (hbr) { SelectObject(hDCMem, hbr); } DiskState->LeftRight[i].Left = leftAdjust; DiskState->LeftRight[i].Right = leftAdjust + cx - 1; // Figure out the type name (ie, unformatted, fat, etc) and // volume label. typeName = NULL; volumeLabel = NULL; DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter); LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR)); if (!typeName) { typeName = wszUnknown; } if (!volumeLabel) { volumeLabel = L""; } wsprintf(text, "\n%ws\n%ws\n%u %s", volumeLabel, typeName, regionDescriptor->SizeMB, mbBuffer); *textBold = 0; if (driveLetter != L' ') { wsprintf(textBold, "%wc:", driveLetter); } UnicodeHack(text, uniText); UnicodeHack(textBold, uniTextBold); // output the text rc.left = leftAdjust + dxBarTextMargin; rc.right = leftAdjust + cx - dxBarTextMargin; rc.top = BarTopYOffset + dyBarTextLine; rc.bottom = BarBottomYOffset; SetBkMode(hDCMem, TRANSPARENT); SelectObject(hDCMem, hFontGraphBold); // If this is an unhealthy ft set member, draw the text in red. if (!isFree && ftObject && (ftObject->State != Healthy) && (ftObject->State != Initializing)) { SetTextColor(hDCMem, RGB(192, 0, 0)); } else { SetTextColor(hDCMem, RGB(0, 0, 0)); } DrawText(hDCMem, uniTextBold, -1, &rc, DT_LEFT | DT_NOPREFIX); SelectObject(hDCMem, hFontGraph); DrawText(hDCMem, uniText, -1, &rc, DT_LEFT | DT_NOPREFIX); #if i386 // if this guy is active make a mark in the upper left // corner of his rectangle. if ((regionDescriptor->SysID != SYSID_UNUSED) && (regionDescriptor->Disk == 0) && (regionDescriptor->RegionType == REGION_PRIMARY) && regionDescriptor->Active) { TextOut(hDCMem, leftAdjust + dxBarTextMargin, BarTopYOffset + 2, TEXT("*"), 1); } #endif #ifdef DOUBLE_SPACE_SUPPORT_INCLUDED // Check for DoubleSpace volumes and update display accordingly dblSpaceIndex = 0; dblSpace = NULL; while (dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace)) { if (dblSpace->Mounted) { SetTextColor(hDCMem, RGB(192,0,0)); } else { SetTextColor(hDCMem, RGB(0,0,0)); } wsprintf(uniText, TEXT("%c: %s"), dblSpace->DriveLetter, dblSpace->FileName); rc.left = leftAdjust + dxBarTextMargin + 60; rc.right = leftAdjust + cx - dxBarTextMargin; rc.top = BarTopYOffset + dyBarTextLine + (dblSpaceIndex * 15); rc.bottom = BarBottomYOffset; DrawText(hDCMem, uniText, -1, &rc, DT_LEFT | DT_NOPREFIX); dblSpaceIndex++; } #endif SetBkColor(hDCMem, previousColor); leftAdjust += cx - 1; } else { DiskState->LeftRight[i].Left = DiskState->LeftRight[i].Right = 0; } } } SelectObject(hDCMem, hpenT); SelectObject(hDCMem, hfontT); } VOID AdjustMenuAndStatus( VOID ) /*++ Routine Description: This routine updates the information in the Status bar if something is selected and if the status bar is to be displayed. Arguments" None Return Value: None --*/ { TCHAR mbBuffer[16], statusBarPartitionString[200], dblSpaceString[200]; DWORD selectionCount, msg, regionIndex; PDISKSTATE diskState; PWSTR volumeLabel, typeName; WCHAR driveLetter; switch (selectionCount = SetUpMenu(&SingleSel,&SingleSelIndex)) { case 0: StatusTextDrlt[0] = 0; StatusTextSize[0] = StatusTextStat[0] = 0; StatusTextVoll[0] = StatusTextType[0] = 0; break; case 1: // Might be part of a partial FT set. if (FtSelectionType != -1) { goto FtSet; } diskState = SingleSel; regionIndex = SingleSelIndex; DetermineRegionInfo(&diskState->RegionArray[regionIndex], &typeName, &volumeLabel, &driveLetter); lstrcpyW(StatusTextType,typeName); lstrcpyW(StatusTextVoll,volumeLabel); if (diskState->RegionArray[regionIndex].SysID == SYSID_UNUSED) { if (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL) { if (diskState->ExistLogical) { msg = IDS_FREEEXT; } else { msg = IDS_EXTENDEDPARTITION; } } else { msg = IDS_FREESPACE; } driveLetter = L' '; StatusTextType[0] = 0; } else { msg = (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL) ? IDS_LOGICALVOLUME : IDS_PARTITION; #if i386 if ((msg == IDS_PARTITION) && (diskState->Disk == 0) && diskState->RegionArray[regionIndex].Active) { msg = IDS_ACTIVEPARTITION; } #endif } LoadString(hModule, msg, statusBarPartitionString, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0])); if (DblSpaceVolumeExists(&diskState->RegionArray[regionIndex])) { LoadString(hModule, IDS_WITH_DBLSPACE, dblSpaceString, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0])); } else { dblSpaceString[0] = dblSpaceString[1] = 0; } wsprintf(StatusTextStat, "%s %s", statusBarPartitionString, dblSpaceString); LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR)); wsprintf(StatusTextSize, "%u %s", diskState->RegionArray[regionIndex].SizeMB, mbBuffer); StatusTextDrlt[0] = driveLetter; StatusTextDrlt[1] = (WCHAR)((driveLetter == L' ') ? 0 : L':'); break; default: FtSet: // Might be an ft set, might be multiple items if (FtSelectionType == -1) { LoadString(hModule, IDS_MULTIPLEITEMS, StatusTextStat, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0])); StatusTextDrlt[0] = 0; StatusTextSize[0] = 0; StatusTextType[0] = StatusTextVoll[0] = 0; } else { PREGION_DESCRIPTOR regionDescriptor; DWORD resid = 0, i; DWORD Size = 0; TCHAR textbuf[STATUS_TEXT_SIZE]; PFT_OBJECT_SET ftSet; PFT_OBJECT ftObject; FT_SET_STATUS setState; ULONG numberOfMembers; WCHAR ftstat[65]; STATUS_CODE status; typeName = NULL; DetermineRegionInfo(&SELECTED_REGION(0), &typeName, &volumeLabel, &driveLetter); if (!typeName) { if (SelectionCount > 1) { DetermineRegionInfo(&SELECTED_REGION(0), &typeName, &volumeLabel, &driveLetter); } } if (!typeName) { typeName = wszUnknown; volumeLabel = L""; } lstrcpyW(StatusTextType, typeName); lstrcpyW(StatusTextVoll, volumeLabel); switch (FtSelectionType) { case Mirror: resid = IDS_STATUS_MIRROR; Size = SELECTED_REGION(0).SizeMB; break; case Stripe: resid = IDS_STATUS_STRIPESET; goto CalcSize; case StripeWithParity: resid = IDS_STATUS_PARITY; goto CalcSize; case VolumeSet: resid = IDS_STATUS_VOLUMESET; goto CalcSize; CalcSize: for (i=0; iSet; if (FtSelectionType != VolumeSet) { regionDescriptor = LocateRegionForFtObject(ftSet->Member0); if (!regionDescriptor) { // The zeroth member is off line ftObject = ftSet->Members; while (ftObject) { // Find member 1 if (ftObject->MemberIndex == 1) { regionDescriptor = LocateRegionForFtObject(ftObject); break; } ftObject = ftObject->Next; } } // If the partition number is zero, then this set has // not been committed to the disk yet. if ((regionDescriptor) && (regionDescriptor->PartitionNumber)) { status = LowFtVolumeStatus(regionDescriptor->Disk, regionDescriptor->PartitionNumber, &setState, &numberOfMembers); if (status == OK_STATUS) { if ((ftSet->Status != FtSetNewNeedsInitialization) && (ftSet->Status != FtSetNew)) { if (ftSet->Status != setState) { PFT_OBJECT tempFtObjectPtr; ftSet->Status = setState; // Determine if each object should be updated. switch (setState) { case FtSetHealthy: // Each object in the set should have // the partition state updated. Determine // the value for the update and walk // the chain to perform the update. for (tempFtObjectPtr = ftSet->Members; tempFtObjectPtr; tempFtObjectPtr = tempFtObjectPtr->Next) { tempFtObjectPtr->State = Healthy; } TotalRedrawAndRepaint(); break; case FtSetInitializing: case FtSetRegenerating: case FtSetDisabled: FdftUpdateFtObjectSet(ftSet, setState); TotalRedrawAndRepaint(); break; default: break; } } } } } } LoadString(hModule, resid, textbuf, sizeof(textbuf)/sizeof(TCHAR)); switch (resid) { case IDS_STATUS_STRIPESET: case IDS_STATUS_VOLUMESET: wsprintf(StatusTextStat, textbuf, ftSet->Ordinal); break; case IDS_STATUS_PARITY: case IDS_STATUS_MIRROR: switch(ftSet->Status) { case FtSetHealthy: resid = IDS_HEALTHY; break; case FtSetNew: case FtSetNewNeedsInitialization: resid = IDS_NEW; break; case FtSetBroken: resid = IDS_BROKEN; break; case FtSetRecoverable: resid = IDS_RECOVERABLE; break; case FtSetRecovered: resid = IDS_REGENERATED; break; case FtSetInitializing: resid = IDS_INITIALIZING; break; case FtSetRegenerating: resid = IDS_REGENERATING; break; case FtSetDisabled: resid = IDS_DISABLED; break; case FtSetInitializationFailed: resid = IDS_INIT_FAILED; break; default: FDASSERT(FALSE); } LoadStringW(hModule, resid, ftstat, sizeof(ftstat)/sizeof(WCHAR)); wsprintf(StatusTextStat, textbuf, ftSet->Ordinal,ftstat); break; default: FDASSERT(FALSE); } LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR)); wsprintf(StatusTextSize, "%u %s", Size, mbBuffer); StatusTextDrlt[0] = driveLetter; StatusTextDrlt[1] = (WCHAR)((driveLetter == L' ') ? 0 : L':'); } } UpdateStatusBarDisplay(); } ULONG PartitionCount( IN ULONG Disk ) /*++ Routine Description: Given a disk index, this routine calculates the number of partitions the disk contains. Arguments: Disk - This disk index for the count. Return Value: The number of partitions on the disk --*/ { unsigned i; ULONG partitions = 0; PREGION_DESCRIPTOR regionDescriptor; for (i=0; iRegionCount; i++) { regionDescriptor = &Disks[Disk]->RegionArray[i]; if ((regionDescriptor->RegionType != REGION_LOGICAL) && (regionDescriptor->SysID != SYSID_UNUSED)) { partitions++; } } return partitions; } BOOL RegisterFileSystemExtend( VOID ) /*++ Routine Description: This function adds registry entries to extend the file system structures in volume sets that have been extended. Arguments: None. Return Value: non-zero if there was a file system that was extended. --*/ { BYTE buf[1024]; PSTR template = "autochk /x "; CHAR extendedDrives[26]; PDISKSTATE diskState; PREGION_DESCRIPTOR regionDescriptor; PFT_OBJECT ftObject; DWORD cExt = 0, i, j, valueType, size, templateLength; HKEY hkey; LONG ec; // Traverse the disks to find any volume sets that // have been extended. for (i = 0; i < DiskCount; i++) { diskState = Disks[i]; for (j = 0; j < diskState->RegionCount; j++) { regionDescriptor = &diskState->RegionArray[j]; if ((ftObject = GET_FT_OBJECT(regionDescriptor)) != NULL && ftObject->MemberIndex == 0 && ftObject->Set->Type == VolumeSet && ftObject->Set->Status == FtSetExtended) { extendedDrives[cExt++] = PERSISTENT_DATA(regionDescriptor)->DriveLetter; } } } if (cExt) { // Fetch the BootExecute value of the Session Manager key. ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\Session Manager"), 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkey); if (ec != NO_ERROR) { return 0; } size = sizeof(buf); ec = RegQueryValueExA(hkey, TEXT("BootExecute"), NULL, &valueType, buf, &size); if (ec != NO_ERROR || valueType != REG_MULTI_SZ) { return 0; } // Decrement size to get rid of the extra trailing null if (size) { size--; } templateLength = strlen(template); for (i = 0; i < cExt; i++) { // Add an entry for this drive to the BootExecute value. strncpy(buf+size, template, templateLength); size += templateLength; buf[size++] = extendedDrives[i]; buf[size++] = ':'; buf[size++] = 0; } // Add an additional trailing null at the end buf[size++] = 0; // Save the value. ec = RegSetValueExA(hkey, TEXT("BootExecute"), 0, REG_MULTI_SZ, buf, size); RegCloseKey( hkey ); if (ec != NO_ERROR) { return 0; } return 1; } return 0; }