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.
596 lines
14 KiB
596 lines
14 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
VolInfo.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the volume information routines for Raw called by
|
|
the dispatch driver.
|
|
|
|
Author:
|
|
|
|
Gary Kimura [GaryKi] 28-Dec-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "RawProcs.h"
|
|
|
|
NTSTATUS
|
|
RawQueryFsVolumeInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_VOLUME_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
RawQueryFsSizeInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_SIZE_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
RawQueryFsDeviceInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_DEVICE_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
RawQueryFsAttributeInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, RawQueryVolumeInformation)
|
|
#pragma alloc_text(PAGE, RawQueryFsVolumeInfo)
|
|
#pragma alloc_text(PAGE, RawQueryFsSizeInfo)
|
|
#pragma alloc_text(PAGE, RawQueryFsDeviceInfo)
|
|
#pragma alloc_text(PAGE, RawQueryFsAttributeInfo)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
RawQueryVolumeInformation (
|
|
IN PVCB Vcb,
|
|
IN PIRP Irp,
|
|
IN PIO_STACK_LOCATION IrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the NtQueryVolumeInformation API call.
|
|
|
|
Arguments:
|
|
|
|
Vcb - Supplies the volume being queried.
|
|
|
|
Irp - Supplies the Irp being processed.
|
|
|
|
IrpSp - Supplies parameters describing the read
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The status for the Irp.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
ULONG Length;
|
|
FS_INFORMATION_CLASS FsInformationClass;
|
|
PVOID Buffer;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Reference our input parameters to make things easier
|
|
//
|
|
|
|
Length = IrpSp->Parameters.QueryVolume.Length;
|
|
FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
|
|
Buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Based on the information class we'll do different actions. Each
|
|
// of the procedures that we're calling fills up the output buffer
|
|
// if possible and returns true if it successfully filled the buffer
|
|
// and false if it couldn't wait for any I/O to complete.
|
|
//
|
|
|
|
switch (FsInformationClass) {
|
|
|
|
case FileFsVolumeInformation:
|
|
|
|
Status = RawQueryFsVolumeInfo( Vcb, Buffer, &Length );
|
|
break;
|
|
|
|
case FileFsSizeInformation:
|
|
|
|
Status = RawQueryFsSizeInfo( Vcb, Buffer, &Length );
|
|
break;
|
|
|
|
case FileFsDeviceInformation:
|
|
|
|
Status = RawQueryFsDeviceInfo( Vcb, Buffer, &Length );
|
|
break;
|
|
|
|
case FileFsAttributeInformation:
|
|
|
|
Status = RawQueryFsAttributeInfo( Vcb, Buffer, &Length );
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the information field to the number of bytes actually filled in,
|
|
// and complete the request.
|
|
//
|
|
|
|
Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
|
|
|
|
RawCompleteRequest( Irp, Status );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
NTSTATUS
|
|
RawQueryFsVolumeInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_VOLUME_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the query volume info call
|
|
|
|
Arguments:
|
|
|
|
Vcb - Supplies the Vcb being queried
|
|
|
|
Buffer - Supplies a pointer to the output buffer where the information
|
|
is to be returned
|
|
|
|
Length - Supplies the length of the buffer in byte. This variable
|
|
upon return recieves the remaining bytes free in the buffer
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Returns the status for the query
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Zero out the buffer, then extract and fill up the non zero fields.
|
|
//
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_FS_VOLUME_INFORMATION) );
|
|
|
|
Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
|
|
|
|
Buffer->SupportsObjects = FALSE;
|
|
|
|
Buffer->VolumeLabelLength = 0;
|
|
|
|
*Length -= FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel[0]);
|
|
|
|
//
|
|
// Set our status and return to our caller
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
NTSTATUS
|
|
RawQueryFsSizeInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_SIZE_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the query volume size call
|
|
|
|
Arguments:
|
|
|
|
Vcb - Supplies the Vcb being queried
|
|
|
|
Buffer - Supplies a pointer to the output buffer where the information
|
|
is to be returned
|
|
|
|
Length - Supplies the length of the buffer in byte. This variable
|
|
upon return recieves the remaining bytes free in the buffer
|
|
|
|
Return Value:
|
|
|
|
Status - Returns the status for the query
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP Irp;
|
|
KEVENT Event;
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
PDEVICE_OBJECT RealDevice;
|
|
|
|
DISK_GEOMETRY DiskGeometry;
|
|
PARTITION_INFORMATION PartitionInformation;
|
|
GET_LENGTH_INFORMATION GetLengthInformation;
|
|
|
|
BOOLEAN DriveIsPartitioned;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Make sure the buffer is large enough
|
|
//
|
|
|
|
if (*Length < sizeof(FILE_FS_SIZE_INFORMATION)) {
|
|
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_FS_SIZE_INFORMATION) );
|
|
|
|
//
|
|
// Prepare for our device control below. The device drivers only
|
|
// have to copy geometry and partition info from in-memory strucures,
|
|
// so it is OK to make these calls even when we can't wait.
|
|
//
|
|
|
|
KeInitializeEvent( &Event, NotificationEvent, FALSE );
|
|
RealDevice = Vcb->Vpb->RealDevice;
|
|
|
|
//
|
|
// Query the disk geometry
|
|
//
|
|
|
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
RealDevice,
|
|
NULL,
|
|
0,
|
|
&DiskGeometry,
|
|
sizeof(DISK_GEOMETRY),
|
|
FALSE,
|
|
&Event,
|
|
&Iosb );
|
|
|
|
if ( Irp == NULL ) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if ( (Status = IoCallDriver( RealDevice, Irp )) == STATUS_PENDING ) {
|
|
|
|
(VOID) KeWaitForSingleObject( &Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER)NULL );
|
|
|
|
Status = Iosb.Status;
|
|
}
|
|
|
|
//
|
|
// If this call didn't succeed, the drive hasn't even been low-level
|
|
// formatted, and thus geometry information is undefined.
|
|
//
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
|
|
*Length = 0;
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// See if we have to check the partition information (floppy disks are
|
|
// the only type that can't have partitions )
|
|
//
|
|
|
|
if ( FlagOn( RealDevice->Characteristics, FILE_FLOPPY_DISKETTE )) {
|
|
|
|
DriveIsPartitioned = FALSE;
|
|
PartitionInformation.PartitionLength.QuadPart = 0;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Query the length info.
|
|
//
|
|
|
|
KeResetEvent( &Event );
|
|
|
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_LENGTH_INFO,
|
|
RealDevice,
|
|
NULL,
|
|
0,
|
|
&GetLengthInformation,
|
|
sizeof(GET_LENGTH_INFORMATION),
|
|
FALSE,
|
|
&Event,
|
|
&Iosb );
|
|
|
|
if ( Irp == NULL ) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if ( (Status = IoCallDriver( RealDevice, Irp )) == STATUS_PENDING ) {
|
|
|
|
(VOID) KeWaitForSingleObject( &Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER)NULL );
|
|
|
|
Status = Iosb.Status;
|
|
}
|
|
|
|
PartitionInformation.PartitionLength = GetLengthInformation.Length;
|
|
|
|
if ( !NT_SUCCESS (Status) ) {
|
|
|
|
//
|
|
// Query the partition table
|
|
//
|
|
|
|
KeResetEvent( &Event );
|
|
|
|
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO,
|
|
RealDevice,
|
|
NULL,
|
|
0,
|
|
&PartitionInformation,
|
|
sizeof(PARTITION_INFORMATION),
|
|
FALSE,
|
|
&Event,
|
|
&Iosb );
|
|
|
|
if ( Irp == NULL ) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if ( (Status = IoCallDriver( RealDevice, Irp )) == STATUS_PENDING ) {
|
|
|
|
(VOID) KeWaitForSingleObject( &Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
(PLARGE_INTEGER)NULL );
|
|
|
|
Status = Iosb.Status;
|
|
}
|
|
|
|
//
|
|
// If we get back invalid device request, the disk is not partitioned
|
|
//
|
|
|
|
if ( !NT_SUCCESS (Status) ) {
|
|
|
|
DriveIsPartitioned = FALSE;
|
|
|
|
} else {
|
|
|
|
DriveIsPartitioned = TRUE;
|
|
}
|
|
|
|
} else {
|
|
|
|
DriveIsPartitioned = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the output buffer
|
|
//
|
|
|
|
Buffer->BytesPerSector = DiskGeometry.BytesPerSector;
|
|
|
|
Buffer->SectorsPerAllocationUnit = 1;
|
|
|
|
//
|
|
// Now, based on whether the disk is partitioned, compute the
|
|
// total number of sectors on this disk.
|
|
//
|
|
|
|
Buffer->TotalAllocationUnits =
|
|
Buffer->AvailableAllocationUnits = ( DriveIsPartitioned == TRUE ) ?
|
|
|
|
RtlExtendedLargeIntegerDivide( PartitionInformation.PartitionLength,
|
|
DiskGeometry.BytesPerSector,
|
|
NULL )
|
|
|
|
:
|
|
|
|
RtlExtendedIntegerMultiply( DiskGeometry.Cylinders,
|
|
DiskGeometry.TracksPerCylinder *
|
|
DiskGeometry.SectorsPerTrack );
|
|
|
|
//
|
|
// Adjust the length variable
|
|
//
|
|
|
|
*Length -= sizeof(FILE_FS_SIZE_INFORMATION);
|
|
|
|
//
|
|
// And return success to our caller
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
NTSTATUS
|
|
RawQueryFsDeviceInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_DEVICE_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the query volume device call
|
|
|
|
Arguments:
|
|
|
|
Vcb - Supplies the Vcb being queried
|
|
|
|
Buffer - Supplies a pointer to the output buffer where the information
|
|
is to be returned
|
|
|
|
Length - Supplies the length of the buffer in byte. This variable
|
|
upon return recieves the remaining bytes free in the buffer
|
|
|
|
Return Value:
|
|
|
|
Status - Returns the status for the query
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Make sure the buffer is large enough
|
|
//
|
|
|
|
if (*Length < sizeof(FILE_FS_DEVICE_INFORMATION)) {
|
|
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_FS_DEVICE_INFORMATION) );
|
|
|
|
//
|
|
// Set the output buffer
|
|
//
|
|
|
|
Buffer->DeviceType = FILE_DEVICE_DISK;
|
|
|
|
Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
|
|
|
|
//
|
|
// Adjust the length variable
|
|
//
|
|
|
|
*Length -= sizeof(FILE_FS_DEVICE_INFORMATION);
|
|
|
|
//
|
|
// And return success to our caller
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Internal support routine
|
|
//
|
|
|
|
NTSTATUS
|
|
RawQueryFsAttributeInfo (
|
|
IN PVCB Vcb,
|
|
IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the query volume attribute call
|
|
|
|
Arguments:
|
|
|
|
Vcb - Supplies the Vcb being queried
|
|
|
|
Buffer - Supplies a pointer to the output buffer where the information
|
|
is to be returned
|
|
|
|
Length - Supplies the length of the buffer in byte. This variable
|
|
upon return recieves the remaining bytes free in the buffer
|
|
|
|
Return Value:
|
|
|
|
Status - Returns the status for the query
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG LengthUsed;
|
|
|
|
UNREFERENCED_PARAMETER( Vcb );
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Check if the buffer we're given is long enough to contain "Raw"
|
|
//
|
|
|
|
LengthUsed = FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName[0]) + 6;
|
|
|
|
if (*Length < LengthUsed) {
|
|
|
|
return STATUS_BUFFER_OVERFLOW;
|
|
}
|
|
|
|
//
|
|
// Set the output buffer
|
|
//
|
|
|
|
Buffer->FileSystemAttributes = 0;
|
|
Buffer->MaximumComponentNameLength = 0;
|
|
Buffer->FileSystemNameLength = 6;
|
|
RtlCopyMemory( &Buffer->FileSystemName[0], L"RAW", 6 );
|
|
|
|
//
|
|
// Adjust the length variable
|
|
//
|
|
|
|
*Length -= LengthUsed;
|
|
|
|
//
|
|
// And return success to our caller
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|