|
|
/*++
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.
// @@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_FILEINFO)
//
// Local support routines
//
VOID CdQueryBasicInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PFILE_BASIC_INFORMATION Buffer, IN OUT PULONG Length );
VOID CdQueryStandardInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PFILE_STANDARD_INFORMATION Buffer, IN OUT PULONG Length );
VOID CdQueryInternalInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PFILE_INTERNAL_INFORMATION Buffer, IN OUT PULONG Length );
VOID CdQueryEaInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PFILE_EA_INFORMATION Buffer, IN OUT PULONG Length );
VOID CdQueryPositionInfo ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN OUT PFILE_POSITION_INFORMATION Buffer, IN OUT PULONG Length );
NTSTATUS CdQueryNameInfo ( IN PIRP_CONTEXT IrpContext, IN PFILE_OBJECT FileObject, IN OUT PFILE_NAME_INFORMATION Buffer, IN OUT PULONG Length );
NTSTATUS CdQueryAlternateNameInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCCB Ccb, IN OUT PFILE_NAME_INFORMATION Buffer, IN OUT PULONG Length );
VOID CdQueryNetworkInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, IN OUT 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
NTSTATUS CdCommonQueryInfo ( IN PIRP_CONTEXT IrpContext, IN 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 )) {
ASSERT( TypeOfOpen == UserDirectoryOpen ); CdCreateInternalStream( IrpContext, Fcb->Vcb, 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; }
NTSTATUS CdCommonSetInfo ( IN PIRP_CONTEXT IrpContext, IN 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 & IrpSp->DeviceObject->AlignmentRequirement) != 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; }
BOOLEAN CdFastQueryBasicInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN 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();
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; }
BOOLEAN CdFastQueryStdInfo ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait, IN 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();
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; }
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();
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, IN OUT PFILE_BASIC_INFORMATION Buffer, IN OUT 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();
//
// 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, IN OUT PFILE_STANDARD_INFORMATION Buffer, IN OUT 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();
//
// 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, IN OUT PFILE_INTERNAL_INFORMATION Buffer, IN OUT 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();
//
// 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, IN OUT PFILE_EA_INFORMATION Buffer, IN OUT 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();
//
// 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, IN OUT PFILE_POSITION_INFORMATION Buffer, IN OUT 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();
//
// 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, IN OUT PFILE_NAME_INFORMATION Buffer, IN OUT 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();
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
//
NTSTATUS CdQueryAlternateNameInfo ( IN PIRP_CONTEXT IrpContext, IN PFCB Fcb, IN PCCB Ccb, IN OUT PFILE_NAME_INFORMATION Buffer, IN OUT 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; DIRENT Dirent;
PUNICODE_STRING NameToUse; ULONG DirentOffset;
COMPOUND_PATH_ENTRY CompoundPathEntry; FILE_ENUM_CONTEXT FileContext;
PFCB ParentFcb; 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; //
// Do an unsafe test to see if we need to create a file object.
//
if (ParentFcb->FileObject == NULL) {
CdCreateInternalStream( IrpContext, ParentFcb->Vcb, 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, IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, IN OUT 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();
//
// 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; }
|