/*++ Copyright (c) 1989 Microsoft Corporation Module Name: NtFastIo.c Abstract: This module implements NT fastio routines. Author: Joe Linn [JoeLinn] 9-Nov-1994 Revision History: --*/ #include "precomp.h" #pragma hdrstop // // The local debug trace level // #define Dbg (DEBUG_TRACE_NTFASTIO) #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, RxFastIoRead) #pragma alloc_text(PAGE, RxFastIoWrite) #pragma alloc_text(PAGE, RxFastLock) #pragma alloc_text(PAGE, RxFastUnlockAll) #pragma alloc_text(PAGE, RxFastUnlockAllByKey) #pragma alloc_text(PAGE, RxFastUnlockSingle) #pragma alloc_text(PAGE, RxFastIoCheckIfPossible) #pragma alloc_text(PAGE, RxFastQueryBasicInfo) #pragma alloc_text(PAGE, RxFastQueryStdInfo) #endif //these declarations would be copied to fsrtl.h BOOLEAN FsRtlCopyRead2 ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject, IN ULONG_PTR TopLevelIrpValue ); BOOLEAN FsRtlCopyWrite2 ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject, IN ULONG_PTR TopLevelIrpValue ); BOOLEAN RxFastIoRead ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, OUT PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) { BOOLEAN ReturnValue; RX_TOPLEVELIRP_CONTEXT TopLevelContext; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxFastIoRead\n")); RxLog(("FastRead %lx:%lx:%lx",FileObject,FileObject->FsContext,FileObject->FsContext2)); RxLog(("------>> %lx@%lx %lx",Length,FileOffset->LowPart,FileOffset->HighPart)); RxWmiLog(LOG, RxFastIoRead_1, LOGPTR(FileObject) LOGPTR(FileObject->FsContext) LOGPTR(FileObject->FsContext2) LOGULONG(Length) LOGULONG(FileOffset->LowPart) LOGULONG(FileOffset->HighPart)); ASSERT(RxIsThisTheTopLevelIrp(NULL)); RxInitializeTopLevelIrpContext( &TopLevelContext, ((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP), (PRDBSS_DEVICE_OBJECT)DeviceObject); ReturnValue = FsRtlCopyRead2 ( FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject, (ULONG_PTR)(&TopLevelContext) ); RxDbgTrace(-1, Dbg, ("RxFastIoRead ReturnValue=%x\n", ReturnValue)); if (ReturnValue) { RxLog( ("FastReadYes %lx ret %lx:%lx", FileObject->FsContext2,IoStatus->Status,IoStatus->Information)); RxWmiLog(LOG, RxFastIoRead_2, LOGPTR(FileObject->FsContext2) LOGULONG(IoStatus->Status) LOGPTR(IoStatus->Information)); } else { RxLog(("FastReadNo %lx",FileObject->FsContext2)); RxWmiLog(LOG, RxFastIoRead_3, LOGPTR(FileObject->FsContext2)); } return ReturnValue; } BOOLEAN RxFastIoWrite ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN PVOID Buffer, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) { BOOLEAN ReturnValue; RX_TOPLEVELIRP_CONTEXT TopLevelContext; PSRV_OPEN SrvOpen; PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxFastIoWrite\n")); SrvOpen = ((PFOBX)(FileObject->FsContext2))->SrvOpen; if (FlagOn(SrvOpen->Flags,SRVOPEN_FLAG_DONTUSE_WRITE_CACHEING)) { //if this flag is set, we have to treat this as an unbuffered Io....sigh. RxDbgTrace(-1, Dbg, ("RxFastIoWrite DONTUSE_WRITE_CACHEING...failing\n")); return FALSE; } ASSERT(RxIsThisTheTopLevelIrp(NULL)); RxInitializeTopLevelIrpContext( &TopLevelContext, ((PIRP)FSRTL_FAST_IO_TOP_LEVEL_IRP), (PRDBSS_DEVICE_OBJECT)DeviceObject); ReturnValue = FsRtlCopyWrite2 ( FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus, DeviceObject, (ULONG_PTR)(&TopLevelContext) ); RxDbgTrace(-1, Dbg, ("RxFastIoWrite ReturnValue=%x\n", ReturnValue)); if (ReturnValue) { RxLog( ("FWY %lx OLP: %lx SLP: %lx IOSB %lx:%lx", FileObject->FsContext2, FileOffset->LowPart, SrvOpen->pFcb->Header.FileSize.LowPart, IoStatus->Status, IoStatus->Information)); RxWmiLog(LOG, RxFastIoWrite_1, LOGPTR(FileObject->FsContext2) LOGULONG(FileOffset->LowPart) LOGULONG(SrvOpen->pFcb->Header.FileSize.LowPart) LOGULONG(IoStatus->Status) LOGPTR(IoStatus->Information)); } else { RxLog(("FastWriteNo %lx",FileObject->FsContext2)); RxWmiLog(LOG, RxFastIoWrite_2, LOGPTR(FileObject->FsContext2)); } return ReturnValue; } BOOLEAN RxFastLock ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast lock call. Arguments: FileObject - Supplies the file object used in this operation FileOffset - Supplies the file offset used in this operation Length - Supplies the length used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation FailImmediately - Indicates if the request should fail immediately if the lock cannot be granted. ExclusiveLock - Indicates if this is a request for an exclusive or shared lock IoStatus - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PFCB Fcb = (PFCB)(FileObject->FsContext); //need a macro PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxFastLock\n", 0)); // // Decode the type of file object we're being asked to process and make // sure it is only a user file open. // if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) { IoStatus->Status = STATUS_INVALID_PARAMETER; IoStatus->Information = 0; RxDbgTrace(-1, Dbg, ("RxFastLock -> TRUE (RxStatus(INVALID_PARAMETER))\n", 0)); return TRUE; } RxDbgTrace(-1, Dbg, ("RxFastLock -> FALSE (fastlocks not yet implemented)\n", 0)); return FALSE; //stuff past here has been massaged but not tested // // Acquire exclusive access to the Fcb this operation can always wait; you need // the resource to synchronize with oplock breaks // FsRtlEnterFileSystem(); ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); try { // // We check whether we can proceed // based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &(Fcb)->Specific.Fcb.Oplock )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request // if (Results = FsRtlFastLock( &Fcb->Specific.Fcb.FileLock, FileObject, FileOffset, Length, ProcessId, Key, FailImmediately, ExclusiveLock, IoStatus, NULL, FALSE )) { // // Set the flag indicating if Fast I/O is possible // //Fcb->Header.IsFastIoPossible = RxIsFastIoPossible( Fcb ); } try_exit: NOTHING; } finally { DebugUnwind( RxFastLock ); // // Release the Fcb, and return to our caller // ExReleaseResourceLite( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); RxDbgTrace(-1, Dbg, ("RxFastLock -> %08lx\n", Results)); } return Results; } BOOLEAN RxFastUnlockSingle ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock single call. Arguments: FileObject - Supplies the file object used in this operation FileOffset - Supplies the file offset used in this operation Length - Supplies the length used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PFCB Fcb = (PFCB)(FileObject->FsContext); //need macro PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxFastUnlockSingle\n", 0)); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and make sure // it is only a user file open // if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) { IoStatus->Status = STATUS_INVALID_PARAMETER; RxDbgTrace(-1, Dbg, ("RxFastUnlockSingle -> TRUE (RxStatus(INVALID_PARAMETER))\n", 0)); return TRUE; } RxDbgTrace(-1, Dbg, ("RxFastUnlockSingle -> FALSE (fastlocks not yet implemented)\n", 0)); return FALSE; //stuff past here has been massaged but not tested // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); try { // // We check whether we can proceed based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &(Fcb)->Specific.Fcb.Oplock )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockSingle( &Fcb->Specific.Fcb.FileLock, FileObject, FileOffset, Length, ProcessId, Key, NULL, FALSE ); // // Set the flag indicating if Fast I/O is possible // //Fcb->Header.IsFastIoPossible = RxIsFastIoPossible( Fcb ); try_exit: NOTHING; } finally { DebugUnwind( RxFastUnlockSingle ); // // Release the Fcb, and return to our caller // ExReleaseResourceLite( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); RxDbgTrace(-1, Dbg, ("RxFastUnlockSingle -> %08lx\n", Results)); } return Results; } BOOLEAN RxFastUnlockAll ( IN PFILE_OBJECT FileObject, PEPROCESS ProcessId, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock all call. Arguments: FileObject - Supplies the file object used in this operation ProcessId - Supplies the process ID used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PFCB Fcb = (PFCB)(FileObject->FsContext); //need macro PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxFastUnlockAll\n", 0)); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and make sure // it is only a user file open. // if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) { IoStatus->Status = STATUS_INVALID_PARAMETER; RxDbgTrace(-1, Dbg, ("RxFastUnlockAll -> TRUE (RxStatus(INVALID_PARAMETER))\n", 0)); return TRUE; } RxDbgTrace(-1, Dbg, ("RxFastUnlockAll -> FALSE (fastlocks not yet implemented)\n", 0)); return FALSE; //stuff past here has been massaged but not tested // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); (VOID) ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); try { // // We check whether we can proceed based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &(Fcb)->Specific.Fcb.Oplock )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockAll( &Fcb->Specific.Fcb.FileLock, FileObject, ProcessId, NULL ); // // Set the flag indicating if Fast I/O is possible // //Fcb->Header.IsFastIoPossible = RxIsFastIoPossible( Fcb ); try_exit: NOTHING; } finally { DebugUnwind( RxFastUnlockAll ); // // Release the Fcb, and return to our caller // ExReleaseResourceLite( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); RxDbgTrace(-1, Dbg, ("RxFastUnlockAll -> %08lx\n", Results)); } return Results; } BOOLEAN RxFastUnlockAllByKey ( IN PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock all by key call. Arguments: FileObject - Supplies the file object used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PFCB Fcb = (PFCB)(FileObject->FsContext); //need macro PAGED_CODE(); RxDbgTrace(+1, Dbg, ("RxFastUnlockAllByKey\n", 0)); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and make sure // it is only a user file open. // if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) { IoStatus->Status = STATUS_INVALID_PARAMETER; RxDbgTrace(-1, Dbg, ("RxFastUnlockAll -> TRUE (RxStatus(INVALID_PARAMETER))\n", 0)); return TRUE; } RxDbgTrace(-1, Dbg, ("RxFastUnlockAll -> FALSE (fastlocks not yet implemented)\n", 0)); return FALSE; //stuff past here has been massaged but not tested // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); (VOID) ExAcquireResourceSharedLite( Fcb->Header.Resource, TRUE ); try { // // We check whether we can proceed based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &(Fcb)->Specific.Fcb.Oplock )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockAllByKey( &Fcb->Specific.Fcb.FileLock, FileObject, ProcessId, Key, NULL ); // // Set the flag indicating if Fast I/O is possible // //Fcb->Header.IsFastIoPossible = RxIsFastIoPossible( Fcb ); try_exit: NOTHING; } finally { DebugUnwind( RxFastUnlockAllByKey ); // // Release the Fcb, and return to our caller // ExReleaseResourceLite( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); RxDbgTrace(-1, Dbg, ("RxFastUnlockAllByKey -> %08lx\n", Results)); } return Results; } #define RxLogAndReturnFalse(x) { \ RxLog(("CheckFast fail %lx %s",FileObject,x)); \ RxWmiLog(LOG, \ RxFastIoCheckIfPossible, \ LOGPTR(FileObject) \ LOGARSTR(x)); \ return FALSE; \ } BOOLEAN RxFastIoCheckIfPossible ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN ULONG Length, IN BOOLEAN Wait, IN ULONG LockKey, IN BOOLEAN CheckForReadOperation, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine checks if fast i/o is possible for a read/write operation Arguments: FileObject - Supplies the file object used in the query FileOffset - Supplies the starting byte offset for the read/write operation Length - Supplies the length, in bytes, of the read/write operation Wait - Indicates if we can wait LockKey - Supplies the lock key CheckForReadOperation - Indicates if this is a check for a read or write operation IoStatus - Receives the status of the operation if our return value is FastIoReturnError Return Value: BOOLEAN - TRUE if fast I/O is possible and FALSE if the caller needs to take the long route. --*/ { PFCB Fcb = (PFCB)(FileObject->FsContext); PFOBX Fobx = (PFOBX)(FileObject->FsContext2); PSRV_OPEN pSrvOpen = Fobx->SrvOpen; LARGE_INTEGER LargeLength; PAGED_CODE(); if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE) { RxLogAndReturnFalse("notfile"); } if (!FsRtlOplockIsFastIoPossible( &Fcb->Specific.Fcb.Oplock )) { RxLogAndReturnFalse("cnd/oplock"); } if (FileObject->DeletePending) { RxLogAndReturnFalse("delpend"); } if (Fcb->NonPaged->OutstandingAsyncWrites != 0) { RxLogAndReturnFalse("asynW"); } if (FlagOn(pSrvOpen->Flags,SRVOPEN_FLAG_ORPHANED)) { RxLogAndReturnFalse("srvopen orphaned"); } if (FlagOn(Fcb->FcbState,FCB_STATE_ORPHANED)) { RxLogAndReturnFalse("orphaned"); } if (BooleanFlagOn( pSrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) { RxLogAndReturnFalse("buf state change"); } if (FlagOn(pSrvOpen->Flags,SRVOPEN_FLAG_FILE_RENAMED) || FlagOn(pSrvOpen->Flags,SRVOPEN_FLAG_FILE_DELETED)) { RxLogAndReturnFalse("ren/del"); } // Ensure that all pending buffering state change requests are processed // before letting the operation through. FsRtlEnterFileSystem(); RxProcessChangeBufferingStateRequestsForSrvOpen(pSrvOpen); FsRtlExitFileSystem(); LargeLength.QuadPart = Length; // // Based on whether this is a read or write operation we call // fsrtl check for read/write // if (CheckForReadOperation) { if (!FlagOn(Fcb->FcbState,FCB_STATE_READCACHEING_ENABLED)) { RxLogAndReturnFalse("notreadC"); } if (!FsRtlFastCheckLockForRead( &Fcb->Specific.Fcb.FileLock, FileOffset, &LargeLength, LockKey, FileObject, PsGetCurrentProcess() )) { RxLogAndReturnFalse("readlock"); } } else { if (!FlagOn(Fcb->FcbState,FCB_STATE_WRITECACHEING_ENABLED)) { RxLogAndReturnFalse("notwriteC"); } // // Also check for a write-protected volume here. // if (!FsRtlFastCheckLockForWrite( &Fcb->Specific.Fcb.FileLock, FileOffset, &LargeLength, LockKey, FileObject, PsGetCurrentProcess() )) { RxLogAndReturnFalse("writelock"); } } // RxLog(("IoPossible %lx",FileObject)); return TRUE; } BOOLEAN RxFastIoDeviceControl( IN struct _FILE_OBJECT *FileObject, IN BOOLEAN Wait, IN PVOID InputBuffer OPTIONAL, IN ULONG InputBufferLength, OUT PVOID OutputBuffer OPTIONAL, IN ULONG OutputBufferLength, IN ULONG IoControlCode, OUT PIO_STATUS_BLOCK IoStatus, IN struct _DEVICE_OBJECT *DeviceObject ) /*++ Routine Description: This routine is for the fast device control call. Arguments: FileObject - Supplies the file object used in this operation Wait - Indicates if we are allowed to wait for the information InputBuffer - Supplies the input buffer InputBufferLength - the length of the input buffer OutputBuffer - the output buffer OutputBufferLength - the length of the output buffer IoControlCode - the IO control code IoStatus - Receives the final status of the operation DeviceObject - the associated device object Return Value: BOOLEAN - TRUE if the operation succeeded and FALSE if the caller needs to take the long route. Notes: The following IO control requests are handled in the first path IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER InputBuffer - pointer to the other file object InputBufferLength - length in bytes of a pointer. OutputBuffer - not used OutputBufferLength - not used IoStatus -- IoStatus.Status set to STATUS_SUCCESS if both the file objects are on the same server, otherwise set to STATUS_NOT_SAME_DEVICE This is a kernel mode interface only. --*/ { BOOLEAN FastIoSucceeded; switch (IoControlCode) { case IOCTL_LMR_ARE_FILE_OBJECTS_ON_SAME_SERVER : { FastIoSucceeded = TRUE; try { if (InputBufferLength == sizeof(HANDLE)) { PFCB pFcb1,pFcb2; HANDLE hFile; PFILE_OBJECT pFileObject2; NTSTATUS Status; pFcb1 = (PFCB)FileObject->FsContext; RtlCopyMemory( &hFile, InputBuffer, sizeof(HANDLE)); Status = ObReferenceObjectByHandle( hFile, FILE_ANY_ACCESS, *IoFileObjectType, UserMode, &pFileObject2, NULL); if ((Status == STATUS_SUCCESS)) { if(pFileObject2->DeviceObject == DeviceObject) { pFcb2 = (PFCB)pFileObject2->FsContext; if ((pFcb2 != NULL) && (NodeTypeIsFcb(pFcb2))) { if (pFcb1->pNetRoot->pSrvCall == pFcb2->pNetRoot->pSrvCall) { IoStatus->Status = STATUS_SUCCESS; } else { IoStatus->Status = STATUS_NOT_SAME_DEVICE; } } else { Status = STATUS_INVALID_PARAMETER; } } else { Status = STATUS_INVALID_PARAMETER; } ObDereferenceObject(pFileObject2); } else { IoStatus->Status = STATUS_INVALID_PARAMETER; } } else { IoStatus->Status = STATUS_INVALID_PARAMETER; } } except( EXCEPTION_EXECUTE_HANDLER ) { // The I/O request was not handled successfully, abort the I/O request with // the error status that we get back from the execption code IoStatus->Status = STATUS_INVALID_PARAMETER; FastIoSucceeded = TRUE; } } break; default: { FastIoSucceeded = FALSE; } } return FastIoSucceeded; } BOOLEAN RxFastQueryBasicInfo ( 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 Results = FALSE; PFCB Fcb = (PFCB)(FileObject->FsContext); PFOBX Fobx = (PFOBX)(FileObject->FsContext2); NODE_TYPE_CODE TypeOfOpen = NodeType(Fcb); BOOLEAN FcbAcquired = FALSE; PAGED_CODE(); // // Determine the type of open for the input file object and only accept // the user file or directory open // if ((TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) && (TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)) { return Results; } FsRtlEnterFileSystem(); // // Get access to the Fcb but only if it is not the paging file // if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) { if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) { FsRtlExitFileSystem(); return Results; } FcbAcquired = TRUE; } try { // // Set it to indicate that the query is a normal file. // Later we might overwrite the attribute. // Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; // // If the fcb is not the root dcb then we will fill in the // buffer otherwise it is all setup for us. // if (NodeType(Fcb) != RDBSS_NTC_ROOT_DCB) { // // Extract the data and fill in the non zero fields of the output // buffer // Buffer->LastWriteTime = Fcb->LastWriteTime; Buffer->ChangeTime = Fcb->LastChangeTime; Buffer->CreationTime = Fcb->CreationTime; Buffer->LastAccessTime = Fcb->LastAccessTime; // // Zero out the field we don't support. // Buffer->ChangeTime = RxLargeZero; if (Fcb->Attributes != 0) { Buffer->FileAttributes = Fcb->Attributes; } else { Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL; } } else { Buffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; } // // If the temporary flag is set, then set it in the buffer. // if (FlagOn( Fcb->FcbState, FCB_STATE_TEMPORARY )) { SetFlag( Buffer->FileAttributes, FILE_ATTRIBUTE_TEMPORARY ); } IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = sizeof(FILE_BASIC_INFORMATION); Results = TRUE; } finally { if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); } FsRtlExitFileSystem(); } // // And return to our caller // return Results; } BOOLEAN RxFastQueryStdInfo ( 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 Results = FALSE; PFCB Fcb = (PFCB)(FileObject->FsContext); PFOBX Fobx = (PFOBX)(FileObject->FsContext2); NODE_TYPE_CODE TypeOfOpen = NodeType(Fcb); BOOLEAN FcbAcquired = FALSE; PAGED_CODE(); // // Determine the type of open for the input file object and only accept // the user file or directory open // if ((TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_FILE) && (TypeOfOpen != RDBSS_NTC_STORAGE_TYPE_DIRECTORY)) { return Results; } // // Get access to the Fcb but only if it is not the paging file // FsRtlEnterFileSystem(); if (!FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) { if (!ExAcquireResourceSharedLite( Fcb->Header.Resource, Wait )) { FsRtlExitFileSystem(); return Results; } FcbAcquired = TRUE; } try { Buffer->NumberOfLinks = 1; Buffer->DeletePending = BooleanFlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE ); // // Case on whether this is a file or a directory, and extract // the information and fill in the fcb/dcb specific parts // of the output buffer. // if (NodeType(Fcb) == RDBSS_NTC_FCB) { // // If we don't alread know the allocation size, we cannot look // it up in the fast path. // if (Fcb->Header.AllocationSize.LowPart == 0xffffffff) { try_return( Results ); } Buffer->AllocationSize = Fcb->Header.AllocationSize; Buffer->EndOfFile = Fcb->Header.FileSize; Buffer->Directory = FALSE; } else { Buffer->AllocationSize = RxLargeZero; Buffer->EndOfFile = RxLargeZero; Buffer->Directory = TRUE; } IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = sizeof(FILE_STANDARD_INFORMATION); Results = TRUE; try_exit: NOTHING; } finally { if (FcbAcquired) { ExReleaseResourceLite( Fcb->Header.Resource ); } FsRtlExitFileSystem(); } // // And return to our caller // return Results; }