/*++ 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; }