text: /*++
  
  Copyright (c) 1989-2000 Microsoft Corporation
  
  Module Name:
  
      VolInfo.c
  
  Abstract:
  
      This module implements the volume information routines for Cdfs called by
      the dispatch driver.
  
  // @@BEGIN_DDKSPLIT
  
  Author:
  
      Brian Andrew    [BrianAn]   01-July-1995
  
  Revision History:
  
  // @@END_DDKSPLIT
  
  --*/
  
  #include "CdProcs.h"
  
  //
  //  The Bug check file id for this module
  //
  
  #define BugCheckFileId                   (CDFS_BUG_CHECK_VOLINFO)
  
  //
  //  Local support routines
  //
  
  NTSTATUS
  CdQueryFsVolumeInfo (
      IN PIRP_CONTEXT IrpContext,
      IN PVCB Vcb,
      IN PFILE_FS_VOLUME_INFORMATION Buffer,
      IN OUT PULONG Length
      );
  
  NTSTATUS
  CdQueryFsSizeInfo (
      IN PIRP_CONTEXT IrpContext,
      IN PVCB Vcb,
      IN PFILE_FS_SIZE_INFORMATION Buffer,
      IN OUT PULONG Length
      );
  
  NTSTATUS
  CdQueryFsDeviceInfo (
      IN PIRP_CONTEXT IrpContext,
      IN PVCB Vcb,
      IN PFILE_FS_DEVICE_INFORMATION Buffer,
      IN OUT PULONG Length
      );
  
  NTSTATUS
  CdQueryFsAttributeInfo (
      IN PIRP_CONTEXT IrpContext,
      IN PVCB Vcb,
      IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer,
      IN OUT PULONG Length
      );
  
  #ifdef ALLOC_PRAGMA
  #pragma alloc_text(PAGE, CdCommonQueryVolInfo)
  #pragma alloc_text(PAGE, CdQueryFsAttributeInfo)
  #pragma alloc_text(PAGE, CdQueryFsDeviceInfo)
  #pragma alloc_text(PAGE, CdQueryFsSizeInfo)
  #pragma alloc_text(PAGE, CdQueryFsVolumeInfo)
  #endif
  
  
  NTSTATUS
  CdCommonQueryVolInfo (
      IN PIRP_CONTEXT IrpContext,
      IN PIRP Irp
      )
  
  /*++
  
  Routine Description:
  
      This is the common routine for querying volume information called by both
      the fsd and fsp threads.
  
  Arguments:
  
      Irp - Supplies the Irp being processed
  
  Return Value:
  
      NTSTATUS - The return status for the operation
  
  --*/
  
  {
      NTSTATUS Status = STATUS_INVALID_PARAMETER;
      PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  
      ULONG Length;
  
      TYPE_OF_OPEN TypeOfOpen;
      PFCB Fcb;
      PCCB Ccb;
  
      PAGED_CODE();
  
      //
      //  Reference our input parameters to make things easier
      //
  
      Length = IrpSp->Parameters.QueryVolume.Length;
  
      //
      //  Decode the file object and fail if this an unopened file object.
      //
  
      TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
  
      if (TypeOfOpen == UnopenedFileObject) {
  
          CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
          return STATUS_INVALID_PARAMETER;
      }
  
      //
      //  Acquire the Vcb for this volume.
      //
  
      CdAcquireVcbShared( IrpContext, Fcb->Vcb, FALSE );
  
      //
      //  Use a try-finally to facilitate cleanup.
      //
  
      try {
  
          //
          //  Verify the Vcb.
          //
  
          CdVerifyVcb( IrpContext, Fcb->Vcb );
  
          //
          //  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 (IrpSp->Parameters.QueryVolume.FsInformationClass) {
  
          case FileFsSizeInformation:
  
              Status = CdQueryFsSizeInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
              break;
  
          case FileFsVolumeInformation:
  
              Status = CdQueryFsVolumeInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
              break;
  
          case FileFsDeviceInformation:
  
              Status = CdQueryFsDeviceInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
              break;
  
          case FileFsAttributeInformation:
  
              Status = CdQueryFsAttributeInfo( IrpContext, Fcb->Vcb, Irp->AssociatedIrp.SystemBuffer, &Length );
              break;
          }
  
          //
          //  Set the information field to the number of bytes actually filled in
          //
  
          Irp->IoStatus.Information = IrpSp->Parameters.QueryVolume.Length - Length;
  
      } finally {
  
          //
          //  Release the Vcb.
          //
  
          CdReleaseVcb( IrpContext, Fcb->Vcb );
      }
  
      //
      //  Complete the request if we didn't raise.
      //
  
      CdCompleteRequest( IrpContext, Irp, Status );
  
      return Status;
  }
  
  
  //
  //  Local support routine
  //
  
  NTSTATUS
  CdQueryFsVolumeInfo (
      IN PIRP_CONTEXT IrpContext,
      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 - Vcb for this volume.
  
      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
  
  --*/
  
  {
      ULONG BytesToCopy;
  
      NTSTATUS Status = STATUS_SUCCESS;
  
      PAGED_CODE();
  
      //
      //  Fill in the data from the Vcb.
      //
  
      Buffer->VolumeCreationTime = *((PLARGE_INTEGER) &Vcb->VolumeDasdFcb->CreationTime);
      Buffer->VolumeSerialNumber = Vcb->Vpb->SerialNumber;
  
      Buffer->SupportsObjects = FALSE;
  
      *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel[0] );
  
      //
      //  Check if the buffer we're given is long enough
      //
  
      if (*Length >= (ULONG) Vcb->Vpb->VolumeLabelLength) {
  
          BytesToCopy = Vcb->Vpb->VolumeLabelLength;
  
      } else {
  
          BytesToCopy = *Length;
  
          Status = STATUS_BUFFER_OVERFLOW;
      }
  
      //
      //  Copy over what we can of the volume label, and adjust *Length
      //
  
      Buffer->VolumeLabelLength = BytesToCopy;
  
      if (BytesToCopy) {
  
          RtlCopyMemory( &Buffer->VolumeLabel[0],
                         &Vcb->Vpb->VolumeLabel[0],
                         BytesToCopy );
      }
  
      *Length -= BytesToCopy;
  
      //
      //  Set our status and return to our caller
      //
  
      return Status;
  }
  
  
  //
  //  Local support routine
  //
  
  NTSTATUS
  CdQueryFsSizeInfo (
      IN PIRP_CONTEXT IrpContext,
      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 - Vcb for this volume.
  
      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();
  
      //
      //  Fill in the output buffer.
      //
  
      Buffer->TotalAllocationUnits.QuadPart = LlSectorsFromBytes( Vcb->VolumeDasdFcb->AllocationSize.QuadPart );
  
      Buffer->AvailableAllocationUnits.QuadPart = 0;
      Buffer->SectorsPerAllocationUnit = 1;
      Buffer->BytesPerSector = SECTOR_SIZE;
  
      //
      //  Adjust the length variable
      //
  
      *Length -= sizeof( FILE_FS_SIZE_INFORMATION );
  
      //
      //  And return success to our caller
      //
  
      return STATUS_SUCCESS;
  }
  
  
  //
  //  Local support routine
  //
  
  NTSTATUS
  CdQueryFsDeviceInfo (
      IN PIRP_CONTEXT IrpContext,
      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 - Vcb for this volume.
  
      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();
  
      //
      //  Update the output buffer.
      //
  
      Buffer->Characteristics = Vcb->TargetDeviceObject->Characteristics;
      Buffer->DeviceType = FILE_DEVICE_CD_ROM;
  
      //
      //  Adjust the length variable
      //
  
      *Length -= sizeof( FILE_FS_DEVICE_INFORMATION );
  
      //
      //  And return success to our caller
      //
  
      return STATUS_SUCCESS;
  }
  
  
  //
  //  Local support routine
  //
  
  NTSTATUS
  CdQueryFsAttributeInfo (
      IN PIRP_CONTEXT IrpContext,
      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 - Vcb for this volume.
  
      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
  
  --*/
  
  {
      ULONG BytesToCopy;
  
      NTSTATUS Status = STATUS_SUCCESS;
  
      PAGED_CODE();
  
      //
      //  Fill out the fixed portion of the buffer.
      //
  
      Buffer->FileSystemAttributes = FILE_CASE_SENSITIVE_SEARCH |
  				   FILE_READ_ONLY_VOLUME;
  
      if (FlagOn( IrpContext->Vcb->VcbState, VCB_STATE_JOLIET )) {
  
          SetFlag( Buffer->FileSystemAttributes, FILE_UNICODE_ON_DISK );
  
          Buffer->MaximumComponentNameLength = 110;
  
      } else {
  
          Buffer->MaximumComponentNameLength = 221;
      }
  
      *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName );
  
      //
      //  Make sure we can copy full unicode characters.
      //
  
      ClearFlag( *Length, 1 );
  
      //
      //  Determine how much of the file system name will fit.
      //
  
      if (*Length >= 8) {
  
          BytesToCopy = 8;
  
      } else {
  
          BytesToCopy = *Length;
          Status = STATUS_BUFFER_OVERFLOW;
      }
  
      *Length -= BytesToCopy;
  
      //
      //  Do the file system name.
      //
  
      Buffer->FileSystemNameLength = BytesToCopy;
  
      RtlCopyMemory( &Buffer->FileSystemName[0], L"CDFS", BytesToCopy );
  
      //
      //  And return to our caller
      //
  
      return Status;
  }
  