You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1087 lines
25 KiB
1087 lines
25 KiB
/*++
|
|
|
|
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 <stdio.h>
|
|
#include <string.h>
|
|
|
|
|
|
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; i<count; i++) {
|
|
|
|
sprintf(buffer, "\\device\\harddisk%u", i);
|
|
pathArray[i] = Malloc(lstrlenA(buffer)+1);
|
|
strcpy(pathArray[i], buffer);
|
|
}
|
|
|
|
*PathList = pathArray;
|
|
*ListLength = count;
|
|
return OK_STATUS;
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowFreeFdiskPathList(
|
|
IN OUT PCHAR* PathList,
|
|
IN ULONG ListLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walk the provided list up to its length and free the memory
|
|
allocated. Upon completion, free the memory for the list
|
|
itself.
|
|
|
|
Arguments:
|
|
|
|
PathList - pointer to base of path list
|
|
ListLength - number of entries in the list
|
|
|
|
Return Value:
|
|
|
|
Always OK_STATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
|
|
for (i=0; i<ListLength; i++) {
|
|
FreeMemory(PathList[i]);
|
|
}
|
|
FreeMemory(PathList);
|
|
return OK_STATUS;
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowOpenNtName(
|
|
IN PCHAR Name,
|
|
IN HANDLE_PT Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is an internal "Low" routine to handle open requests.
|
|
|
|
Arguments:
|
|
|
|
Name - pointer to the NT name for the open.
|
|
Handle - pointer for the handle returned.
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
OBJECT_ATTRIBUTES oa;
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
ANSI_STRING ansiName;
|
|
UNICODE_STRING unicodeName;
|
|
|
|
RtlInitAnsiString(&ansiName, Name);
|
|
status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
|
|
oa.Length = sizeof(OBJECT_ATTRIBUTES);
|
|
oa.ObjectName = &unicodeName;
|
|
oa.Attributes = OBJ_CASE_INSENSITIVE;
|
|
|
|
status = DmOpenFile(Handle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&oa,
|
|
&statusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
FDLOG((1,"LowOpen: 1st open failed with 0x%x\n", status));
|
|
|
|
// try a 2nd time to get around an FS glitch or a test
|
|
// bug where this doesn't work on an attempt to delete a
|
|
// partition
|
|
|
|
Sleep(500);
|
|
status = DmOpenFile(Handle,
|
|
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
|
&oa,
|
|
&statusBlock,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_SYNCHRONOUS_IO_ALERT);
|
|
FDLOG((1,"LowOpen: 2nd open 0x%x\n", status));
|
|
}
|
|
RtlFreeUnicodeString(&unicodeName);
|
|
return status;
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowOpenDriveLetter(
|
|
IN CHAR DriveLetter,
|
|
IN HANDLE_PT Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a drive letter, open it and return a handle.
|
|
|
|
Arguments:
|
|
|
|
DriveLetter - the letter to open
|
|
Handle - a pointer to a handle
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
char ntDeviceName[100];
|
|
|
|
sprintf(ntDeviceName,
|
|
"\\DosDevices\\%c:",
|
|
DriveLetter);
|
|
return LowOpenNtName(ntDeviceName, Handle);
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowOpenPartition(
|
|
IN PCHAR DevicePath,
|
|
IN ULONG Partition,
|
|
OUT HANDLE_PT Handle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Construct the NT device name for the Partition value given
|
|
and perform the NT APIs to open the device.
|
|
|
|
Arguments:
|
|
|
|
DevicePath - the string to the device without the partition
|
|
portion of the name. This is constructed using
|
|
the Partition value passed
|
|
Partition - the partion desired
|
|
Handle - pointer to a handle pointer for the result
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
char ntDeviceName[100];
|
|
|
|
sprintf(ntDeviceName,
|
|
"%s\\partition%u",
|
|
DevicePath,
|
|
Partition);
|
|
return LowOpenNtName(ntDeviceName, Handle);
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowOpenDisk(
|
|
IN PCHAR DevicePath,
|
|
OUT HANDLE_PT DiskId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the NT actions to open a device.
|
|
|
|
Arguments:
|
|
|
|
DevicePath - Ascii device name
|
|
DiskId - pointer to a handle pointer for the returned
|
|
handle value
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
return(LowOpenPartition(DevicePath, 0, DiskId));
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowCloseDisk(
|
|
IN HANDLE_T DiskId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Close a disk handle.
|
|
|
|
Arguments:
|
|
|
|
DiskId - the actual NT handle
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
return(DmClose(DiskId));
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowLockDrive(
|
|
IN HANDLE_T DiskId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the NT API to cause a volume to be locked.
|
|
This is a File System device control.
|
|
|
|
Arguments:
|
|
|
|
DiskId - the actual NT handle to the drive
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
|
|
status = NtFsControlFile(DiskId,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
FSCTL_LOCK_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
FDLOG((1, "LowLock: failed with 0x%x\n", status));
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowUnlockDrive(
|
|
IN HANDLE_T DiskId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the NT API to cause a volume to be unlocked.
|
|
This is a File System device control.
|
|
|
|
Arguments:
|
|
|
|
DiskId - the actual NT handle to the drive
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
|
|
status = NtFsControlFile(DiskId,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
FSCTL_DISMOUNT_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0);
|
|
status = NtFsControlFile(DiskId,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
FSCTL_UNLOCK_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0);
|
|
return status;
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowGetDriveGeometry(
|
|
IN PCHAR Path,
|
|
OUT PULONG TotalSectorCount,
|
|
OUT PULONG SectorSize,
|
|
OUT PULONG SectorsPerTrack,
|
|
OUT PULONG Heads
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Routine collects information concerning the geometry
|
|
of a specific drive.
|
|
|
|
Arguments:
|
|
|
|
Path - Ascii path name to get to disk object
|
|
this is not a full path, but rather
|
|
a path without the Partition indicator
|
|
\device\harddiskX
|
|
TotalSectorCount- pointer to ULONG for result
|
|
SectorSize - pointer to ULONG for result
|
|
SectorsPerTrack - pointer to ULONG for result
|
|
Heads - pointer to ULONG for result
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
IO_STATUS_BLOCK statusBlock;
|
|
DISK_GEOMETRY diskGeometry;
|
|
STATUS_CODE status;
|
|
HANDLE handle;
|
|
|
|
if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
|
|
return status;
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&diskGeometry,
|
|
sizeof(DISK_GEOMETRY));
|
|
if (!NT_SUCCESS(status)) {
|
|
return (STATUS_CODE)status;
|
|
}
|
|
LowCloseDisk(handle);
|
|
|
|
*SectorSize = diskGeometry.BytesPerSector;
|
|
*SectorsPerTrack = diskGeometry.SectorsPerTrack;
|
|
*Heads = diskGeometry.TracksPerCylinder;
|
|
*TotalSectorCount = (RtlExtendedIntegerMultiply(diskGeometry.Cylinders,
|
|
*SectorsPerTrack * *Heads)).LowPart;
|
|
return(OK_STATUS);
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowGetDiskLayout(
|
|
IN PCHAR Path,
|
|
OUT PDRIVE_LAYOUT_INFORMATION *DriveLayout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the necessary NT API calls to get the drive
|
|
layout from the disk and return it in a memory buffer
|
|
allocated by this routine.
|
|
|
|
Arguments:
|
|
|
|
Path - Ascii path name to get to disk object
|
|
this is not a full path, but rather
|
|
a path without the Partition indicator
|
|
\device\harddiskX
|
|
|
|
DriveLayout - pointer to pointer for the drive layout result
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
PDRIVE_LAYOUT_INFORMATION layout;
|
|
IO_STATUS_BLOCK statusBlock;
|
|
STATUS_CODE status;
|
|
ULONG bufferSize;
|
|
HANDLE handle;
|
|
|
|
bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
|
|
+ (500 * sizeof(PARTITION_INFORMATION));
|
|
|
|
if ((layout = AllocateMemory(bufferSize)) == NULL) {
|
|
RETURN_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
|
|
FreeMemory(layout);
|
|
return status;
|
|
}
|
|
|
|
status = NtDeviceIoControlFile(handle,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
&statusBlock,
|
|
IOCTL_DISK_GET_DRIVE_LAYOUT,
|
|
NULL,
|
|
0,
|
|
layout,
|
|
bufferSize);
|
|
LowCloseDisk(handle);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
if (status == STATUS_BAD_MASTER_BOOT_RECORD) {
|
|
|
|
FDLOG((1,"LowGetDiskLayout: Disk device %s has bad MBR\n",Path));
|
|
|
|
// Zero the drive layout information for the fdengine to process.
|
|
|
|
RtlZeroMemory(layout, bufferSize);
|
|
} else {
|
|
FDLOG((0,"LowGetDiskLayout: Status %lx getting layout for disk device %s\n",status,Path));
|
|
FreeMemory(layout);
|
|
return status;
|
|
}
|
|
} else {
|
|
|
|
FDLOG((2,"LowGetDiskLayout: layout received from ioctl for %s follows:\n",Path));
|
|
LOG_DRIVE_LAYOUT(layout);
|
|
}
|
|
|
|
// Check to insure that the drive supports dynamic partitioning.
|
|
|
|
*DriveLayout = layout;
|
|
return OK_STATUS;
|
|
}
|
|
|
|
|
|
STATUS_CODE
|
|
LowSetDiskLayout(
|
|
IN PCHAR Path,
|
|
IN PDRIVE_LAYOUT_INFORMATION DriveLayout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Perform the NT API actions of opening Partition0 for
|
|
the specified drive and setting the drive layout.
|
|
|
|
Arguments:
|
|
|
|
Path - Ascii path name to get to disk object
|
|
this is not a full path, but rather
|
|
a path without the Partition indicator
|
|
\device\harddiskX
|
|
|
|
DriveLayout - new layout to set
|
|
|
|
Return Value:
|
|
|
|
NT status
|
|
|
|
--*/
|
|
|
|
{
|
|
IO_STATUS_BLOCK statusBlock;
|
|
STATUS_CODE status;
|
|
HANDLE handle;
|
|
ULONG bufferSize;
|
|
|
|
if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
|
|
|
|
return status;
|
|
} else {
|
|
|
|
FDLOG((2, "LowSetDiskLayout: calling ioctl for %s, layout follows:\n", Path));
|
|
LOG_DRIVE_LAYOUT(DriveLayout);
|
|
}
|
|
|
|
bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
|
|
+ ( (DriveLayout->PartitionCount - 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);
|
|
}
|