/*++ Copyright (c) 1991-1994 Microsoft Corporation Module Name: ntlow.c Abstract: This file contains the low-level I/O routines, implemented to run on NT. Author: Ted Miller (tedm) 8-Nov-1991 Revision History: Bob Rinne (bobri) 2-Feb-1994 Dynamic partitioning changes. --*/ #include "fdisk.h" #include #include STATUS_CODE LowQueryFdiskPathList( OUT PCHAR **PathList, OUT PULONG ListLength ) /*++ Routine Description: This routine determines how many drives are present in the system and returns a list of Ascii strings for the names of each of the drives found. When a drive is located, a check is made to insure that the associated DosName for the physical drive is also present in the system. Arguments: PathList - pointer to a pointer for the list ListLength - the number of entries returned in the list Return Value: Error status if there is a problem. --*/ { HANDLE dummyHandle; STATUS_CODE status; ULONG count = 0; ULONG i; char buffer[100]; PCHAR *pathArray; while (1) { sprintf(buffer, "\\device\\harddisk%u", count); status = LowOpenDisk(buffer, &dummyHandle); // Only STATUS_OBJECT_PATH_NOT_FOUND can terminate the count. if (NT_SUCCESS(status)) { char dosNameBuffer[80]; LowCloseDisk(dummyHandle); // Insure that the physicaldrive name is present sprintf(dosNameBuffer, "\\dosdevices\\PhysicalDrive%u", count); status = LowOpenNtName(dosNameBuffer, &dummyHandle); if (NT_SUCCESS(status)) { LowCloseDisk(dummyHandle); } else { // Not there, create it. sprintf(buffer, "\\device\\harddisk%u\\Partition0", count); DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) dosNameBuffer, (LPCTSTR) buffer); } } else if (status == STATUS_OBJECT_PATH_NOT_FOUND) { break; } else if (status == STATUS_ACCESS_DENIED) { return status; } count++; } pathArray = Malloc(count * sizeof(PCHAR)); for (i=0; iPartitionCount - 1) * sizeof(PARTITION_INFORMATION)); status = NtDeviceIoControlFile(handle, 0, NULL, NULL, &statusBlock, IOCTL_DISK_SET_DRIVE_LAYOUT, DriveLayout, bufferSize, DriveLayout, bufferSize); LowCloseDisk(handle); return status; } STATUS_CODE LowWriteSectors( IN HANDLE_T VolumeId, IN ULONG SectorSize, IN ULONG StartingSector, IN ULONG NumberOfSectors, IN PVOID Buffer ) /*++ Routine Description: Routine to write to a volume handle. This routine insulates the NT issues concerning the call from the caller. Arguments: VolumeId - actually the NT handle. SectorSize - used to calculate starting byte offset for I/O StartingSector - starting sector for write. NumberOfSectors - size of I/O in sectors Buffer - the location for the data Return Value: Standard NT status values --*/ { IO_STATUS_BLOCK statusBlock; LARGE_INTEGER byteOffset; byteOffset = RtlExtendedIntegerMultiply(RtlConvertUlongToLargeInteger(StartingSector), (LONG)SectorSize); statusBlock.Status = 0; statusBlock.Information = 0; return(NtWriteFile(VolumeId, 0, NULL, NULL, &statusBlock, Buffer, NumberOfSectors * SectorSize, &byteOffset, NULL)); } STATUS_CODE LowReadSectors( IN HANDLE_T VolumeId, IN ULONG SectorSize, IN ULONG StartingSector, IN ULONG NumberOfSectors, IN PVOID Buffer ) /*++ Routine Description: Routine to read from a volume handle. This routine insulates the NT issues concerning the call from the caller. Arguments: VolumeId - actually the NT handle. SectorSize - used to calculate starting byte offset for I/O StartingSector - starting sector for write. NumberOfSectors - size of I/O in sectors Buffer - the location for the data Return Value: Standard NT status values --*/ { IO_STATUS_BLOCK statusBlock; LARGE_INTEGER byteOffset; byteOffset = RtlExtendedIntegerMultiply(RtlConvertUlongToLargeInteger(StartingSector), (LONG)SectorSize); statusBlock.Status = 0; statusBlock.Information = 0; return(NtReadFile(VolumeId, 0, NULL, NULL, &statusBlock, Buffer, NumberOfSectors * SectorSize, &byteOffset, NULL)); } STATUS_CODE LowFtVolumeStatus( IN ULONG Disk, IN ULONG Partition, IN PFT_SET_STATUS FtStatus, IN PULONG NumberOfMembers ) /*++ Routine Description: Open the requested partition and query the FT state. Arguments: DriveLetter - the letter for the current state FtState - a pointer to a location to return state NumberOfMembers - a pointer to a ULONG for number of members in the FT set. Return Value: Standard NT status values --*/ { HANDLE handle; STATUS_CODE status; IO_STATUS_BLOCK statusBlock; FT_SET_INFORMATION setInfo; status = LowOpenPartition(GetDiskName(Disk), Partition, &handle); if (status == OK_STATUS) { status = NtDeviceIoControlFile(handle, 0, NULL, NULL, &statusBlock, FT_QUERY_SET_STATE, NULL, 0, &setInfo, sizeof(setInfo)); LowCloseDisk(handle); if (status == OK_STATUS) { switch (setInfo.SetState) { case FtStateOk: *FtStatus = FtSetHealthy; break; case FtHasOrphan: switch (setInfo.Type) { case Mirror: *FtStatus = FtSetBroken; break; case StripeWithParity: *FtStatus = FtSetRecoverable; break; } break; case FtRegenerating: *FtStatus = FtSetRegenerating; break; case FtCheckParity: *FtStatus = FtSetInitializationFailed; break; case FtInitializing: *FtStatus = FtSetInitializing; break; case FtDisabled: // This will never happen. *FtStatus = FtSetDisabled; break; case FtNoCheckData: default: // BUGBUG: there is no mapping here. *FtStatus = FtSetHealthy; break; } *NumberOfMembers = setInfo.NumberOfMembers; } } else { // If the FT set could not be opened, then it must be // disabled if the return code is "No such device". if (status == 0xc000000e) { *FtStatus = FtSetDisabled; status = OK_STATUS; } } // Always update the state to the caller. return status; } STATUS_CODE LowFtVolumeStatusByLetter( IN CHAR DriveLetter, IN PFT_SET_STATUS FtStatus, IN PULONG NumberOfMembers ) /*++ Routine Description: Open the requested drive letter and query the FT state. Arguments: DriveLetter - the letter for the current state FtState - a pointer to a location to return state NumberOfMembers - a pointer to a ULONG for number of members in the FT set. Return Value: Standard NT status values --*/ { HANDLE handle; STATUS_CODE status; IO_STATUS_BLOCK statusBlock; FT_SET_INFORMATION setInfo; *NumberOfMembers = 1; status = LowOpenDriveLetter(DriveLetter, &handle); if (status == OK_STATUS) { status = NtDeviceIoControlFile(handle, 0, NULL, NULL, &statusBlock, FT_QUERY_SET_STATE, NULL, 0, &setInfo, sizeof(setInfo)); LowCloseDisk(handle); if (status == OK_STATUS) { switch (setInfo.SetState) { case FtStateOk: *FtStatus = FtSetHealthy; break; case FtHasOrphan: switch (setInfo.Type) { case Mirror: *FtStatus = FtSetBroken; break; case StripeWithParity: *FtStatus = FtSetRecoverable; break; } break; case FtRegenerating: *FtStatus = FtSetRegenerating; break; case FtCheckParity: *FtStatus = FtSetInitializationFailed; break; case FtInitializing: *FtStatus = FtSetInitializing; break; case FtDisabled: // This will never happen. *FtStatus = FtSetDisabled; break; case FtNoCheckData: default: // BUGBUG: there is no mapping here. *FtStatus = FtSetHealthy; break; } *NumberOfMembers = setInfo.NumberOfMembers; } } else { // If the FT set could not be opened, then it must be // disabled if the return code is "No such device". if (status == 0xc000000e) { *FtStatus = FtSetDisabled; status = OK_STATUS; } } // Always update the state to the caller. return status; } #define NUMBER_OF_HANDLES_TRACKED 500 HANDLE OpenHandleArray[NUMBER_OF_HANDLES_TRACKED]; BOOLEAN DmFirstTime = TRUE; ULONG HandleHighWaterMark = 0; NTSTATUS DmOpenFile( OUT PHANDLE FileHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG ShareAccess, IN ULONG OpenOptions ) /*++ Routine Description: A debugging aid to track open and closes of partitions. Arguments: Same as for NtOpenFile() Return Value: Same as for NtOpenFile() --*/ { ULONG index; NTSTATUS status; if (DmFirstTime) { DmFirstTime = FALSE; for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) { OpenHandleArray[index] = (HANDLE) 0; } } status = NtOpenFile(FileHandle, DesiredAccess, ObjectAttributes, IoStatusBlock, ShareAccess, OpenOptions); if (NT_SUCCESS(status)) { for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) { if (OpenHandleArray[index] == (HANDLE) 0) { OpenHandleArray[index] = *FileHandle; if (index > HandleHighWaterMark) { HandleHighWaterMark = index; } break; } } } return status; } NTSTATUS DmClose( IN HANDLE Handle ) /*++ Routine Description: A debugging aid for tracking open and closes Arguments: Same as for NtClose() Return Value: Same as for NtClose() --*/ { ULONG index; for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) { if (OpenHandleArray[index] == Handle) { OpenHandleArray[index] = (HANDLE) 0; break; } } return NtClose(Handle); }