text: /*++
  
  Copyright (c) 1989-2000 Microsoft Corporation
  
  Module Name:
  
      FileInfo.c
  
  Abstract:
  
      This module implements the File Information routines for Cdfs called by
      the Fsd/Fsp dispatch drivers.
  
  
  --*/
  
  #include "CdProcs.h"
  
  //
  //  The Bug check file id for this module
  //
  
  #define BugCheckFileId                   (CDFS_BUG_CHECK_FILEINFO)
  
  //
  //  Local support routines
  //
  
  VOID
  CdQueryBasicInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_BASIC_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  VOID
  CdQueryStandardInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_STANDARD_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  VOID
  CdQueryInternalInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_INTERNAL_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  VOID
  CdQueryEaInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_EA_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  VOID
  CdQueryPositionInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFILE_OBJECT FileObject,
      _Out_ PFILE_POSITION_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  NTSTATUS
  CdQueryNameInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFILE_OBJECT FileObject,
      _Out_ PFILE_NAME_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  _Requires_lock_held_(_Global_critical_region_)
  NTSTATUS
  CdQueryAlternateNameInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _In_ PCCB Ccb,
      _Out_ PFILE_NAME_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  VOID
  CdQueryNetworkInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_NETWORK_OPEN_INFORMATION Buffer,
      _Inout_ PULONG Length
      );
  
  #ifdef ALLOC_PRAGMA
  #pragma alloc_text(PAGE, CdCommonQueryInfo)
  #pragma alloc_text(PAGE, CdCommonSetInfo)
  #pragma alloc_text(PAGE, CdFastQueryBasicInfo)
  #pragma alloc_text(PAGE, CdFastQueryStdInfo)
  #pragma alloc_text(PAGE, CdFastQueryNetworkInfo)
  #pragma alloc_text(PAGE, CdQueryAlternateNameInfo)
  #pragma alloc_text(PAGE, CdQueryBasicInfo)
  #pragma alloc_text(PAGE, CdQueryEaInfo)
  #pragma alloc_text(PAGE, CdQueryInternalInfo)
  #pragma alloc_text(PAGE, CdQueryNameInfo)
  #pragma alloc_text(PAGE, CdQueryNetworkInfo)
  #pragma alloc_text(PAGE, CdQueryPositionInfo)
  #pragma alloc_text(PAGE, CdQueryStandardInfo)
  #endif
  
  
  _Requires_lock_held_(_Global_critical_region_)
  NTSTATUS
  CdCommonQueryInfo (
      _Inout_ PIRP_CONTEXT IrpContext,
      _Inout_ PIRP Irp
      )
  
  /*++
  
  Routine Description:
  
      This is the common routine for query file information called by both the
      fsd and fsp threads.
  
  Arguments:
  
      Irp - Supplies the Irp to process.
  
  Return Value:
  
      NTSTATUS - The return status for this operation.
  
  --*/
  
  {
      NTSTATUS Status = STATUS_SUCCESS;
      PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  
      ULONG Length;
      FILE_INFORMATION_CLASS FileInformationClass;
      PFILE_ALL_INFORMATION Buffer;
  
      TYPE_OF_OPEN TypeOfOpen;
      PFCB Fcb;
      PCCB Ccb;
  
      BOOLEAN ReleaseFcb = FALSE;
  
      PAGED_CODE();
  
      //
      //  Reference our input parameters to make things easier
      //
  
      Length = IrpSp->Parameters.QueryFile.Length;
      FileInformationClass = IrpSp->Parameters.QueryFile.FileInformationClass;
      Buffer = Irp->AssociatedIrp.SystemBuffer;
  
      //
      //  Decode the file object
      //
  
      TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
  
      //
      //  Use a try-finally to facilitate cleanup.
      //
  
      try {
  
          //
          //  We only support query on file and directory handles.
          //
  
          switch (TypeOfOpen) {
  
          case UserDirectoryOpen :
          case UserFileOpen :
  
              //
              //  Acquire shared access to this file.  NOTE that this could be
              //  a recursive acquire,  if we already preacquired in
              //  CdAcquireForCreateSection().
              //
  
              CdAcquireFileShared( IrpContext, Fcb );
              ReleaseFcb = TRUE;
  
              //
              //  Make sure we have the correct sizes for a directory.
              //
  
              if (!FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED )) {
  
                  NT_ASSERT( TypeOfOpen == UserDirectoryOpen );
                  CdVerifyOrCreateDirStreamFile( IrpContext, Fcb);
              }
  
              //
              //  Make sure the Fcb is in a usable condition.  This will raise
              //  an error condition if the volume is unusable
              //
  
              CdVerifyFcbOperation( IrpContext, Fcb );
  
              //
              //  Based on the information class we'll do different
              //  actions.  Each of hte procedures that we're calling fills
              //  up the output buffer, if possible.  They will raise the
              //  status STATUS_BUFFER_OVERFLOW for an insufficient buffer.
              //  This is considered a somewhat unusual case and is handled
              //  more cleanly with the exception mechanism rather than
              //  testing a return status value for each call.
              //
  
              switch (FileInformationClass) {
  
              case FileAllInformation:
  
                  //
                  //  We don't allow this operation on a file opened by file Id.
                  //
  
                  if (FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_ID )) {
  
                      Status = STATUS_INVALID_PARAMETER;
                      break;
                  }
  
                  //
                  //  In this case go ahead and call the individual routines to
                  //  fill in the buffer.  Only the name routine will
                  //  pointer to the output buffer and then call the
                  //  individual routines to fill in the buffer.
                  //
  
                  Length -= (sizeof( FILE_ACCESS_INFORMATION ) +
                             sizeof( FILE_MODE_INFORMATION ) +
                             sizeof( FILE_ALIGNMENT_INFORMATION ));
  
                  CdQueryBasicInfo( IrpContext, Fcb, &Buffer->BasicInformation, &Length );
                  CdQueryStandardInfo( IrpContext, Fcb, &Buffer->StandardInformation, &Length );
                  CdQueryInternalInfo( IrpContext, Fcb, &Buffer->InternalInformation, &Length );
                  CdQueryEaInfo( IrpContext, Fcb, &Buffer->EaInformation, &Length );
                  CdQueryPositionInfo( IrpContext, IrpSp->FileObject, &Buffer->PositionInformation, &Length );
                  Status = CdQueryNameInfo( IrpContext, IrpSp->FileObject, &Buffer->NameInformation, &Length );
  
                  break;
  
              case FileBasicInformation:
  
                  CdQueryBasicInfo( IrpContext, Fcb, (PFILE_BASIC_INFORMATION) Buffer, &Length );
                  break;
  
              case FileStandardInformation:
  
                  CdQueryStandardInfo( IrpContext, Fcb, (PFILE_STANDARD_INFORMATION) Buffer, &Length );
                  break;
  
              case FileInternalInformation:
  
                  CdQueryInternalInfo( IrpContext, Fcb, (PFILE_INTERNAL_INFORMATION) Buffer, &Length );
                  break;
  
              case FileEaInformation:
  
                  CdQueryEaInfo( IrpContext, Fcb, (PFILE_EA_INFORMATION) Buffer, &Length );
                  break;
  
              case FilePositionInformation:
  
                  CdQueryPositionInfo( IrpContext, IrpSp->FileObject, (PFILE_POSITION_INFORMATION) Buffer, &Length );
                  break;
  
              case FileNameInformation:
  
                  //
                  //  We don't allow this operation on a file opened by file Id.
                  //
  
                  if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_ID )) {
  
                      Status = CdQueryNameInfo( IrpContext, IrpSp->FileObject, (PFILE_NAME_INFORMATION) Buffer, &Length );
  
                  } else {
  
                      Status = STATUS_INVALID_PARAMETER;
                  }
  
                  break;
  
              case FileAlternateNameInformation:
  
                  if (!FlagOn( Ccb->Flags, CCB_FLAG_OPEN_BY_ID )) {
  
                      Status = CdQueryAlternateNameInfo( IrpContext, Fcb, Ccb, (PFILE_NAME_INFORMATION) Buffer, &Length );
  
                  } else {
  
                      Status = STATUS_INVALID_PARAMETER;
                  }
  
                  break;
  
              case FileNetworkOpenInformation:
  
                  CdQueryNetworkInfo( IrpContext, Fcb, (PFILE_NETWORK_OPEN_INFORMATION) Buffer, &Length );
                  break;
  
              default :
  
                  Status = STATUS_INVALID_PARAMETER;
              }
  
              break;
  
          default :
  
              Status = STATUS_INVALID_PARAMETER;
          }
  
          //
          //  Set the information field to the number of bytes actually filled in
          //  and then complete the request
          //
  
          Irp->IoStatus.Information = IrpSp->Parameters.QueryFile.Length - Length;
  
      } finally {
  
          //
          //  Release the file.
          //
  
          if (ReleaseFcb) {
  
              CdReleaseFile( IrpContext, Fcb );
          }
      }
  
      //
      //  Complete the request if we didn't raise.
      //
  
      CdCompleteRequest( IrpContext, Irp, Status );
  
      return Status;
  }
  
  
  _Requires_lock_held_(_Global_critical_region_)
  NTSTATUS
  CdCommonSetInfo (
      _Inout_ PIRP_CONTEXT IrpContext,
      _Inout_ PIRP Irp
      )
  
  /*++
  
  Routine Description:
  
      This is the common routine for set file information called by both the
      fsd and fsp threads.  We only support operations which set the file position.
  
  Arguments:
  
      Irp - Supplies the Irp to process.
  
  Return Value:
  
      NTSTATUS - The return status for this operation.
  
  --*/
  
  {
      NTSTATUS Status = STATUS_INVALID_PARAMETER;
  
      TYPE_OF_OPEN TypeOfOpen;
      PFCB Fcb;
      PCCB Ccb;
  
      PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
  
      PFILE_POSITION_INFORMATION Buffer;
  
      PAGED_CODE();
  
      //
      //  Decode the file object
      //
  
      TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb );
  
      //
      //  We only support a SetPositionInformation on a user file.
      //
  
      if ((TypeOfOpen != UserFileOpen) ||
          (IrpSp->Parameters.QueryFile.FileInformationClass != FilePositionInformation)) {
  
          CdCompleteRequest( IrpContext, Irp, Status );
          return Status;
      }
  
      //
      //  Acquire shared access to this file.
      //
  
      CdAcquireFileShared( IrpContext, Fcb );
  
      try {
  
          //
          //  Make sure the Fcb is in a usable condition.  This
          //  will raise an error condition if the fcb is unusable
          //
  
          CdVerifyFcbOperation( IrpContext, Fcb );
  
          Buffer = Irp->AssociatedIrp.SystemBuffer;
  
          //
          //  Check if the file does not use intermediate buffering.  If it
          //  does not use intermediate buffering then the new position we're
          //  supplied must be aligned properly for the device
          //
  
          if (FlagOn( IrpSp->FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) &&
              ((Buffer->CurrentByteOffset.LowPart & Fcb->Vcb->BlockMask) != 0)) {
  
              try_return( NOTHING );
          }
  
          //
          //  The input parameter is fine so set the current byte offset and
          //  complete the request
          //
  
          //
          //  Lock the Fcb to provide synchronization.
          //
  
          CdLockFcb( IrpContext, Fcb );
          IrpSp->FileObject->CurrentByteOffset = Buffer->CurrentByteOffset;
          CdUnlockFcb( IrpContext, Fcb );
  
          Status = STATUS_SUCCESS;
  
      try_exit: NOTHING;
      } finally {
  
          CdReleaseFile( IrpContext, Fcb );
      }
  
      //
      //  Complete the request if there was no raise.
      //
  
      CdCompleteRequest( IrpContext, Irp, Status );
      return Status;
  }
  
  
  _Function_class_(FAST_IO_QUERY_BASIC_INFO)
  _IRQL_requires_same_
  _Success_(return != FALSE)
  BOOLEAN
  CdFastQueryBasicInfo (
      _In_ PFILE_OBJECT FileObject,
      _In_ BOOLEAN Wait,
      _Out_ PFILE_BASIC_INFORMATION Buffer,
      _Out_ PIO_STATUS_BLOCK IoStatus,
      _In_ PDEVICE_OBJECT DeviceObject
      )
  
  /*++
  
  Routine Description:
  
      This routine is for the fast query call for basic file information.
  
  Arguments:
  
      FileObject - Supplies the file object used in this operation
  
      Wait - Indicates if we are allowed to wait for the information
  
      Buffer - Supplies the output buffer to receive the basic information
  
      IoStatus - Receives the final status of the operation
  
  Return Value:
  
      BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
          needs to take the long route.
  
  --*/
  
  {
      BOOLEAN Result = FALSE;
      TYPE_OF_OPEN TypeOfOpen;
  
      PFCB Fcb;
  
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( DeviceObject );
  
      ASSERT_FILE_OBJECT( FileObject );
  
      FsRtlEnterFileSystem();
  
      //
      //  Decode the file object to find the type of open and the data
      //  structures.
      //
  
      TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
  
      //
      //  We only support this request on user file or directory objects.
      //
  
      if ((TypeOfOpen != UserFileOpen) &&
          ((TypeOfOpen != UserDirectoryOpen) || !FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED))) {
  
          FsRtlExitFileSystem();
          return FALSE;
      }
  
      //
      //  Acquire the file shared to access the Fcb.
      //
  
      if (!ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
  
          FsRtlExitFileSystem();
          return FALSE;
      }
  
      //
      //  Use a try-finally to facilitate cleanup.
      //
  
      try {
  
          //
          //  Only deal with 'good' Fcb's.
          //
  
          if (CdVerifyFcbOperation( NULL, Fcb )) {
  
              //
              //  Fill in the input buffer from the Fcb fields.
              //
  
              Buffer->CreationTime.QuadPart =
              Buffer->LastWriteTime.QuadPart =
              Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
  
              Buffer->LastAccessTime.QuadPart = 0;
  
              Buffer->FileAttributes = Fcb->FileAttributes;
  
              //
              //  Update the IoStatus block with the size of this data.
              //
  
              IoStatus->Status = STATUS_SUCCESS;
              IoStatus->Information = sizeof( FILE_BASIC_INFORMATION );
  
              Result = TRUE;
          }
  
      } finally {
  
          ExReleaseResourceLite( Fcb->Resource );
  
          FsRtlExitFileSystem();
      }
  
      return Result;
  }
  
  
  _Function_class_(FAST_IO_QUERY_STANDARD_INFO)
  _IRQL_requires_same_
  _Success_(return != FALSE)
  BOOLEAN
  CdFastQueryStdInfo (
      _In_ PFILE_OBJECT FileObject,
      _In_ BOOLEAN Wait,
      _Out_ PFILE_STANDARD_INFORMATION Buffer,
      _Out_ PIO_STATUS_BLOCK IoStatus,
      _In_ PDEVICE_OBJECT DeviceObject
      )
  
  /*++
  
  Routine Description:
  
      This routine is for the fast query call for standard file information.
  
  Arguments:
  
      FileObject - Supplies the file object used in this operation
  
      Wait - Indicates if we are allowed to wait for the information
  
      Buffer - Supplies the output buffer to receive the basic information
  
      IoStatus - Receives the final status of the operation
  
  Return Value:
  
      BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
          needs to take the long route.
  
  --*/
  
  {
      BOOLEAN Result = FALSE;
      TYPE_OF_OPEN TypeOfOpen;
  
      PFCB Fcb;
  
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( DeviceObject );
  
      ASSERT_FILE_OBJECT( FileObject );
  
      FsRtlEnterFileSystem();
  
      //
      //  Decode the file object to find the type of open and the data
      //  structures.
      //
  
      TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
  
      //
      //  We only support this request on initialized user file or directory objects.
      //
  
      if ((TypeOfOpen != UserFileOpen) &&
          ((TypeOfOpen != UserDirectoryOpen) || !FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED ))) {
  
          FsRtlExitFileSystem();
          return FALSE;
      }
  
      //
      //  Acquire the file shared to access the Fcb.
      //
  
      if (!ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
  
          FsRtlExitFileSystem();
          return FALSE;
      }
  
      //
      //  Use a try-finally to facilitate cleanup.
      //
  
      try {
  
          //
          //  Only deal with 'good' Fcb's.
          //
  
          if (CdVerifyFcbOperation( NULL, Fcb )) {
  
              //
              //  Check whether this is a directory.
              //
  
              if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
  
                  Buffer->AllocationSize.QuadPart =
                  Buffer->EndOfFile.QuadPart = 0;
  
                  Buffer->Directory = TRUE;
  
              } else {
  
                  Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
                  Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
  
                  Buffer->Directory = FALSE;
              }
  
              Buffer->NumberOfLinks = 1;
              Buffer->DeletePending = FALSE;
  
              //
              //  Update the IoStatus block with the size of this data.
              //
  
              IoStatus->Status = STATUS_SUCCESS;
              IoStatus->Information = sizeof( FILE_STANDARD_INFORMATION );
  
              Result = TRUE;
          }
  
      } finally {
  
          ExReleaseResourceLite( Fcb->Resource );
  
          FsRtlExitFileSystem();
      }
  
      return Result;
  }
  
  
  _Function_class_(FAST_IO_QUERY_NETWORK_OPEN_INFO)
  _IRQL_requires_same_
  _Success_(return != FALSE)
  BOOLEAN
  CdFastQueryNetworkInfo (
      _In_ PFILE_OBJECT FileObject,
      _In_ BOOLEAN Wait,
      _Out_ PFILE_NETWORK_OPEN_INFORMATION Buffer,
      _Out_ PIO_STATUS_BLOCK IoStatus,
      _In_ PDEVICE_OBJECT DeviceObject
      )
  
  /*++
  
  Routine Description:
  
      This routine is for the fast query call for network file information.
  
  Arguments:
  
      FileObject - Supplies the file object used in this operation
  
      Wait - Indicates if we are allowed to wait for the information
  
      Buffer - Supplies the output buffer to receive the basic information
  
      IoStatus - Receives the final status of the operation
  
  Return Value:
  
      BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
          needs to take the long route.
  
  --*/
  
  {
      BOOLEAN Result = FALSE;
      TYPE_OF_OPEN TypeOfOpen;
  
      PFCB Fcb;
  
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( DeviceObject );
  
      ASSERT_FILE_OBJECT( FileObject );
  
      FsRtlEnterFileSystem();
  
      //
      //  Decode the file object to find the type of open and the data
      //  structures.
      //
  
      TypeOfOpen = CdFastDecodeFileObject( FileObject, &Fcb );
  
      //
      //  We only support this request on user file or directory objects.
      //
  
      if ((TypeOfOpen != UserFileOpen) &&
          ((TypeOfOpen != UserDirectoryOpen) || !FlagOn( Fcb->FcbState, FCB_STATE_INITIALIZED))) {
  
          FsRtlExitFileSystem();
          return FALSE;
      }
  
      //
      //  Acquire the file shared to access the Fcb.
      //
  
      if (!ExAcquireResourceSharedLite( Fcb->Resource, Wait )) {
  
          FsRtlExitFileSystem();
          return FALSE;
      }
  
      //
      //  Use a try-finally to facilitate cleanup.
      //
  
      try {
  
          //
          //  Only deal with 'good' Fcb's.
          //
  
          if (CdVerifyFcbOperation( NULL, Fcb )) {
  
              //
              //  Fill in the input buffer from the Fcb fields.
              //
  
              Buffer->CreationTime.QuadPart =
              Buffer->LastWriteTime.QuadPart =
              Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
  
              Buffer->LastAccessTime.QuadPart = 0;
  
              Buffer->FileAttributes = Fcb->FileAttributes;
  
              //
              //  Check whether this is a directory.
              //
  
              if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
  
                  Buffer->AllocationSize.QuadPart =
                  Buffer->EndOfFile.QuadPart = 0;
  
              } else {
  
                  Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
                  Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
              }
  
              //
              //  Update the IoStatus block with the size of this data.
              //
  
              IoStatus->Status = STATUS_SUCCESS;
              IoStatus->Information = sizeof( FILE_NETWORK_OPEN_INFORMATION );
  
              Result = TRUE;
          }
  
      } finally {
  
          ExReleaseResourceLite( Fcb->Resource );
  
          FsRtlExitFileSystem();
      }
  
      return Result;
  }
  
  
  //
  //  Local support routine
  //
  
  VOID
  CdQueryBasicInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_BASIC_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
   Description:
  
      This routine performs the query basic information function for Cdfs
  
  Arguments:
  
      Fcb - Supplies the Fcb being queried, it has been verified
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      None
  
  --*/
  
  {
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
  
      //
      //  We only support creation, last modify and last write times on Cdfs.
      //
  
      Buffer->LastWriteTime.QuadPart =
      Buffer->CreationTime.QuadPart =
      Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
  
      Buffer->LastAccessTime.QuadPart = 0;
  
      Buffer->FileAttributes = Fcb->FileAttributes;
  
      //
      //  Update the length and status output variables
      //
  
      *Length -= sizeof( FILE_BASIC_INFORMATION );
  
      return;
  }
  
  
  //
  //  Local support routine
  //
  
  VOID
  CdQueryStandardInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_STANDARD_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  /*++
  
  Routine Description:
  
      This routine performs the query standard information function for cdfs.
  
  Arguments:
  
      Fcb - Supplies the Fcb being queried, it has been verified
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      None
  
  --*/
  
  {
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
  
      //
      //  There is only one link and delete is never pending on a Cdrom file.
      //
  
      Buffer->NumberOfLinks = 1;
      Buffer->DeletePending = FALSE;
  
      //
      //  We get the sizes from the header.  Return a size of zero
      //  for all directories.
      //
  
      if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
  
          Buffer->AllocationSize.QuadPart =
          Buffer->EndOfFile.QuadPart = 0;
  
          Buffer->Directory = TRUE;
  
      } else {
  
          Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
          Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
  
          Buffer->Directory = FALSE;
      }
  
      //
      //  Update the length and status output variables
      //
  
      *Length -= sizeof( FILE_STANDARD_INFORMATION );
  
      return;
  }
  
  
  //
  //  Local support routine
  //
  
  VOID
  CdQueryInternalInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_INTERNAL_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
  Routine Description:
  
      This routine performs the query internal information function for cdfs.
  
  Arguments:
  
      Fcb - Supplies the Fcb being queried, it has been verified
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      None
  
  --*/
  
  {
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
  
      //
      //  Index number is the file Id number in the Fcb.
      //
  
      Buffer->IndexNumber = Fcb->FileId;
      *Length -= sizeof( FILE_INTERNAL_INFORMATION );
  
      return;
  }
  
  
  //
  //  Local support routine
  //
  
  VOID
  CdQueryEaInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_EA_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
  Routine Description:
  
      This routine performs the query Ea information function for cdfs.
  
  Arguments:
  
      Fcb - Supplies the Fcb being queried, it has been verified
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      None
  
  --*/
  
  {
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
      UNREFERENCED_PARAMETER( Fcb );
  
      //
      //  No Ea's on Cdfs volumes.
      //
  
      Buffer->EaSize = 0;
      *Length -= sizeof( FILE_EA_INFORMATION );
  
      return;
  }
  
  
  //
  //  Local support routine
  //
  
  VOID
  CdQueryPositionInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFILE_OBJECT FileObject,
      _Out_ PFILE_POSITION_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
  Routine Description:
  
      This routine performs the query position information function for cdfs.
  
  Arguments:
  
      FileObject - Supplies the File object being queried
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      None
  
  --*/
  
  {
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
  
      //
      //  Get the current position found in the file object.
      //
  
      Buffer->CurrentByteOffset = FileObject->CurrentByteOffset;
  
      //
      //  Update the length and status output variables
      //
  
      *Length -= sizeof( FILE_POSITION_INFORMATION );
  
      return;
  }
  
  
  //
  //  Local support routine
  //
  
  NTSTATUS
  CdQueryNameInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFILE_OBJECT FileObject,
      _Out_ PFILE_NAME_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
  Routine Description:
  
      This routine performs the query name information function for cdfs.
  
  Arguments:
  
      FileObject - Supplies the file object containing the name.
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      NTSTATUS - STATUS_BUFFER_OVERFLOW if the entire name can't be copied.
  
  --*/
  
  {
      NTSTATUS Status = STATUS_SUCCESS;
      ULONG LengthToCopy;
  
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
  
      NT_ASSERT(*Length >= sizeof(ULONG));
      
      //
      //  Simply copy the name in the file object to the user's buffer.
      //
  
      //
      //  Place the size of the filename in the user's buffer and reduce the remaining
      //  size to match.
      //
  
      Buffer->FileNameLength = LengthToCopy = FileObject->FileName.Length;
      *Length -= sizeof(ULONG);
  
      if (LengthToCopy > *Length) {
  
          LengthToCopy = *Length;
          Status = STATUS_BUFFER_OVERFLOW;
      }
  
      RtlCopyMemory( Buffer->FileName, FileObject->FileName.Buffer, LengthToCopy );
  
      //
      //  Reduce the available bytes by the amount stored into this buffer.  In the overflow
      //  case, this simply drops to zero.  The returned filenamelength will indicate to the
      //  caller how much space is required.
      //
  
      *Length -= LengthToCopy;
  
      return Status;
  }
  
  
  //
  //  Local support routine
  //
  
  _Requires_lock_held_(_Global_critical_region_)
  NTSTATUS
  CdQueryAlternateNameInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _In_ PCCB Ccb,
      _Out_ PFILE_NAME_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
  Routine Description:
  
      This routine performs the query alternate name information function.
      We lookup the dirent for this file and then check if there is a
      short name.
  
  Arguments:
  
      Fcb - Supplies the Fcb being queried, it has been verified.
  
      Ccb - Ccb for this open handle.
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned.
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      NTSTATUS - STATUS_SUCCESS if the whole name would fit into the user buffer,
                 STATUS_OBJECT_NAME_NOT_FOUND if we can't return the name,
                 STATUS_BUFFER_OVERFLOW otherwise.
  
  --*/
  
  {
      NTSTATUS Status = STATUS_SUCCESS;
  
      DIRENT_ENUM_CONTEXT DirContext = {0};
      DIRENT Dirent = {0};
  
      PUNICODE_STRING NameToUse;
      ULONG DirentOffset;
  
      COMPOUND_PATH_ENTRY CompoundPathEntry = {0};
      FILE_ENUM_CONTEXT FileContext;
  
      PFCB ParentFcb = NULL;
      BOOLEAN ReleaseParentFcb = FALSE;
  
      BOOLEAN CleanupFileLookup = FALSE;
      BOOLEAN CleanupDirectoryLookup = FALSE;
  
      WCHAR ShortNameBuffer[ BYTE_COUNT_8_DOT_3 / 2 ];
      USHORT ShortNameLength;
  
      PAGED_CODE();
  
      //
      //  Initialize the buffer length to zero.
      //
  
      Buffer->FileNameLength = 0;
  
      //
      //  If this is the root or this file was opened using a version number then
      //  there is no short name.
      //
  
      if ((Fcb == Fcb->Vcb->RootIndexFcb) ||
          FlagOn( Ccb->Flags, CCB_FLAG_OPEN_WITH_VERSION)) {
  
          return STATUS_OBJECT_NAME_NOT_FOUND;
      }
  
      //
      //  Use a try-finally to cleanup the structures.
      //
  
      try {
  
          ParentFcb = Fcb->ParentFcb;
          CdAcquireFileShared( IrpContext, ParentFcb );
          ReleaseParentFcb = TRUE;
      
          CdVerifyOrCreateDirStreamFile( IrpContext, ParentFcb);
  
          if (CdFidIsDirectory( Fcb->FileId)) {
  
              //
              //  Fcb is for a directory, so we need to dig the dirent from the parent.  In
              //  order to do this we need to get the name of the directory from its pathtable
              //  entry and then search in the parent for a matching dirent.
              //
              //  This could be optimized somewhat.
              //
  
              CdInitializeCompoundPathEntry( IrpContext, &CompoundPathEntry );
              CdInitializeFileContext( IrpContext, &FileContext );
  
              CleanupDirectoryLookup = TRUE;
  
              CdLookupPathEntry( IrpContext,
                                 CdQueryFidPathTableOffset( Fcb->FileId ),
                                 Fcb->Ordinal,
                                 FALSE,
                                 &CompoundPathEntry );
  
              CdUpdatePathEntryName( IrpContext, &CompoundPathEntry.PathEntry, TRUE );
  
              if (!CdFindDirectory( IrpContext,
                                    ParentFcb,
                                    &CompoundPathEntry.PathEntry.CdCaseDirName,
                                    TRUE,
                                    &FileContext )) {
  
                  //
                  //  If we failed to find the child directory by name in the parent
                  //  something is quite wrong with this disc.
                  //
  
                  CdRaiseStatus( IrpContext, STATUS_DISK_CORRUPT_ERROR );
              }
  
              NameToUse = &FileContext.InitialDirent->Dirent.CdCaseFileName.FileName;
              DirentOffset = FileContext.InitialDirent->Dirent.DirentOffset;
          
          } else {
  
              //
              //  Initialize the search dirent structures.
              //
          
              CdInitializeDirContext( IrpContext, &DirContext );
              CdInitializeDirent( IrpContext, &Dirent );
      
              CleanupFileLookup = TRUE;
          
              CdLookupDirent( IrpContext,
                              ParentFcb,
                              CdQueryFidDirentOffset( Fcb->FileId ),
                              &DirContext );
      
              CdUpdateDirentFromRawDirent( IrpContext,
                                           ParentFcb,
                                           &DirContext,
                                           &Dirent );
  
              //
              //  Now update the dirent name.
              //
      
              CdUpdateDirentName( IrpContext, &Dirent, TRUE );
      
              NameToUse = &Dirent.CdCaseFileName.FileName;
              DirentOffset = Dirent.DirentOffset;
          }
  
          //
          //  If the name is 8.3 then fail this request.
          //
  
          if (CdIs8dot3Name( IrpContext,
                             *NameToUse )) {
  
  
              try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
          }
  
          CdGenerate8dot3Name( IrpContext,
                               NameToUse,
                               DirentOffset,
                               ShortNameBuffer,
                               &ShortNameLength );
  
          //
          //  We now have the short name.  We have left it in Unicode form so copy it directly.
          //
  
          Buffer->FileNameLength = ShortNameLength;
  
          if (Buffer->FileNameLength + sizeof( ULONG ) > *Length) {
  
              Buffer->FileNameLength = *Length - sizeof( ULONG );
              Status = STATUS_BUFFER_OVERFLOW;
          }
  
          RtlCopyMemory( Buffer->FileName, ShortNameBuffer, Buffer->FileNameLength );
  
      try_exit:  NOTHING;
      } finally {
  
          if (CleanupFileLookup) {
  
              CdCleanupDirContext( IrpContext, &DirContext );
              CdCleanupDirent( IrpContext, &Dirent );
  
          } else if (CleanupDirectoryLookup) {
  
              CdCleanupCompoundPathEntry( IrpContext, &CompoundPathEntry );
              CdCleanupFileContext( IrpContext, &FileContext );
          }
  
          if (ReleaseParentFcb) {
  
              CdReleaseFile( IrpContext, ParentFcb );
          }
      }
  
      //
      //  Reduce the available bytes by the amount stored into this buffer.
      //
  
      if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
  
          *Length -= sizeof( ULONG ) + Buffer->FileNameLength;
      }
  
      return Status;
  }
  
  
  //
  //  Local support routine
  //
  
  VOID
  CdQueryNetworkInfo (
      _In_ PIRP_CONTEXT IrpContext,
      _In_ PFCB Fcb,
      _Out_ PFILE_NETWORK_OPEN_INFORMATION Buffer,
      _Inout_ PULONG Length
      )
  
  /*++
  
   Description:
  
      This routine performs the query network open information function for Cdfs
  
  Arguments:
  
      Fcb - Supplies the Fcb being queried, it has been verified
  
      Buffer - Supplies a pointer to the buffer where the information is to
          be returned
  
      Length - Supplies the length of the buffer in bytes, and receives the
          remaining bytes free in the buffer upon return.
  
  Return Value:
  
      None
  
  --*/
  
  {
      PAGED_CODE();
  
      UNREFERENCED_PARAMETER( IrpContext );
  
      //
      //  We only support creation, last modify and last write times on Cdfs.
      //
  
      Buffer->LastWriteTime.QuadPart =
      Buffer->CreationTime.QuadPart =
      Buffer->ChangeTime.QuadPart = Fcb->CreationTime;
  
      Buffer->LastAccessTime.QuadPart = 0;
  
      Buffer->FileAttributes = Fcb->FileAttributes;
  
      //
      //  We get the sizes from the header.  Return a size of zero
      //  for all directories.
      //
  
      if (FlagOn( Fcb->FileAttributes, FILE_ATTRIBUTE_DIRECTORY )) {
  
          Buffer->AllocationSize.QuadPart =
          Buffer->EndOfFile.QuadPart = 0;
  
      } else {
  
          Buffer->AllocationSize.QuadPart = Fcb->AllocationSize.QuadPart;
          Buffer->EndOfFile.QuadPart = Fcb->FileSize.QuadPart;
      }
  
      //
      //  Update the length and status output variables
      //
  
      *Length -= sizeof( FILE_NETWORK_OPEN_INFORMATION );
  
      return;
  }
  
  