/*++ Copyright (c) 1993 Microsoft Corporation Module Name: sppartit.c Abstract: Partitioning module in text setup. Author: Ted Miller (tedm) 7-September-1993 Revision History: --*/ #include "spprecmp.h" #pragma hdrstop #include PPARTITIONED_DISK PartitionedDisks; // // Disk region containing the local source directory // in the winnt.exe setup case. // // If WinntSetup is TRUE, then this should be non-null. // If it is not non-null, then we couldn't locate the local source. // // PDISK_REGION LocalSourceRegion; // // Flag indicating whether we detected any HPFS volumes. // Used during upgrades, so we can warn the user that he won't // be able to see or convert the drives from >= nt4.00. // BOOLEAN AnyHpfsDrives; VOID SpPtReadPartitionTables( IN PPARTITIONED_DISK pDisk ); VOID SpPtInitializePartitionStructures( IN ULONG DiskNumber ); VOID SpPtDeterminePartitionTypes( IN ULONG DiskNumber ); VOID SpPtDetermineVolumeFreeSpace( IN ULONG DiskNumber ); VOID SpPtLocateSystemPartitions( VOID ); NTSTATUS SpMasterBootCode( IN ULONG DiskNumber, IN HANDLE Partition0Handle, OUT PULONG NewNTFTSignature ); VOID SpPtGuessDriveLetters( VOID ); NTSTATUS SpPtInitialize( VOID ) { ULONG disk; PHARD_DISK harddisk; PPARTITIONED_DISK partdisk; ULONG Disk0Ordinal = 0; ASSERT(HardDisksDetermined); // // If there are no hard disks, bail now. // if(!HardDiskCount) { SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0); SpkbdDrain(); while(SpkbdGetKeypress() != KEY_F3) ; SpDone(FALSE,TRUE); } CLEAR_CLIENT_SCREEN(); #ifdef _X86_ Disk0Ordinal = SpDetermineDisk0(); #endif // // Allocate an array for the partitioned disk descriptors. // PartitionedDisks = SpMemAlloc(HardDiskCount * sizeof(PARTITIONED_DISK)); if(!PartitionedDisks) { return(STATUS_NO_MEMORY); } RtlZeroMemory(PartitionedDisks,HardDiskCount * sizeof(PARTITIONED_DISK)); // // For each hard disk attached to the system, read its partition table. // for(disk=0; diskDescription ); partdisk = &PartitionedDisks[disk]; partdisk->HardDisk = harddisk; // // Read the partition tables. // SpPtReadPartitionTables(partdisk); // // Initialize structures that are based on the partition tables. // SpPtInitializePartitionStructures(disk); // // Determine the type name for each partition on this disk. // SpPtDeterminePartitionTypes(disk); } // // Guess drive letters. // SpPtGuessDriveLetters(); // // DoubleSpace initialization. // // // Load dblspace.ini file // if( SpLoadDblspaceIni() ) { SpDisplayStatusText( SP_STAT_EXAMINING_DISK_N, DEFAULT_STATUS_ATTRIBUTE, HardDisks[Disk0Ordinal].Description ); // // Build lists of compressed drives and add them to the DISK_REGION // structures // SpInitializeCompressedDrives(); } for(disk=0; diskExtendedDiskRegions : pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { pRegion->TypeName[0] = 0; pRegion->Filesystem = FilesystemUnknown; // // If this is a free space, skip it. // if(!pRegion->PartitionedSpace) { continue; } // // Fetch the system id. // SysId = pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId; // // If this is the extended partition, skip it. // if(IsContainerPartition(SysId)) { continue; } // // If this is a 'recognized' partition type, then determine // the filesystem on it. Otherwise use a precanned name. // if(PartitionNameIds[SysId] == (UCHAR)(-1)) { FsType = SpIdentifyFileSystem( HardDisks[DiskNumber].DevicePath, HardDisks[DiskNumber].Geometry.BytesPerSector, SpPtGetOrdinal(pRegion,PartitionOrdinalOnDisk) ); // // Hpfs is no longer recognized but we do detect it // so we can prompt the user, etc. If we see any HPFS // here, tell the user he won't see them under NT. // if(FsType == FilesystemHpfs) { if(!UnattendedOperation && !WarnedHpfs) { while(1) { SpDisplayScreen(SP_SCRN_HPFS,3,HEADER_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_F3_EQUALS_EXIT, 0 ); if(SpWaitValidKey(ValidKeys,NULL,NULL) == KEY_F3) { SpConfirmExit(); } else { break; } } CLEAR_CLIENT_SCREEN(); SpDisplayStatusText( SP_STAT_EXAMINING_DISK_N, DEFAULT_STATUS_ATTRIBUTE, pDisk->HardDisk->Description ); WarnedHpfs = TRUE; } FsType = FilesystemUnknown; AnyHpfsDrives = TRUE; } NameId = SP_TEXT_FS_NAME_BASE + FsType; pRegion->Filesystem = FsType; } else { NameId = SP_TEXT_PARTITION_NAME_BASE + (ULONG)PartitionNameIds[SysId]; } // // Get the final type name from the resources. // SpFormatMessage( pRegion->TypeName, sizeof(pRegion->TypeName), NameId ); } } } VOID SpPtDetermineRegionSpace( IN PDISK_REGION pRegion ) { HANDLE Handle; OBJECT_ATTRIBUTES Obja; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; FILE_FS_SIZE_INFORMATION SizeInfo; ULONG r; NTSTATUS Status; WCHAR Buffer[512]; struct LABEL_BUFFER { FILE_FS_VOLUME_INFORMATION VolumeInfo; WCHAR Label[256]; } LabelBuffer; PFILE_FS_VOLUME_INFORMATION LabelInfo; #ifdef _X86_ static BOOLEAN LookForUndelete = TRUE; PWSTR UndeleteFiles[1] = { L"SENTRY" }; #endif PWSTR LocalSourceFiles[1] = { LocalSourceDirectory }; ULONG ExtraSpace; // // Assume unknown. // pRegion->FreeSpaceKB = (ULONG)(-1); pRegion->AdjustedFreeSpaceKB = (ULONG)(-1); // // If region is free space of an unknown type, skip it. // if(pRegion->Filesystem >= FilesystemFirstKnown) { // // Form the name of the root directory. // SpNtNameFromRegion(pRegion,Buffer,sizeof(Buffer),PartitionOrdinalCurrent); SpConcatenatePaths(Buffer,L""); // // Delete \pagefile.sys if it's there. This makes disk free space // calculations a little easier. // SpDeleteFile(Buffer,L"pagefile.sys",NULL); #ifdef _X86_ // // Check to see if Undelete (dos 6) delete sentry or delete tracking // methods are in use. If so, give a warning because the free space // value we will display for this drive will be off. // if(LookForUndelete && (pRegion->Filesystem == FilesystemFat) && SpNFilesExist(Buffer,UndeleteFiles,ELEMENT_COUNT(UndeleteFiles),TRUE)) { SpDisplayScreen(SP_SCRN_FOUND_UNDELETE,3,HEADER_HEIGHT+1); SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE); SpkbdDrain(); while(SpkbdGetKeypress() != ASCI_CR) ; LookForUndelete = FALSE; } #endif // // If this is a winnt setup, then look for the local source // on this drive if we haven't found it already. // if(WinntSetup && !LocalSourceRegion && SpNFilesExist(Buffer,LocalSourceFiles,ELEMENT_COUNT(LocalSourceFiles),TRUE)) { PWSTR SifName; PVOID SifHandle; ULONG ErrorLine; NTSTATUS Status; PWSTR p; LocalSourceRegion = pRegion; pRegion->IsLocalSource = TRUE; ExtraSpace = 0; // // Open the small ini file that text setup put there to tell us // how much space is taken up by the local source. // wcscpy((PWSTR)TemporaryBuffer,Buffer); SpConcatenatePaths((PWSTR)TemporaryBuffer,LocalSourceDirectory); SpConcatenatePaths((PWSTR)TemporaryBuffer,L"size.sif"); SifName = SpDupStringW((PWSTR)TemporaryBuffer); Status = SpLoadSetupTextFile(SifName,NULL,0,&SifHandle,&ErrorLine); if(NT_SUCCESS(Status)) { p = SpGetSectionKeyIndex(SifHandle,L"Data",L"Size",0); if(p) { ExtraSpace = (ULONG)SpStringToLong(p,NULL,10); } SpFreeTextFile(SifHandle); } SpMemFree(SifName); KdPrint(("SETUP: %ws is the local source (occupying %lx bytes)\n",Buffer,ExtraSpace)); } // // Open the root directory on the partition's filesystem. // INIT_OBJA(&Obja,&UnicodeString,Buffer); Status = ZwCreateFile( &Handle, FILE_GENERIC_READ, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to open %ws (%lx)\n",Buffer,Status)); //pRegion->Filesystem = FilesystemUnknown; return; } // // Fetch volume size info. // Status = ZwQueryVolumeInformationFile( Handle, &IoStatusBlock, &SizeInfo, sizeof(SizeInfo), FileFsSizeInformation ); if(NT_SUCCESS(Status)) { LARGE_INTEGER FreeBytes; LARGE_INTEGER AdjustedFreeBytes; // // Calculate the amount of free space on the drive. // Use the Rtl multiply routine because there is a compiler // problem/chip errata on MIPS with 64-bit arithmetic // (tedm 2/28/96). // FreeBytes = RtlExtendedIntegerMultiply( SizeInfo.AvailableAllocationUnits, SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector ); AdjustedFreeBytes = FreeBytes; if(pRegion->IsLocalSource) { AdjustedFreeBytes.QuadPart += ExtraSpace; } // // convert this to a number of KB. // pRegion->FreeSpaceKB = RtlExtendedLargeIntegerDivide(FreeBytes,1024,&r).LowPart; if(r >= 512) { pRegion->FreeSpaceKB++; } pRegion->AdjustedFreeSpaceKB = RtlExtendedLargeIntegerDivide(AdjustedFreeBytes,1024,&r).LowPart; if(r >= 512) { pRegion->AdjustedFreeSpaceKB++; } if( pRegion->Filesystem == FilesystemDoubleSpace ) { // // If this the regison is a double space drive, then initialize // sector count correctly, so that the drive size can be calculated // correctly later on. // pRegion->SectorCount = (ULONG)( SizeInfo.TotalAllocationUnits.QuadPart * SizeInfo.SectorsPerAllocationUnit ); } } else { KdPrint(("SETUP: ZwQueryVolumeInformationFile for freespace failed (%lx)\n",Status)); } // // Fetch volume label info. // Status = ZwQueryVolumeInformationFile( Handle, &IoStatusBlock, &LabelBuffer, sizeof(LabelBuffer), FileFsVolumeInformation ); if(NT_SUCCESS(Status)) { ULONG SaveCharCount; LabelInfo = &LabelBuffer.VolumeInfo; // // We'll only save away the first characters of // the volume label. // SaveCharCount = min( LabelInfo->VolumeLabelLength + sizeof(WCHAR), sizeof(pRegion->VolumeLabel) ) / sizeof(WCHAR); if(SaveCharCount) { SaveCharCount--; // allow for terminating NUL. } wcsncpy(pRegion->VolumeLabel,LabelInfo->VolumeLabel,SaveCharCount); pRegion->VolumeLabel[SaveCharCount] = 0; } else { KdPrint(("SETUP: ZwQueryVolumeInformationFile for label failed (%lx)\n",Status)); } ZwClose(Handle); } } VOID SpPtDetermineVolumeFreeSpace( IN ULONG DiskNumber ) { PPARTITIONED_DISK pDisk; PDISK_REGION pRegion; unsigned pass; #ifdef FULL_DOUBLE_SPACE_SUPPORT PDISK_REGION CompressedDrive; #endif // FULL_DOUBLE_SPACE_SUPPORT pDisk = &PartitionedDisks[DiskNumber]; for(pass=0; pass<2; pass++) { pRegion = pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { SpPtDetermineRegionSpace( pRegion ); #ifdef FULL_DOUBLE_SPACE_SUPPORT if( ( pRegion->Filesystem == FilesystemFat ) && ( pRegion->NextCompressed != NULL ) ) { // // If the region is a FAT partition that contains compressed // volumes, then determine the available space on each // compressed volume // for( CompressedDrive = pRegion->NextCompressed; CompressedDrive; CompressedDrive = CompressedDrive->NextCompressed ) { SpPtDetermineRegionSpace( CompressedDrive ); } } #endif // FULL_DOUBLE_SPACE_SUPPORT } } } VOID SpPtLocateSystemPartitions( VOID ) { #ifdef _X86_ PDISK_REGION pRegion; ULONG Disk0Ordinal = SpDetermineDisk0(); // // On x86 machines, we will mark any primary partitions on drive 0 // as system partition, since such a partition is potentially bootable. // for(pRegion=PartitionedDisks[Disk0Ordinal].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { // // Skip if free space or extended partition. // if(pRegion->PartitionedSpace && !IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId)) { // // It's a primary partition -- declare it a system partition. // pRegion->IsSystemPartition = TRUE; } } #else PDISK_REGION pRegion; PPARTITIONED_DISK pDisk; unsigned pass; PUCHAR pch; PWSTR p,*Components; ULONG NumComponents,i,disk; // // On ARC machines, system partitions are specifically enumerated // in the NVRAM boot environment. // // // Get the systempartition environment variable. // pch = SppGetArcEnvVar(SYSTEMPARTITION); SpGetEnvVarWComponents(pch,&Components,&NumComponents); SpMemFree(pch); // // Convert each of the components into NT pathnames. // for(i=0; iExtendedDiskRegions : pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { // // Skip if not a partition or extended partition. // if(pRegion->PartitionedSpace && !IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId)) { // // Get the nt pathname for this region. // SpNtNameFromRegion( pRegion, (PWSTR)TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalOriginal ); // // Determine if it is a system partition. // for(i=0; iIsSystemPartition = TRUE; break; } } } } } } SpFreeEnvVarComponents(Components); #endif } VOID SpPtReadPartitionTables( IN PPARTITIONED_DISK pDisk ) /*++ Routine Description: Read partition tables from a given disk. Arguments: pDisk - supplies pointer to disk descriptor to be filled in. Return Value: None. --*/ { NTSTATUS Status; HANDLE Handle; PUCHAR Buffer; PUCHAR UnalignedBuffer; PON_DISK_MBR pBr; BOOLEAN InMbr; ULONG ExtendedStart; ULONG NextSector; PMBR_INFO pEbr,pLastEbr; BOOLEAN FoundLink; ULONG i,x; BOOLEAN Ignore; ULONG bps; ULONG SectorsInBootrec; // // If this disk is off-line, nothing to do. // if(pDisk->HardDisk->Status != DiskOnLine) { return; } // // Open partition 0 of this disk. // Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,FALSE); if(!NT_SUCCESS(Status)) { pDisk->HardDisk->Status = DiskOffLine; return; } bps = pDisk->HardDisk->Geometry.BytesPerSector; SectorsInBootrec = (512/bps) ? (512/bps) : 1; // // Allocate and align a buffer for sector i/o. // ASSERT(sizeof(ON_DISK_MBR)==512); UnalignedBuffer = SpMemAlloc(2 * SectorsInBootrec * bps); Buffer = ALIGN(UnalignedBuffer,bps); // // Read the MBR (sector 0). // NextSector = 0; #ifdef _X86_ readmbr: #endif Status = SpReadWriteDiskSectors(Handle,NextSector,SectorsInBootrec,bps,Buffer,FALSE); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: Unable to read mbr for disk %ws (%lx)\n",pDisk->HardDisk->DevicePath,Status)); pDisk->HardDisk->Status = DiskOffLine; ZwClose(Handle); SpMemFree(UnalignedBuffer); return; } // // Move the data we just read into the partitioned disk descriptor. // RtlMoveMemory(&pDisk->MbrInfo.OnDiskMbr,Buffer,sizeof(ON_DISK_MBR)); // // If this MBR is not valid, initialize it. Otherwise, fetch all logical drives // (EBR) info as well. // if(U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) == MBR_SIGNATURE) { #ifdef _X86_ // // EZDrive support: if the first entry in the partition table is // type 0x55, then the actual partition table is on sector 1. // // Only for x86 because on non-x86, the firmware can't see EZDrive // partitions, so we don;t want to install on them! // if(!NextSector && (pDisk->MbrInfo.OnDiskMbr.PartitionTable[0].SystemId == 0x55)) { NextSector = 1; pDisk->HardDisk->EZDrive = TRUE; goto readmbr; } #endif pDisk->MbrWasValid = TRUE; pBr = &pDisk->MbrInfo.OnDiskMbr; InMbr = TRUE; ExtendedStart = 0; pLastEbr = NULL; do { // // Look at all the entries in the current boot record to see if there // is a link entry. // FoundLink = FALSE; for(i=0; iPartitionTable[i].SystemId)) { FoundLink = TRUE; NextSector = ExtendedStart + U_ULONG(pBr->PartitionTable[i].RelativeSectors); if(NextSector == 0) { // // Then we've got ourselves one seriously screwed up boot record. We'll // just return, and present this mess as free space. // // BUGBUG we should warn the user that we are going to ignore // partitions past this point because the structures are damaged. // KdPrint(("SETUP: Bad partition table for %ws\n",pDisk->HardDisk->DevicePath)); ZwClose(Handle); SpMemFree(UnalignedBuffer); return; } pEbr = SpMemAlloc(sizeof(MBR_INFO)); ASSERT(pEbr); RtlZeroMemory(pEbr,sizeof(MBR_INFO)); // // Sector number on the disk where this boot sector is. // pEbr->OnDiskSector = NextSector; if(InMbr) { ExtendedStart = NextSector; InMbr = FALSE; } // // Read the next boot sector and break out of the loop through // the current partition table. // Status = SpReadWriteDiskSectors( Handle, NextSector, SectorsInBootrec, bps, Buffer, FALSE ); RtlMoveMemory(&pEbr->OnDiskMbr,Buffer,sizeof(ON_DISK_MBR)); if(!NT_SUCCESS(Status) || (U_USHORT(pEbr->OnDiskMbr.AA55Signature) != MBR_SIGNATURE)) { // // BUGBUG we should warn the user that we are going to ignore // partitions part this point because we could not read the disk // or the structures are damaged. // KdPrint(("SETUP: Unable to read ebr on %ws at sector %lx (%lx)\n",pDisk->HardDisk->DevicePath,NextSector,Status)); ZwClose(Handle); if(pLastEbr) { SpMemFree(pEbr); } SpMemFree(UnalignedBuffer); return; } pBr = &pEbr->OnDiskMbr; // // We just read the next boot sector. If all that boot sector contains // is a link entry, the only thing we need the boot sector for is to find // the next boot sector. This happens when there is free space at the start // of the extended partition. // Ignore = TRUE; for(x=0; xPartitionTable[x].SystemId != PARTITION_ENTRY_UNUSED) && !IsContainerPartition(pBr->PartitionTable[x].SystemId)) { Ignore = FALSE; break; } } // // Link the Ebr into the logical volume list if we're not ignoring it. // if(!Ignore) { if(pLastEbr) { pLastEbr->Next = pEbr; } else { ASSERT(pDisk->FirstEbrInfo.Next == NULL); pDisk->FirstEbrInfo.Next = pEbr; } pLastEbr = pEbr; } break; } } } while(FoundLink); } else { pDisk->MbrWasValid = FALSE; RtlZeroMemory(&pDisk->MbrInfo,sizeof(MBR_INFO)); U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = MBR_SIGNATURE; U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = SpComputeSerialNumber(); } // // Close partition0. // ZwClose(Handle); SpMemFree(UnalignedBuffer); return; } PDISK_REGION SpPtAllocateDiskRegionStructure( IN ULONG DiskNumber, IN ULONG StartSector, IN ULONG SectorCount, IN BOOLEAN PartitionedSpace, IN PMBR_INFO MbrInfo, IN ULONG TablePosition ) /*++ Routine Description: Allcoate and initialize a structure of type DISK_REGION. Arguments: Values to be filled into the fields of the newly allocated disk region structure. Return Value: Pointer to new disk region structure. --*/ { PDISK_REGION p; p = SpMemAlloc(sizeof(DISK_REGION)); ASSERT(p); if(p) { RtlZeroMemory(p,sizeof(DISK_REGION)); p->DiskNumber = DiskNumber; p->StartSector = StartSector; p->SectorCount = SectorCount; p->PartitionedSpace = PartitionedSpace; p->MbrInfo = MbrInfo; p->TablePosition = TablePosition; } return(p); } VOID SpPtInsertDiskRegionStructure( IN PDISK_REGION Region, IN OUT PDISK_REGION *ListHead ) { PDISK_REGION RegionCur,RegionPrev; // // Insert the region entry into the relevent list of region entries. // Note that these lists are kept sorted by start sector. // if(RegionCur = *ListHead) { if(Region->StartSector < RegionCur->StartSector) { // // Stick at head of list. // Region->Next = RegionCur; *ListHead = Region; } else { while(1) { RegionPrev = RegionCur; RegionCur = RegionCur->Next; if(RegionCur) { if(RegionCur->StartSector > Region->StartSector) { Region->Next = RegionCur; RegionPrev->Next = Region; break; } } else { // // Stick at end of list. // RegionPrev->Next = Region; break; } } } } else { *ListHead = Region; } } VOID SpPtAssignOrdinals( IN PPARTITIONED_DISK pDisk, IN BOOLEAN InitCurrentOrdinals, IN BOOLEAN InitOnDiskOrdinals, IN BOOLEAN InitOriginalOrdinals ) { PMBR_INFO pBrInfo; ULONG i; USHORT ordinal; ordinal = 0; for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) { for(i=0; iOnDiskMbr.PartitionTable[i]; if((pte->SystemId != PARTITION_ENTRY_UNUSED) && !IsContainerPartition(pte->SystemId)) { ordinal++; if(InitCurrentOrdinals) { pBrInfo->CurrentOrdinals[i] = ordinal; } if(InitOnDiskOrdinals) { pBrInfo->OnDiskOrdinals[i] = ordinal; } if(InitOriginalOrdinals) { pBrInfo->OriginalOrdinals[i] = ordinal; } } else { if(InitCurrentOrdinals) { pBrInfo->CurrentOrdinals[i] = 0; } if(InitOnDiskOrdinals) { pBrInfo->OnDiskOrdinals[i] = 0; } if(InitOriginalOrdinals) { pBrInfo->OriginalOrdinals[i] = 0; } } } } } VOID SpPtInitializePartitionStructures( IN ULONG DiskNumber ) /*++ Routine Description: Perform additional initialization on the partition structures, beyond what has been performed in SpPtReadPartitionTables. Specifically, determine partition ordinals, offsets, and sizes. Arguments: DiskNumber - disk ordinal of disk descriptor to be filled in. Return Value: None. --*/ { ULONG i,pass; PMBR_INFO pBrInfo; BOOLEAN InMbr; ULONG ExtendedStart = 0; ULONG ExtendedEnd,ExtendedSize; ULONG offset,size; ULONG bps; PDISK_REGION pRegion,pRegionCur,pRegionPrev; PPARTITIONED_DISK pDisk = &PartitionedDisks[DiskNumber]; // // If this disk is off-line, nothing to do. // if(pDisk->HardDisk->Status != DiskOnLine) { return; } InMbr = TRUE; bps = pDisk->HardDisk->Geometry.BytesPerSector; // // Link the EBR chain to the MBR. // pDisk->MbrInfo.Next = &pDisk->FirstEbrInfo; for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) { for(i=0; iOnDiskMbr.PartitionTable[i]; if(pte->SystemId != PARTITION_ENTRY_UNUSED) { if(IsContainerPartition(pte->SystemId)) { // // If we're in the MBR, ExtendedStart will be 0. // offset = ExtendedStart + U_ULONG(pte->RelativeSectors); size = U_ULONG(pte->SectorCount); // // Track the start of the extended partition. // if(InMbr) { ExtendedStart = U_ULONG(pte->RelativeSectors); ExtendedEnd = ExtendedStart + U_ULONG(pte->SectorCount); ExtendedSize = ExtendedEnd - ExtendedStart; } } else { // // In the MBR, the relative sectors field is the sector offset // to the partition. In EBRs, the relative sectors field is the // number of sectors between the start of the boot sector and // the start of the filesystem data area. We will consider such // partitions to start with their boot sectors. // offset = InMbr ? U_ULONG(pte->RelativeSectors) : pBrInfo->OnDiskSector; size = U_ULONG(pte->SectorCount) + (InMbr ? 0 : U_ULONG(pte->RelativeSectors)); } if(InMbr || !IsContainerPartition(pte->SystemId)) { // // Create a region entry for this used space. // pRegion = SpPtAllocateDiskRegionStructure( DiskNumber, offset, size, TRUE, pBrInfo, i ); ASSERT(pRegion); // // Insert the region entry into the relevent list of region entries. // Note that these lists are kept sorted by start sector. // SpPtInsertDiskRegionStructure( pRegion, InMbr ? &pDisk->PrimaryDiskRegions : &pDisk->ExtendedDiskRegions ); } } } if(InMbr) { InMbr = FALSE; } } // // Initialize partition ordinals. // SpPtAssignOrdinals(pDisk,TRUE,TRUE,TRUE); // // Now go through the regions for this disk and insert free space descriptors // where necessary. // // Pass 0 for the MBR; pass 1 for logical drives. // for(pass=0; pass<(ULONG)(ExtendedStart ? 2 : 1); pass++) { if(pRegionPrev = (pass ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions)) { ULONG EndSector,FreeSpaceSize; ASSERT(pRegionPrev->PartitionedSpace); // // Handle any space occurring *before* the first partition. // if(pRegionPrev->StartSector != (pass ? ExtendedStart : 0)) { ASSERT(pRegionPrev->StartSector > (pass ? ExtendedStart : 0)); pRegion = SpPtAllocateDiskRegionStructure( DiskNumber, pass ? ExtendedStart : 0, pRegionPrev->StartSector - (pass ? ExtendedStart : 0), FALSE, NULL, 0 ); ASSERT(pRegion); pRegion->Next = pRegionPrev; if(pass) { // extended pDisk->ExtendedDiskRegions = pRegion; } else { // mbr pDisk->PrimaryDiskRegions = pRegion; } } pRegionCur = pRegionPrev->Next; while(pRegionCur) { // // If the start of this partition plus its size is less than the // start of the next partition, then we need a new region. // EndSector = pRegionPrev->StartSector + pRegionPrev->SectorCount; FreeSpaceSize = pRegionCur->StartSector - EndSector; if((LONG)FreeSpaceSize > 0) { pRegion = SpPtAllocateDiskRegionStructure( DiskNumber, EndSector, FreeSpaceSize, FALSE, NULL, 0 ); ASSERT(pRegion); pRegionPrev->Next = pRegion; pRegion->Next = pRegionCur; } pRegionPrev = pRegionCur; pRegionCur = pRegionCur->Next; } // // Space at end of disk/extended partition. // EndSector = pRegionPrev->StartSector + pRegionPrev->SectorCount; FreeSpaceSize = (pass ? ExtendedEnd : pDisk->HardDisk->DiskSizeSectors) - EndSector; if((LONG)FreeSpaceSize > 0) { pRegionPrev->Next = SpPtAllocateDiskRegionStructure( DiskNumber, EndSector, FreeSpaceSize, FALSE, NULL, 0 ); ASSERT(pRegionPrev->Next); } } else { // // Show whole disk/extended partition as free. // if(pass) { // // Extended partition. // ASSERT(ExtendedStart); pDisk->ExtendedDiskRegions = SpPtAllocateDiskRegionStructure( DiskNumber, ExtendedStart, ExtendedSize, FALSE, NULL, 0 ); ASSERT(pDisk->ExtendedDiskRegions); } else { // // MBR. // pDisk->PrimaryDiskRegions = SpPtAllocateDiskRegionStructure( DiskNumber, 0, pDisk->HardDisk->DiskSizeSectors, FALSE, NULL, 0 ); ASSERT(pDisk->PrimaryDiskRegions); } } } } VOID SpPtCountPrimaryPartitions( IN PPARTITIONED_DISK pDisk, OUT PULONG TotalPrimaryPartitionCount, OUT PULONG RecognizedPrimaryPartitionCount, OUT PBOOLEAN ExtendedExists ) { ULONG TotalCount; ULONG RecognizedCount; ULONG u; UCHAR SysId; #define DOS_PARTITION(x) (((x)==1) || ((x)==4) || ((x)==6) || ((x)==7)) TotalCount = 0; RecognizedCount = 0; *ExtendedExists = FALSE; for(u=0; uMbrInfo.OnDiskMbr.PartitionTable[u].SystemId; if(SysId != PARTITION_ENTRY_UNUSED) { TotalCount++; if(DOS_PARTITION(SysId)) { RecognizedCount++; } if(IsContainerPartition(SysId)) { *ExtendedExists = TRUE; } } } *TotalPrimaryPartitionCount = TotalCount; *RecognizedPrimaryPartitionCount = RecognizedCount; } PDISK_REGION SpPtLookupRegionByStart( IN PPARTITIONED_DISK pDisk, IN BOOLEAN ExtendedPartition, IN ULONG StartSector ) /*++ Routine Description: Locate a disk region, based on its starting sector. The starting sector must match the starting sector of an existing region EXACTLY for it to be considered a match. Arguments: pDisk - supplies disk on which to look for the region. ExtendedPartition - if TRUE, then look in the extended partition to find a match. Otherwise look in the main list. StartSector - supplies the sector number of the first sector of the region. Return Value: NULL is region could not be found; otherwise a pointer to the matching disk region structure. --*/ { PDISK_REGION p; for( p = (ExtendedPartition ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions); p && (StartSector != p->StartSector); p = p->Next) { ; } return(p); } ULONG SpPtAlignStart( IN PHARD_DISK pHardDisk, IN ULONG StartSector, IN BOOLEAN ForExtended ) /*++ Routine Description: Snap a start sector to a cylinder boundary if it is not already on a cylinder boundary. Any alignment that is necessary is performed towards the end of the disk. If the start sector is on cylinder 0, then alignment is to track 1 for primary partitions, or to track 0 on cylinder 1 for extended partitions. Arguments: pHardDisk - supplies disk descriptor for disk that the start sector is on. StartSector - supplies the sector number of the first sector of the region. ForExtended - if TRUE, then align the start sector as appropriate for creating an extended partition. Otherwise align for a pimary partition or logical drive. Return Value: New (aligned) start sector. May or may not be different than StartSector. --*/ { PDISK_GEOMETRY pGeometry; ULONG r; ULONG C,H,S; pGeometry = &pHardDisk->Geometry; // // Convert the start sector into cylinder, head, sector address. // C = StartSector / pHardDisk->SectorsPerCylinder; r = StartSector % pHardDisk->SectorsPerCylinder; H = r / pGeometry->SectorsPerTrack; S = r % pGeometry->SectorsPerTrack; // // Align as necessary. // if(C) { if(H || S) { H = S = 0; C++; } } else { // // Start cylinder is 0. If the caller wants to create an // extended partition, bump the start cylinder up to 1. // if(ForExtended) { C = 1; H = S = 0; } else { // // Start cylinder is 0 and the caller does not want to // create an extended partition. In this case, we want // to start the partition on cylinder 0, track 1. If the // start is beyond this already, start on cylinder 1. // if((H == 0) || ((H == 1) && !S)) { H = 1; S = 0; } else { H = S = 0; C = 1; } } } // // Now calculate and return the new start sector. // return((C * pHardDisk->SectorsPerCylinder) + (H * pGeometry->SectorsPerTrack) + S); } VOID SpPtQueryMinMaxCreationSizeMB( IN ULONG DiskNumber, IN ULONG StartSector, IN BOOLEAN ForExtended, IN BOOLEAN InExtended, OUT PULONG MinSize, OUT PULONG MaxSize ) /*++ Routine Description: Given the starting sector of an unpartitioned space on a disk, determine the minimum and maximum size in megabytes of the partition that can be created in the space, taking all alignment and rounding requirements into account. Arguments: DiskNumber - ordinal of disk on which partition will be created. StartSector - starting sector of an unpartitioned space on the disk. ForExtended - if TRUE, then the caller wants to know how large an extended partition in that space could be. This may be smaller than the general case, because an extended partition cannot start on cylinder 0. InExtended - if TRUE, then we want to create a logical drive. Otherwise we want to create a primary (including extended) partition. If TRUE, ForExtended must be FALSE. MinSize - receives minimum size in megabytes for a partition in the space. MaxSize - receives maximum size in megabytes for a partition in the space. Return Value: None. --*/ { PPARTITIONED_DISK pDisk; ULONG AlignedStartSector; ULONG AlignedEndSector; ULONG SectorCount; PDISK_REGION pRegion; LARGE_INTEGER MB,temp; ULONG remainder; ULONG LeftOverSectors; *MinSize = 0; *MaxSize = 0; ASSERT(DiskNumber < HardDiskCount); if(InExtended) { ASSERT(!ForExtended); } pDisk = &PartitionedDisks[DiskNumber]; // // Look up this region. // pRegion = SpPtLookupRegionByStart(pDisk,InExtended,StartSector); ASSERT(pRegion); if(!pRegion) { return; } ASSERT(!pRegion->PartitionedSpace); if(pRegion->PartitionedSpace) { return; } // // Align the start to a proper boundary. // AlignedStartSector = SpPtAlignStart(pDisk->HardDisk,StartSector,ForExtended); // // Determine the maximum aligned end sector. // AlignedEndSector = pRegion->StartSector + pRegion->SectorCount; if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) { AlignedEndSector -= LeftOverSectors; } // // Calculate the number of sectors in the properly aligned space. // SectorCount = AlignedEndSector - AlignedStartSector; ASSERT((LONG)SectorCount >= 0); // // Convert sectors to MB. // temp.QuadPart = UInt32x32To64(SectorCount,pDisk->HardDisk->Geometry.BytesPerSector); MB = RtlExtendedLargeIntegerDivide(temp,1024*1024,&remainder); ASSERT(!MB.HighPart); // // If the remainder was greater than or equal to a half meg, // bump up the number of megabytes. // *MaxSize = (MB.LowPart + ((remainder >= (512*1024)) ? 1 : 0)); // // The mimimum size is one cylinder except that if a cylinder // is smaller than 1 meg, the min size is 1 meg. // temp.QuadPart = UInt32x32To64( pDisk->HardDisk->SectorsPerCylinder, pDisk->HardDisk->Geometry.BytesPerSector ); *MinSize = RtlExtendedLargeIntegerDivide(temp,1024*1024,&remainder).LowPart; if((*MinSize == 0) || (remainder >= (512*1024))) { (*MinSize)++; } } ULONG SpPtSectorCountToMB( IN PHARD_DISK pHardDisk, IN ULONG SectorCount ) { LARGE_INTEGER ByteCount; ULONG MB,r; // // Calculate the number of bytes that this number of // sectors represents. // ByteCount.QuadPart = UInt32x32To64( pHardDisk->Geometry.BytesPerSector, SectorCount ); // // Calculate the number of megabytes this represents. // MB = RtlExtendedLargeIntegerDivide(ByteCount,(1024*1024),&r).LowPart; // // Round up if necessary. // if(r >= (512*1024)) { MB++; } return(MB); } VOID SpPtInitializeCHSFields( IN PHARD_DISK HardDisk, IN ULONG AbsoluteStartSector, IN ULONG AbsoluteSectorCount, OUT PON_DISK_PTE pte ) { ULONG sC,sH,sS,r; ULONG eC,eH,eS; ULONG LastSector; sC = AbsoluteStartSector / HardDisk->SectorsPerCylinder; r = AbsoluteStartSector % HardDisk->SectorsPerCylinder; sH = r / HardDisk->Geometry.SectorsPerTrack; sS = r % HardDisk->Geometry.SectorsPerTrack; LastSector = AbsoluteStartSector + AbsoluteSectorCount - 1; eC = LastSector / HardDisk->SectorsPerCylinder; r = LastSector % HardDisk->SectorsPerCylinder; eH = r / HardDisk->Geometry.SectorsPerTrack; eS = r % HardDisk->Geometry.SectorsPerTrack; // // If this partition extends past the 1024th cylinder, // place reasonable values in the CHS fields. // if(eC >= 1024) { pte->StartCylinder = 0; pte->StartHead = 0; pte->StartSector = 2; pte->EndCylinder = 0; pte->EndHead = 0; pte->EndSector = 3; } else { // // Pack the CHS values into int13 format. // pte->StartCylinder = (UCHAR)sC; pte->StartHead = (UCHAR)sH; pte->StartSector = (UCHAR)((sS & 0x3f) | ((sC >> 2) & 0xc0)) + 1; pte->EndCylinder = (UCHAR)eC; pte->EndHead = (UCHAR)eH; pte->EndSector = (UCHAR)((eS & 0x3f) | ((eC >> 2) & 0xc0)) + 1; } } BOOLEAN SpPtCreate( IN ULONG DiskNumber, IN ULONG StartSector, IN ULONG SizeMB, IN BOOLEAN InExtended, IN UCHAR SysId, OUT PDISK_REGION *ActualDiskRegion OPTIONAL ) /*++ Routine Description: Create a partition in a given free space. Arguments: DiskNumber - supplies the number of the disk on which we are creating the partition. StartSector - supplies the start sector of the free space in which the parititon is to be created. This must exactly match the start sector of the free space, and can be in either the primary space list or the list of spaces in the extended partition. SizeMB - supplies the size in megabytes of the partition. InExtended - if TRUE, then the free space is within the extended partition, and thus we are creating a logical drive. If FALSE, then the free space is an ordinary unpartitioned space, and we are creating a primary partition. SysId - supplies the system id to give the partition. This may not be 5/f (PARTITION_EXTENDED) if InExtended is TRUE or is an extended partition already exists. No other checks are performed on this value. ActualDiskRegion - if supplied, receives a pointer to the disk region in which the partition was created. Return Value: TRUE if the partition was created successfully. FALSE otherwise. --*/ { PPARTITIONED_DISK pDisk; ULONG SectorCount; ULONG AlignedStartSector; ULONG AlignedEndSector; PDISK_REGION pRegion,pRegionPrev,pRegionNew,*pRegionHead; ULONG LeftOverSectors; PMBR_INFO pBrInfo; ULONG slot,i,spt; PON_DISK_PTE pte; ULONG ExtendedStart; // // Look up the disk region that describes this free space. // pDisk = &PartitionedDisks[DiskNumber]; pRegion = SpPtLookupRegionByStart(pDisk,InExtended,StartSector); ASSERT(pRegion); if(!pRegion) { return(FALSE); } if(ActualDiskRegion) { *ActualDiskRegion = pRegion; } ASSERT(!pRegion->PartitionedSpace); if(pRegion->PartitionedSpace) { return(FALSE); } if(InExtended) { ASSERT(!IsContainerPartition(SysId)); // // Locate the start sector of the extended partition. // for(i=0; iMbrInfo.OnDiskMbr.PartitionTable[i].SystemId)) { ExtendedStart = U_ULONG(pDisk->MbrInfo.OnDiskMbr.PartitionTable[i].RelativeSectors); break; } } ASSERT(ExtendedStart); if(!ExtendedStart) { return(FALSE); } } // // Determine the number of sectors in the size passed in. // Note: the calculation is performed such that intermediate results // won't overflow a ULONG. // SectorCount = SizeMB * ((1024*1024)/pDisk->HardDisk->Geometry.BytesPerSector); // // Align the start sector. // AlignedStartSector = SpPtAlignStart( pDisk->HardDisk, StartSector, (BOOLEAN)IsContainerPartition(SysId) ); // // Determine the end sector based on the size passed in. // AlignedEndSector = AlignedStartSector + SectorCount; // // Align the ending sector to a cylinder boundary. If it is not already // aligned and is more than half way into the final cylinder, align it up, // otherwise align it down. // if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) { AlignedEndSector -= LeftOverSectors; if(LeftOverSectors > pDisk->HardDisk->SectorsPerCylinder/2) { AlignedEndSector += pDisk->HardDisk->SectorsPerCylinder; } } // // If the ending sector is past the end of the free space, shrink it // so it fits. // while(AlignedEndSector > pRegion->StartSector + pRegion->SectorCount) { AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder; } ASSERT((LONG)AlignedEndSector > 0); if((LONG)AlignedEndSector < 0) { return(FALSE); } // // If we are creating a logical drive, create a new mbr structure // for it. // if(InExtended) { // // Create a boot record for this new logical drive; use slot #0 // for the partition entry (and slot #1 for the extended record, // if necessary). // pBrInfo = SpMemAlloc(sizeof(MBR_INFO)); ASSERT(pBrInfo); RtlZeroMemory(pBrInfo,sizeof(MBR_INFO)); slot = 0; } else { // // Look for a free slot in the MBR's partition table. // pBrInfo = &pDisk->MbrInfo; for(slot=0; slotOnDiskMbr.PartitionTable[slot].SystemId == PARTITION_ENTRY_UNUSED) { break; } } if(slot == PTABLE_DIMENSION) { ASSERT(0); return(FALSE); } } // // Initialize the partition table entry. // spt = pDisk->HardDisk->Geometry.SectorsPerTrack; pte = &pBrInfo->OnDiskMbr.PartitionTable[slot]; pte->ActiveFlag = 0; pte->SystemId = SysId; U_ULONG(pte->RelativeSectors) = InExtended ? spt : AlignedStartSector; U_ULONG(pte->SectorCount) = AlignedEndSector - AlignedStartSector - (InExtended ? spt : 0); SpPtInitializeCHSFields( pDisk->HardDisk, AlignedStartSector + (InExtended ? spt : 0), AlignedEndSector - AlignedStartSector - (InExtended ? spt : 0), pte ); // // If we're in the extended partition we mark all entries in the // boot record as dirty. Sometimes there is a turd boot record on // the disk already, and by setting all entries to dirty we get // the crud cleaned out if necessary. The only entries that should be // in an EBR are the type 6 or whatever and a type 5 if there are // additional logical drives in the extended partition. // if(InExtended) { for(i=0; iDirty[i] = TRUE; } } else { pBrInfo->Dirty[slot] = TRUE; } // // Don't zap the first sector of the extended partition, // as this wipes out the first logical drive, and precludes // access to all logical drives! // if(!IsContainerPartition(SysId)) { pBrInfo->ZapBootSector[slot] = TRUE; } // // Find the previous region (ie, the one that points to this one). // This region (if it exists) will be partitioned space (otherwise // it would have been part of the region we are trying to create // a partition in!) // pRegionHead = InExtended ? &pDisk->ExtendedDiskRegions : &pDisk->PrimaryDiskRegions; if(*pRegionHead == pRegion) { pRegionPrev = NULL; } else { for(pRegionPrev = *pRegionHead; pRegionPrev; pRegionPrev = pRegionPrev->Next) { if(pRegionPrev->Next == pRegion) { ASSERT(pRegionPrev->PartitionedSpace); break; } } } if(InExtended) { PMBR_INFO PrevEbr; // // The new logical drive goes immediately after the // previous logical drive (if any). Remember that if there is // a previous region, it will be partitioned space (otherwise // it would be a part of the region we are trying to create // a partition in). // PrevEbr = pRegionPrev ? pRegionPrev->MbrInfo : NULL; if(PrevEbr) { pBrInfo->Next = PrevEbr->Next; PrevEbr->Next = pBrInfo; } else { // // No previous EBR or region. This means we are creating // a logical drive at the beginning of the extended partition // so set the First Ebr pointer to point to the new Ebr. // Note that this does not mean that the extended partition // is empty; the Next pointer in the new Ebr structure is // set later. // pDisk->FirstEbrInfo.Next = pBrInfo; if(pRegion->Next) { // // If there is a region following the one we're creating // the partition in, it must be partitioned space, or else // it would be part of the region we're creating the partition in. // ASSERT(pRegion->Next->PartitionedSpace); ASSERT(pRegion->Next->MbrInfo); pBrInfo->Next = pRegion->Next->MbrInfo; } else { // // No more partitioned space in the extended partition; // the logical drive we are creating is the only one. // pBrInfo->Next = NULL; } } pBrInfo->OnDiskSector = AlignedStartSector; // // Create a link entry in the previous logical drive (if any). // if(PrevEbr) { // // If there is a link entry in there already, blow it away. // for(i=0; iOnDiskMbr.PartitionTable[i].SystemId)) { RtlZeroMemory(&PrevEbr->OnDiskMbr.PartitionTable[i],sizeof(ON_DISK_PTE)); PrevEbr->Dirty[i] = TRUE; break; } } // // Find a free slot for the link entry. // for(i=0; iOnDiskMbr.PartitionTable[i]; if(pte->SystemId == PARTITION_ENTRY_UNUSED) { pte->SystemId = PARTITION_EXTENDED; pte->ActiveFlag = 0; U_ULONG(pte->RelativeSectors) = AlignedStartSector - ExtendedStart; U_ULONG(pte->SectorCount) = AlignedEndSector - AlignedStartSector; SpPtInitializeCHSFields( pDisk->HardDisk, AlignedStartSector, U_ULONG(pte->SectorCount), pte ); PrevEbr->Dirty[i] = TRUE; break; } } } // // Create a link entry in this new logical drive if necessary. // if(pBrInfo->Next) { // // Find the next entry's logical drive. // for(i=0; iNext->OnDiskMbr.PartitionTable[i].SystemId != PARTITION_ENTRY_UNUSED) && !IsContainerPartition(pBrInfo->Next->OnDiskMbr.PartitionTable[i].SystemId)) { pte = &pBrInfo->OnDiskMbr.PartitionTable[1]; pte->SystemId = PARTITION_EXTENDED; pte->ActiveFlag = 0; U_ULONG(pte->RelativeSectors) = pBrInfo->Next->OnDiskSector - ExtendedStart; U_ULONG(pte->SectorCount) = U_ULONG(pBrInfo->Next->OnDiskMbr.PartitionTable[i].RelativeSectors) + U_ULONG(pBrInfo->Next->OnDiskMbr.PartitionTable[i].SectorCount); SpPtInitializeCHSFields( pDisk->HardDisk, pBrInfo->Next->OnDiskSector, U_ULONG(pte->SectorCount), pte ); break; } } } } // // If we just created a new extended partition, we need to // create a blank region descriptor for it in the extended region list. // if(!InExtended && IsContainerPartition(SysId)) { ASSERT(pDisk->ExtendedDiskRegions == NULL); pDisk->ExtendedDiskRegions = SpPtAllocateDiskRegionStructure( DiskNumber, AlignedStartSector, AlignedEndSector - AlignedStartSector, FALSE, NULL, 0 ); ASSERT(pDisk->ExtendedDiskRegions); } // // Create a new disk region for the new free space at the // beginning and end of the free space, if any. // if(AlignedStartSector - pRegion->StartSector) { pRegionNew = SpPtAllocateDiskRegionStructure( DiskNumber, pRegion->StartSector, AlignedStartSector - pRegion->StartSector, FALSE, NULL, 0 ); ASSERT(pRegionNew); if(pRegionPrev) { pRegionPrev->Next = pRegionNew; } else { *pRegionHead = pRegionNew; } pRegionNew->Next = pRegion; } if(pRegion->StartSector + pRegion->SectorCount - AlignedEndSector) { pRegionNew = SpPtAllocateDiskRegionStructure( DiskNumber, AlignedEndSector, pRegion->StartSector + pRegion->SectorCount - AlignedEndSector, FALSE, NULL, 0 ); pRegionNew->Next = pRegion->Next; pRegion->Next = pRegionNew; } // // Adjust the current disk region. // pRegion->StartSector = AlignedStartSector; pRegion->SectorCount = AlignedEndSector - AlignedStartSector; pRegion->PartitionedSpace = TRUE; pRegion->TablePosition = slot; pRegion->MbrInfo = pBrInfo; pRegion->VolumeLabel[0] = 0; pRegion->Filesystem = FilesystemNewlyCreated; pRegion->FreeSpaceKB = (ULONG)(-1); pRegion->AdjustedFreeSpaceKB = (ULONG)(-1); SpFormatMessage( pRegion->TypeName, sizeof(pRegion->TypeName), SP_TEXT_FS_NAME_BASE + pRegion->Filesystem ); // // Adjust partition ordinals on this disk. // SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE); // // Reassign drive letters. // SpPtGuessDriveLetters(); return(TRUE); } BOOLEAN SpPtDelete( IN ULONG DiskNumber, IN ULONG StartSector ) { PPARTITIONED_DISK pDisk; PDISK_REGION pRegion,pRegionPrev,*pRegionHead,pRegionNext; BOOLEAN InExtended; PON_DISK_PTE pte; PMBR_INFO pEbrPrev,pEbr; ULONG i,j; PHARD_DISK pHardDisk; ULONG PartitionOrdinal; NTSTATUS Status; HANDLE Handle; // // First try to look up this region in the extended partition. // If we can find it, assume it's a logical drive. // pDisk = &PartitionedDisks[DiskNumber]; pRegion = SpPtLookupRegionByStart(pDisk,TRUE,StartSector); if(pRegion && pRegion->PartitionedSpace) { InExtended = TRUE; } else { InExtended = FALSE; pRegion = SpPtLookupRegionByStart(pDisk,FALSE,StartSector); } ASSERT(pRegion); if(!pRegion) { return(FALSE); } ASSERT(pRegion->PartitionedSpace); if(!pRegion->PartitionedSpace) { return(FALSE); } // // At this point, we dismount the volume (if it's not newly created), // so we don't run into problems later on when we go to format // if(pRegion->Filesystem > FilesystemNewlyCreated) { pHardDisk = &HardDisks[pRegion->DiskNumber]; PartitionOrdinal = SpPtGetOrdinal(pRegion, PartitionOrdinalOnDisk); // // Open the partition for read/write access. // This shouldn't lock the volume so we need to lock it below. // Status = SpOpenPartition( pHardDisk->DevicePath, PartitionOrdinal, &Handle, TRUE ); if(!NT_SUCCESS(Status)) { KdPrint(( "SETUP: SpPtDelete: unable to open %ws partition %u (%lx)\n", pHardDisk->DevicePath, PartitionOrdinal, Status )); goto AfterDismount; } // // Lock the drive. // Status = SpLockUnlockVolume(Handle, TRUE); // // We shouldn't have any file opened that would cause this volume // to already be locked, so if we get failure (ie, STATUS_ACCESS_DENIED) // something is really wrong. This typically indicates something is // wrong with the hard disk that won't allow us to access it. // if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: SpPtDelete: status %lx, unable to lock drive\n", Status)); ZwClose(Handle); goto AfterDismount; } // // Dismount the drive // Status = SpDismountVolume(Handle); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: SpPtDelete: status %lx, unable to dismount drive\n", Status)); SpLockUnlockVolume(Handle, FALSE); ZwClose(Handle); goto AfterDismount; } // // Unlock the drive // Status = SpLockUnlockVolume(Handle, FALSE); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: SpPtDelete: status %lx, unable to unlock drive\n", Status)); } ZwClose(Handle); } AfterDismount: // // Find the previous region (ie, the one that points to this one). // pRegionHead = InExtended ? &pDisk->ExtendedDiskRegions : &pDisk->PrimaryDiskRegions; if(*pRegionHead == pRegion) { pRegionPrev = NULL; } else { for(pRegionPrev = *pRegionHead; pRegionPrev; pRegionPrev = pRegionPrev->Next) { if(pRegionPrev->Next == pRegion) { break; } } } // // Additional processing for logical drives. // if(InExtended) { // // Locate the previous and next logical drives (if any). // pEbr = pRegion->MbrInfo; for(pEbrPrev=pDisk->FirstEbrInfo.Next; pEbrPrev; pEbrPrev=pEbrPrev->Next) { if(pEbrPrev->Next == pEbr) { break; } } // // If there is a previous logical drive, blow aways its link // entry, because it points to the logical drive we're deleting. // if(pEbrPrev) { for(i=0; iOnDiskMbr.PartitionTable[i]; if(IsContainerPartition(pte->SystemId)) { RtlZeroMemory(pte,sizeof(ON_DISK_PTE)); break; } } } // // If there is a next logical drive and a previous logical drive, // set a new link entry in previous logical drive to point to // the next logical drive. // if(pEbrPrev && pEbr->Next) { // // Locate the link entry in the logical drive being deleted. // for(i=0; iOnDiskMbr.PartitionTable[i].SystemId)) { // // Locate an empty slot in the previous logical drive's boot record // and copy the link entry // for(j=0; jOnDiskMbr.PartitionTable[j].SystemId == PARTITION_ENTRY_UNUSED) { // // Copy the link entry. // RtlMoveMemory( &pEbr->OnDiskMbr.PartitionTable[i], &pEbrPrev->OnDiskMbr.PartitionTable[j], sizeof(ON_DISK_PTE) ); break; } } break; } } } // // Remove the EBR for this logical drive. // if(pEbrPrev) { pEbrPrev->Next = pEbr->Next; } else { ASSERT(pDisk->FirstEbrInfo.Next == pEbr); pDisk->FirstEbrInfo.Next = pEbr->Next; } SpMemFree(pEbr); } else { ASSERT(pRegion->MbrInfo == &pDisk->MbrInfo); pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition]; ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED); // // Mark the entry dirty in the MBR. // pDisk->MbrInfo.Dirty[pRegion->TablePosition] = TRUE; // // If this is the extended partition, verify that it is empty. // if(IsContainerPartition(pte->SystemId)) { ASSERT(pDisk->ExtendedDiskRegions); ASSERT(pDisk->ExtendedDiskRegions->PartitionedSpace == FALSE); ASSERT(pDisk->ExtendedDiskRegions->Next == NULL); ASSERT(pDisk->FirstEbrInfo.Next == NULL); if(pDisk->ExtendedDiskRegions->Next || pDisk->FirstEbrInfo.Next) { return(FALSE); } // // Free the single disk region that covers the entire extended partition. // SpMemFree(pDisk->ExtendedDiskRegions); pDisk->ExtendedDiskRegions = NULL; } // // Adjust the PTE for this partition by zeroing it out. // RtlZeroMemory(pte,sizeof(ON_DISK_PTE)); } // // Adjust fields in the region to describe this space as free. // pRegion->MbrInfo->ZapBootSector[pRegion->TablePosition] = FALSE; pRegion->PartitionedSpace = FALSE; pRegion->MbrInfo = NULL; pRegion->TablePosition = 0; // // If previous region is free space, coalesce it and the region // we just made free. // if(pRegionPrev && !pRegionPrev->PartitionedSpace) { PDISK_REGION p; ASSERT(pRegionPrev->StartSector + pRegionPrev->SectorCount == pRegion->StartSector); pRegion->SectorCount = pRegion->StartSector + pRegion->SectorCount - pRegionPrev->StartSector; pRegion->StartSector = pRegionPrev->StartSector; // // Delete the previous region. // if(pRegionPrev == *pRegionHead) { // // The previous region was the first region. // *pRegionHead = pRegion; } else { for(p = *pRegionHead; p; p=p->Next) { if(p->Next == pRegionPrev) { ASSERT(p->PartitionedSpace); p->Next = pRegion; break; } } } SpMemFree(pRegionPrev); } // // If the next region is free space, coalesce it and the region // we just made free. // if((pRegionNext = pRegion->Next) && !pRegionNext->PartitionedSpace) { ASSERT(pRegion->StartSector + pRegion->SectorCount == pRegionNext->StartSector); pRegion->SectorCount = pRegionNext->StartSector + pRegionNext->SectorCount - pRegion->StartSector; // // Delete the next region. // pRegion->Next = pRegionNext->Next; SpMemFree(pRegionNext); } // // Adjust the partition ordinals on this disk. // SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE); // // Reassign drive letters. // SpPtGuessDriveLetters(); return(TRUE); } BOOLEAN SpPtExtend( IN PDISK_REGION Region ) /*++ Routine Description: Extends a partition by claiming any free space immedately following it on the disk. The end boundary of the existing partition is adjusted so that the partition encompasses the free space. The partition may not be the extended partition and it may not be a logical drive within the extended partition. Note that no filesystem structures are manipulated or examined by this routine. Essentially it deals only with the partition table entry. Arguments: Region - supplies the region descriptor for the partition to be extended. That partition must not be the extended partition and it cannot be a logical drive either. Return Value: Boolean value indicating whether anything actually changed. --*/ { PDISK_REGION NextRegion; PPARTITIONED_DISK pDisk; PMBR_INFO pBrInfo; PON_DISK_PTE pte; ULONG NewEndSector; pDisk = &PartitionedDisks[Region->DiskNumber]; ASSERT(Region->PartitionedSpace); if(!Region->PartitionedSpace) { return(FALSE); } pBrInfo = Region->MbrInfo; pte = &pBrInfo->OnDiskMbr.PartitionTable[Region->TablePosition]; // // Make sure it's not the extended partition and is not // in the extended partition. // if(pBrInfo->OnDiskSector || IsContainerPartition(pte->SystemId)) { return(FALSE); } // // If there's no next region then there's nothing to do. // If there is a next region make sure it's empty. // NextRegion = Region->Next; if(!NextRegion) { return(FALSE); } if(NextRegion->PartitionedSpace) { return(FALSE); } // // Claim the entire free region and align the ending sector // to a cylinder boundary. // NewEndSector = NextRegion->StartSector + NextRegion->SectorCount; NewEndSector -= NewEndSector % pDisk->HardDisk->SectorsPerCylinder; #if 0 // // Cap the end at the 1024th cylinder if necessary. // if(Cap1024Cylinders && ((NewEndSector / pDisk->HardDisk->SectorsPerCylinder) >= 1024)) { NewEndSector = 1024 * pDisk->HardDisk->SectorsPerCylinder; } #endif // // Fix up the size and end CHS fields in the partition table entry // for the partition. // U_ULONG(pte->SectorCount) = NewEndSector - Region->StartSector; SpPtInitializeCHSFields( pDisk->HardDisk, Region->StartSector, NewEndSector - Region->StartSector, pte ); pBrInfo->Dirty[Region->TablePosition] = TRUE; // // If there is space left over at the end of the free region // we just stuck onto the end of the existing partition, // adjust the free region's descriptor. Else get rid of it. // if(NextRegion->StartSector + NextRegion->SectorCount == NewEndSector) { Region->Next = NextRegion->Next; SpMemFree(NextRegion); } else { NextRegion->SectorCount = NextRegion->StartSector + NextRegion->SectorCount - NewEndSector; NextRegion->StartSector = NewEndSector; } return(TRUE); } #ifdef _X86_ VOID SpPtMarkActive( IN ULONG TablePosition ) /*++ Routine Description: Mark a partition on drive 0 active, and deactivate all others. Arguments: TablePosition - supplies offset within partition table (0-3) of the partition entry to be activated. Return Value: None. --*/ { ULONG i; PON_DISK_PTE pte; ULONG Disk0Ordinal; ASSERT(TablePosition < PTABLE_DIMENSION); Disk0Ordinal = SpDetermineDisk0(); // // Deactivate all others. // for(i=0; iSystemId != PARTITION_ENTRY_UNUSED) && pte->ActiveFlag && (i != TablePosition)) { pte->ActiveFlag = 0; PartitionedDisks[0].MbrInfo.Dirty[i] = TRUE; } } // // Activate the one we want to activate. // pte = &PartitionedDisks[Disk0Ordinal].MbrInfo.OnDiskMbr.PartitionTable[TablePosition]; ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED); ASSERT(!IsContainerPartition(pte->SystemId)); ASSERT(PartitionNameIds[pte->SystemId] == (UCHAR)(-1)); if(!pte->ActiveFlag) { pte->ActiveFlag = 0x80; PartitionedDisks[Disk0Ordinal].MbrInfo.Dirty[TablePosition] = TRUE; } } #endif NTSTATUS SpPtCommitChanges( IN ULONG DiskNumber, OUT PBOOLEAN AnyChanges ) { PPARTITIONED_DISK pDisk; ULONG DiskLayoutSize; PDISK_REGION pRegion; PMBR_INFO pBrInfo; ULONG BootRecordCount; BOOLEAN NeedDummyEbr; PDRIVE_LAYOUT_INFORMATION DriveLayout; PPARTITION_INFORMATION PartitionInfo; ULONG PartitionEntry; ULONG bps; PON_DISK_PTE pte; ULONG ExtendedStart; ULONG Offset; NTSTATUS Status; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; ULONG i; ULONG ZapSector; PUCHAR Buffer,UBuffer; ULONG NewSig; ASSERT(DiskNumber < HardDiskCount); pDisk = &PartitionedDisks[DiskNumber]; *AnyChanges = FALSE; bps = pDisk->HardDisk->Geometry.BytesPerSector; ExtendedStart = 0; // // Determine the number of boot records that will used on this disk. // There is one for the MBR, and one for each logical drive. // BootRecordCount = 1; for(pRegion=pDisk->ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace) { BootRecordCount++; } } // // Determine whether a dummy boot record is rquired at the start // of the extended partition. This is the case when there is free // space at its start. // if(pDisk->ExtendedDiskRegions && !pDisk->ExtendedDiskRegions->PartitionedSpace && pDisk->ExtendedDiskRegions->Next) { NeedDummyEbr = TRUE; BootRecordCount++; } else { NeedDummyEbr = FALSE; } // // Allocate a disk layout structure whose size is based on the // number of boot records. This assumes that the structure contains // one partition information structure in its definition. // DiskLayoutSize = sizeof(DRIVE_LAYOUT_INFORMATION) + (BootRecordCount * PTABLE_DIMENSION * sizeof(PARTITION_INFORMATION)) - sizeof(PARTITION_INFORMATION); DriveLayout = SpMemAlloc(DiskLayoutSize); ASSERT(DriveLayout); RtlZeroMemory(DriveLayout,DiskLayoutSize); // // Set up some of the fields of the drive layout structure. // DriveLayout->PartitionCount = BootRecordCount * sizeof(PTABLE_DIMENSION); // // Go through each boot record and initialize the matching // partition information structure in the drive layout structure. // for(PartitionEntry=0,pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) { for(i=0; iUserData[i] = NULL; } // // If we are going to need a dummy logical drive, // leave space for it here. // if(pBrInfo == &pDisk->FirstEbrInfo) { if(NeedDummyEbr) { PartitionEntry += PTABLE_DIMENSION; } continue; } ASSERT(PartitionEntry < BootRecordCount*PTABLE_DIMENSION); for(i=0; iPartitionEntry[PartitionEntry+i]; // // Transfer this partition table entry // into the drive layout structure, field by field. // pte = &pBrInfo->OnDiskMbr.PartitionTable[i]; // // If this is the extended partition, remember where it starts. // if((pBrInfo == &pDisk->MbrInfo) && IsContainerPartition(pte->SystemId) && !ExtendedStart) { ExtendedStart = U_ULONG(pte->RelativeSectors); } if(pte->SystemId != PARTITION_ENTRY_UNUSED) { if(!IsContainerPartition(pte->SystemId)) { pBrInfo->UserData[i] = PartitionInfo; } // // Calculate starting offset. If we are within // the extended parttion and this is a type 5 entry, // then the relative sector field counts the number of sectors // between the main extended partition's first sector and // the logical drive described by this entry. // Otherwise, the relative sectors field describes the number // of sectors between the boot record and the actual start // of the partition. // if((pBrInfo != &pDisk->MbrInfo) && IsContainerPartition(pte->SystemId)) { ASSERT(ExtendedStart); Offset = ExtendedStart + U_ULONG(pte->RelativeSectors); } else { Offset = pBrInfo->OnDiskSector + U_ULONG(pte->RelativeSectors); } PartitionInfo->StartingOffset.QuadPart = UInt32x32To64(Offset,bps); // // Calculate size. // PartitionInfo->PartitionLength.QuadPart = UInt32x32To64(U_ULONG(pte->SectorCount),bps); } // // Other fields. // PartitionInfo->PartitionType = pte->SystemId; PartitionInfo->BootIndicator = pte->ActiveFlag; PartitionInfo->RewritePartition = pBrInfo->Dirty[i]; if(pBrInfo->Dirty[i]) { *AnyChanges = TRUE; } pBrInfo->Dirty[i] = FALSE; } PartitionEntry += PTABLE_DIMENSION; } // // If there are no changes, just return success now. // if(!(*AnyChanges)) { SpMemFree(DriveLayout); return(STATUS_SUCCESS); } // // If there is free space at the start of the extended partition, // then we need to generate a dummy boot record. // if(NeedDummyEbr) { pRegion = pDisk->ExtendedDiskRegions->Next; ASSERT(pRegion->PartitionedSpace); ASSERT(pRegion->StartSector == pRegion->MbrInfo->OnDiskSector); ASSERT(ExtendedStart == pDisk->ExtendedDiskRegions->StartSector); PartitionInfo = &DriveLayout->PartitionEntry[PTABLE_DIMENSION]; PartitionInfo->StartingOffset.QuadPart = UInt32x32To64(pRegion->StartSector,bps); PartitionInfo->PartitionLength.QuadPart = UInt32x32To64(pRegion->SectorCount,bps); PartitionInfo->PartitionType = PARTITION_EXTENDED; PartitionInfo->RewritePartition = TRUE; } // // We now have everything set up. Open partition 0 on the disk. // Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,TRUE); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: committing changes, unable to open disk %u (%lx)\n",DiskNumber,Status)); SpMemFree(DriveLayout); return(Status); } // // Make sure the mbr is valid before writing the changes. // if(!pDisk->MbrWasValid) { Status = SpMasterBootCode(DiskNumber,Handle,&NewSig); if(NT_SUCCESS(Status)) { // // If a new NTFT signature was generated, propagate it. // if(NewSig) { U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = NewSig; } } else { KdPrint(("SETUP: committing changes on disk %u, SpMasterBootCode returns %lx\n",DiskNumber,Status)); ZwClose(Handle); SpMemFree(DriveLayout); return(Status); } } DriveLayout->Signature = U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature); // // Write the changes. // Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_SET_DRIVE_LAYOUT, DriveLayout, DiskLayoutSize, DriveLayout, DiskLayoutSize ); // Deferred freeing memory till later on because we still need info in this structure (lonnym) // SpMemFree(DriveLayout); if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: committing changes on disk %u, ioctl returns %lx\n",DiskNumber,Status)); SpMemFree(DriveLayout); ZwClose(Handle); return(Status); } // // Allocate a buffer for zapping. // UBuffer = SpMemAlloc(2*bps); ASSERT(UBuffer); Buffer = ALIGN(UBuffer,bps); RtlZeroMemory(Buffer,bps); for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) { for(i=0; iUserData[i]) { PartitionInfo = (PPARTITION_INFORMATION)pBrInfo->UserData[i]; // // The partition ordinal better be non-0! // if(PartitionInfo->PartitionNumber) { // // Update current partition ordinal. // pBrInfo->CurrentOrdinals[i] = (USHORT)PartitionInfo->PartitionNumber; } else { SpBugCheck( SETUP_BUGCHECK_PARTITION, PARTITIONBUG_A, DiskNumber, pBrInfo->CurrentOrdinals[i] ); } } // // If there were any newly created partitions in this boot record, // zap their filesystem boot sectors. // if(pBrInfo->ZapBootSector[i]) { // // We shouldn't be zapping any partitions that don't exist. // ASSERT(pBrInfo->OnDiskMbr.PartitionTable[i].SystemId != PARTITION_ENTRY_UNUSED); // // This calculation is correct for partitions and logical drives. // ZapSector = pBrInfo->OnDiskSector + U_ULONG(pBrInfo->OnDiskMbr.PartitionTable[i].RelativeSectors); // // The consequences for screw-up here are so huge that a special check // is warranted to make sure we're not clobbering the MBR. // ASSERT(ZapSector); if(ZapSector) { Status = SpReadWriteDiskSectors( Handle, ZapSector, 1, bps, Buffer, TRUE ); } else { Status = STATUS_SUCCESS; } if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: zapping sector %lx on disk %u returned %lx\n",ZapSector,DiskNumber,Status)); SpMemFree(DriveLayout); SpMemFree(UBuffer); ZwClose(Handle); return(Status); } pBrInfo->ZapBootSector[i] = FALSE; } } } SpMemFree(UBuffer); ZwClose(Handle); // // Reassign on-disk ordinals (but not original ones). // SpPtAssignOrdinals(pDisk,FALSE,TRUE,FALSE); SpMemFree(DriveLayout); return(STATUS_SUCCESS); } NTSTATUS SpMasterBootCode( IN ULONG DiskNumber, IN HANDLE Partition0Handle, OUT PULONG NewNTFTSignature ) { NTSTATUS Status; ULONG BytesPerSector; PUCHAR Buffer; ULONG SectorCount; PON_DISK_MBR Mbr; BytesPerSector = HardDisks[DiskNumber].Geometry.BytesPerSector; SectorCount = max(1,sizeof(ON_DISK_MBR)/BytesPerSector); *NewNTFTSignature = 0; // // Allocate and align a buffer. // Buffer = SpMemAlloc(2 * SectorCount * BytesPerSector); Mbr = ALIGN(Buffer,BytesPerSector); // // Read sector 0 (or 1, for EZDrive) // Status = SpReadWriteDiskSectors( Partition0Handle, HardDisks[DiskNumber].EZDrive ? 1 : 0, SectorCount, BytesPerSector, Mbr, FALSE ); if(NT_SUCCESS(Status)) { // // If it's valid, leave it alone. // If it's not valid, put in boot code, zero out the partition table, // and write the (now valid) sector back out. // if(U_USHORT(Mbr->AA55Signature) != MBR_SIGNATURE) { ASSERT(X86BOOTCODE_SIZE == sizeof(ON_DISK_MBR)); RtlMoveMemory(Mbr,x86BootCode,X86BOOTCODE_SIZE); *NewNTFTSignature = SpComputeSerialNumber(); U_ULONG(Mbr->NTFTSignature) = *NewNTFTSignature; U_USHORT(Mbr->AA55Signature) = MBR_SIGNATURE; // // Write the sector(s). // Status = SpReadWriteDiskSectors( Partition0Handle, HardDisks[DiskNumber].EZDrive ? 1 : 0, SectorCount, BytesPerSector, Mbr, TRUE ); } } SpMemFree(Buffer); return(Status); } VOID SpPtGetSectorLayoutInformation( IN PDISK_REGION Region, OUT PULONG HiddenSectors, OUT PULONG VolumeSectorCount ) /*++ Routine Description: Given a region describing a partition or logical drive, return information about its layout on disk appropriate for the BPB when the volume is formatted. Arguments: Region - supplies a pointer to the disk region descriptor for the partition or logical drive in question. HiidenSectors - receives the value that should be placed in the hidden sectors field of the BPB when the volume is formatted. HiidenSectors - receives the value that should be placed in the sector count field of the BPB when the volume is formatted. Return Value: None. --*/ { PON_DISK_PTE pte; ASSERT(Region->PartitionedSpace); pte = &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition]; *HiddenSectors = U_ULONG(pte->RelativeSectors); *VolumeSectorCount = U_ULONG(pte->SectorCount); } ULONG SpPtGetOrdinal( IN PDISK_REGION Region, IN PartitionOrdinalType OrdinalType ) { ULONG ord; switch(OrdinalType) { case PartitionOrdinalOriginal: ord = Region->MbrInfo->OriginalOrdinals[Region->TablePosition]; break; case PartitionOrdinalOnDisk: ord = Region->MbrInfo->OnDiskOrdinals[Region->TablePosition]; break; case PartitionOrdinalCurrent: ord = Region->MbrInfo->CurrentOrdinals[Region->TablePosition]; break; } return(ord); } //////////////////////////////////////////////////////////////////////////////////////////// VOID SpPtDoDelete( IN PDISK_REGION pRegion, IN PWSTR RegionDescription ); #define MENU_LEFT_X 3 #define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X)) #define MENU_INDENT 4 BOOLEAN SpPtRegionDescription( IN PPARTITIONED_DISK pDisk, IN PDISK_REGION pRegion, OUT PWCHAR Buffer, IN ULONG BufferSize ) { WCHAR DriveLetter[3]; ULONG RegionSizeMB; ULONG FreeSpace; ULONG MessageId; WCHAR TypeName[((sizeof(pRegion->TypeName)+sizeof(pRegion->VolumeLabel))/sizeof(WCHAR))+4]; #ifdef _FASTRECOVER_ ULONG RequiredKB; ULONG RequiredMB; #endif // // Get the size of the region. // RegionSizeMB = SpPtSectorCountToMB(pDisk->HardDisk, pRegion->SectorCount); // // Don't show spaces smaller than 1 MB. // if(!RegionSizeMB) { return(FALSE); } #ifdef _FASTRECOVER_ if (!LocalSourceRegion) { SpFetchDiskSpaceRequirements(UnattendedSifHandle,&RequiredKB,NULL); RequiredMB = RequiredKB / 1024; if (pRegion->PartitionedSpace) { if (pRegion->Filesystem != FilesystemUnknown) { if ((pRegion->FreeSpaceKB == (ULONG)(-1) && RequiredMB <= RegionSizeMB) || (RequiredMB <= (pRegion->FreeSpaceKB / 1024))) LocalSourceRegion = pRegion; } } else { if (RequiredMB <= RegionSizeMB) LocalSourceRegion = pRegion; } } #endif // // Get the drive letter field, type of region, and amount of free space, // if this is a used region. // if(pRegion->PartitionedSpace) { if(pRegion->DriveLetter) { if( pRegion->Filesystem != FilesystemFat ) { DriveLetter[0] = pRegion->DriveLetter; } else { if( pRegion->NextCompressed == NULL ) { DriveLetter[0] = pRegion->DriveLetter; } else { DriveLetter[0] = pRegion->HostDrive; } } DriveLetter[1] = L':'; } else { if( pRegion->Filesystem != FilesystemDoubleSpace ) { DriveLetter[0] = L'-'; DriveLetter[1] = L'-'; } else { DriveLetter[0] = pRegion->MountDrive; DriveLetter[1] = L':'; } } DriveLetter[2] = 0; // // Format the type name, which may include the volume label. // wcscpy(TypeName,pRegion->TypeName); if(pRegion->VolumeLabel[0]) { wcscat(TypeName,L" ("); wcscat(TypeName,pRegion->VolumeLabel); wcscat(TypeName,L")"); } // // Format the text based on whether we know the amount of free space. // if(pRegion->FreeSpaceKB == (ULONG)(-1)) { SpFormatMessage( Buffer, BufferSize, SP_TEXT_REGION_DESCR_2, DriveLetter, SplangPadString(-35,TypeName), RegionSizeMB ); } else { ULONG AuxFreeSpaceKB; AuxFreeSpaceKB = (pRegion->IsLocalSource)? pRegion->AdjustedFreeSpaceKB : pRegion->FreeSpaceKB; // // If there is less than 1 meg of free space, // then use KB as the units for free space. // Otherwise, use MB. // if(AuxFreeSpaceKB < 1024) { MessageId = SP_TEXT_REGION_DESCR_1a; FreeSpace = AuxFreeSpaceKB; } else { MessageId = SP_TEXT_REGION_DESCR_1; FreeSpace = AuxFreeSpaceKB / 1024; } SpFormatMessage( Buffer, BufferSize, MessageId, DriveLetter, SplangPadString(-35,TypeName), RegionSizeMB, FreeSpace ); } } else { // // Not a used region, use a separate format string. // SpFormatMessage(Buffer,BufferSize,SP_TEXT_REGION_DESCR_3,RegionSizeMB); } return(TRUE); } BOOLEAN SpPtIterateRegionList( IN PVOID Menu, IN PPARTITIONED_DISK pDisk, IN PDISK_REGION pRegion, IN BOOLEAN InMbr, OUT PDISK_REGION *FirstRegion ) { WCHAR Buffer[256]; #ifdef FULL_DOUBLE_SPACE_SUPPORT PDISK_REGION Pointer; #endif // FULL_DOUBLE_SPACE_SUPPORT for( ;pRegion; pRegion=pRegion->Next) { PMBR_INFO pBrInfo = pRegion->MbrInfo; // // If this is the extended partition, // iterate its contents now. // if(pRegion->PartitionedSpace && IsContainerPartition(pBrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId)) { // // This better be in the MBR! // ASSERT(InMbr); if(!SpPtIterateRegionList(Menu,pDisk,pDisk->ExtendedDiskRegions,FALSE,FirstRegion)) { return(FALSE); } } else { // // Format a description of this region and add it to the menu. // if(SpPtRegionDescription(pDisk,pRegion,Buffer,sizeof(Buffer))) { if(*FirstRegion == NULL) { *FirstRegion = pRegion; } if(!SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),TRUE,(ULONG)pRegion)) { return(FALSE); } #ifdef FULL_DOUBLE_SPACE_SUPPORT if( ( pRegion->Filesystem == FilesystemFat ) && ( ( Pointer = pRegion->NextCompressed ) != NULL ) ) { for( ; Pointer; Pointer = Pointer->NextCompressed ) { if(SpPtRegionDescription(pDisk,Pointer,Buffer,sizeof(Buffer))) { if(!SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),TRUE,(ULONG)Pointer)) { return(FALSE); } } } } #endif // FULL_DOUBLE_SPACE_SUPPORT } } } return(TRUE); } BOOLEAN SpPtGenerateMenu( IN PVOID Menu, IN PPARTITIONED_DISK pDisk, OUT PDISK_REGION *FirstRegion ) { WCHAR Buffer[256]; // // Add the disk name/description. // if(!SpMnAddItem(Menu,pDisk->HardDisk->Description,MENU_LEFT_X,MENU_WIDTH,FALSE,0)) { return(FALSE); } // // Only add a line between the disk anme and partitions if we have space on // the screen. Not fatal if the space can't be added. // if(!SplangQueryMinimizeExtraSpacing()) { SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0); } // // If the disk is off-line, add a message indicating such. // if(pDisk->HardDisk->Status == DiskOffLine) { SpFormatMessage( Buffer, sizeof(Buffer), (pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) ? SP_TEXT_HARD_DISK_NO_MEDIA : SP_TEXT_DISK_OFF_LINE ); return(SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),FALSE,0)); } if(!SpPtIterateRegionList(Menu,pDisk,pDisk->PrimaryDiskRegions,TRUE,FirstRegion)) { return(FALSE); } return(SplangQueryMinimizeExtraSpacing() ? TRUE : SpMnAddItem(Menu,L"",MENU_LEFT_X,MENU_WIDTH,FALSE,0)); } // // We will change item #0 in the array below as appropriate for // the currently highlighted region. // ULONG PartitionMnemonics[2] = { 0,0 }; VOID SpPtMenuCallback( IN ULONG UserData ) { PDISK_REGION pRegion = (PDISK_REGION)UserData; // // Don't allow deletion of the partition if the 'partition' is really // a DoubleSpace drive, if it contains the local source, or if it is our // system partition (in the floppyless boot case on x86). // if((pRegion->Filesystem == FilesystemDoubleSpace) || pRegion->IsLocalSource #ifdef _X86_ || (IsFloppylessBoot && pRegion == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL))) #endif ) { PartitionMnemonics[0] = 0; SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_INSTALL, SP_STAT_F1_EQUALS_HELP, SP_STAT_F3_EQUALS_EXIT, 0 ); } else { PartitionMnemonics[0] = pRegion->PartitionedSpace ? MnemonicDeletePartition : MnemonicCreatePartition; SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_INSTALL, pRegion->PartitionedSpace ? SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION, SP_STAT_F1_EQUALS_HELP, SP_STAT_F3_EQUALS_EXIT, 0 ); } } NTSTATUS SpPtPrepareDisks( IN PVOID SifHandle, OUT PDISK_REGION *InstallRegion, OUT PDISK_REGION *SystemPartitionRegion, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource ) { PPARTITIONED_DISK pDisk; ULONG DiskNo; PVOID Menu; ULONG MenuTopY; ULONG ValidKeys[4] = { ASCI_CR, KEY_F1, KEY_F3, 0 }; ULONG Keypress; PDISK_REGION pRegion; PDISK_REGION FirstRegion,DefaultRegion; BOOLEAN unattended; #ifndef _X86_ // // Select a system partition from among those defined in NV-RAM. // *SystemPartitionRegion = SpPtValidSystemPartition(SifHandle); (*SystemPartitionRegion)->IsSystemPartition = 2; #endif unattended = UnattendedOperation; while(1) { // // Display the text that goes above the menu on the partitioning screen. // SpDisplayScreen(SP_SCRN_PARTITION,3,CLIENT_TOP+1); // // Calculate menu placement. Leave one blank line // and one line for a frame. // MenuTopY = NextMessageTopLine+2; // // Create a menu. // Menu = SpMnCreate( MENU_LEFT_X, MenuTopY, MENU_WIDTH, VideoVars.ScreenHeight-MenuTopY-(SplangQueryMinimizeExtraSpacing() ? 1 : 2)-STATUS_HEIGHT ); if(!Menu) { return(STATUS_NO_MEMORY); } // // Build up a menu of partitions and free spaces. // FirstRegion = NULL; for(DiskNo=0; DiskNoIsSystemPartition) { SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_SYSPART,3,HEADER_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, 0 ); if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) { return; } } // // CR is no longer a valid key. // ValidKeys[1] = 0; pDisk = &PartitionedDisks[pRegion->DiskNumber]; // // Put up the confirmation screen. // if( ( pRegion->Filesystem == FilesystemFat ) && ( pRegion->NextCompressed != NULL ) ) { // // Warn the user that the partition contains compressed volumes // Count = SpGetNumberOfCompressedDrives( pRegion ); SpStartScreen( SP_SCRN_CONFIRM_REMOVE_PARTITION_COMPRESSED, 3, CLIENT_TOP+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescription, pDisk->HardDisk->Description, Count ); } else { SpStartScreen( SP_SCRN_CONFIRM_REMOVE_PARTITION, 3, CLIENT_TOP+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescription, pDisk->HardDisk->Description ); } // // Display the staus text. // SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_L_EQUALS_DELETE, SP_STAT_ESC_EQUALS_CANCEL, 0 ); k = SpWaitValidKey(ValidKeys,NULL,Mnemonics); if(k == ASCI_ESC) { return; } // // User wants to go ahead. // Determine whether this is the last logical drive in the // extended partition. // if((pRegion->MbrInfo == pDisk->FirstEbrInfo.Next) && (pDisk->FirstEbrInfo.Next->Next == NULL)) { LastLogical = TRUE; } else { LastLogical = FALSE; } // // Get rid of the compressed drives, if any // if( pRegion->NextCompressed != NULL ) { SpDisposeCompressedDrives( pRegion->NextCompressed ); pRegion->NextCompressed = NULL; pRegion->MountDrive = 0; pRegion->HostDrive = 0; } b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector); ASSERT(b); // // If we deleted the last logical drive in the extended partition, // then remove the extended partition also. // if(LastLogical) { // // Locate the extended partition. // for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace && IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId)) { // // Found it -- now delete it. // b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector); ASSERT(b); break; } } } } ValidationValue SpPtGetSizeCB( IN ULONG Key ) { if(Key == ASCI_ESC) { // // User wants to bail. // return(ValidateTerminate); } if(Key & KEY_NON_CHARACTER) { return(ValidateIgnore); } // // Allow only digits. // return(((Key >= L'0') && (Key <= L'9')) ? ValidateAccept : ValidateReject); } BOOLEAN SpPtDoCreate( IN PDISK_REGION pRegion, OUT PDISK_REGION *pActualRegion, OPTIONAL IN BOOLEAN ForNT ) { ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; BOOLEAN b; PPARTITIONED_DISK pDisk; ULONG MinMB,MaxMB; ULONG TotalPrimary,RecogPrimary; BOOLEAN InExtended; UCHAR CreateSysId; BOOLEAN ExtendedExists; ULONG SizeMB,RealSizeMB; WCHAR Buffer[200]; WCHAR SizeBuffer[10]; ASSERT(!pRegion->PartitionedSpace); pDisk = &PartitionedDisks[pRegion->DiskNumber]; // // Determine whether this space is within the extended partition. // InExtended = (BOOLEAN)(SpPtLookupRegionByStart(pDisk,TRUE,pRegion->StartSector) != NULL); // // Determine the type of partition to create in the space. // // If the free space is within the extended partition, create // a logical drive. // // If there is no primary partition, create a primary partition. // // If there is a primary partition and no extended partition, // create an extended partition spanning the entire space and // then a logical drive within it of the size given by the user. // // If there is space in the partition table, create a primary partition. // if(InExtended) { CreateSysId = PARTITION_HUGE; } else { // // Get statistics about primary partitions. // SpPtCountPrimaryPartitions(pDisk,&TotalPrimary,&RecogPrimary,&ExtendedExists); // // If there is no primary partition, create one. // if(!RecogPrimary) { CreateSysId = PARTITION_HUGE; } else { // // Make sure we can create a new primary/extended partition. // if(TotalPrimary < PTABLE_DIMENSION) { // // If there is an extended partition, then we have no choice but // to create another primary. // CreateSysId = ExtendedExists ? PARTITION_HUGE : PARTITION_EXTENDED; } else { while(1) { ULONG ks[3] = { KEY_F1,ASCI_CR,0 }; SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,3,CLIENT_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F1_EQUALS_HELP, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); switch(SpWaitValidKey(ks,NULL,NULL)) { case ASCI_CR: return(FALSE); case KEY_F1: SpHelp(SP_HELP_PARTITION_TABLE_FULL, NULL, SPHELP_HELPTEXT); break; } } } } } // // Get the mimimum and maximum sizes for the partition. // SpPtQueryMinMaxCreationSizeMB( pRegion->DiskNumber, pRegion->StartSector, (BOOLEAN)IsContainerPartition(CreateSysId), InExtended, &MinMB, &MaxMB ); if(ForNT) { SizeMB = MaxMB; } else { // // Put up a screen displaying min/max size info. // SpStartScreen( SP_SCRN_CONFIRM_CREATE_PARTITION, 3, CLIENT_TOP+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, pDisk->HardDisk->Description, MinMB, MaxMB ); // // Display the staus text. // SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CREATE, SP_STAT_ESC_EQUALS_CANCEL, 0 ); // // Get and display the size prompt. // SpFormatMessage(Buffer,sizeof(Buffer),SP_TEXT_SIZE_PROMPT); SpvidDisplayString(Buffer,DEFAULT_ATTRIBUTE,3,NextMessageTopLine); // // Get the size from the user. // do { swprintf(SizeBuffer,L"%u",MaxMB); if(!SpGetInput(SpPtGetSizeCB,SplangGetColumnCount(Buffer)+5,NextMessageTopLine,5,SizeBuffer,TRUE)) { // // User pressed escape and bailed. // return(FALSE); } SizeMB = (ULONG)SpStringToLong(SizeBuffer,NULL,10); } while((SizeMB < MinMB) || (SizeMB > MaxMB)); } if(IsContainerPartition(CreateSysId)) { RealSizeMB = SizeMB; SizeMB = MaxMB; } // // Create the partition. // b = SpPtCreate( pRegion->DiskNumber, pRegion->StartSector, SizeMB, InExtended, CreateSysId, pActualRegion ); ASSERT(b); // // Create the logical drive if we just created the extended partition. // if(IsContainerPartition(CreateSysId)) { ASSERT(!InExtended); b = SpPtCreate( pRegion->DiskNumber, pRegion->StartSector, RealSizeMB, TRUE, PARTITION_HUGE, pActualRegion ); ASSERT(b); } return(TRUE); } // // The following table contains offsets from SP_TEXT_PARTITION_NAME_BASE // to get the message id of the name of each type of partition. // A -1 entry means there is no name in the message file for this type // of partition or that the filesystem should be determined instead. // // #define PT(id) ((UCHAR)((SP_TEXT_PARTITION_NAME_##id)-SP_TEXT_PARTITION_NAME_BASE)) #define UNKNOWN PT(UNK) #define M1 ((UCHAR)(-1)) UCHAR PartitionNameIds[256] = { M1,M1,PT(XENIX),PT(XENIX), // 00-03 M1,M1,M1,M1, // 04-07 UNKNOWN,UNKNOWN,PT(BOOTMANAGER),PT(FAT32), // 08-0b PT(FAT32),UNKNOWN,M1,M1, // 0c-0f UNKNOWN,UNKNOWN,PT(EISA),UNKNOWN, // 10-13 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 14-17 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 18-1b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 1c-1f UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 20-23 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 24-27 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 28-2b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 2c-2f UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 30-33 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 34-37 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 38-3b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 3c-3f UNKNOWN,PT(PPCBOOT),UNKNOWN,UNKNOWN, // 40-43 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 44-47 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 48-4b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 4c-4f UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 50-53 UNKNOWN,PT(EZDRIVE),UNKNOWN,UNKNOWN, // 54-57 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 58-5b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 5c-5f UNKNOWN,UNKNOWN,UNKNOWN,PT(UNIX), // 60-63 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 64-67 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 68-6b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 6c-6f UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 70-73 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 74-77 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 78-7b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 7c-7f UNKNOWN,PT(NTFT),UNKNOWN,UNKNOWN, // 80-83 PT(NTFT),UNKNOWN,PT(NTFT),PT(NTFT), // 84-87 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 88-8b UNKNOWN,UNKNOWN,PT(NTFT),UNKNOWN, // 8c-8f UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 90-93 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 94-97 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 98-9b UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // 9c-9f UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a0-a3 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a4-a7 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // a8-ab UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // ac-af UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b0-b3 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b4-b7 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // b8-bb UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // bc-bf UNKNOWN,PT(NTFT),UNKNOWN,UNKNOWN, // c0-c3 PT(NTFT),UNKNOWN,PT(NTFT),PT(NTFT), // c4-c7 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // c8-cb UNKNOWN,UNKNOWN,PT(NTFT),UNKNOWN, // cc-cf UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d0-d3 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d4-d7 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // d8-db UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // dc-df UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e0-e3 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e4-e7 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // e8-eb UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // ec-ef UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f0-f3 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f4-f7 UNKNOWN,UNKNOWN,UNKNOWN,UNKNOWN, // f8-fb UNKNOWN,UNKNOWN,UNKNOWN,PT(XENIXTABLE) // fc-ff }; VOID SpPtGuessDriveLetters( VOID ) { ULONG disk; PPARTITIONED_DISK pDisk; PDISK_REGION *Sort; PON_DISK_PTE pte; ULONG ActiveIndex; UCHAR SysId; WCHAR dlet; PDISK_REGION pRegion; ULONG i; // // Initialize all drive letters to nothing. // for(disk=0; diskNext) { pRegion->DriveLetter = 0; } for(pRegion=PartitionedDisks[disk].ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) { pRegion->DriveLetter = 0; } } Sort = SpMemAlloc(PTABLE_DIMENSION * HardDiskCount * sizeof(PDISK_REGION)); if(!Sort) { KdPrint(("SETUP: Can't allocate memory for drive letter assignment\n")); return; } RtlZeroMemory(Sort,PTABLE_DIMENSION * HardDiskCount * sizeof(PDISK_REGION)); dlet = L'C'; for(disk=0; diskHardDisk->Characteristics & FILE_REMOVABLE_MEDIA)) { for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace) { pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition]; SysId = pte->SystemId; if(!IsContainerPartition(SysId) && (PartitionNameIds[SysId] == (UCHAR)(-1))) { // // This guy gets a drive letter. // ASSERT(pRegion->TablePosition < PTABLE_DIMENSION); Sort[(disk*PTABLE_DIMENSION) + pRegion->TablePosition] = pRegion; if(pte->ActiveFlag && (ActiveIndex != (ULONG)(-1))) { ActiveIndex = pRegion->TablePosition; } } } } // // If we found an active partition, shove it to the start of // the list for this drive unless it's already at the start. // if((ActiveIndex != (ULONG)(-1)) && ActiveIndex) { PDISK_REGION p; ASSERT(ActiveIndex < PTABLE_DIMENSION); p = Sort[(disk*PTABLE_DIMENSION)+ActiveIndex]; RtlMoveMemory( &Sort[(disk*PTABLE_DIMENSION)+1], &Sort[(disk*PTABLE_DIMENSION)], ActiveIndex * sizeof(PDISK_REGION) ); Sort[disk*PTABLE_DIMENSION] = p; } } } // // Now assign drive letters to the first primary partitions // for each non-removable on-line disk. // for(disk=0; diskDriveLetter = dlet++; Sort[(disk*PTABLE_DIMENSION)+i] = NULL; if(dlet > L'Z') { goto dletdone; } break; } } } // // For each disk, assign drive letters to all the logical drives. // For removable drives, we assume a single partition, and that // partition gets a drive letter as if it were a logical drive. // for(disk=0; diskHardDisk->Characteristics & FILE_REMOVABLE_MEDIA) { // // Give the first primary partition the drive letter // and ignore other partitions. Even if there are no // partitions, reserve a drive letter. // for(pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace) { pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition]; SysId = pte->SystemId; if(!IsContainerPartition(SysId) && (PartitionNameIds[SysId] == (UCHAR)(-1))) { pRegion->DriveLetter = dlet; break; } } } dlet++; if(dlet > L'Z') { goto dletdone; } } else { for(pRegion=pDisk->ExtendedDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace) { pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition]; SysId = pte->SystemId; if(!IsContainerPartition(SysId) && (PartitionNameIds[SysId] == (UCHAR)(-1))) { // // This guy gets a drive letter. // pRegion->DriveLetter = dlet++; if(dlet > L'Z') { goto dletdone; } } } } } } // // For each non-removable on-line disk, assign drive letters // to all remaining primary partitions. // for(disk=0; diskDriveLetter = dlet++; if(dlet > L'Z') { goto dletdone; } } } } dletdone: SpMemFree(Sort); }