/*++ 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 // // For NEC98 boot memu code. // #include //NEC98 extern BOOLEAN DriveAssignFromA; //NEC98 extern BOOLEAN ConsoleRunning; extern BOOLEAN ForceConsole; extern BOOLEAN ValidArcSystemPartition; extern PSETUP_COMMUNICATION CommunicationParams; PPARTITIONED_DISK PartitionedDisks; // // Disk region containing the local source directory // in the winnt.exe setup case. // // If WinntSetup is TRUE and WinntFromCd is FALSE, then this // should be non-null. If it is not non-null, then we couldn't locate // the local source. // // PDISK_REGION LocalSourceRegion; #if defined(REMOTE_BOOT) // // For remote boot, we create a fake disk region for the net(0) device. // PDISK_REGION RemoteBootTargetRegion = NULL; #endif // defined(REMOTE_BOOT) // // RemoteBootSetup is true when Source and target paths are through the redirector // with possibly no system partition. // // RemoteInstallSetup is true when we are doing a remote install. // // RemoteSysPrepSetup is true when we are doing a remote install of a sys prep image. // // RemoteSysPrepVolumeIsNtfs is true when the sysprep image we're copying down // represents an ntfs volume. // BOOLEAN RemoteBootSetup = FALSE; BOOLEAN RemoteInstallSetup = FALSE; BOOLEAN RemoteSysPrepSetup = FALSE; BOOLEAN RemoteSysPrepVolumeIsNtfs = FALSE; VOID SpPtReadPartitionTables( IN PPARTITIONED_DISK pDisk ); VOID SpPtInitializePartitionStructures( IN ULONG DiskNumber ); VOID SpPtDeterminePartitionTypes( IN ULONG DiskNumber ); VOID SpPtDetermineVolumeFreeSpace( IN ULONG DiskNumber ); VOID SpPtLocateSystemPartitions( VOID ); VOID SpPtDeleteDriveLetters( VOID ); ValidationValue SpPtnGetSizeCB( IN ULONG Key ); //begin NEC98 NTSTATUS SpInitializeHardDisk_Nec98( PDISK_REGION ); VOID SpReassignOnDiskOrdinals( IN PPARTITIONED_DISK pDisk ); VOID ConvertPartitionTable( IN PPARTITIONED_DISK pDisk, IN PUCHAR Buffer, IN ULONG bps ); //end NEC98 NTSTATUS SpMasterBootCode( IN ULONG DiskNumber, IN HANDLE Partition0Handle, OUT PULONG NewNTFTSignature ); VOID SpPtAssignDriveLetters( VOID ); //begin NEC98 VOID SpPtRemapDriveLetters( IN BOOLEAN DriveAssign_AT ); VOID SpPtUnAssignDriveLetters( VOID ); WCHAR SpDeleteDriveLetter( IN PWSTR DeviceName ); VOID SpTranslatePteInfo( IN PON_DISK_PTE pPte, IN PREAL_DISK_PTE pRealPte, IN BOOLEAN Write // into real PTE ); VOID SpTranslateMbrInfo( IN PON_DISK_MBR pMbr, IN PREAL_DISK_MBR pRealMbr, IN ULONG bps, IN BOOLEAN Write // into real MBR ); VOID SpDetermineFormatTypeNec98( IN PPARTITIONED_DISK pDisk, IN PREAL_DISK_MBR_NEC98 pRealMbrNec98 ); //end NEC98 PDISK_PARTITION SpGetPartitionDescriptionFromRegistry( IN PVOID Buffer, IN ULONG DiskSignature, IN PLARGE_INTEGER StartingOffset, IN PLARGE_INTEGER Length ); VOID SpPtFindLocalSourceRegionOnDynamicVolumes( VOID ); NTSTATUS SpPtCheckDynamicVolumeForOSInstallation( IN PDISK_REGION Region ); #ifndef NEW_PARTITION_ENGINE 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) { #if defined(REMOTE_BOOT) // // If this is a diskless remote boot setup, it's OK for there to be // no hard disks. Otherwise, this is a fatal error. // if (!RemoteBootSetup || RemoteInstallSetup) #endif // defined(REMOTE_BOOT) { SpDisplayScreen(SP_SCRN_NO_HARD_DRIVES,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0); SpInputDrain(); while(SpInputGetKeypress() != KEY_F3) ; SpDone(0,FALSE,TRUE); } return STATUS_SUCCESS; } CLEAR_CLIENT_SCREEN(); #ifdef _X86_ Disk0Ordinal = SpDetermineDisk0(); // // If the user booted off of a high-density floppy (e.g. an ls-120), then // it's possible that we've locked the device in its bay. For this // reason, we're going to tell the drive to unlock floppy0. // { NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING UnicodeString; HANDLE Handle; WCHAR OpenPath[64]; PREVENT_MEDIA_REMOVAL PMRemoval; wcscpy(OpenPath,L"\\device\\floppy0"); INIT_OBJA(&ObjectAttributes,&UnicodeString,OpenPath); // // Open him. // Status = ZwCreateFile( &Handle, FILE_GENERIC_WRITE, &ObjectAttributes, &IoStatusBlock, NULL, // allocation size FILE_ATTRIBUTE_NORMAL, FILE_SHARE_VALID_FLAGS, // full sharing FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, // no EAs 0 ); if( NT_SUCCESS(Status) ) { // // Tell him to let go. // PMRemoval.PreventMediaRemoval = FALSE; Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_STORAGE_MEDIA_REMOVAL, &PMRemoval, sizeof(PMRemoval), NULL, 0 ); ZwClose(Handle); if( !NT_SUCCESS(Status) ) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Setup: SpPtInitialize - Failed to tell the floppy to release its media.\n")); } } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Setup: SpPtInitialize - Failed to open the floppy.\n")); } } #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); } // // Assign drive letters to the various partitions // SpPtAssignDriveLetters(); // // 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; SysId = SpPtGetPartitionType(pRegion); // // If this is the extended partition, skip it. // if(IsContainerPartition(SysId)) { continue; } // // Initialize the FT related information // if( IsRecognizedPartition(SysId) && (((SysId & VALID_NTFT) == VALID_NTFT) || ((SysId & PARTITION_NTFT) == PARTITION_NTFT)) ) { pRegion->FtPartition = TRUE; } // // Initialize the dynamic volume relatated information // if( (SysId == PARTITION_LDM) ) { pRegion->DynamicVolume = TRUE; // // Find out if the dynamic volume is suitable for OS installation // SpPtCheckDynamicVolumeForOSInstallation(pRegion); } // // If this is a 'recognized' partition type, then determine // the filesystem on it. Otherwise use a precanned name. // Note that we also determine the file system type if this is an // FT partition of type 'mirror', that is not the mirror shadow. // We don't care about the shadow since we cannot determine // its file system anyway (we can't access sector 0 of the shadow). // if((PartitionNameIds[SysId] == (UCHAR)(-1)) || ( pRegion->FtPartition ) || ( pRegion->DynamicVolume ) ) { FsType = SpIdentifyFileSystem( HardDisks[DiskNumber].DevicePath, HardDisks[DiskNumber].Geometry.BytesPerSector, SpPtGetOrdinal(pRegion,PartitionOrdinalOnDisk) ); 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 ); } } } #endif // ! NEW_PARTITION_ENGINE 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 = SPPT_REGION_FREESPACE_KB(pRegion); pRegion->AdjustedFreeSpaceKB = pRegion->FreeSpaceKB; pRegion->BytesPerCluster = (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); SpInputDrain(); while(SpInputGetKeypress() != 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 && !WinntFromCd && !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(TemporaryBuffer,Buffer); SpConcatenatePaths(TemporaryBuffer,LocalSourceDirectory); SpConcatenatePaths(TemporaryBuffer,L"size.sif"); SifName = SpDupStringW(TemporaryBuffer); Status = SpLoadSetupTextFile(SifName,NULL,0,&SifHandle,&ErrorLine,TRUE,FALSE); if(NT_SUCCESS(Status)) { p = SpGetSectionKeyIndex(SifHandle,L"Data",L"Size",0); if(p) { ExtraSpace = (ULONG)SpStringToLong(p,NULL,10); } SpFreeTextFile(SifHandle); } SpMemFree(SifName); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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) { // // Only about 1/4 of the total space is moved during textmode. // Remember too that gui-mode copies the files, so only 25% // of this space is reusable during setup... // AdjustedFreeBytes.QuadPart += (ExtraSpace >> 2); } // // 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++; } pRegion->BytesPerCluster = SizeInfo.SectorsPerAllocationUnit * SizeInfo.BytesPerSector; 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 { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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 { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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 } } } #ifdef OLD_PARTITION_ENGINE VOID SpPtLocateSystemPartitions( VOID ) { if(!SpIsArc()) { // // NEC98 must not write boot.ini on C: // if (!IsNEC_98) { //NEC98 PDISK_REGION pRegion; ULONG Disk0Ordinal = SpDetermineDisk0(); // // Note: On X86 we currently don't allow system partitions to reside // on GPT disks // if (SPPT_IS_MBR_DISK(Disk0Ordinal)) { // // 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(SpPtGetPartitionType(pRegion)) && (pRegion->ExtendedType == 0)) { // // It's a primary partition -- declare it a system partition. // pRegion->IsSystemPartition = TRUE; } } } } } else { PDISK_REGION pRegion; PPARTITIONED_DISK pDisk; unsigned pass; ULONG disk; PSP_BOOT_ENTRY BootEntry; // // On ARC machines, system partitions are specifically enumerated // in the NVRAM boot environment. // for(disk=0; diskExtendedDiskRegions : pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { UCHAR SystemId = SpPtGetPartitionType(pRegion); // // Skip if not a partition or extended partition. // if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) { // // Get the nt pathname for this region. // SpNtNameFromRegion( pRegion, TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalOriginal ); // // Determine if it is a system partition. // for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) { if((BootEntry->LoaderPartitionNtName != NULL) && !_wcsicmp(BootEntry->LoaderPartitionNtName,TemporaryBuffer)) { pRegion->IsSystemPartition = TRUE; break; } } } } } } } } } #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; if (!IsNEC_98) { //NEC98 SectorsInBootrec = (512/bps) ? (512/bps) : 1; } else { // we read two sectors because 0 sector include BootCode , 1 sector include // PatitionTables. (In AT Machine,0 sector include BootCode and PartitionTable.) SectorsInBootrec = 2; } //NEC98 // // Allocate and align a buffer for sector i/o. // // MBR size is not 512 on NEC98. // if (!IsNEC_98) { 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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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. // if (!IsNEC_98) { //NEC98 RtlMoveMemory(&pDisk->MbrInfo.OnDiskMbr,Buffer,sizeof(ON_DISK_MBR)); } else { SpDetermineFormatTypeNec98(pDisk,(PREAL_DISK_MBR_NEC98)Buffer); if(pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT) { // // Move the data we just read into the partitioned disk descriptor. // SpTranslateMbrInfo(&pDisk->MbrInfo.OnDiskMbr,(PREAL_DISK_MBR)Buffer,bps,FALSE); } else { // // Translate patririon table information from NEC98 format to PC/AT format. // ConvertPartitionTable(pDisk,Buffer,bps); // // Read NTFT Signature at 16th sector to check if hard disk is valid. // RtlZeroMemory(Buffer,bps); SpReadWriteDiskSectors(Handle,16,1,bps,Buffer,FALSE); // // check "AA55" at the end of 16th sector. // if(((PUSHORT)Buffer)[bps/2 - 1] == BOOT_RECORD_SIGNATURE){ U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = (((PULONG)Buffer)[0]); } else { U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = 0x00000000; } } } //NEC98 // // 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_ // // No NEC98 supports EZ Drive. // if (!IsNEC_98) { //NEC98 // // 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->Int13Hooker = HookerEZDrive; goto readmbr; } // // Also check for on-track. // if(!NextSector && (pDisk->MbrInfo.OnDiskMbr.PartitionTable[0].SystemId == 0x54)) { pDisk->HardDisk->Int13Hooker = HookerOnTrackDiskManager; } } //NEC98 #endif #if defined(REMOTE_BOOT) if (RemoteBootSetup && !RemoteInstallSetup && (U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) == 0)) { // // Uh, oh, we've got a case where the signature on the disk is 0, which is // bad for remote boot because we use 0 as flag for a diskless machine. Let's // write a new signature on the disk. // U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = SpComputeSerialNumber(); RtlMoveMemory(Buffer, &pDisk->MbrInfo.OnDiskMbr, sizeof(ON_DISK_MBR)); Status = SpReadWriteDiskSectors(Handle,NextSector,SectorsInBootrec,bps,Buffer,TRUE); // // Ignore the status - if it failed, then it failed. The only thing that will // happen is that the user will get a warning that they need to reformat later. // } #endif // defined(REMOTE_BOOT) 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 messed up boot record. We'll // just return, and present this mess as free space. // // NOTE: maybe we should warn the user that we are going to ignore // partitions past this point because the structures are damaged. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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 ); if(!IsNEC_98) { RtlMoveMemory(&pEbr->OnDiskMbr,Buffer,sizeof(ON_DISK_MBR)); } else { if(pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT) { SpTranslateMbrInfo(&pEbr->OnDiskMbr,(PREAL_DISK_MBR)Buffer,bps,FALSE); } else { ConvertPartitionTable(pDisk,Buffer,bps); } } if(!NT_SUCCESS(Status) || (U_USHORT(pEbr->OnDiskMbr.AA55Signature) != MBR_SIGNATURE)) { // // NOTE: maybe 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. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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; if(!IsNEC_98) { RtlZeroMemory(&pDisk->MbrInfo,sizeof(MBR_INFO)); } else { RtlZeroMemory(Buffer,bps*SectorsInBootrec); SpTranslateMbrInfo(&pDisk->MbrInfo.OnDiskMbr,(PREAL_DISK_MBR)Buffer,bps,FALSE); } U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = MBR_SIGNATURE; U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = SpComputeSerialNumber(); } #if 0 if (IsNEC_98) { //NEC98 // // Read NTFT Signature at 16th sector to check if hard disk is valid. // (I wish to replace below codes by HAL function later.) // RtlZeroMemory(Buffer,bps); SpReadWriteDiskSectors(Handle, 16, 1, bps, Buffer, FALSE); if(((PUSHORT)Buffer)[bps/2 - 1] == BOOT_RECORD_SIGNATURE){ U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = (((PULONG)Buffer)[0]); } else { U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature) = 0x00000000; } } //NEC98 #endif //0 // // Close partition0. // ZwClose(Handle); SpMemFree(UnalignedBuffer); return; } PDISK_REGION SpPtAllocateDiskRegionStructure( IN ULONG DiskNumber, IN ULONGLONG StartSector, IN ULONGLONG 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; p->FtPartition = FALSE; p->DynamicVolume = FALSE; p->DynamicVolumeSuitableForOS = FALSE; } 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; ULONGLONG ExtendedStart = 0; ULONGLONG ExtendedEnd,ExtendedSize; ULONGLONG 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. // if(!IsNEC_98 || (pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) { pDisk->MbrInfo.Next = &pDisk->FirstEbrInfo; } else { // // There are no extended partition on NEC98. // pDisk->MbrInfo.Next = NULL;; } //NEC98 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)) { ULONGLONG 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; TotalCount = 0; RecognizedCount = 0; *ExtendedExists = FALSE; for(u=0; uMbrInfo.OnDiskMbr.PartitionTable[u].SystemId; if(SysId != PARTITION_ENTRY_UNUSED) { TotalCount++; if(IsRecognizedPartition(SysId) && !(SysId & VALID_NTFT) && !(SysId & PARTITION_NTFT)) { RecognizedCount++; } if(IsContainerPartition(SysId)) { *ExtendedExists = TRUE; } } } *TotalPrimaryPartitionCount = TotalCount; *RecognizedPrimaryPartitionCount = RecognizedCount; } PDISK_REGION SpPtLookupRegionByStart( IN PPARTITIONED_DISK pDisk, IN BOOLEAN ExtendedPartition, IN ULONGLONG 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 Region = NULL; #ifdef NEW_PARTITION_ENGINE ExtendedPartition = FALSE; #else #ifdef GPT_PARTITION_ENGINE if (pDisk->HardDisk->DiskFormatType == DISK_FORMAT_TYPE_GPT)) ExtendedPartition = FALSE; #endif // GPT_PARTITION_ENGINE #endif // NEW_PARTITION_ENGINE Region = (ExtendedPartition) ? pDisk->ExtendedDiskRegions : pDisk->PrimaryDiskRegions; while (Region && (StartSector != Region->StartSector)) { Region = Region->Next; } return Region; } ULONG SpPtAlignStart( IN PHARD_DISK pHardDisk, IN ULONGLONG 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; ULONGLONG r; ULONGLONG 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 { if (!IsNEC_98 || (pHardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) { //NEC98 // // 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; } } else { // // if Start cylinder is 0, force start Cylinder 1. // C = 1; H = S = 0; } //NEC98 } } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP:SpPtAlignStart():C:%I64d,H:%I64d,S:%I64d\n", C, H, S)); // // Now calculate and return the new start sector. // return (ULONG)((C * pHardDisk->SectorsPerCylinder) + (H * pGeometry->SectorsPerTrack) + S); } VOID SpPtQueryMinMaxCreationSizeMB( IN ULONG DiskNumber, IN ULONGLONG StartSector, IN BOOLEAN ForExtended, IN BOOLEAN InExtended, OUT PULONGLONG MinSize, OUT PULONGLONG MaxSize, OUT PBOOLEAN ReservedRegion ) /*++ 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. ReservedRegion - Receives a flag that indicates if the region is entirely in the last cylinder. Because the last cylinder should be reserved for dynamic volumes, this routine will return 0 as MaxSize, if the region is in such a cylinder Return Value: None. --*/ { PPARTITIONED_DISK pDisk; ULONGLONG AlignedStartSector; ULONGLONG AlignedEndSector; ULONGLONG SectorCount; PDISK_REGION pRegion; ULONGLONG MB, ByteSize; ULONGLONG Remainder; ULONGLONG LeftOverSectors; *MinSize = 0; *MaxSize = 0; *ReservedRegion = FALSE; 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; } // // If this is the first free space inside the extended partition // we need to decrement the StartSector so that while creating // first logical inside the extended we don't create the // logical at one cylinder offset // if (SPPT_IS_REGION_NEXT_TO_FIRST_CONTAINER(pRegion) && StartSector) { StartSector--; } // // Align the start to a proper boundary. // AlignedStartSector = SpPtAlignStart(pDisk->HardDisk,StartSector,ForExtended); // // Determine the maximum aligned end sector. // AlignedEndSector = StartSector + pRegion->SectorCount; if(LeftOverSectors = AlignedEndSector % pDisk->HardDisk->SectorsPerCylinder) { AlignedEndSector -= LeftOverSectors; } // // Find out if last sector is in the last cylinder. If it is then align it down. // This is because we should not allow the user to create a partition that contains the last cylinder. // This is necessary so that we reserve a cylinder at the end of the disk, so that users // can convert the disk to dynamic after the system is installed. // // (guhans) Don't align down if this is ASR. ASR already takes this into account. // if(!DockableMachine && !SpDrEnabled() && SPPT_IS_MBR_DISK(DiskNumber) && (!pRegion->Next) && (AlignedEndSector >= (pDisk->HardDisk->CylinderCount - 1) * pDisk->HardDisk->SectorsPerCylinder)) { AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder; if(AlignedEndSector == AlignedStartSector) { // // If after alignment, the partition size is zero, then the user was attempting to // create a partition in the last cylinder of the disk. Since this cylinder is // reserved for LDM (dynamic volume), just return 0 as maximum partition size, and // also indicate to the caller that the region is reserved. // *ReservedRegion = TRUE; *MinSize = 0; *MaxSize = 0; return; } } // // Calculate the number of sectors in the properly aligned space. // SectorCount = AlignedEndSector - AlignedStartSector; // // Convert sectors to MB. // ByteSize = SectorCount * pDisk->HardDisk->Geometry.BytesPerSector; MB = ByteSize / (1024 * 1024); Remainder = ByteSize % (1024 * 1024); // // If the remainder was greater than or equal to a half meg, // bump up the number of megabytes. // *MaxSize = (MB + ((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. // ByteSize = pDisk->HardDisk->SectorsPerCylinder * pDisk->HardDisk->Geometry.BytesPerSector; *MinSize = ByteSize / (1024 * 1024); Remainder = ByteSize % (1024 * 1024); if((*MinSize == 0) || (Remainder >= (512 * 1024))) { (*MinSize)++; } } ULONGLONG SpPtSectorCountToMB( IN PHARD_DISK pHardDisk, IN ULONGLONG SectorCount ) { ULONGLONG ByteCount; ULONGLONG MB,r; // // Calculate the number of bytes that this number of // sectors represents. // ByteCount = (pHardDisk->Geometry.BytesPerSector * SectorCount); // // Calculate the number of megabytes this represents. // r = ByteCount % (1024 * 1204); MB = ByteCount / (1024 * 1024); // // Round up if necessary. // if(r >= (512*1024)) { MB++; } return (MB); } VOID SpPtInitializeCHSFields( IN PHARD_DISK HardDisk, IN ULONGLONG AbsoluteStartSector, IN ULONGLONG AbsoluteSectorCount, OUT PON_DISK_PTE pte ) { ULONGLONG sC,sH,sS,r; ULONGLONG eC,eH,eS; ULONGLONG 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 defined(NEC_98) //NEC98 if (!IsNEC_98 || (HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) { //NEC98 #endif //NEC98 if(eC >= 1024) { sC = 1023; sH = HardDisk->Geometry.TracksPerCylinder - 1; sS = HardDisk->Geometry.SectorsPerTrack - 1; eC = sC; eH = sH; eS = sS; } // // 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; #if defined(NEC_98) //NEC98 } else { // // No NEC98 have "1024th cylinder limit". // pte->StartCylinderLow = (UCHAR)sC; pte->StartCylinderHigh = (UCHAR)(sC >> 4); pte->StartHead = (UCHAR)sH; pte->StartSector = (UCHAR)sS; pte->EndCylinderLow = (UCHAR)eC; pte->EndCylinderHigh = (UCHAR)(eC >> 4); pte->EndHead = (UCHAR)eH; pte->EndSector = (UCHAR)eS; } //NEC98 #endif //NEC98 } #ifndef NEW_PARTITION_ENGINE BOOLEAN SpPtCreate( IN ULONG DiskNumber, IN ULONGLONG StartSector, IN ULONGLONG SizeMB, IN BOOLEAN InExtended, IN PPARTITION_INFORMATION_EX PartInfo, 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; ULONGLONG SectorCount; ULONGLONG AlignedStartSector; ULONGLONG AlignedEndSector; PDISK_REGION pRegion,pRegionPrev,pRegionNew,*pRegionHead; ULONGLONG LeftOverSectors; PMBR_INFO pBrInfo; ULONG slot,i,spt; PON_DISK_PTE pte; ULONGLONG ExtendedStart; UCHAR SysId; #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(DiskNumber)) { return SpPtnCreate(DiskNumber, StartSector, 0, // SizeInSectors: Not used except in ASR SizeMB, InExtended, TRUE, PartInfo, ActualDiskRegion); } #endif SysId = PartInfo->Mbr.PartitionType; // // 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; } // // Find out if last sector is in the last cylinder. If it is then align it down. // This is necessary so that we reserve a cylinder at the end of the disk, so that users // can convert the disk to dynamic after the system is installed. // // (guhans) Don't align down if this is ASR. ASR already takes this into account. // if( !DockableMachine && !SpDrEnabled() && (AlignedEndSector > (pDisk->HardDisk->CylinderCount - 1) * pDisk->HardDisk->SectorsPerCylinder) ) { AlignedEndSector -= pDisk->HardDisk->SectorsPerCylinder; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: End of partition was aligned down 1 cylinder \n")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: AlignedStartSector = %lx \n", AlignedStartSector)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: AlignedEndSector = %lx \n", AlignedEndSector)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SectorsPerCylinder = %lx \n", pDisk->HardDisk->SectorsPerCylinder)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: CylinderCount = %lx \n", pDisk->HardDisk->CylinderCount)); } 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) = (ULONG)(InExtended ? spt : AlignedStartSector); U_ULONG(pte->SectorCount) = (ULONG)(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) = (ULONG)(AlignedStartSector - ExtendedStart); U_ULONG(pte->SectorCount) = (ULONG)(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) = (ULONG)(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 ); SpPtCommitChanges(DiskNumber,(PUCHAR)&i); // // Adjust partition ordinals on this disk. // SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE); // // Get the nt pathname for this region. // if (!IsContainerPartition(SysId)) { SpNtNameFromRegion( pRegion, TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalCurrent ); // // Assign a drive letter for this region // if (!SpDrEnabled()) { pRegion->DriveLetter = SpGetDriveLetter( TemporaryBuffer, NULL ); if (pRegion->DriveLetter == 0) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpGetDriveLetter failed on %ls\n", TemporaryBuffer)); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Partition = %ls (%ls), DriveLetter = %wc: \n", TemporaryBuffer, (InExtended)? L"Extended" : L"Primary", pRegion->DriveLetter)); } } } return(TRUE); } BOOLEAN SpPtDelete( IN ULONG DiskNumber, IN ULONGLONG 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; #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(DiskNumber)) return SpPtnDelete(DiskNumber, StartSector); #endif // // 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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtDelete: status %lx, unable to lock drive\n", Status)); ZwClose(Handle); goto AfterDismount; } // // Dismount the drive // Status = SpDismountVolume(Handle); if(!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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)); pEbrPrev->Dirty[i] = TRUE; 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 and mark the new link entry dirty // so it gets updated on-disk. We do this even though on the // typical disk it will have been marked dirty above. This one here // handles the case of a wierd situation where the type 6/7/whatever // is in slot 0 and the link entry was in slot 2 or 3. In that case, // the RtlZeroMemory code above will have cleaned out a slot that is // different than the one we're using here for the new link entry. // RtlMoveMemory( &pEbrPrev->OnDiskMbr.PartitionTable[j], &pEbr->OnDiskMbr.PartitionTable[i], sizeof(ON_DISK_PTE) ); pEbrPrev->Dirty[j] = TRUE; 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; pRegion->DriveLetter = L'\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); } SpPtCommitChanges(DiskNumber,(PUCHAR)&i); // // Adjust the partition ordinals on this disk. // SpPtAssignOrdinals(pDisk,FALSE,FALSE,FALSE); // // No need to reassign drive letters // return(TRUE); } #endif // !NEW_PARTITION_ENGINE BOOLEAN SpPtExtend( IN PDISK_REGION Region, IN ULONGLONG SizeMB OPTIONAL ) /*++ 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. SizeMB - if specified, indicates the size in MB by which the partition will grow. If not specified, the partition grows to encompass all the free space in the adjacent free space. Return Value: Boolean value indicating whether anything actually changed. --*/ { PDISK_REGION NextRegion; PPARTITIONED_DISK pDisk; PMBR_INFO pBrInfo; PON_DISK_PTE pte; ULONG BytesPerSector; ULONGLONG NewEndSector; ULONGLONG SectorCount; PVOID UnalignedBuffer; PON_DISK_MBR AlignedBuffer; HANDLE Handle; NTSTATUS Status; // // We aren't going to support this anymore on NT5. It's too messy. // return FALSE; /* pDisk = &PartitionedDisks[Region->DiskNumber]; BytesPerSector = pDisk->HardDisk->Geometry.BytesPerSector; 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); } // // Convert the passed in size to a sector count. // if(SizeMB) { SectorCount = SizeMB * ((1024*1024)/BytesPerSector); if(SectorCount > NextRegion->SectorCount) { SectorCount = NextRegion->SectorCount; } } else { SectorCount = NextRegion->SectorCount; } // // Claim the part of the free region we need and align the ending sector // to a cylinder boundary. // NewEndSector = NextRegion->StartSector + SectorCount; NewEndSector -= NewEndSector % pDisk->HardDisk->SectorsPerCylinder; // // 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; } // // Now we have to something tricky. We don't want to inform the disk driver // about what we just did because he will delete the device object for // the partition, which causes problems the next time we hit the disk, say to // page in part of usetup.exe to get a message. We whack the partition table // entry directly, knowing that a) we've been called after SpPtCommitChanges // and b) no one cares about the new size until after we've rebooted. // UnalignedBuffer = SpMemAlloc(2*BytesPerSector); AlignedBuffer = ALIGN(UnalignedBuffer,BytesPerSector); Status = SpOpenPartition0(pDisk->HardDisk->DevicePath,&Handle,TRUE); if(NT_SUCCESS(Status)) { Status = SpReadWriteDiskSectors(Handle,0,1,BytesPerSector,AlignedBuffer,FALSE); if(NT_SUCCESS(Status)) { if(!IsNEC_98) { RtlMoveMemory( &AlignedBuffer->PartitionTable[Region->TablePosition], &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition], sizeof(ON_DISK_PTE) ); } else { PREAL_DISK_MBR pRealBuffer = (PREAL_DISK_MBR)AlignedBuffer; ASSERT(pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT); SpTranslatePteInfo( &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition], &pRealBuffer->PartitionTable[Region->TablePosition], TRUE ); } Status = SpReadWriteDiskSectors(Handle,0,1,BytesPerSector,AlignedBuffer,TRUE); if(!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtExtend: can't write sector 0, status %lx",Status)); } } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtExtend: can't read sector 0, status %lx",Status)); } ZwClose(Handle); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtExtend: can't open disk, status %lx",Status)); } SpMemFree(UnalignedBuffer); if(!NT_SUCCESS(Status)) { FatalPartitionUpdateError(pDisk->HardDisk->Description); } return(TRUE); */ } 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)); // @mtp - Original ASSERT(( PartitionNameIds[pte->SystemId] == (UCHAR)(-1)) || (pte->SystemId == PARTITION_LDM)); ASSERT((PartitionNameIds[pte->SystemId] == (UCHAR)(-1)) || (pte->SystemId == PARTITION_LDM) || ( SpDrEnabled() && IsRecognizedPartition(pte->SystemId) && ( ((pte->SystemId & VALID_NTFT) == VALID_NTFT ) || ((pte->SystemId & PARTITION_NTFT) == PARTITION_NTFT) ) ) ); if(!pte->ActiveFlag) { pte->ActiveFlag = 0x80; PartitionedDisks[Disk0Ordinal].MbrInfo.Dirty[TablePosition] = TRUE; } } #ifndef NEW_PARTITION_ENGINE 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; ULONGLONG ExtendedStart; ULONGLONG Offset; NTSTATUS Status; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; ULONG i; ULONGLONG ZapSector; PUCHAR Buffer,UBuffer; ULONG NewSig; ULONGLONG RewriteSector[PTABLE_DIMENSION]; //NEC98 ULONG cnt,RewriteCnt=0; //NEC98 #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(DiskNumber)) return SpPtnCommitChanges(DiskNumber, AnyChanges); #endif 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++; } } if (IsNEC_98) { //NEC98 ZapSector = 0; #if defined(NEC_98) //NEC98 // // Set RealDiskPosition. This value will be valid after changing partition. // for(i=0,pRegion=pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace) { pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].RealDiskPosition = (UCHAR)i; i++; } } #endif //NEC98 } //NEC98 // // 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++; *AnyChanges = TRUE; } 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 = (!IsNEC_98) ? (BootRecordCount * sizeof(PTABLE_DIMENSION)) : (BootRecordCount * PTABLE_DIMENSION); //NEC98 // // 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); // // Store start offset of newly created partition to clear sector later. // if(IsNEC_98 && pBrInfo->Dirty[i]) { RewriteSector[RewriteCnt++] = Offset; } } // // 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; // // Rewrite all other entries to ensure that if there was logica drive (first in the chain) // that was deleted, it will really go away. There won't be any effect if we overwrite a // logical drive that didn't exist // for( i = 1; i < PTABLE_DIMENSION; i ++ ) { PartitionInfo = &DriveLayout->PartitionEntry[PTABLE_DIMENSION + i]; 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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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. // Note that we slam in new boot code whenever any changes have been made. // We do this to guaranteee proper support for xint13 booting, etc. // if (!IsNEC_98) { //NEC98 // // If MBR of target hard disk is invalid, initialize it when select target partition. // so don't rewrite MBR now. // 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 { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: committing changes on disk %u, SpMasterBootCode returns %lx\n",DiskNumber,Status)); ZwClose(Handle); SpMemFree(DriveLayout); return(Status); } } //NEC98 DriveLayout->Signature = U_ULONG(pDisk->MbrInfo.OnDiskMbr.NTFTSignature); #if 0 // // We dump after the call to the IOCTL because it can change some of the data in the structure, // such as PartitionNumber // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dumping DriveLayout before calling IOCTL_DISK_SET_DRIVE_LAYOUT: \n")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionCount = %lx\n", DriveLayout->PartitionCount)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->Signature = %lx \n\n", DriveLayout->Signature)); for(i = 0; i < DriveLayout->PartitionCount; i++) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].StartingOffset = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].StartingOffset.u.HighPart, DriveLayout->PartitionEntry[i].StartingOffset.u.LowPart)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionLength = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].PartitionLength.u.HighPart, DriveLayout->PartitionEntry[i].PartitionLength.u.LowPart)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].HiddenSectors = 0x%08lx\n", i, DriveLayout->PartitionEntry[i].HiddenSectors)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionNumber = %d\n", i, DriveLayout->PartitionEntry[i].PartitionNumber)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionType = 0x%02x\n", i, DriveLayout->PartitionEntry[i].PartitionType)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].BootIndicator = %ls\n", i, DriveLayout->PartitionEntry[i].BootIndicator? L"TRUE" : L"FALSE")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RecognizedPartition = %ls\n", i, DriveLayout->PartitionEntry[i].RecognizedPartition? L"TRUE" : L"FALSE")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RewritePartition = %ls\n\n", i, DriveLayout->PartitionEntry[i].RewritePartition? L"TRUE" : L"FALSE")); } #endif // // 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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: committing changes on disk %u, ioctl returns %lx\n",DiskNumber,Status)); SpMemFree(DriveLayout); ZwClose(Handle); return(Status); } #if 0 // // We dump after the call to the IOCTL because it can change some of the data in the structure, // such as PartitionNumber // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Dumping DriveLayout after IOCTL_DISK_SET_DRIVE_LAYOUT was called: \n")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionCount = %lx\n", DriveLayout->PartitionCount)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->Signature = %lx \n\n", DriveLayout->Signature)); for(i = 0; i < DriveLayout->PartitionCount; i++) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].StartingOffset = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].StartingOffset.u.HighPart, DriveLayout->PartitionEntry[i].StartingOffset.u.LowPart)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionLength = 0x%08lx%08lx\n", i, DriveLayout->PartitionEntry[i].PartitionLength.u.HighPart, DriveLayout->PartitionEntry[i].PartitionLength.u.LowPart)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].HiddenSectors = 0x%08lx\n", i, DriveLayout->PartitionEntry[i].HiddenSectors)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionNumber = %d\n", i, DriveLayout->PartitionEntry[i].PartitionNumber)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].PartitionType = 0x%02x\n", i, DriveLayout->PartitionEntry[i].PartitionType)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].BootIndicator = %ls\n", i, DriveLayout->PartitionEntry[i].BootIndicator? L"TRUE" : L"FALSE")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RecognizedPartition = %ls\n", i, DriveLayout->PartitionEntry[i].RecognizedPartition? L"TRUE" : L"FALSE")); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: DriveLayout->PartitionEntry[%d].RewritePartition = %ls\n\n", i, DriveLayout->PartitionEntry[i].RewritePartition? L"TRUE" : L"FALSE")); } #endif // // Allocate a buffer for zapping. // UBuffer = SpMemAlloc(2*bps); ASSERT(UBuffer); Buffer = ALIGN(UBuffer,bps); RtlZeroMemory(Buffer,bps); if (IsNEC_98) { //NEC98 // // Clear 1st sector of target partition. // for(cnt = 0; cnt < RewriteCnt; cnt++){ Status = SpReadWriteDiskSectors(Handle, RewriteSector[cnt], 1, bps, Buffer, TRUE); if(!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: clear sector %lx on disk %u returned %lx\n",ZapSector,DiskNumber,Status)); SpMemFree(DriveLayout); SpMemFree(UBuffer); ZwClose(Handle); return(Status); } } } //NEC98 for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) { for(i=0; iOnDiskMbr.PartitionTable[i]; } if ((!IsNEC_98) ? (pBrInfo->UserData[i]) : (PVOID)(pte->SystemId != PARTITION_ENTRY_UNUSED)) { //NEC98 #if defined(NEC_98) //NEC98 PartitionInfo = (!IsNEC_98) ? (PPARTITION_INFORMATION)pBrInfo->UserData[i] : &DriveLayout->PartitionEntry[pte->RealDiskPosition]; //NEC98 #else PartitionInfo = (PPARTITION_INFORMATION)pBrInfo->UserData[i]; #endif // // 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 (!IsNEC_98) { //NEC98 // // 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 messing 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)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "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; } } //NEC98 } } SpMemFree(UBuffer); ZwClose(Handle); // // Reassign on-disk ordinals (but not original ones). // SpPtAssignOrdinals(pDisk,FALSE,TRUE,FALSE); if (IsNEC_98) { //NEC98 // // If newly created partition's position is before existing partition, // OnDiskOrdinals is not equal number of volume infomation position on NEC98 // SpReassignOnDiskOrdinals(pDisk); } //NEC98 SpMemFree(DriveLayout); return(STATUS_SUCCESS); } #endif // ! NEW_PARTITION_ENGINE NTSTATUS SpMasterBootCode( IN ULONG DiskNumber, IN HANDLE Partition0Handle, OUT PULONG NewNTFTSignature ) /*++ Routine Description: Write new master boot code onto a drive. If the mbr has a valid signature, the existing partition table and NTFT signature are preserved. Otherwise the partition table is zeroed out and a new ntft signature is generated. Arguments: DiskNumber - supplies 0-based system ordinal for the disk. Partition0Handle - supplies an open handle for partition 0 on the disk. The handle must have read and write access. NewNTFTSignature - receives a value indicating the new NTFT signature, if one was generated and written to the disk. If 0 is received, then a new ntft signature was not generated and written. Return Value: NT Status code indicating outcome. --*/ { 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 mbr // Status = SpReadWriteDiskSectors( Partition0Handle, (HardDisks[DiskNumber].Int13Hooker == HookerEZDrive) ? 1 : 0, SectorCount, BytesPerSector, Mbr, FALSE ); if(NT_SUCCESS(Status)) { if(U_USHORT(Mbr->AA55Signature) == MBR_SIGNATURE) { // // Valid. Slam in new boot code if there's no int13 hooker. // if(HardDisks[DiskNumber].Int13Hooker == NoHooker) { ASSERT(&((PON_DISK_MBR)0)->BootCode == 0); RtlMoveMemory(Mbr,x86BootCode,sizeof(Mbr->BootCode)); Status = SpReadWriteDiskSectors( Partition0Handle, 0, SectorCount, BytesPerSector, Mbr, TRUE ); } } else { // // Invalid. Construct a boot sector. // 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].Int13Hooker == HookerEZDrive) ? 1 : 0, SectorCount, BytesPerSector, Mbr, TRUE ); if (NT_SUCCESS(Status)) { PHARD_DISK Disk = SPPT_GET_HARDDISK(DiskNumber); Disk->Signature = Disk->DriveLayout.Mbr.Signature = *NewNTFTSignature; } } } SpMemFree(Buffer); return(Status); } #ifndef NEW_PARTITION_ENGINE VOID SpPtGetSectorLayoutInformation( IN PDISK_REGION Region, OUT PULONGLONG HiddenSectors, OUT PULONGLONG 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; #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(Region->DiskNumber)) { SpPtnGetSectorLayoutInformation(Region, HiddenSectors, VolumeSectorCount); return; } #endif 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; #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(Region->DiskNumber)) return SpPtnGetOrdinal(Region, OrdinalType); #endif if(Region->PartitionedSpace && (!Region->DynamicVolume || Region->MbrInfo) ) { // // This is either a basic volume, or a dynamic volume that is listed on the MBR/EBR // 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; } } else { // // Dynamic volume that is not listed on MBR or EBR // ord = Region->TablePosition; } return(ord); } #endif // NEW_PARTITION_ENGINE #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]; ULONGLONG RegionSizeMB; ULONGLONG FreeSpace; ULONG MessageId; WCHAR TypeName[((sizeof(pRegion->TypeName)+sizeof(pRegion->VolumeLabel))/sizeof(WCHAR))+4]; BOOLEAN NewDescription = FALSE; // // Get the size of the region. // RegionSizeMB = SpPtSectorCountToMB(pDisk->HardDisk, pRegion->SectorCount); // // Don't show spaces smaller than 1 MB. // if(!RegionSizeMB) { return(FALSE); } // // 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; #ifdef NEW_PARTITION_ENGINE NewDescription = TRUE; #endif #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(pRegion->DiskNumber)) { NewDescription = TRUE; } else { NewDescription = FALSE; } #endif // // Format the partition name // TypeName[0] = 0; if (SPPT_IS_REGION_PARTITIONED(pRegion)) { SpPtnGetPartitionName(pRegion, TypeName, sizeof(TypeName) / sizeof(TypeName[0])); } else { swprintf( TypeName, L"\\Harddisk%u\\Partition%u", pRegion->DiskNumber, pRegion->PartitionNumber ); } // // 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), (ULONG)RegionSizeMB ); } else { ULONGLONG 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; // // Make sure we don't look bad... // if( FreeSpace > RegionSizeMB ) { FreeSpace = RegionSizeMB; } } SpFormatMessage( Buffer, BufferSize, MessageId, DriveLetter, SplangPadString(-35,TypeName), (ULONG)RegionSizeMB, (ULONG)FreeSpace ); } } else { // // Not a used region, use a separate format string. // SpFormatMessage(Buffer, BufferSize, SP_TEXT_REGION_DESCR_3, (ULONG)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 Buffer[0] = UNICODE_NULL; 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_PTR)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. // // Also disallow installation or create/delete partition into // removable meida on NEC98. Because NT cannot boot from it. // if(pDisk->HardDisk->Status == DiskOffLine) { SpFormatMessage( Buffer, sizeof(Buffer), (pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) ? (!IsNEC_98 ? SP_TEXT_HARD_DISK_NO_MEDIA : SP_TEXT_DISK_OFF_LINE) : SP_TEXT_DISK_OFF_LINE ); return(SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),FALSE,0)); } #if 0 else if(IsNEC_98 && (pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA)) { SpFormatMessage(Buffer,sizeof(Buffer),SP_TEXT_DISK_OFF_LINE); return(SpMnAddItem(Menu,Buffer,MENU_LEFT_X+MENU_INDENT,MENU_WIDTH-(2*MENU_INDENT),FALSE,0)); } #endif //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[4] = {0}; VOID SpPtMenuCallback( IN ULONG_PTR UserData ) { if (UserData){ PDISK_REGION pRegion = (PDISK_REGION)UserData; // // Don't allow deletion of the partition if the 'partition' is really // a DoubleSpace drive. // if(pRegion->Filesystem == FilesystemDoubleSpace) { PartitionMnemonics[0] = 0; if (ConsoleRunning) { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ESC_EQUALS_CANCEL, 0 ); } else { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_INSTALL, SP_STAT_F3_EQUALS_EXIT, 0 ); } } else { PHARD_DISK Disk = SPPT_GET_HARDDISK(pRegion->DiskNumber); BOOLEAN FlipStyle = FALSE; BOOLEAN MakeSysPart = FALSE; FilesystemType FsType = pRegion->Filesystem; #ifndef OLD_PARTITION_ENGINE FlipStyle = SpPtnIsDiskStyleChangeAllowed(pRegion->DiskNumber); #endif // // If it is a Reserved (MSR/OEM) partition on a GPT disk do not provide an option of deleting // it unless we are in Recovery Console // // NOTE: Here we do not check for IA64 specifically as this change is with respect to // GPT disks having reserved partitions and potentially even X86 machines can have // GPT disks in the future and we need to block installation to their reserved partitions. // PartitionMnemonics[0] = pRegion->PartitionedSpace ? ((SPPT_IS_REGION_RESERVED_GPT_PARTITION(pRegion) && !ForceConsole) ? 0 : MnemonicDeletePartition) : MnemonicCreatePartition; PartitionMnemonics[1] = FlipStyle ? MnemonicChangeDiskStyle : 0; #ifdef NEW_PARTITION_ENGINE if (SPPT_IS_REGION_SYSTEMPARTITION(pRegion)) { ValidArcSystemPartition = TRUE; } if (!ValidArcSystemPartition && !FlipStyle && SpIsArc() && (FsType != FilesystemNtfs) && SpPtnIsValidESPPartition(pRegion)) { // // Need to allow conversion to system partition // MakeSysPart = TRUE; PartitionMnemonics[1] = MnemonicMakeSystemPartition; } #endif if (ConsoleRunning) { if (MakeSysPart) { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ESC_EQUALS_CANCEL, pRegion->PartitionedSpace ? SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION, SP_STAT_M_EQUALS_MAKE_SYSPART, FlipStyle ? SP_STAT_S_EQUALS_CHANGE_DISK_STYLE : 0, 0 ); } else { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ESC_EQUALS_CANCEL, pRegion->PartitionedSpace ? SP_STAT_D_EQUALS_DELETE_PARTITION : SP_STAT_C_EQUALS_CREATE_PARTITION, FlipStyle ? SP_STAT_S_EQUALS_CHANGE_DISK_STYLE : 0, 0 ); } } else { if (FlipStyle) { 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_S_EQUALS_CHANGE_DISK_STYLE, SP_STAT_F3_EQUALS_EXIT, 0 ); } else { if (MakeSysPart) { 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_M_EQUALS_MAKE_SYSPART, SP_STAT_F3_EQUALS_EXIT, 0 ); } else { // // If it is a reserved partition (GPT (MSR/OEM)) partition do not display an option // for deleting it unless we are in Recovery Console // SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_INSTALL, pRegion->PartitionedSpace ? ((SPPT_IS_REGION_RESERVED_GPT_PARTITION(pRegion) && !ForceConsole) ? SP_EMPTY_OPTION : SP_STAT_D_EQUALS_DELETE_PARTITION) : SP_STAT_C_EQUALS_CREATE_PARTITION, SP_STAT_F3_EQUALS_EXIT, 0 ); } } } } } } BOOLEAN SpPtIsNotReservedPartition( IN ULONG_PTR UserData, IN ULONG Key ) { BOOLEAN Result = TRUE; if ((ASCI_CR == Key) && (NULL != (PDISK_REGION)UserData) && (SPPT_IS_REGION_RESERVED_GPT_PARTITION((PDISK_REGION)UserData))) { Result = FALSE; } return Result; } void SpEnumerateDiskRegions( IN PSPENUMERATEDISKREGIONS EnumRoutine, IN ULONG_PTR Context ) { ULONG DiskNo; PDISK_REGION pThisRegion; for(DiskNo=0; (DiskNoNext) { if (!EnumRoutine( &PartitionedDisks[DiskNo], pThisRegion, Context )) { return; } } for(pThisRegion=PartitionedDisks[DiskNo].ExtendedDiskRegions; pThisRegion; pThisRegion=pThisRegion->Next) { if (!EnumRoutine( &PartitionedDisks[DiskNo], pThisRegion, Context )) { return; } } } } #if DBG void SpPtDumpPartitionData( void ) { ULONG DiskNo; PDISK_REGION pThisRegion; for(DiskNo=0; (DiskNoNext) { if (pThisRegion->FreeSpaceKB != -1) { KdPrintEx(( DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: diskno=%d, sector-start=%d, sector-count=%d, free=%dKB\n", pThisRegion->DiskNumber, pThisRegion->StartSector, pThisRegion->SectorCount, pThisRegion->FreeSpaceKB )); } } } } #endif #ifdef OLD_PARTITION_ENGINE NTSTATUS SpPtPrepareDisks( IN PVOID SifHandle, OUT PDISK_REGION *InstallRegion, OUT PDISK_REGION *SystemPartitionRegion, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource, IN BOOLEAN RemoteBootRepartition ) { PPARTITIONED_DISK pDisk; WCHAR Buffer[256]; ULONG DiskNo; PVOID Menu; ULONG MenuTopY; ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 }; ULONG ValidKeysCmdCons[2] = { ASCI_ESC, 0 }; ULONG Keypress; PDISK_REGION pRegion; PDISK_REGION FirstRegion,DefaultRegion; BOOLEAN unattended; BOOLEAN createdMenu; //SpPtDumpPartitionData(); if (SpIsArc()) { // // Select a system partition from among those defined in NV-RAM. // *SystemPartitionRegion = SpPtValidSystemPartitionArc(SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource); (*SystemPartitionRegion)->IsSystemPartition = 2; } unattended = UnattendedOperation; while(1) { createdMenu = FALSE; Keypress = 0; #if defined(REMOTE_BOOT) if (RemoteBootSetup && !RemoteInstallSetup && HardDiskCount == 0) { // // If there are no hard disks, allow diskless install // pRegion = NULL; // // Run through the rest of the code as if the user had just // hit enter to select this partition. // Keypress = ASCI_CR; } else #endif // defined(REMOTE_BOOT) if (unattended && RemoteBootRepartition) { ULONG DiskNumber; // // Prepare the disk for remote boot installation. This involves // converting disk 0 into as big a partition as possible. // if (*SystemPartitionRegion != NULL) { DiskNumber = (*SystemPartitionRegion)->DiskNumber; } else { #ifdef _X86_ DiskNumber = SpDetermineDisk0(); #else DiskNumber = 0; #endif } if (NT_SUCCESS(SpPtPartitionDiskForRemoteBoot(DiskNumber, &pRegion))) { SpPtRegionDescription( &PartitionedDisks[pRegion->DiskNumber], pRegion, Buffer, sizeof(Buffer) ); // // Run through the rest of the code as if the user had just // hit enter to select this partition. // Keypress = ASCI_CR; } } if (Keypress == 0) { // // Display the text that goes above the menu on the partitioning screen. // SpDisplayScreen(ConsoleRunning?SP_SCRN_PARTITION_CMDCONS: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); } createdMenu = TRUE; // // Build up a menu of partitions and free spaces. // FirstRegion = NULL; for(DiskNo=0; DiskNoDynamicVolume || LocalSourceRegion->DynamicVolumeSuitableForOS) ) { pRegion = LocalSourceRegion; Keypress = ASCI_CR; } else { pRegion = NULL; if (AutoPartitionPicker && !ConsoleRunning #if defined(REMOTE_BOOT) && (!RemoteBootSetup || RemoteInstallSetup) #endif // defined(REMOTE_BOOT) ) { PDISK_REGION pThisRegion; ULONG RequiredKB = 0; ULONG SectorNo; ULONG pass; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: -------------------------------------------------------------\n" )); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Looking for an install partition\n\n" )); for(DiskNo=0; (DiskNoNext,SectorNo++) { // // Fetch the amount of free space required on the windows nt drive. // SpFetchDiskSpaceRequirements( SifHandle, pThisRegion->BytesPerCluster, &RequiredKB, NULL); if (SpPtDeterminePartitionGood(pThisRegion,RequiredKB,TRUE)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Selected install partition = (%d,%d),(%wc:),(%ws)\n", DiskNo,SectorNo,pThisRegion->DriveLetter,pThisRegion->VolumeLabel)); pRegion = pThisRegion; Keypress = ASCI_CR; break; } } } } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: -------------------------------------------------------------\n" )); } if( !pRegion ) { // // If there is a local source, make it the default partition. // DefaultRegion = (LocalSourceRegion && (!LocalSourceRegion->DynamicVolume || LocalSourceRegion->DynamicVolumeSuitableForOS))? LocalSourceRegion : FirstRegion; // // Call the menu callback to initialize the status line. // SpPtMenuCallback((ULONG_PTR)DefaultRegion); SpMnDisplay( Menu, (ULONG_PTR)DefaultRegion, TRUE, ConsoleRunning?ValidKeysCmdCons:ValidKeys, PartitionMnemonics, SpPtMenuCallback, SpPtIsNotReservedPartition, &Keypress, (PULONG_PTR)(&pRegion) ); } } } // // Now act on the user's selection. // if(Keypress & KEY_MNEMONIC) { Keypress &= ~KEY_MNEMONIC; } if (IsNEC_98) { //NEC98 // // If target hard drive has no/wrong MBR, force initialize it right now. // PPARTITIONED_DISK pDisk; ULONG ValidKeysInit[] = {ASCI_ESC, 0 }; ULONG MnemonicKeysInit[] = { MnemonicInitializeDisk, 0 }; pDisk = &PartitionedDisks[pRegion->DiskNumber]; if(!(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) && ((U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) != MBR_SIGNATURE) || (pDisk->HardDisk->FormatType != DISK_FORMAT_TYPE_NEC98)) && ((Keypress == MnemonicCreatePartition) || (Keypress == MnemonicDeletePartition) || (Keypress == ASCI_CR))) { //SpDisplayScreen(SP_SCRN_INIT_DISK_NEC98,3,HEADER_HEIGHT+1); SpStartScreen( SP_SCRN_INIT_DISK_NEC98, 3, CLIENT_TOP+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, pDisk->HardDisk->Description ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_I_EQUALS_INIT_NEC98, SP_STAT_ESC_EQUALS_CANCEL, 0 ); if(SpWaitValidKey(ValidKeysInit,NULL,MnemonicKeysInit) == ASCI_ESC) { SpMnDestroy(Menu); continue; } // // It will be not return, if successfully complete. // return( SpInitializeHardDisk_Nec98(pRegion) ); } } //NEC98 switch(Keypress) { case MnemonicCreatePartition: SpPtDoCreate(pRegion,NULL,FALSE,0,0,TRUE); break; case MnemonicDeletePartition: SpPtDoDelete(pRegion,SpMnGetText(Menu,(ULONG_PTR)pRegion),TRUE); break; case KEY_F3: SpConfirmExit(); break; case ASCI_ESC: if (ConsoleRunning) { SpPtDoCommitChanges(); } if (createdMenu) { SpMnDestroy(Menu); return(STATUS_SUCCESS); } return(STATUS_SUCCESS); case ASCI_CR: if(SpPtDoPartitionSelection(&pRegion, (!createdMenu) ? Buffer : SpMnGetText(Menu,(ULONG_PTR)pRegion), SifHandle, unattended, SetupSourceDevicePath, DirectoryOnSetupSource, RemoteBootRepartition)) { // // We're done here. // if (createdMenu) { SpMnDestroy(Menu); } *InstallRegion = pRegion; #if defined(REMOTE_BOOT) // // Set the install region differently if this is a remote // boot -- in that case, the install region is always remote. // if (RemoteBootSetup && !RemoteInstallSetup) { *InstallRegion = RemoteBootTargetRegion; } #endif // defined(REMOTE_BOOT) if (!SpIsArc()) { if (!IsNEC_98) { //NEC98 *SystemPartitionRegion = SpPtValidSystemPartition(); } else { *SystemPartitionRegion = *InstallRegion; } //NEC98 }else{ // // Select a system partition from among those defined in NV-RAM. // We have to do this again because the user may have deleted the // system partition previously detected. // Note that SpPtValidSystemPartitionArc(SifHandle) will not return if // a valid system partition is not found. // *SystemPartitionRegion = SpPtValidSystemPartitionArc(SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource); } #if defined(REMOTE_BOOT) ASSERT(*SystemPartitionRegion || (RemoteBootSetup && !RemoteInstallSetup && (HardDiskCount == 0))); #else ASSERT(*SystemPartitionRegion); #endif // defined(REMOTE_BOOT) return(STATUS_SUCCESS); } else { // // Something happened when we tried to select the // partition. Make sure that autopartition-picker // doesn't invoke next time through our while loop. // AutoPartitionPicker = FALSE; } break; } if (createdMenu) { SpMnDestroy(Menu); } unattended = FALSE; } } VOID SpPtDoDelete( IN PDISK_REGION pRegion, IN PWSTR RegionDescription, IN BOOLEAN ConfirmIt ) { ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; // do not change order ULONG Mnemonics[2] = { MnemonicDeletePartition2, 0 }; ULONG k; BOOLEAN b; PPARTITIONED_DISK pDisk; BOOLEAN LastLogical; ULONG Count; #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(pRegion->DiskNumber)) { SpPtnDoDelete(pRegion, RegionDescription, ConfirmIt); return; } #endif // // Special warning if this is a system partition. // // Do not check system partition on NEC98. // if (!IsNEC_98) { //NEC98 if(ConfirmIt && pRegion->IsSystemPartition) { 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; } } } //NEC98 if(ConfirmIt && pRegion->DynamicVolume) { SpDisplayScreen(SP_SCRN_CONFIRM_REMOVE_DYNVOL,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 (ConfirmIt) { 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. // if (ConfirmIt) { 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; } SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_PLEASE_WAIT, 0); } // // 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); if (!b) { if (ConfirmIt) { SpDisplayScreen(SP_SCRN_PARTITION_DELETE_FAILED,3,HEADER_HEIGHT+1); SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE); SpInputDrain(); while(SpInputGetKeypress() != ASCI_CR) ; } return; } // // If we deleted the last logical drive in the extended partition, // then remove the extended partition also. // // Do not check system partition on NEC98. // if (!IsNEC_98) { //NEC98 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; } } } } //NEC98 // // Delete the drive letters if the necessary. This is to ensure that the drive letters assigned to CD-ROM // drives will go away, when the the disks have no partitioned space. // SpPtDeleteDriveLetters(); } BOOLEAN SpPtDoCreate( IN PDISK_REGION pRegion, OUT PDISK_REGION *pActualRegion, OPTIONAL IN BOOLEAN ForNT, IN ULONGLONG DesiredMB OPTIONAL, IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL, IN BOOLEAN ConfirmIt ) { ULONG ValidKeys[3] = { ASCI_ESC, ASCI_CR, 0 }; BOOLEAN b; PPARTITIONED_DISK pDisk; ULONGLONG MinMB,MaxMB; ULONG TotalPrimary,RecogPrimary; BOOLEAN InExtended; UCHAR CreateSysId; UCHAR RealSysId; BOOLEAN ExtendedExists; ULONGLONG SizeMB,RealSizeMB; WCHAR Buffer[200]; WCHAR SizeBuffer[10]; BOOLEAN Beyond1024; BOOLEAN ReservedRegion; UCHAR DesiredSysId = 0; PARTITION_INFORMATION_EX NewPartInfo; #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(pRegion->DiskNumber)) { return SpPtnDoCreate(pRegion, pActualRegion, ForNT, DesiredMB, PartInfo, ConfirmIt); } #endif RtlZeroMemory(&NewPartInfo, sizeof(PARTITION_INFORMATION_EX)); DesiredSysId = PartInfo ? PartInfo->Mbr.PartitionType : 0; ASSERT(!pRegion->PartitionedSpace); pDisk = &PartitionedDisks[pRegion->DiskNumber]; // // Determine whether this space is within the extended partition. // # if 0 // // No NEC98 has Extended partition. // All of partition on NEC98 are Primary. // InExtended = (!IsNEC_98) ? (BOOLEAN)(SpPtLookupRegionByStart(pDisk,TRUE,pRegion->StartSector) != NULL) : FALSE; //NEC98 # endif //0 InExtended = (BOOLEAN)(SpPtLookupRegionByStart(pDisk,TRUE,pRegion->StartSector) != NULL); Beyond1024 = SpIsRegionBeyondCylinder1024(pRegion); if( pDisk->HardDisk->Geometry.MediaType == RemovableMedia ) { ULONG pass; PDISK_REGION p; // // If the user is attempting to create a partition on a removable drive, then make sure that // the drive doesn't already contain a primary partition or a logical drive. // for( pass = 0; pass < 2; pass++ ) { for( p = (pass == 0)? pDisk->PrimaryDiskRegions : pDisk->ExtendedDiskRegions; p; p = p->Next ) { if( p->PartitionedSpace ) { PON_DISK_PTE pte; UCHAR TmpSysId; pte = &p->MbrInfo->OnDiskMbr.PartitionTable[p->TablePosition]; TmpSysId = pte->SystemId; if( !IsContainerPartition(TmpSysId) ) { ULONG ValidKeys1[2] = { ASCI_CR ,0 }; // // Disk is already partitioned // SpDisplayScreen(SP_SCRN_REMOVABLE_ALREADY_PARTITIONED,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return( FALSE ); } } } } } // // Determine the type of partition to create for this space, // excluding any issues with extended partitions. // if (DesiredSysId != 0) { // // If the caller specified a partition type, use it unless it // won't work due to being beyond 1024 cylinders. // #if 0 RealSysId = DesiredSysId; if (Beyond1024) { if (RealSysId == PARTITION_FAT32) { RealSysId = PARTITION_FAT32_XINT13; } else { RealSysId = PARTITION_XINT13; } } #else // // Keep this code in until I determine if we will be explicitly // creating extended partitions. // RealSysId = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE; #endif } else { RealSysId = Beyond1024 ? PARTITION_XINT13 : PARTITION_HUGE; } // // 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 = RealSysId; } else { // // Get statistics about primary partitions. // SpPtCountPrimaryPartitions(pDisk,&TotalPrimary,&RecogPrimary,&ExtendedExists); // // If there is no primary partition, create one. // if(!RecogPrimary) { CreateSysId = RealSysId; } 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. // if(ExtendedExists) { CreateSysId = RealSysId; } else { // // Firmware doesn't understand type F link partitions. // No great need to use on x86 either; assume that creating // logical drives with the correct type is good enough. // // // No NEC98 has PARTITION_EXTENDED, just PARTITION_HUGE only. // CreateSysId = (!IsNEC_98 || (pDisk->HardDisk->FormatType == DISK_FORMAT_TYPE_PCAT)) ? PARTITION_EXTENDED : PARTITION_HUGE; //NEC98 if((CreateSysId == PARTITION_EXTENDED) && Beyond1024) { CreateSysId = PARTITION_XINT13_EXTENDED; } } } else { if (ConfirmIt) { while (TRUE) { ULONG ks[2] = { ASCI_CR,0 }; SpDisplayScreen(SP_SCRN_PART_TABLE_FULL,3,CLIENT_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); switch(SpWaitValidKey(ks,NULL,NULL)) { case ASCI_CR: return(FALSE); } } } else { return TRUE; } } } } // // Get the mimimum and maximum sizes for the partition. // ReservedRegion = FALSE; SpPtQueryMinMaxCreationSizeMB( pRegion->DiskNumber, pRegion->StartSector, (BOOLEAN)IsContainerPartition(CreateSysId), InExtended, &MinMB, &MaxMB, &ReservedRegion ); if( ReservedRegion ) { ULONG ValidKeys1[2] = { ASCI_CR ,0 }; SpStartScreen( SP_SCRN_REGION_RESERVED, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return(FALSE); } if(ForNT) { // // If a size was requested then try to use that, otherwise use // the maximum. // if (DesiredMB != 0) { if (DesiredMB <= MaxMB) { SizeMB = DesiredMB; } else { return FALSE; } } else { 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(SpPtnGetSizeCB,SplangGetColumnCount(Buffer)+5,NextMessageTopLine,5,SizeBuffer,TRUE, 0)) { // // 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; } NewPartInfo.PartitionStyle = PARTITION_STYLE_MBR; NewPartInfo.Mbr.PartitionType = CreateSysId; // // Create the partition. // b = SpPtCreate( pRegion->DiskNumber, pRegion->StartSector, SizeMB, InExtended, &NewPartInfo, pActualRegion ); ASSERT(b); // // Create the logical drive if we just created the extended partition. // if(IsContainerPartition(CreateSysId)) { ASSERT(!InExtended); NewPartInfo.Mbr.PartitionType = RealSysId; b = SpPtCreate( pRegion->DiskNumber, pRegion->StartSector, RealSizeMB, TRUE, &NewPartInfo, pActualRegion ); ASSERT(b); } return(TRUE); } #endif // NEW_PARTITION_ENGINE // // 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),M1, // 08-0b M1,UNKNOWN,M1,M1, // 0c-0f UNKNOWN,UNKNOWN,PT(EISA),UNKNOWN, // 10-13 UNKNOWN,UNKNOWN,PT(BMHIDE),PT(BMHIDE), // 14-17 UNKNOWN,UNKNOWN,UNKNOWN,PT(BMHIDE), // 18-1b PT(BMHIDE),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 PT(PWRQST),UNKNOWN,UNKNOWN,UNKNOWN, // 3c-3f UNKNOWN,PT(PPCBOOT),PT(VERIT),PT(VERIT), // 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 PT(ONTRACK),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,PT(NTFT), // 88-8b PT(NTFT),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,PT(NTFT), // c8-cb PT(NTFT),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 }; WCHAR SpGetDriveLetter( IN PWSTR DeviceName, OUT PMOUNTMGR_MOUNT_POINT * MountPoint OPTIONAL ) /*++ Routine Description: This routine returns the drive letter associated to a given device. Arguments: DeviceName - Supplies the device name. MountPoint - If specified, causes the function to allocate a mount manager point and fills it in. Return Value: A drive letter, if one exists. --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES Obja; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle; DWORD nameLen; DWORD mountPointSize; PMOUNTMGR_MOUNT_POINT mountPoint; PMOUNTMGR_MOUNT_POINTS mountPoints; PMOUNTMGR_TARGET_NAME mountTarget; DWORD bytes; WCHAR driveLetter; DWORD i; PWSTR s; LARGE_INTEGER DelayTime; INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME); Status = ZwOpenFile( &Handle, (ACCESS_MASK)(FILE_GENERIC_READ), &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE , FILE_NON_DIRECTORY_FILE ); if( !NT_SUCCESS( Status ) ) { return L'\0'; } // // setup a good device name // nameLen = wcslen(DeviceName); mountPointSize = sizeof(MOUNTMGR_TARGET_NAME) + nameLen*sizeof(WCHAR) + 28; mountTarget = SpMemAlloc(mountPointSize); if (!mountTarget) { ZwClose(Handle); return L'\0'; } RtlZeroMemory(mountTarget, mountPointSize); mountTarget->DeviceNameLength = (USHORT) nameLen*sizeof(WCHAR); RtlCopyMemory((PCHAR) &mountTarget->DeviceName, DeviceName, nameLen*sizeof(WCHAR)); // // this loop is necessary as a synchronization // method. we have previously committed changes, but // the volume manager has not had a chance to // do it's thing so here we wait...... // for (i=0; i<20; i++) { Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, mountTarget, mountPointSize, NULL, 0 ); if (!NT_SUCCESS( Status )) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION failed - %08x\n",Status)); DelayTime.HighPart = -1; DelayTime.LowPart = (ULONG)(-5000000); KeDelayExecutionThread(KernelMode,FALSE,&DelayTime); } else { // // On removable disks, a drive letter may not have been assigned yet. // So make sure one is assigned on this case. // MOUNTMGR_DRIVE_LETTER_INFORMATION DriveLetterInformation; NTSTATUS Status1; Status1 = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, mountTarget, mountPointSize, &DriveLetterInformation, sizeof(MOUNTMGR_DRIVE_LETTER_INFORMATION) ); if (!NT_SUCCESS( Status1 )) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER failed. Status = %lx \n",Status1)); } break; } } if (!NT_SUCCESS( Status )) { SpMemFree(mountTarget); ZwClose(Handle); return L'\0'; } SpMemFree(mountTarget); nameLen = wcslen(DeviceName); mountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) + nameLen*sizeof(WCHAR) + 28; mountPoint = SpMemAlloc(mountPointSize); if (!mountPoint) { ZwClose(Handle); return L'\0'; } RtlZeroMemory(mountPoint, mountPointSize); mountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); mountPoint->DeviceNameLength = (USHORT) nameLen*sizeof(WCHAR); RtlCopyMemory((PCHAR) mountPoint + sizeof(MOUNTMGR_MOUNT_POINT), DeviceName, nameLen*sizeof(WCHAR)); mountPoints = SpMemAlloc( 4096 ); if (!mountPoints) { SpMemFree(mountPoint); ZwClose(Handle); return L'\0'; } Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_QUERY_POINTS, mountPoint, mountPointSize, mountPoints, 4096 ); if (!NT_SUCCESS( Status )) { if (Status == STATUS_BUFFER_OVERFLOW) { bytes = mountPoints->Size; SpMemFree(mountPoints); mountPoints = SpMemAlloc(bytes); if (!mountPoints) { SpMemFree(mountPoint); ZwClose(Handle); return L'\0'; } Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_QUERY_POINTS, mountPoint, mountPointSize, mountPoints, bytes ); if (!NT_SUCCESS( Status )) { SpMemFree(mountPoints); SpMemFree(mountPoint); ZwClose(Handle); return L'\0'; } } else { mountPoints->NumberOfMountPoints = 0; } } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: IOCTL_MOUNTMGR_QUERY_POINTS : Number = %d \n", mountPoints->NumberOfMountPoints)); driveLetter = 0; for (i = 0; i < mountPoints->NumberOfMountPoints; i++) { if (mountPoints->MountPoints[i].SymbolicLinkNameLength != 28) { continue; } s = (PWSTR) ((PCHAR) mountPoints + mountPoints->MountPoints[i].SymbolicLinkNameOffset); if (s[0] != L'\\' || (s[1] != L'D' && s[1] != L'd') || (s[2] != L'O' && s[2] != L'o') || (s[3] != L'S' && s[3] != L's') || (s[4] != L'D' && s[4] != L'd') || (s[5] != L'E' && s[5] != L'e') || (s[6] != L'V' && s[6] != L'v') || (s[7] != L'I' && s[7] != L'i') || (s[8] != L'C' && s[8] != L'c') || (s[9] != L'E' && s[9] != L'e') || (s[10]!= L'S' && s[10]!= L's') || s[11] != L'\\' || s[13] != L':') { continue; } if (s[12] < ((!IsNEC_98) ? L'C' : L'A') || s[12] > L'Z') { //NEC98 continue; } driveLetter = s[12]; if (ARGUMENT_PRESENT( MountPoint )) { ULONG newMountPointSize; PMOUNTMGR_MOUNT_POINT newMountPoint, oldMountPoint; ULONG currentOffset; // // The caller wants us to return the actual mount point information. // oldMountPoint = &mountPoints->MountPoints[i]; newMountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) + oldMountPoint->SymbolicLinkNameLength + oldMountPoint->UniqueIdLength + oldMountPoint->DeviceNameLength; newMountPoint = SpMemAlloc(newMountPointSize); if (newMountPoint) { currentOffset = sizeof(MOUNTMGR_MOUNT_POINT); newMountPoint->SymbolicLinkNameLength = oldMountPoint->SymbolicLinkNameLength; newMountPoint->SymbolicLinkNameOffset = currentOffset; memcpy((PCHAR)newMountPoint + newMountPoint->SymbolicLinkNameOffset, (PCHAR)mountPoints + oldMountPoint->SymbolicLinkNameOffset, oldMountPoint->SymbolicLinkNameLength); currentOffset += oldMountPoint->SymbolicLinkNameLength; newMountPoint->UniqueIdLength = oldMountPoint->UniqueIdLength; newMountPoint->UniqueIdOffset = currentOffset; memcpy((PCHAR)newMountPoint + newMountPoint->UniqueIdOffset, (PCHAR)mountPoints + oldMountPoint->UniqueIdOffset, oldMountPoint->UniqueIdLength); currentOffset += oldMountPoint->UniqueIdLength; newMountPoint->DeviceNameLength = oldMountPoint->DeviceNameLength; newMountPoint->DeviceNameOffset = currentOffset; memcpy((PCHAR)newMountPoint + newMountPoint->DeviceNameOffset, (PCHAR)mountPoints + oldMountPoint->DeviceNameOffset, oldMountPoint->DeviceNameLength); *MountPoint = newMountPoint; } } break; } SpMemFree(mountPoints); SpMemFree(mountPoint); ZwClose(Handle); return driveLetter; } WCHAR SpDeleteDriveLetter( IN PWSTR DeviceName ) /*++ Routine Description: This routine returns the drive letter associated to a given device. Arguments: DeviceName - Supplies the device name. Return Value: A drive letter, if one exists. --*/ { NTSTATUS Status; OBJECT_ATTRIBUTES Obja; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle; DWORD nameLen; DWORD mountPointSize; PMOUNTMGR_MOUNT_POINT mountPoint; PMOUNTMGR_MOUNT_POINTS mountPoints; DWORD bytes; WCHAR driveLetter; INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME); Status = ZwOpenFile( &Handle, (ACCESS_MASK)(FILE_GENERIC_READ), &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE , FILE_NON_DIRECTORY_FILE ); if( !NT_SUCCESS( Status ) ) { return L'\0'; } nameLen = wcslen(DeviceName); mountPointSize = sizeof(MOUNTMGR_MOUNT_POINT) + nameLen*sizeof(WCHAR) + 28; mountPoint = SpMemAlloc(mountPointSize); if (!mountPoint) { ZwClose(Handle); return L'\0'; } RtlZeroMemory(mountPoint, sizeof(MOUNTMGR_MOUNT_POINT)); mountPoint->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); mountPoint->DeviceNameLength = (USHORT) nameLen*sizeof(WCHAR); RtlCopyMemory((PCHAR) mountPoint + sizeof(MOUNTMGR_MOUNT_POINT), DeviceName, nameLen*sizeof(WCHAR)); mountPoints = SpMemAlloc( 4096 ); if (!mountPoints) { SpMemFree(mountPoint); ZwClose(Handle); return L'\0'; } Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_DELETE_POINTS, mountPoint, mountPointSize, mountPoints, 4096 ); if (!NT_SUCCESS( Status )) { if (Status == STATUS_BUFFER_OVERFLOW) { bytes = mountPoints->Size; SpMemFree(mountPoints); mountPoints = SpMemAlloc(bytes); if (!mountPoints) { SpMemFree(mountPoint); ZwClose(Handle); return L'\0'; } Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_DELETE_POINTS, mountPoint, mountPointSize, mountPoints, bytes ); if (!NT_SUCCESS( Status )) { SpMemFree(mountPoints); SpMemFree(mountPoint); ZwClose(Handle); return L'\0'; } } else { mountPoints->NumberOfMountPoints = 0; } } driveLetter = 0; SpMemFree(mountPoints); SpMemFree(mountPoint); ZwClose(Handle); return driveLetter; } VOID SpPtDeleteDriveLetters( VOID ) /*++ Routine Description: This routine will delete all drive letters assigned to disks and CD-ROM drives. The deletion will occur only if setup was started booting from the CD or boot floppies (in which case drive letter migration does not take place), and only if the non-removable dissks have no partitioned spaces. This ensures that on a clean install from the CD or boot floppies, the drive letters assigned to partitions on removable disks and CD-ROM drives will always be greater than the drive letters assigned to partitions on non-removable disks (unless the partitions on the removable disks were created before the ones in the removable disks, during textmode setup). Arguments: None. Return Value: None. --*/ { ULONG disk; PDISK_REGION pRegion; unsigned pass; BOOLEAN PartitionedSpaceFound = FALSE; if( WinntSetup ) { // // If setup started from winnt32.exe then do not delete the drive letters since we want to preserve them // return; } // // Setup started booting from a CD or from the boot floppies // Find out if the disks contain at least one partition that is not a container. // Note that we do not take into consideration partitions that are on removable media. // This is to avoid the situation in which a newly created partition on a non-removable disk ends up with // a drive letter that is greater than the one assigned to an existing partition on a removable disk. // for(disk = 0; !PartitionedSpaceFound && (diskGeometry.MediaType != RemovableMedia) { for(pass=0; !PartitionedSpaceFound && (pass<2); pass++) { pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions; for( ; !PartitionedSpaceFound && pRegion; pRegion=pRegion->Next) { UCHAR SystemId = PARTITION_ENTRY_UNUSED; #ifdef OLD_PARTITION_TABLE SystemId = pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId; #else if (SPPT_IS_MBR_DISK(disk) && SPPT_IS_REGION_PARTITIONED(pRegion)) { SystemId = SPPT_GET_PARTITION_TYPE(pRegion); } #endif if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) { PartitionedSpaceFound = TRUE; } } } } } if( !PartitionedSpaceFound ) { // // If the disks have no partitioned regions that are not a container, // then delete all drive letters, so that the drive letters for each CD-ROM drive // also get deleted. // NTSTATUS Status; OBJECT_ATTRIBUTES Obja; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING UnicodeString; HANDLE Handle; INIT_OBJA(&Obja,&UnicodeString,MOUNTMGR_DEVICE_NAME); Status = ZwOpenFile( &Handle, (ACCESS_MASK)(FILE_GENERIC_READ | FILE_GENERIC_WRITE), &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE ); if( NT_SUCCESS( Status ) ) { MOUNTMGR_MOUNT_POINT MountMgrMountPoint; MountMgrMountPoint.SymbolicLinkNameOffset = 0; MountMgrMountPoint.SymbolicLinkNameLength = 0; MountMgrMountPoint.UniqueIdOffset = 0; MountMgrMountPoint.UniqueIdLength = 0; MountMgrMountPoint.DeviceNameOffset = 0; MountMgrMountPoint.DeviceNameLength = 0; Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_MOUNTMGR_DELETE_POINTS, &MountMgrMountPoint, sizeof( MOUNTMGR_MOUNT_POINT ), TemporaryBuffer, sizeof( TemporaryBuffer ) ); if( !NT_SUCCESS( Status ) ) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete drive letters. ZwDeviceIoControl( IOCTL_MOUNTMGR_DELETE_POINTS ) failed. Status = %lx \n", Status)); } else { // // If the drive letters got deleted then reset the drive letters assigned to all partitions. // Note that we only really care about resetting the drive letters on the partitions on the // removable disks, since, if we got that far, there won't be any partition on the non-removable // disks // for(disk = 0; (diskGeometry.MediaType == RemovableMedia) { for(pass=0; pass<2; pass++) { pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { UCHAR SystemId = SpPtGetPartitionType(pRegion); if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) { pRegion->DriveLetter = 0; } } } } } } ZwClose( Handle ); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to delete drive letters. ZwOpenFile( %ls ) failed. Status = %lx \n", MOUNTMGR_DEVICE_NAME, Status)); } } } VOID SpPtAssignDriveLetters( VOID ) { ULONG disk; PDISK_REGION pRegion; unsigned pass; // // Before initializing the drive letters, delete them if necessary. // This is to get rid of the letters assigned to CD-ROM drives and removables, when the disks have no // partitioned space. // SpPtDeleteDriveLetters(); // // Initialize all drive letters to nothing. // If it the region is a partitioned space, then assign a drive letter also. // for(disk=0; diskGeometry.MediaType != RemovableMedia)) { for(pass=0; pass<2; pass++) { pRegion = pass ? PartitionedDisks[disk].ExtendedDiskRegions : PartitionedDisks[disk].PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { UCHAR SystemId = SpPtGetPartitionType(pRegion); pRegion->DriveLetter = 0; if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) { // // Get the nt pathname for this region. // SpNtNameFromRegion( pRegion, TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalCurrent ); // // Assign a drive letter for this region // pRegion->DriveLetter = SpGetDriveLetter( TemporaryBuffer, NULL ); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Partition = %ls (%ls), DriveLetter = %wc: \n", TemporaryBuffer, (pass)? L"Extended" : L"Primary", pRegion->DriveLetter)); } } } } } } VOID SpPtRemapDriveLetters( IN BOOLEAN DriveAssign_AT ) { PWSTR p; NTSTATUS Status; UNICODE_STRING StartDriveLetterFrom; UNICODE_STRING Dummy; STRING ntDeviceName; UCHAR deviceNameBuffer[256] = "\\Device\\Harddisk0\\Partition1"; UCHAR systemRootBuffer[256] = "C:\\$WIN_NT$.~BT"; ANSI_STRING ansiString; BOOLEAN ForceUnmap = FALSE; RTL_QUERY_REGISTRY_TABLE SetupTypeTable[]= { {NULL, RTL_QUERY_REGISTRY_DIRECT, L"DriveLetter", &StartDriveLetterFrom, REG_SZ, &Dummy, 0 }, {NULL,0,NULL,NULL,REG_NONE,NULL,0} }; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveAssign_AT = %d.\n",(DriveAssign_AT ? 1 : 0))); // // Determin whether how to drive assign is 98 (HD start is A) or // AT (HD start C). // RtlInitUnicodeString(&StartDriveLetterFrom, NULL); RtlInitUnicodeString(&Dummy, NULL); Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, L"\\Registry\\MACHINE\\SYSTEM\\Setup", SetupTypeTable, NULL, NULL); if (NT_SUCCESS(Status)) { if ((StartDriveLetterFrom.Buffer[0] == L'C') || (StartDriveLetterFrom.Buffer[0] == L'c')) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: DriveLetter is in setupreg.hiv.\n")); if (!DriveAssign_AT) { // // Delete hive value "DriveLetter". // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Re-assign as NEC assign.\n")); Status = RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\MACHINE\\SYSTEM\\Setup", L"DriveLetter"); if (!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Fail to delete KEY DriveLetter.\n")); } } } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: There is no DriveLetter.\n")); if (DriveAssign_AT) { // // Add hive value "DriveLetter" as "C". // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Re-assign as AT assign.\n")); Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE, L"\\Registry\\Machine\\System\\Setup", L"DriveLetter", REG_SZ, L"C", sizeof(L"C")+sizeof(WCHAR)); if (!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Fail to add KEY DriveLetter.\n")); } } } ForceUnmap = TRUE; } // // Cancel all drive letters and Remap drive letters. // if (ForceUnmap) { SpPtUnAssignDriveLetters(); ntDeviceName.Buffer = deviceNameBuffer; ntDeviceName.MaximumLength = sizeof(deviceNameBuffer); ntDeviceName.Length = 0; ansiString.MaximumLength = sizeof(systemRootBuffer); ansiString.Length = 0; ansiString.Buffer = systemRootBuffer; IoAssignDriveLetters( *(PLOADER_PARAMETER_BLOCK *)KeLoaderBlock, &ntDeviceName, ansiString.Buffer, &ansiString ); } RtlFreeUnicodeString(&StartDriveLetterFrom); RtlFreeUnicodeString(&Dummy); } VOID SpPtUnAssignDriveLetters( VOID ) { ULONG disk; PDISK_REGION pRegion; unsigned pass; ULONG CdCount, cdrom, dlet; UNICODE_STRING linkString; WCHAR tempBuffer[] = L"\\DosDevices\\A:"; // // Release all drive letters of device. // If it the region is a partitioned space, then assign a drive letter also. // for(disk=0; diskNext) { UCHAR SystemId = SpPtGetPartitionType(pRegion); //pRegion->DriveLetter = 0; if(pRegion->PartitionedSpace && !IsContainerPartition(SystemId)) { // // Get the nt pathname for this region. // SpNtNameFromRegion( pRegion, TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalOriginal ); // // Assign a drive letter for this region // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: delete Partition = %ls (%ls), DriveLetter = %wc: \n", TemporaryBuffer, (pass)? L"Extended" : L"Primary", pRegion->DriveLetter)); SpDeleteDriveLetter( TemporaryBuffer ); pRegion->DriveLetter = 0; } } } } if(CdCount = IoGetConfigurationInformation()->CdRomCount) { // // Unlink CD-ROM drive letters. // for(cdrom=0; cdromHardDisk->FormatType == DISK_FORMAT_TYPE_GPT) { SpPtnDeletePartitionsForRemoteBoot(pDisk, startRegion, endRegion, Extended); return; } #endif // // Delete all disk regions from startRegion to endRegion. // pRegion = startRegion; while (pRegion) { // // Before deleting this region, we need to save the next region // to delete, since the list may get modified as a result of // deleting this one (but a partitioned region won't get // changed, only free ones). Note that endRegion might // be unpartitioned so we need to be careful to check for // the exit case. // pNextDeleteRegion = pRegion->Next; while (pNextDeleteRegion) { if (pNextDeleteRegion->PartitionedSpace) { break; } else { if (pNextDeleteRegion == endRegion) { passedEndRegion = TRUE; } pNextDeleteRegion = pNextDeleteRegion->Next; } } // // If this is the extended partition, first kill all the // logical drives. // if (IsContainerPartition(pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition].SystemId)) { ASSERT(!Extended); SpPtDeletePartitionsForRemoteBoot( pDisk, pDisk->ExtendedDiskRegions, NULL, TRUE // used to check for another recursion ); } // // Remove any boot entries pointing to this region. // SpPtDeleteBootSetsForRegion(pRegion); // // Get rid of the compressed drives, if any // if( pRegion->NextCompressed != NULL ) { SpDisposeCompressedDrives( pRegion->NextCompressed ); pRegion->NextCompressed = NULL; pRegion->MountDrive = 0; pRegion->HostDrive = 0; } if (pRegion->PartitionedSpace) { b = SpPtDelete(pRegion->DiskNumber,pRegion->StartSector); } ASSERT(b); if ((pRegion == endRegion) || passedEndRegion) { break; } pRegion = pNextDeleteRegion; } } #endif // ! NEW_PARTITION_ENGINE NTSTATUS SpPtPartitionDiskForRemoteBoot( IN ULONG DiskNumber, OUT PDISK_REGION *RemainingRegion ) { PPARTITIONED_DISK pDisk; PDISK_REGION pRegion; ULONG PartitionCount = 0; ULONGLONG firstRegionStartSector; PDISK_REGION firstRegion = NULL, lastRegion = NULL; BOOLEAN IsGPTDisk = FALSE; pDisk = &PartitionedDisks[DiskNumber]; IsGPTDisk = SPPT_IS_GPT_DISK(DiskNumber); // // Scan through the disk and see how many contiguous recognized // partitions there are. // if (pDisk->HardDisk->Status == DiskOffLine) { return STATUS_DEVICE_OFF_LINE; } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpPtPartitionDiskForRemoteBoot: cylinder size is %lx\n", pDisk->HardDisk->SectorsPerCylinder)); pRegion = pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { if (!pRegion->PartitionedSpace) { // // If the region is not partitioned, then add it to our list // to merge if we have one. // if (firstRegion) { // // If this is a final free region covering the last // partial cylinder on the disk, then don't add it. // if ((pRegion->Next == NULL) && (pRegion->SectorCount < pDisk->HardDisk->SectorsPerCylinder) && ((pRegion->StartSector % pDisk->HardDisk->SectorsPerCylinder) == 0)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Skipping final partial cylinder free region %lx for %lx\n", pRegion->StartSector, pRegion->SectorCount)); } else { lastRegion = pRegion; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Adding free region %lx for %lx\n", pRegion->StartSector, pRegion->SectorCount)); } } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Skipping free region %lx for %lx\n", pRegion->StartSector, pRegion->SectorCount)); } } else { PON_DISK_PTE pte; UCHAR SystemId = 0; if (IsGPTDisk) { if (SPPT_IS_RECOGNIZED_FILESYSTEM(pRegion->Filesystem)) { // // TBD : Fix for cases where FT / Dynamic volumes can // reside on the GPT disk // SystemId = PARTITION_FAT32; } else { SystemId = PARTITION_ENTRY_UNUSED; } } else { SystemId = SpPtGetPartitionType(pRegion); } if (IsContainerPartition(SystemId)) { // // If this is the extended partition, we want to remove it. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Adding extended region [type %d] %lx for %lx\n", SystemId, pRegion->StartSector, pRegion->SectorCount)); if (!firstRegion) { firstRegion = pRegion; } lastRegion = pRegion; } else if ((PartitionNameIds[SystemId] == (UCHAR)(-1)) || (PartitionNameIds[SystemId] == PT(VERIT))) { // // For a recognized partition, remove it if we have already found // a firstRegion; otherwise we will start our list with this // region. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Adding recognized region [type %d] %lx for %lx\n", SystemId, pRegion->StartSector, pRegion->SectorCount)); if (!firstRegion) { firstRegion = pRegion; } lastRegion = pRegion; } else { // // If the partition is *not* recognized, and we have a list we // have been keeping, then stop before this one, otherwise // skip it. // if (firstRegion) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Stopping at unrecognized region [type %d] %lx for %lx\n", SystemId, pRegion->StartSector, pRegion->SectorCount)); break; } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Skipping unrecognized region [type %d] %lx for %lx\n", SystemId, pRegion->StartSector, pRegion->SectorCount)); } } } } // // We should have found at least one region. If we didn't then the // disk is alternating unpartitioned and unrecognized regions. In this // case, use the largest unpartitioned region. // if (firstRegion == NULL) { ULONGLONG BiggestUnpartitionedSectorCount = 0; pRegion = pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { if (!pRegion->PartitionedSpace) { if (pRegion->SectorCount > BiggestUnpartitionedSectorCount) { firstRegion = pRegion; BiggestUnpartitionedSectorCount = pRegion->SectorCount; } } } if (firstRegion == NULL) { return STATUS_DEVICE_OFF_LINE; } lastRegion = firstRegion; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "Adding single free region %lx for %lx\n", firstRegion->StartSector, firstRegion->SectorCount)); } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "first is %lx, last is %lx\n", firstRegion, lastRegion)); // // If we found exactly one region and it has a known filesystem on // it, then we don't need to do any repartitioning. We still delete // if the filesystem is unknown because later in setup there are // some checks that the Filesystem is valid for this region, so by // deleting it here we will ensure that Filesystem becomes // NewlyCreated which is considered acceptable. // // We also don't need to repartition if we have just one region // and it is already unpartitioned. // if (firstRegion == lastRegion) { SpPtDeleteBootSetsForRegion(firstRegion); if (!firstRegion->PartitionedSpace) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "One region, unpartitioned, not repartitioning\n")); *RemainingRegion = firstRegion; return STATUS_SUCCESS; } else if ((firstRegion->Filesystem == FilesystemNtfs) || (firstRegion->Filesystem == FilesystemFat) || (firstRegion->Filesystem == FilesystemFat32)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "One region, filesystem %d, not repartitioning\n", firstRegion->Filesystem)); *RemainingRegion = firstRegion; return STATUS_SUCCESS; } } // // We need to remove all the regions between firstRegion and // lastRegion. Save the start sector of firstRegion for later, // since after this call firstRegion may be invalid. // firstRegionStartSector = firstRegion->StartSector; SpPtDeletePartitionsForRemoteBoot( pDisk, firstRegion, lastRegion, FALSE // these are not extended regions ); // // Now we need to find the region occupying the space we have // freed. We scan for the region that includes firstRegionStartSector // (the region we find may start before then if there was a small free // region before it). // for (pRegion = pDisk->PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { if (pRegion->StartSector <= firstRegionStartSector) { firstRegion = pRegion; } else { break; } } // // Return this -- SpPtPrepareDisks handles the case where the // selected region is free. // *RemainingRegion = firstRegion; return STATUS_SUCCESS; } // // Hard Disk Inialize data for NEC98 // #define IPL_SIZE 0x8000 //NEC98 NTSTATUS SpInitializeHardDisk_Nec98( IN PDISK_REGION pRegionDisk ) { PHARD_DISK pHardDisk; WCHAR DevicePath[(sizeof(DISK_DEVICE_NAME_BASE)+sizeof(L"000"))/sizeof(WCHAR)]; ULONG i,bps; HANDLE Handle; NTSTATUS Sts; PUCHAR Buffer,UBuffer; ULONG buffersize; ULONG sectoraddress; PUCHAR HdutlBuffer; IO_STATUS_BLOCK IoStatusBlock; pHardDisk = &HardDisks[pRegionDisk->DiskNumber]; bps = HardDisks[pRegionDisk->DiskNumber].Geometry.BytesPerSector; Sts = SpOpenPartition0(pHardDisk->DevicePath,&Handle,TRUE); if(!NT_SUCCESS(Sts)) { return(Sts); } // // Initialize Hard Disk // if(bps==256){ bps=512; } HdutlBuffer = SpMemAlloc(IPL_SIZE); if(!HdutlBuffer) { SpMemFree(HdutlBuffer); ZwClose(Handle); return(STATUS_NO_MEMORY); } RtlZeroMemory(HdutlBuffer,IPL_SIZE); // // Clear head of hard drive, instead of Physical Format. // Sts = SpReadWriteDiskSectors(Handle,0,(ULONG)(IPL_SIZE/bps),bps,HdutlBuffer,TRUE); if(!NT_SUCCESS(Sts)) { SpMemFree(HdutlBuffer); ZwClose(Handle); return(Sts); } // // Set IPL Information // // // Write Boot Code // sectoraddress=0; switch(bps){ case 2048: buffersize=0x800; break; case 1024: buffersize=0x400; break; case 256: buffersize=0x100; break; case 512: buffersize=0x200; break; default : buffersize=0x800; //***max*** bps=0x800; } Sts = SpReadWriteDiskSectors(Handle,sectoraddress,(ULONG)(buffersize/bps),bps,x86PC98BootCode,TRUE); if(!NT_SUCCESS(Sts)) { SpMemFree(HdutlBuffer); ZwClose(Handle); return(Sts); } // // Write Volume Info // sectoraddress=1; switch(bps){ case 2048: buffersize=0x800; break; //***1sec*** case 1024: buffersize=0xc00; break; //***3sec*** case 256: buffersize=0x300; break; //***3sec*** case 512: buffersize=0x200; break; //***1sec*** default : buffersize=0x800; //***max**** } Sts = SpReadWriteDiskSectors(Handle,sectoraddress,(ULONG)(buffersize/bps),bps,HdutlBuffer,TRUE); if(!NT_SUCCESS(Sts)) { SpMemFree(HdutlBuffer); ZwClose(Handle); return(Sts); } // // Write Boot Menu // switch(bps){ case 2048: buffersize=0x2000; //***8KB*** sectoraddress=2; break; case 1024: buffersize=0x2000; //***8KB*** sectoraddress=4; break; case 256: buffersize=0x1c00; //***7KB*** sectoraddress=4; break; case 512: buffersize=0x1c00; //***7KB*** sectoraddress=2; break; default : buffersize=0x1c00; //***min*** } Sts = SpReadWriteDiskSectors(Handle,sectoraddress,(ULONG)(buffersize/bps),bps,x86PC98BootMenu,TRUE); if(!NT_SUCCESS(Sts)) { SpMemFree(HdutlBuffer); return(Sts); } // // Write NTFT Signature. // RtlZeroMemory(HdutlBuffer,bps); ((PULONG)HdutlBuffer)[0] = SpComputeSerialNumber(); ((PUSHORT)HdutlBuffer)[bps/2 - 1] = BOOT_RECORD_SIGNATURE; Sts = SpReadWriteDiskSectors(Handle,16,1,bps,HdutlBuffer,TRUE); if(!NT_SUCCESS(Sts)) { SpMemFree(HdutlBuffer); ZwClose(Handle); return(Sts); } SpMemFree(HdutlBuffer); ZwClose(Handle); // // Do ShutDown // SpDisplayScreen(SP_SCRN_INIT_REQUIRES_REBOOT_NEC98,3,4); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_REBOOT, 0 ); SpInputDrain(); while(SpInputGetKeypress() != KEY_F3) ; HalReturnToFirmware(HalRebootRoutine); return(STATUS_SUCCESS); } VOID SpReassignOnDiskOrdinals( IN PPARTITIONED_DISK pDisk ) { #if defined(NEC_98) //NEC98 PMBR_INFO pBrInfo; ULONG i; for(pBrInfo=&pDisk->MbrInfo; pBrInfo; pBrInfo=pBrInfo->Next) { for(i=0; iOnDiskMbr.PartitionTable[i]; if((pte->SystemId != PARTITION_ENTRY_UNUSED) && !IsContainerPartition(pte->SystemId)) { // // Reset real disk potition into OnDiskordinals. // RealDiskPosition value is zero origin, but partition // number start one. // pBrInfo->OnDiskOrdinals[i] = pte->RealDiskPosition + 1; } else { pBrInfo->OnDiskOrdinals[i] = 0; } } } #endif //NEC98 } // // Now, only for NEC98. // VOID SpTranslatePteInfo( IN PON_DISK_PTE pPte, IN PREAL_DISK_PTE pRealPte, IN BOOLEAN Write // into real PTE ) { ASSERT(pRealPte); ASSERT(pPte); if( Write ) { // // Initialize PTE // RtlZeroMemory(pRealPte, sizeof(REAL_DISK_PTE)); // // Copy PTE entries from real on-disk PTE. // pRealPte->ActiveFlag = pPte->ActiveFlag; pRealPte->StartHead = pPte->StartHead; pRealPte->StartSector = pPte->StartSector; pRealPte->StartCylinder = pPte->StartCylinder; pRealPte->SystemId = pPte->SystemId; pRealPte->EndHead = pPte->EndHead; pRealPte->EndSector = pPte->EndSector; pRealPte->EndCylinder = pPte->EndCylinder; RtlMoveMemory(&pRealPte->RelativeSectors, &pPte->RelativeSectors, sizeof(pPte->RelativeSectors)); //4 RtlMoveMemory(&pRealPte->SectorCount, &pPte->SectorCount, sizeof(pPte->SectorCount)); //4 } else { // // Initialize PTE // RtlZeroMemory(pPte, sizeof(ON_DISK_PTE)); // // Copy PTE entries from real on-disk PTE. // pPte->ActiveFlag = pRealPte->ActiveFlag; pPte->StartHead = pRealPte->StartHead; pPte->StartSector = pRealPte->StartSector; pPte->StartCylinder = pRealPte->StartCylinder; pPte->SystemId = pRealPte->SystemId; pPte->EndHead = pRealPte->EndHead; pPte->EndSector = pRealPte->EndSector; pPte->EndCylinder = pRealPte->EndCylinder; RtlMoveMemory(&pPte->RelativeSectors, &pRealPte->RelativeSectors, sizeof(pRealPte->RelativeSectors)); //4 RtlMoveMemory(&pPte->SectorCount, &pRealPte->SectorCount, sizeof(pPte->SectorCount)); //4 } } // // Now, only for NEC98. // VOID SpTranslateMbrInfo( IN PON_DISK_MBR pMbr, IN PREAL_DISK_MBR pRealMbr, IN ULONG bps, IN BOOLEAN Write // into real MBR ) { PREAL_DISK_PTE pRealPte; PON_DISK_PTE pPte; ULONG TmpData; ULONG i; pRealPte = pRealMbr->PartitionTable; pPte = pMbr->PartitionTable; ASSERT(pRealMbr); ASSERT(pMbr); if( Write ) { // // Initialize REAL_DISK_MBR // RtlZeroMemory(pRealMbr, sizeof(REAL_DISK_MBR)); // // Copy MBR entries into real on-disk MBR. // RtlMoveMemory(&pRealMbr->BootCode, &pMbr->BootCode, sizeof(pMbr->BootCode)); //440 RtlMoveMemory(&pRealMbr->NTFTSignature, &pMbr->NTFTSignature, sizeof(pMbr->NTFTSignature)); //4 RtlMoveMemory(&pRealMbr->Filler, &pMbr->Filler, sizeof(pMbr->Filler)); //2 RtlMoveMemory(&pRealMbr->AA55Signature, &pMbr->AA55Signature, sizeof(pMbr->AA55Signature)); //2 } else { // // Initialize ON_DISK_MBR // RtlZeroMemory(pMbr, sizeof(ON_DISK_MBR)); // // Copy MBR entries from real on-disk MBR. // RtlMoveMemory(&pMbr->BootCode, &pRealMbr->BootCode, sizeof(pMbr->BootCode)); //440 RtlMoveMemory(&pMbr->NTFTSignature, &pRealMbr->NTFTSignature, sizeof(pMbr->NTFTSignature)); //4 RtlMoveMemory(&pMbr->Filler, &pRealMbr->Filler, sizeof(pMbr->Filler)); //2 RtlMoveMemory(&pMbr->AA55Signature, &pRealMbr->AA55Signature, sizeof(pMbr->AA55Signature)); //2 } // // Translate PTEs from real on-disk PTEs. // for(i=0; iMbrInfo.OnDiskMbr.PartitionTable; for(i=0; iHardDisk->SectorsPerCylinder).LowPart; TmpData = (ULONG)(PteNec[i].EndCylinderLow + 1); // In case of Low is 0xFF, Overflowed bit will be loss by OR. TmpData += ((ULONG)PteNec[i].EndCylinderHigh << 8); U_ULONG(p[i].SectorCount) = RtlEnlargedUnsignedMultiply(TmpData, pDisk->HardDisk->SectorsPerCylinder).LowPart - U_ULONG(p[i].RelativeSectors); // // Set Ipl Address // TmpData = (ULONG)PteNec[i].IPLCylinderLow; TmpData |= ((ULONG)PteNec[i].IPLCylinderHigh << 8); TmpData = RtlEnlargedUnsignedMultiply(TmpData,pDisk->HardDisk->SectorsPerCylinder).LowPart; TmpData += (ULONG)(PteNec[i].IPLHead * pDisk->HardDisk->Geometry.SectorsPerTrack); TmpData += PteNec[i].IPLSector; U_ULONG(p[i].IPLSectors) = TmpData; } } U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = ((PUSHORT)Buffer)[bps/2 - 1]; if(bps == 256){ U_USHORT(pDisk->MbrInfo.OnDiskMbr.AA55Signature) = 0x0000; } #endif //NEC98 } #define IPL_SIGNATURE_NEC98 "IPL1" VOID SpDetermineFormatTypeNec98( IN PPARTITIONED_DISK pDisk, IN PREAL_DISK_MBR_NEC98 pRealMbrNec98 ) { UCHAR FormatType; if(!IsNEC_98) { FormatType = DISK_FORMAT_TYPE_PCAT; } else { if(pDisk->HardDisk->Characteristics & FILE_REMOVABLE_MEDIA) { // // All removable media are AT format. // FormatType = DISK_FORMAT_TYPE_PCAT; } else { if(U_USHORT(pRealMbrNec98->AA55Signature) == MBR_SIGNATURE) { if(!_strnicmp(pRealMbrNec98->IPLSignature,IPL_SIGNATURE_NEC98, sizeof(IPL_SIGNATURE_NEC98)-1)) { // // NEC98-format requires AA55Signature and "IPL1". // FormatType = DISK_FORMAT_TYPE_NEC98; } else { FormatType = DISK_FORMAT_TYPE_PCAT; } } else { FormatType = DISK_FORMAT_TYPE_UNKNOWN; } } } pDisk->HardDisk->FormatType = FormatType; #if 0 pDisk->HardDisk->MaxPartitionTables = ((FormatType == DISK_FORMAT_TYPE_PCAT) ? NUM_PARTITION_TABLE_ENTRIES : NUM_PARTITION_TABLE_ENTRIES_NEC98); #endif //0 return; } NTSTATUS SpPtSearchLocalSourcesInDynamicDisk( IN ULONG disk ) { NTSTATUS Status; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES Obja; HANDLE DirectoryHandle; BOOLEAN RestartScan; ULONG Context; BOOLEAN MoreEntries; POBJECT_DIRECTORY_INFORMATION DirInfo; // // Open the \ArcName directory. // INIT_OBJA(&Obja,&UnicodeString,HardDisks[disk].DevicePath); Status = ZwOpenDirectoryObject(&DirectoryHandle,DIRECTORY_ALL_ACCESS,&Obja); if(NT_SUCCESS(Status)) { RestartScan = TRUE; Context = 0; MoreEntries = TRUE; do { Status = SpQueryDirectoryObject( DirectoryHandle, RestartScan, &Context ); if(NT_SUCCESS(Status)) { PWSTR DirectoryName; DirInfo = (POBJECT_DIRECTORY_INFORMATION) ((PSERVICE_QUERY_DIRECTORY_OBJECT)&CommunicationParams->Buffer)->Buffer; wcsncpy(TemporaryBuffer,DirInfo->Name.Buffer,DirInfo->Name.Length / sizeof(WCHAR)); (TemporaryBuffer)[DirInfo->Name.Length/sizeof(WCHAR)] = 0; DirectoryName = SpDupStringW(TemporaryBuffer); SpStringToLower(TemporaryBuffer); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Checking directory object %ws\\%ws \n", HardDisks[disk].DevicePath, DirectoryName)); if( _wcsicmp(TemporaryBuffer,L"partition0") && wcsstr(TemporaryBuffer,L"partition") ) { FilesystemType FsType; WCHAR FsName[32]; ULONG NameId; ULONG PartitionNumber; PartitionNumber = SpStringToLong( DirectoryName + ((sizeof(L"partition") - sizeof(WCHAR)) / sizeof(WCHAR)), NULL, 10 ); FsType = SpIdentifyFileSystem( HardDisks[disk].DevicePath, HardDisks[disk].Geometry.BytesPerSector, PartitionNumber ); NameId = SP_TEXT_FS_NAME_BASE + FsType; SpFormatMessage( FsName, sizeof(FsName), NameId ); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: File system in dynamic volume %ws\\%ws is %ws. \n", HardDisks[disk].DevicePath, DirectoryName, FsName)); if( FsType >= FilesystemFirstKnown ) { PWSTR LocalSourceFiles[1] = { LocalSourceDirectory }; wcscpy( TemporaryBuffer,HardDisks[disk].DevicePath ); SpConcatenatePaths( TemporaryBuffer,DirectoryName ); if(SpNFilesExist(TemporaryBuffer,LocalSourceFiles,ELEMENT_COUNT(LocalSourceFiles),TRUE)) { // // Found local source directory // PDISK_REGION pRegion; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Found %ws in dynamic volume %ws\\%ws. \n", LocalSourceDirectory, HardDisks[disk].DevicePath, DirectoryName)); pRegion = SpPtAllocateDiskRegionStructure( disk, 0, 0, TRUE, NULL, PartitionNumber ); pRegion->DynamicVolume = TRUE; pRegion->DynamicVolumeSuitableForOS = FALSE; pRegion->IsLocalSource = TRUE; pRegion->Filesystem = FsType; LocalSourceRegion = pRegion; MoreEntries = FALSE; } } } SpMemFree( DirectoryName ); } else { MoreEntries = FALSE; if(Status == STATUS_NO_MORE_ENTRIES) { Status = STATUS_SUCCESS; } } RestartScan = FALSE; } while(MoreEntries); ZwClose(DirectoryHandle); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open %ws directory. Status = %lx\n", HardDisks[disk].DevicePath, Status)); } return( Status ); } VOID SpPtFindLocalSourceRegionOnDynamicVolumes( VOID ) { ULONG disk; PPARTITIONED_DISK partdisk; PDISK_REGION pRegion; BOOLEAN DiskIsDynamic; ULONG pass; ASSERT(HardDisksDetermined); // // For each hard disk attached to the system, read its partition table. // for(disk=0; diskPrimaryDiskRegions : partdisk->ExtendedDiskRegions); pRegion && !DiskIsDynamic; pRegion = pRegion->Next ) { if( pRegion->DynamicVolume ) { // // This is a dynamic disk. // DiskIsDynamic = TRUE; // // Scan all dynamic volumes in the disk for the $win_nt$.~ls // SpPtSearchLocalSourcesInDynamicDisk( disk ); } } } } } NTSTATUS SpPtCheckDynamicVolumeForOSInstallation( IN PDISK_REGION Region ) { NTSTATUS Status; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; PARTITION_INFORMATION PartitionInfo; ULONG bps; ULONG r; ULONG StartSector; ULONG SectorCount; ULONG RelativeSectors; ASSERT(Region->DynamicVolume); Status = SpOpenPartition( HardDisks[Region->DiskNumber].DevicePath, SpPtGetOrdinal(Region,PartitionOrdinalOnDisk), &Handle, FALSE ); #if DBG SpNtNameFromRegion( Region, TemporaryBuffer, sizeof(TemporaryBuffer), PartitionOrdinalOnDisk); #endif if( !NT_SUCCESS(Status) ) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to open dynamic volume %ws. Status = %lx\n",TemporaryBuffer, Status)); return(Status); } Status = ZwDeviceIoControlFile( Handle, NULL, NULL, NULL, &IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &PartitionInfo, sizeof(PartitionInfo) ); if(NT_SUCCESS(Status)) { bps = HardDisks[Region->DiskNumber].Geometry.BytesPerSector; RelativeSectors = 0; if( SpPtLookupRegionByStart(&PartitionedDisks[Region->DiskNumber], TRUE, Region->StartSector) == Region ) { // // The region is on an extended partition (logical drive) // PON_DISK_PTE pte; // // TBD : fix this // pte = &Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition]; RelativeSectors = U_ULONG(pte->RelativeSectors); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dynamic volume %ws is logical drive on extended partition. RelativeSectors = %lx \n",TemporaryBuffer, RelativeSectors)); } StartSector = RtlExtendedLargeIntegerDivide(PartitionInfo.StartingOffset,bps,&r).LowPart; SectorCount = RtlExtendedLargeIntegerDivide(PartitionInfo.PartitionLength,bps,&r).LowPart; Region->DynamicVolumeSuitableForOS = ((Region->StartSector + RelativeSectors) == StartSector) && ((Region->SectorCount - RelativeSectors) == SectorCount); if( Region->DynamicVolumeSuitableForOS ) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dynamic volume %ws is suitable for OS installation\n",TemporaryBuffer)); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: Dynamic volume %ws is not suitable for OS installation\n",TemporaryBuffer)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: StartSector = %lx (from MBR)\n", Region->StartSector)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SectorCount = %lx (from MBR)\n", Region->SectorCount)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: StartSector = %lx (from IOCTL_DISK_GET_PARTITION_INFO)\n", StartSector)); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SectorCount = %lx (from IOCTL_DISK_GET_PARTITION_INFO)\n", SectorCount)); } } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to get partition info for dynamic volume %ws. Status = %lx\n",TemporaryBuffer, Status)); } ZwClose(Handle); return(Status); } UCHAR SpPtGetPartitionType( IN PDISK_REGION Region ) { UCHAR SystemId = PARTITION_ENTRY_UNUSED; if (!Region->PartitionedSpace) return SystemId; #ifdef OLD_PARTITION_ENGINE SystemId = Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition].SystemId; #endif #ifdef NEW_PARTITION_ENGINE SystemId = PARTITION_FAT32; if (SPPT_IS_MBR_DISK(Region->DiskNumber)) { SystemId = SPPT_GET_PARTITION_TYPE(Region); } #endif #ifdef GPT_PARTITION_ENGINE SystemId = PARTITION_FAT32; if (SPPT_IS_MBR_DISK(Region->DiskNumber)) { SystemId = Region->MbrInfo->OnDiskMbr.PartitionTable[Region->TablePosition].SystemId; } #endif return SystemId; } BOOLEAN SpPtnIsRegionSpecialMBRPartition( IN PDISK_REGION Region ) { BOOLEAN Result = FALSE; if (Region && SPPT_IS_MBR_DISK(Region->DiskNumber) && SPPT_IS_REGION_PARTITIONED(Region)) { UCHAR PartId = PartitionNameIds[SPPT_GET_PARTITION_TYPE(Region)]; Result = (PartId != (UCHAR)0xFF) && (SPPT_GET_PARTITION_TYPE(Region) != PARTITION_LDM) && ((PartId + SP_TEXT_PARTITION_NAME_BASE) != SP_TEXT_PARTITION_NAME_UNK); } return Result; } PWSTR SpPtnGetPartitionName( IN PDISK_REGION Region, IN OUT PWSTR NameBuffer, IN ULONG NameBufferSize ) /*++ Routine Description: Formats the name of the partition, with volume label and file system type and returns it. Note : Region is assumed to be of partitioned type Arguments: Region - The region whose name is to be formatted NameBuffer - Buffer in which the name needs to be formatted NameBuffer - The size of the NameBuffer (in characters) Return Value: Formatted partition name for the region, if any. --*/ { BOOLEAN SpecialPartition = FALSE; if (NameBuffer) { if (Region) { if (SpPtnIsRegionSpecialMBRPartition(Region)) { WCHAR Buffer[128]; SpFormatMessage(Buffer, sizeof(Buffer), SP_TEXT_PARTITION_NAME_BASE + PartitionNameIds[SPPT_GET_PARTITION_TYPE(Region)]); SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_PARTNAME_DESCR_3, Region->PartitionNumber, Buffer); } else if (Region->VolumeLabel[0]) { SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_PARTNAME_DESCR_1, Region->PartitionNumber, Region->VolumeLabel, Region->TypeName); } else { SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_PARTNAME_DESCR_2, Region->PartitionNumber, Region->TypeName); } wcsncpy(NameBuffer, TemporaryBuffer, NameBufferSize - 1); NameBuffer[NameBufferSize - 1] = 0; // Null terminate } else { *NameBuffer = 0; // Null terminate } } return NameBuffer; }