556 lines
12 KiB
C
556 lines
12 KiB
C
/*++
|
||
|
||
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_EX PartitionInformation;
|
||
|
||
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;
|
||
|
||
} else {
|
||
|
||
//
|
||
// Query the partition table
|
||
//
|
||
|
||
KeResetEvent( &Event );
|
||
|
||
Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO_EX,
|
||
RealDevice,
|
||
NULL,
|
||
0,
|
||
&PartitionInformation,
|
||
sizeof(PARTITION_INFORMATION_EX),
|
||
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;
|
||
}
|
||
}
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|