VOID FatFspDispatch ( IN PVOID Context ) /*++ Routine Description: This is the main FSP thread routine that is executed to receive and dispatch IRP requests. Each FSP thread begins its execution here. There is one thread created at system initialization time and subsequent threads created as needed. Arguments: Context - Supplies the thread id. Return Value: None - This routine never exits --*/ { NTSTATUS Status; PIRP Irp; PIRP_CONTEXT IrpContext; PIO_STACK_LOCATION IrpSp; BOOLEAN VcbDeleted; PVOLUME_DEVICE_OBJECT VolDo; PAGED_CODE(); IrpContext = (PIRP_CONTEXT)Context; Irp = IrpContext->OriginatingIrp; IrpSp = IoGetCurrentIrpStackLocation( Irp ); // // Now because we are the Fsp we will force the IrpContext to // indicate true on Wait. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT | IRP_CONTEXT_FLAG_IN_FSP); // // If this request has an associated volume device object, remember it. // if ( IrpSp->FileObject != NULL ) { VolDo = CONTAINING_RECORD( IrpSp->DeviceObject, VOLUME_DEVICE_OBJECT, DeviceObject ); } else { VolDo = NULL; } // // Now case on the function code. For each major function code, // either call the appropriate FSP routine or case on the minor // function and then call the FSP routine. The FSP routine that // we call is responsible for completing the IRP, and not us. // That way the routine can complete the IRP and then continue // post processing as required. For example, a read can be // satisfied right away and then read can be done. // // We'll do all of the work within an exception handler that // will be invoked if ever some underlying operation gets into // trouble (e.g., if FatReadSectorsSync has trouble). // while ( TRUE ) { DebugTrace(0, Dbg, "FatFspDispatch: Irp = 0x%08lx\n", Irp); // // If this Irp was top level, note it in our thread local storage. // FsRtlEnterFileSystem(); if ( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_RECURSIVE_CALL) ) { IoSetTopLevelIrp( (PIRP)FSRTL_FSP_TOP_LEVEL_IRP ); } else { IoSetTopLevelIrp( Irp ); } #if (__NDAS_FAT_PRIMARY__ || __NDAS_FAT_SECONDARY__) do { #if __NDAS_FAT_SECONDARY__ BOOLEAN volDoResourceAcquired = FALSE; #endif try { #if __NDAS_FAT_SECONDARY__ Status = STATUS_SUCCESS; if (Irp && IS_SECONDARY_FILEOBJECT(IoGetCurrentIrpStackLocation(Irp)->FileObject)) { BOOLEAN volDoRecoveryResourceAcquired = FALSE; ASSERT( FatIsTopLevelRequest(IrpContext) ); NDAS_ASSERT( FlagOn(IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT) ); while (TRUE) { ASSERT( volDoRecoveryResourceAcquired == FALSE ); ASSERT( volDoResourceAcquired == FALSE ); if (FlagOn(VolDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { volDoRecoveryResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolDo->RecoveryResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (!FlagOn(VolDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { SecondaryReleaseResourceLite( IrpContext, &VolDo->RecoveryResource ); volDoRecoveryResourceAcquired = FALSE; continue; } volDoResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &VolDo->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); try { SecondaryRecoverySessionStart( VolDo->Secondary, IrpContext ); } finally { SecondaryReleaseResourceLite( IrpContext, &VolDo->Resource ); volDoResourceAcquired = FALSE; SecondaryReleaseResourceLite( IrpContext, &VolDo->RecoveryResource ); volDoRecoveryResourceAcquired = FALSE; } continue; } volDoResourceAcquired = SecondaryAcquireResourceSharedLite( IrpContext, &VolDo->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); ASSERT( volDoResourceAcquired == TRUE ); break; } } #endif switch ( IrpContext->MajorFunction ) { // // For Create Operation, // case IRP_MJ_CREATE: (VOID) FatCommonCreate( IrpContext, Irp ); break; // // For close operations. We do a little kludge here in case // this close causes a volume to go away. It will NULL the // VolDo local variable so that we will not try to look at // the overflow queue. // case IRP_MJ_CLOSE: { PVCB Vcb; PFCB Fcb; PCCB Ccb; TYPE_OF_OPEN TypeOfOpen; // // Extract and decode the file object // TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); // // Do the close. We have a slightly different format // for this call because of the async closes. // Status = FatCommonClose( Vcb, Fcb, Ccb, TypeOfOpen, TRUE, &VcbDeleted ); // // If the VCB was deleted, do not try to access it later. // if (VcbDeleted) { VolDo = NULL; } ASSERT(Status == STATUS_SUCCESS); FatCompleteRequest( IrpContext, Irp, Status ); break; } // // For read operations // case IRP_MJ_READ: (VOID) FatCommonRead( IrpContext, Irp ); break; // // For write operations, // case IRP_MJ_WRITE: (VOID) FatCommonWrite( IrpContext, Irp ); break; // // For Query Information operations, // case IRP_MJ_QUERY_INFORMATION: (VOID) FatCommonQueryInformation( IrpContext, Irp ); break; // // For Set Information operations, // case IRP_MJ_SET_INFORMATION: (VOID) FatCommonSetInformation( IrpContext, Irp ); break; // // For Query EA operations, // case IRP_MJ_QUERY_EA: (VOID) FatCommonQueryEa( IrpContext, Irp ); break; // // For Set EA operations, // case IRP_MJ_SET_EA: (VOID) FatCommonSetEa( IrpContext, Irp ); break; // // For Flush buffers operations, // case IRP_MJ_FLUSH_BUFFERS: (VOID) FatCommonFlushBuffers( IrpContext, Irp ); break; // // For Query Volume Information operations, // case IRP_MJ_QUERY_VOLUME_INFORMATION: (VOID) FatCommonQueryVolumeInfo( IrpContext, Irp ); break; // // For Set Volume Information operations, // case IRP_MJ_SET_VOLUME_INFORMATION: (VOID) FatCommonSetVolumeInfo( IrpContext, Irp ); break; // // For File Cleanup operations, // case IRP_MJ_CLEANUP: (VOID) FatCommonCleanup( IrpContext, Irp ); break; // // For Directory Control operations, // case IRP_MJ_DIRECTORY_CONTROL: (VOID) FatCommonDirectoryControl( IrpContext, Irp ); break; // // For File System Control operations, // case IRP_MJ_FILE_SYSTEM_CONTROL: (VOID) FatCommonFileSystemControl( IrpContext, Irp ); break; // // For Lock Control operations, // case IRP_MJ_LOCK_CONTROL: (VOID) FatCommonLockControl( IrpContext, Irp ); break; // // For Device Control operations, // case IRP_MJ_DEVICE_CONTROL: (VOID) FatCommonDeviceControl( IrpContext, Irp ); break; // // For the Shutdown operation, // case IRP_MJ_SHUTDOWN: (VOID) FatCommonShutdown( IrpContext, Irp ); break; // // For plug and play operations. // case IRP_MJ_PNP: // // I don't believe this should ever occur, but allow for the unexpected. // (VOID) FatCommonPnp( IrpContext, Irp ); break; // // For any other major operations, return an invalid // request. // default: FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); break; } #if __NDAS_FAT_SECONDARY__ if (volDoResourceAcquired) { SecondaryReleaseResourceLite( NULL, &VolDo->Resource ); volDoResourceAcquired = FALSE; } #endif } except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) { #if __NDAS_FAT_SECONDARY__ if (volDoResourceAcquired) { SecondaryReleaseResourceLite( NULL, &VolDo->Resource ); volDoResourceAcquired = FALSE; } #endif // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with // the error status that we get back from the // execption code. // Status = FatProcessException( IrpContext, Irp, GetExceptionCode() ); } } while (Status == STATUS_CANT_WAIT);
NTSTATUS FatQueryDirectory ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This routine performs the query directory operation. It is responsible for either completing of enqueuing the input Irp. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PVCB Vcb; PDCB Dcb; PCCB Ccb; PBCB Bcb; ULONG i; PUCHAR Buffer; CLONG UserBufferLength; PUNICODE_STRING UniArgFileName; WCHAR LongFileNameBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE]; UNICODE_STRING LongFileName; FILE_INFORMATION_CLASS FileInformationClass; ULONG FileIndex; BOOLEAN RestartScan; BOOLEAN ReturnSingleEntry; BOOLEAN IndexSpecified; BOOLEAN InitialQuery; VBO CurrentVbo; BOOLEAN UpdateCcb; PDIRENT Dirent; UCHAR Fat8Dot3Buffer[12]; OEM_STRING Fat8Dot3String; ULONG DiskAllocSize; ULONG NextEntry; ULONG LastEntry; PFILE_DIRECTORY_INFORMATION DirInfo; PFILE_FULL_DIR_INFORMATION FullDirInfo; PFILE_BOTH_DIR_INFORMATION BothDirInfo; PFILE_ID_FULL_DIR_INFORMATION IdFullDirInfo; PFILE_ID_BOTH_DIR_INFORMATION IdBothDirInfo; PFILE_NAMES_INFORMATION NamesInfo; PAGED_CODE(); // // Get the current Stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); // // Display the input values. // DebugTrace(+1, Dbg, "FatQueryDirectory...\n", 0); DebugTrace( 0, Dbg, " Wait = %08lx\n", FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); DebugTrace( 0, Dbg, " Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, " ->Length = %08lx\n", IrpSp->Parameters.QueryDirectory.Length); DebugTrace( 0, Dbg, " ->FileName = %08lx\n", IrpSp->Parameters.QueryDirectory.FileName); DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass); DebugTrace( 0, Dbg, " ->FileIndex = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex); DebugTrace( 0, Dbg, " ->UserBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer); DebugTrace( 0, Dbg, " ->RestartScan = %08lx\n", FlagOn( IrpSp->Flags, SL_RESTART_SCAN )); DebugTrace( 0, Dbg, " ->ReturnSingleEntry = %08lx\n", FlagOn( IrpSp->Flags, SL_RETURN_SINGLE_ENTRY )); DebugTrace( 0, Dbg, " ->IndexSpecified = %08lx\n", FlagOn( IrpSp->Flags, SL_INDEX_SPECIFIED )); // // Reference our input parameters to make things easier // UserBufferLength = IrpSp->Parameters.QueryDirectory.Length; FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass; FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex; UniArgFileName = IrpSp->Parameters.QueryDirectory.FileName; RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN); ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY); IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED); // // Check on the type of open. We return invalid parameter for all // but UserDirectoryOpens. Also check that the filename is a valid // UNICODE string. // if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Dcb, &Ccb) != UserDirectoryOpen || (UniArgFileName && UniArgFileName->Length % sizeof(WCHAR))) { FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace(-1, Dbg, "FatQueryDirectory -> STATUS_INVALID_PARAMETER\n", 0); return STATUS_INVALID_PARAMETER; } // // Initialize the local variables. // Bcb = NULL; UpdateCcb = TRUE; Dirent = NULL; Fat8Dot3String.MaximumLength = 12; Fat8Dot3String.Buffer = Fat8Dot3Buffer; LongFileName.Length = 0; LongFileName.MaximumLength = sizeof( LongFileNameBuffer); LongFileName.Buffer = LongFileNameBuffer; InitialQuery = (BOOLEAN)((Ccb->UnicodeQueryTemplate.Buffer == NULL) && !FlagOn(Ccb->Flags, CCB_FLAG_MATCH_ALL)); Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; DiskAllocSize = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster; // // If this is the initial query, then grab exclusive access in // order to update the search string in the Ccb. We may // discover that we are not the initial query once we grab the Fcb // and downgrade our status. // if (InitialQuery) { if (!FatAcquireExclusiveFcb( IrpContext, Dcb )) { DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0); Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status); return Status; } if (Ccb->UnicodeQueryTemplate.Buffer != NULL) { InitialQuery = FALSE; FatConvertToSharedFcb( IrpContext, Dcb ); } } else { if (!FatAcquireSharedFcb( IrpContext, Dcb )) { DebugTrace(0, Dbg, "FatQueryDirectory -> Enqueue to Fsp\n", 0); Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatQueryDirectory -> %08lx\n", Status); return Status; } } try { ULONG BaseLength; ULONG BytesConverted; // // If we are in the Fsp now because we had to wait earlier, // we must map the user buffer, otherwise we can use the // user's buffer directly. // Buffer = FatMapUserBuffer( IrpContext, Irp ); // // Make sure the Dcb is still good. // FatVerifyFcb( IrpContext, Dcb ); // // Determine where to start the scan. Highest priority is given // to the file index. Lower priority is the restart flag. If // neither of these is specified, then the Vbo offset field in the // Ccb is used. // if (IndexSpecified) { CurrentVbo = FileIndex + sizeof( DIRENT ); } else if (RestartScan) { CurrentVbo = 0; } else { CurrentVbo = Ccb->OffsetToStartSearchFrom; } // // If this is the first try then allocate a buffer for the file // name. // if (InitialQuery) { // // If either: // // - No name was specified // - An empty name was specified // - We received a '*' // - The user specified the DOS equivolent of ????????.??? // // then match all names. // if ((UniArgFileName == NULL) || (UniArgFileName->Length == 0) || (UniArgFileName->Buffer == NULL) || ((UniArgFileName->Length == sizeof(WCHAR)) && (UniArgFileName->Buffer[0] == L'*')) || ((UniArgFileName->Length == 12*sizeof(WCHAR)) && (RtlEqualMemory( UniArgFileName->Buffer, Fat8QMdot3QM, 12*sizeof(WCHAR) )))) { Ccb->ContainsWildCards = TRUE; SetFlag( Ccb->Flags, CCB_FLAG_MATCH_ALL ); } else { BOOLEAN ExtendedName = FALSE; OEM_STRING LocalBestFit; // // First and formost, see if the name has wild cards. // Ccb->ContainsWildCards = FsRtlDoesNameContainWildCards( UniArgFileName ); // // Now check to see if the name contains any extended // characters // for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) { if (UniArgFileName->Buffer[i] >= 0x80) { ExtendedName = TRUE; break; } } // // OK, now do the conversions we need. // if (ExtendedName) { Status = RtlUpcaseUnicodeString( &Ccb->UnicodeQueryTemplate, UniArgFileName, TRUE ); if (!NT_SUCCESS(Status)) { try_return( Status ); } SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE ); // // Upcase the name and convert it to the Oem code page. // Status = RtlUpcaseUnicodeStringToCountedOemString( &LocalBestFit, UniArgFileName, TRUE ); // // If this conversion failed for any reason other than // an unmappable character fail the request. // if (!NT_SUCCESS(Status)) { if (Status == STATUS_UNMAPPABLE_CHARACTER) { SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ); } else { try_return( Status ); } } else { SetFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT ); } } else { PVOID Buffers; // // This case is optimized because I know I only have to // worry about a-z. // Buffers = FsRtlAllocatePoolWithTag( PagedPool, UniArgFileName->Length + UniArgFileName->Length / sizeof(WCHAR), TAG_FILENAME_BUFFER ); Ccb->UnicodeQueryTemplate.Buffer = Buffers; Ccb->UnicodeQueryTemplate.Length = UniArgFileName->Length; Ccb->UnicodeQueryTemplate.MaximumLength = UniArgFileName->Length; LocalBestFit.Buffer = (PUCHAR)Buffers + UniArgFileName->Length; LocalBestFit.Length = UniArgFileName->Length / sizeof(WCHAR); LocalBestFit.MaximumLength = LocalBestFit.Length; SetFlag( Ccb->Flags, CCB_FLAG_FREE_UNICODE ); for (i=0; i < UniArgFileName->Length / sizeof(WCHAR); i++) { WCHAR c = UniArgFileName->Buffer[i]; LocalBestFit.Buffer[i] = (UCHAR) (Ccb->UnicodeQueryTemplate.Buffer[i] = (c < 'a' ? c : c <= 'z' ? c - ('a' - 'A') : c)); } } // // At this point we now have the upcased unicode name, // and the two Oem names if they could be represented in // this code page. // // Now determine if the Oem names are legal for what we // going to try and do. Mark them as not usable is they // are not legal. Note that we can optimize extended names // since they are actually both the same string. // if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ) && !FatIsNameShortOemValid( IrpContext, LocalBestFit, Ccb->ContainsWildCards, FALSE, FALSE )) { if (ExtendedName) { RtlFreeOemString( &LocalBestFit ); ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT ); } SetFlag( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE ); } // // OK, now both locals oem strings correctly reflect their // usability. Now we want to load up the Ccb structure. // // Now we will branch on two paths of wheather the name // is wild or not. // if (!FlagOn( Ccb->Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE )) { if (Ccb->ContainsWildCards) { Ccb->OemQueryTemplate.Wild = LocalBestFit; } else { FatStringTo8dot3( IrpContext, LocalBestFit, &Ccb->OemQueryTemplate.Constant ); if (FlagOn(Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT)) { RtlFreeOemString( &LocalBestFit ); ClearFlag( Ccb->Flags, CCB_FLAG_FREE_OEM_BEST_FIT ); } } } } // // We convert to shared access. // FatConvertToSharedFcb( IrpContext, Dcb ); } LastEntry = 0; NextEntry = 0; switch (FileInformationClass) { case FileDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); break; case FileFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); break; case FileIdFullDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileName[0] ); break; case FileNamesInformation: BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); break; case FileBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); break; case FileIdBothDirectoryInformation: BaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileName[0] ); break; default: try_return( Status = STATUS_INVALID_INFO_CLASS ); } // // At this point we are about to enter our query loop. We have // determined the index into the directory file to begin the // search. LastEntry and NextEntry are used to index into the user // buffer. LastEntry is the last entry we've added, NextEntry is // current one we're working on. If NextEntry is non-zero, then // at least one entry was added. // while ( TRUE ) { VBO NextVbo; ULONG FileNameLength; ULONG BytesRemainingInBuffer; DebugTrace(0, Dbg, "FatQueryDirectory -> Top of loop\n", 0); // // If the user had requested only a single match and we have // returned that, then we stop at this point. // if (ReturnSingleEntry && NextEntry != 0) { try_return( Status ); } // // We call FatLocateDirent to lock down the next matching dirent. // FatLocateDirent( IrpContext, Dcb, Ccb, CurrentVbo, &Dirent, &Bcb, &NextVbo, NULL, &LongFileName); // // If we didn't receive a dirent, then we are at the end of the // directory. If we have returned any files, we exit with // success, otherwise we return STATUS_NO_MORE_FILES. // if (!Dirent) { DebugTrace(0, Dbg, "FatQueryDirectory -> No dirent\n", 0); if (NextEntry == 0) { UpdateCcb = FALSE; if (InitialQuery) { Status = STATUS_NO_SUCH_FILE; } else { Status = STATUS_NO_MORE_FILES; } } try_return( Status ); } // // Protect access to the user buffer with an exception handler. // Since (at our request) IO doesn't buffer these requests, we have // to guard against a user messing with the page protection and other // such trickery. // try { if (LongFileName.Length == 0) { // // Now we have an entry to return to our caller. We'll convert // the name from the form in the dirent to a <name>.<ext> form. // We'll case on the type of information requested and fill up // the user buffer if everything fits. // Fat8dot3ToString( IrpContext, Dirent, TRUE, &Fat8Dot3String ); // // Determine the UNICODE length of the file name. // FileNameLength = RtlOemStringToCountedUnicodeSize(&Fat8Dot3String); // // Here are the rules concerning filling up the buffer: // // 1. The Io system garentees that there will always be // enough room for at least one base record. // // 2. If the full first record (including file name) cannot // fit, as much of the name as possible is copied and // STATUS_BUFFER_OVERFLOW is returned. // // 3. If a subsequent record cannot completely fit into the // buffer, none of it (as in 0 bytes) is copied, and // STATUS_SUCCESS is returned. A subsequent query will // pick up with this record. // BytesRemainingInBuffer = UserBufferLength - NextEntry; if ( (NextEntry != 0) && ( (BaseLength + FileNameLength > BytesRemainingInBuffer) || (UserBufferLength < NextEntry) ) ) { DebugTrace(0, Dbg, "Next entry won't fit\n", 0); try_return( Status = STATUS_SUCCESS ); } ASSERT( BytesRemainingInBuffer >= BaseLength ); // // Zero the base part of the structure. // RtlZeroMemory( &Buffer[NextEntry], BaseLength ); switch ( FileInformationClass ) { // // Now fill the base parts of the strucure that are applicable. // case FileBothDirectoryInformation: case FileFullDirectoryInformation: case FileIdBothDirectoryInformation: case FileIdFullDirectoryInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0); // // Get the Ea file length. // FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry]; // // If the EAs are corrupt, ignore the error. We don't want // to abort the directory query. // try { FatGetEaLength( IrpContext, Vcb, Dirent, &FullDirInfo->EaSize ); } except(EXCEPTION_EXECUTE_HANDLER) { FatResetExceptionState( IrpContext ); FullDirInfo->EaSize = 0; } case FileDirectoryInformation: DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry]; FatGetDirTimes( IrpContext, Dirent, DirInfo ); DirInfo->EndOfFile.QuadPart = Dirent->FileSize; if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) { DirInfo->AllocationSize.QuadPart = (((Dirent->FileSize + DiskAllocSize - 1) / DiskAllocSize) * DiskAllocSize ); } DirInfo->FileAttributes = Dirent->Attributes != 0 ? Dirent->Attributes : FILE_ATTRIBUTE_NORMAL; DirInfo->FileIndex = NextVbo; DirInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String); break; case FileNamesInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0); NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry]; NamesInfo->FileIndex = NextVbo; NamesInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String ); break; default: FatBugCheck( FileInformationClass, 0, 0 ); } BytesConverted = 0; Status = RtlOemToUnicodeN( (PWCH)&Buffer[NextEntry + BaseLength], BytesRemainingInBuffer - BaseLength, &BytesConverted, Fat8Dot3String.Buffer, Fat8Dot3String.Length ); // // Check for the case that a single entry doesn't fit. // This should only get this far on the first entry // if (BytesConverted < FileNameLength) { ASSERT( NextEntry == 0 ); Status = STATUS_BUFFER_OVERFLOW; } // // Set up the previous next entry offset // *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry; // // And indicate how much of the user buffer we have currently // used up. We must compute this value before we long align // ourselves for the next entry // Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) + BaseLength + BytesConverted; // // If something happened with the conversion, bail here. // if ( !NT_SUCCESS( Status ) ) { try_return( NOTHING ); } } else { ULONG ShortNameLength; FileNameLength = LongFileName.Length; // // Here are the rules concerning filling up the buffer: // // 1. The Io system garentees that there will always be // enough room for at least one base record. // // 2. If the full first record (including file name) cannot // fit, as much of the name as possible is copied and // STATUS_BUFFER_OVERFLOW is returned. // // 3. If a subsequent record cannot completely fit into the // buffer, none of it (as in 0 bytes) is copied, and // STATUS_SUCCESS is returned. A subsequent query will // pick up with this record. // BytesRemainingInBuffer = UserBufferLength - NextEntry; if ( (NextEntry != 0) && ( (BaseLength + FileNameLength > BytesRemainingInBuffer) || (UserBufferLength < NextEntry) ) ) { DebugTrace(0, Dbg, "Next entry won't fit\n", 0); try_return( Status = STATUS_SUCCESS ); } ASSERT( BytesRemainingInBuffer >= BaseLength ); // // Zero the base part of the structure. // RtlZeroMemory( &Buffer[NextEntry], BaseLength ); switch ( FileInformationClass ) { // // Now fill the base parts of the strucure that are applicable. // case FileBothDirectoryInformation: case FileIdBothDirectoryInformation: BothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&Buffer[NextEntry]; // // Now we have an entry to return to our caller. We'll convert // the name from the form in the dirent to a <name>.<ext> form. // We'll case on the type of information requested and fill up // the user buffer if everything fits. // Fat8dot3ToString( IrpContext, Dirent, FALSE, &Fat8Dot3String ); ASSERT( Fat8Dot3String.Length <= 12 ); Status = RtlOemToUnicodeN( &BothDirInfo->ShortName[0], 12*sizeof(WCHAR), &ShortNameLength, Fat8Dot3String.Buffer, Fat8Dot3String.Length ); ASSERT( Status != STATUS_BUFFER_OVERFLOW ); ASSERT( ShortNameLength <= 12*sizeof(WCHAR) ); // // Copy the length into the dirinfo structure. Note // that the LHS below is a USHORT, so it can not // be specificed as the OUT parameter above. // BothDirInfo->ShortNameLength = (UCHAR)ShortNameLength; // // If something happened with the conversion, bail here. // if ( !NT_SUCCESS( Status ) ) { try_return( NOTHING ); } case FileFullDirectoryInformation: case FileIdFullDirectoryInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file full directory information\n", 0); // // Get the Ea file length. // FullDirInfo = (PFILE_FULL_DIR_INFORMATION)&Buffer[NextEntry]; // // If the EAs are corrupt, ignore the error. We don't want // to abort the directory query. // try { FatGetEaLength( IrpContext, Vcb, Dirent, &FullDirInfo->EaSize ); } except(EXCEPTION_EXECUTE_HANDLER) { FatResetExceptionState( IrpContext ); FullDirInfo->EaSize = 0; } case FileDirectoryInformation: DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry]; FatGetDirTimes( IrpContext, Dirent, DirInfo ); DirInfo->EndOfFile.QuadPart = Dirent->FileSize; if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) { DirInfo->AllocationSize.QuadPart = ( (( Dirent->FileSize + DiskAllocSize - 1 ) / DiskAllocSize ) * DiskAllocSize ); } DirInfo->FileAttributes = Dirent->Attributes != 0 ? Dirent->Attributes : FILE_ATTRIBUTE_NORMAL; DirInfo->FileIndex = NextVbo; DirInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String); break; case FileNamesInformation: DebugTrace(0, Dbg, "FatQueryDirectory -> Getting file names information\n", 0); NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry]; NamesInfo->FileIndex = NextVbo; NamesInfo->FileNameLength = FileNameLength; DebugTrace(0, Dbg, "FatQueryDirectory -> Name = \"%Z\"\n", &Fat8Dot3String ); break; default: FatBugCheck( FileInformationClass, 0, 0 ); } BytesConverted = BytesRemainingInBuffer - BaseLength >= FileNameLength ? FileNameLength : BytesRemainingInBuffer - BaseLength; RtlCopyMemory( &Buffer[NextEntry + BaseLength], &LongFileName.Buffer[0], BytesConverted ); // // Set up the previous next entry offset // *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry; // // And indicate how much of the user buffer we have currently // used up. We must compute this value before we long align // ourselves for the next entry // Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information ) + BaseLength + BytesConverted; // // Check for the case that a single entry doesn't fit. // This should only get this far on the first entry. // if (BytesConverted < FileNameLength) { ASSERT( NextEntry == 0 ); try_return( Status = STATUS_BUFFER_OVERFLOW ); } } // // Finish up by filling in the FileId // switch ( FileInformationClass ) { case FileIdBothDirectoryInformation: IdBothDirInfo = (PFILE_ID_BOTH_DIR_INFORMATION)&Buffer[NextEntry]; IdBothDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo ); break; case FileIdFullDirectoryInformation: IdFullDirInfo = (PFILE_ID_FULL_DIR_INFORMATION)&Buffer[NextEntry]; IdFullDirInfo->FileId.QuadPart = FatGenerateFileIdFromDirentAndOffset( Dcb, Dirent, NextVbo ); break; default: break; } } except (EXCEPTION_EXECUTE_HANDLER) { // // We had a problem filling in the user's buffer, so stop and // fail this request. This is the only reason any exception // would have occured at this level. // Irp->IoStatus.Information = 0; UpdateCcb = FALSE; try_return( Status = GetExceptionCode()); } // // Set ourselves up for the next iteration // LastEntry = NextEntry; NextEntry += (ULONG)QuadAlign(BaseLength + BytesConverted); CurrentVbo = NextVbo + sizeof( DIRENT ); } try_exit: NOTHING; } finally {
NTSTATUS NdFatSecondaryCommonWrite3 ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS status; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT fileObject = irpSp->FileObject; struct Write write; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; BOOLEAN fcbAcquired = FALSE; BOOLEAN writeToEof; PUCHAR inputBuffer; ULONG totalWriteLength; ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); ASSERT (!FlagOn(Irp->Flags, IRP_PAGING_IO)); typeOfOpen = FatDecodeFileObject( fileObject, &vcb, &fcb, &ccb ); ASSERT( typeOfOpen == UserFileOpen ); if (FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { /*if (FlagOn( fcb->FcbState, FCB_STATE_FILE_DELETED )) { ASSERT( FALSE ); FatRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL ); } else */{ ASSERT( FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); status = STATUS_FILE_CORRUPT_ERROR; FatCompleteRequest( IrpContext, Irp, status ); return status; } } writeToEof = (irpSp->Parameters.Write.ByteOffset.QuadPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1); write.ByteOffset = irpSp->Parameters.Write.ByteOffset; write.Key = irpSp->Parameters.Write.Key; write.Length = irpSp->Parameters.Write.Length; ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); //FatAcquireSharedFcb( IrpContext, fcb ); //fcbAcquired = TRUE; try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->Secondary->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); if (FlagOn(Irp->Flags, IRP_PAGING_IO)) { try_return( status = STATUS_FILE_LOCK_CONFLICT ); } else { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } } inputBuffer = FatMapUserBuffer( IrpContext, Irp ); totalWriteLength = 0; do { ULONG inputBufferLength; _U8 *ndfsWinxpRequestData; _U64 primaryFileHandle; if (fcb->UncleanCount == 0) { DebugTrace( 0, Dbg2, "NdFatSecondaryCommonWrite2: fileName = %wZ\n", &fileObject->FileName ); totalWriteLength = write.Length; status = STATUS_FILE_CLOSED; break; } if (!FlagOn(ccb->NdFatFlags, ND_FAT_CLEANUP_COMPLETE)) { primaryFileHandle = ccb->PrimaryFileHandle; } else { PLIST_ENTRY ccbListEntry; ExAcquireFastMutex( &fcb->CcbQMutex ); for (primaryFileHandle = 0, ccbListEntry = fcb->CcbQueue.Flink; ccbListEntry != &fcb->CcbQueue; ccbListEntry = ccbListEntry->Flink) { if (!FlagOn(CONTAINING_RECORD(ccbListEntry, CCB, FcbListEntry)->NdFatFlags, ND_FAT_CLEANUP_COMPLETE)) { primaryFileHandle = CONTAINING_RECORD(ccbListEntry, CCB, FcbListEntry)->PrimaryFileHandle; break; } } ExReleaseFastMutex( &fcb->CcbQMutex ); } ASSERT( primaryFileHandle ); inputBufferLength = ((write.Length-totalWriteLength) <= volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize) ? (write.Length-totalWriteLength) : volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize; secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_WRITE, volDo->Secondary->Thread.SessionContext.PrimaryMaxDataSize ); if (secondaryRequest == NULL) { FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_WRITE, inputBufferLength ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Irp; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_WRITE; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = primaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; ndfsWinxpRequestHeader->Write.Length = inputBufferLength; ndfsWinxpRequestHeader->Write.Key = write.Key; if (writeToEof) ndfsWinxpRequestHeader->Write.ByteOffset = write.ByteOffset.QuadPart; else ndfsWinxpRequestHeader->Write.ByteOffset = write.ByteOffset.QuadPart + totalWriteLength; ndfsWinxpRequestHeader->Write.ForceWrite = TRUE; DebugTrace2( 0, Dbg, ("ndfsWinxpRequestHeader->Write.ByteOffset = %I64d, ndfsWinxpRequestHeader->Write.Length = %d\n", ndfsWinxpRequestHeader->Write.ByteOffset, ndfsWinxpRequestHeader->Write.Length) ); ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1); if (inputBufferLength) { try { RtlCopyMemory( ndfsWinxpRequestData, inputBuffer + totalWriteLength, inputBufferLength ); } except (EXCEPTION_EXECUTE_HANDLER) { DebugTrace2( 0, Dbg2, ("RedirectIrp: Exception - Input buffer is not valid\n") ); status = GetExceptionCode(); break; } } //if (fcb->Header.FileSize.LowPart < 100) // DbgPrint( "data = %s\n", ndfsWinxpRequestData ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { secondaryRequest = NULL; status = STATUS_IO_DEVICE_ERROR; leave; } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); if (FlagOn(Irp->Flags, IRP_PAGING_IO)) { try_return( status = STATUS_FILE_LOCK_CONFLICT ); } else { FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { DebugTrace2( 0, Dbg, ("ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); if (totalWriteLength) status = STATUS_SUCCESS; else status = ndfsWinxpReplytHeader->Status; ASSERT( ndfsWinxpReplytHeader->Information == 0 ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; break; } totalWriteLength += ndfsWinxpReplytHeader->Information; ASSERT( ndfsWinxpReplytHeader->Information <= inputBufferLength ); ASSERT( ndfsWinxpReplytHeader->Information != 0 ); DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } while( totalWriteLength < write.Length ); try_exit: NOTHING; } finally { if (!AbnormalTermination()) { if (totalWriteLength) { Irp->IoStatus.Information = totalWriteLength; Irp->IoStatus.Status = STATUS_SUCCESS; } else { Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; } } DebugTrace2( 0, Dbg, ("write.ByteOffset.QuadPart = %I64x, write.Length = %x, totalWriteRequestLength = %x lastStatus = %x\n", write.ByteOffset.QuadPart, write.Length, totalWriteLength, status) ); if (!FlagOn(ccb->NdFatFlags, ND_FAT_CLEANUP_COMPLETE) && Irp->IoStatus.Status != STATUS_SUCCESS) { DebugTrace2( 0, Dbg, ("write.ByteOffset.QuadPart = %I64x, write.Length = %x, totalWriteRequestLength = %x lastStatus = %x\n", write.ByteOffset.QuadPart, write.Length, totalWriteLength, status) ); PrintIrp( Dbg, "RedirectIrpMajorWrite", NULL, Irp ); } if (secondarySessionResourceAcquired == TRUE) SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); if (fcbAcquired) { FatReleaseFcb( IrpContext, fcb ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } FatCompleteRequest( IrpContext, Irp, status ); return status; }
NTSTATUS NdFatSecondaryCommonWrite ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) { NTSTATUS status; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( Irp ); PFILE_OBJECT fileObject = irpSp->FileObject; struct Write write; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; BOOLEAN fcbAcquired = FALSE; ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); typeOfOpen = FatDecodeFileObject( fileObject, &vcb, &fcb, &ccb ); ASSERT( typeOfOpen == UserFileOpen ); if (FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { /*if (FlagOn( fcb->FcbState, FCB_STATE_FILE_DELETED )) { ASSERT( FALSE ); FatRaiseStatus( IrpContext, STATUS_FILE_DELETED, NULL, NULL ); } else */{ ASSERT( FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); return STATUS_FILE_CORRUPT_ERROR; } } if (irpSp->Parameters.Write.ByteOffset.QuadPart == FILE_WRITE_TO_END_OF_FILE && irpSp->Parameters.Write.ByteOffset.HighPart == -1) { write.ByteOffset = fcb->Header.FileSize; } else { write.ByteOffset = irpSp->Parameters.Write.ByteOffset; } write.Key = 0; write.Length = irpSp->Parameters.Write.Length; if (FlagOn(Irp->Flags, IRP_PAGING_IO)) { ASSERT( (write.ByteOffset.QuadPart + write.Length) <= ((fcb->Header.AllocationSize.QuadPart + PAGE_SIZE - 1) & ~((LONGLONG) (PAGE_SIZE-1))) ); return STATUS_SUCCESS; } ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); //ASSERT( !FlagOn( IrpContext->State, IRP_CONTEXT_STATE_LAZY_WRITE ) ); if ( (write.ByteOffset.QuadPart + write.Length) <= fcb->Header.FileSize.LowPart) { return STATUS_SUCCESS; } if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { return STATUS_PENDING; ASSERT( FALSE ); DebugTrace2( 0, Dbg, ("Can't wait in NdFatSecondaryCommonWrite\n") ); status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace2( -1, Dbg2, ("NdFatSecondaryCommonWrite: FatFsdPostRequest -> %08lx\n", status) ); return status; } DebugTrace2( 0, Dbg, ("write.ByteOffset.QuadPart + write.Length > fcb->Header.AllocationSize.QuadPart = %d " "ExIsResourceAcquiredSharedLite(fcb->Header.Resource) = %d\n", ((write.ByteOffset.QuadPart + write.Length) > fcb->Header.AllocationSize.QuadPart), ExIsResourceAcquiredSharedLite(fcb->Header.Resource)) ); if ((write.ByteOffset.QuadPart + write.Length) > fcb->Header.AllocationSize.QuadPart) { FatAcquireExclusiveFcb( IrpContext, fcb ); fcbAcquired = TRUE; } try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->Secondary->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_SET_INFORMATION, volDo->Secondary->Thread.SessionContext.SecondaryMaxDataSize ); if (secondaryRequest == NULL) { FatRaiseStatus( IrpContext, STATUS_INSUFFICIENT_RESOURCES ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_SET_INFORMATION, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); //ndfsWinxpRequestHeader->IrpTag = (_U32)Irp; ndfsWinxpRequestHeader->IrpMajorFunction = IRP_MJ_SET_INFORMATION; ndfsWinxpRequestHeader->IrpMinorFunction = 0; ndfsWinxpRequestHeader->FileHandle = ccb->PrimaryFileHandle; ndfsWinxpRequestHeader->IrpFlags = 0; ndfsWinxpRequestHeader->IrpSpFlags = 0; ndfsWinxpRequestHeader->SetFile.FileHandle = 0; ndfsWinxpRequestHeader->SetFile.Length = sizeof( FILE_END_OF_FILE_INFORMATION ); ndfsWinxpRequestHeader->SetFile.FileInformationClass = FileEndOfFileInformation; ndfsWinxpRequestHeader->SetFile.EndOfFileInformation.EndOfFile = write.ByteOffset.QuadPart + write.Length; secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (status != STATUS_SUCCESS) { secondaryRequest = NULL; status = STATUS_IO_DEVICE_ERROR; leave; } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; status = ndfsWinxpReplytHeader->Status; Irp->IoStatus.Information = write.Length; if (ndfsWinxpReplytHeader->Status != STATUS_SUCCESS) { DebugTrace2( 0, Dbg2, ("NdNtfsSecondaryCommonWrite: ndfsWinxpReplytHeader->Status = %x\n", ndfsWinxpReplytHeader->Status) ); ASSERT( ndfsWinxpReplytHeader->Information == 0 ); } else ASSERT( ndfsWinxpReplytHeader->FileInformationSet ); if (ndfsWinxpReplytHeader->FileInformationSet) { PNDFS_FAT_MCB_ENTRY mcbEntry; ULONG index; BOOLEAN lookupResut; VBO vcn; LBO lcn; //LBO startingLcn; ULONG clusterCount; //DbgPrint( "w ndfsWinxpReplytHeader->FileSize = %x\n", ndfsWinxpReplytHeader->FileSize ); if (ndfsWinxpReplytHeader->AllocationSize != fcb->Header.AllocationSize.QuadPart) { ASSERT( ExIsResourceAcquiredExclusiveLite(fcb->Header.Resource) ); ASSERT( ndfsWinxpReplytHeader->AllocationSize > fcb->Header.AllocationSize.QuadPart ); mcbEntry = (PNDFS_FAT_MCB_ENTRY)( ndfsWinxpReplytHeader+1 ); for (index=0, vcn=0; index < ndfsWinxpReplytHeader->NumberOfMcbEntry; index++, mcbEntry++) { lookupResut = FatLookupMcbEntry( vcb, &fcb->Mcb, vcn, &lcn, &clusterCount, NULL ); if (lookupResut == TRUE && vcn < fcb->Header.AllocationSize.QuadPart) { ASSERT( lookupResut == TRUE ); //ASSERT( startingLcn == lcn ); ASSERT( vcn == mcbEntry->Vcn ); ASSERT( lcn == (((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector) ); ASSERT( clusterCount <= mcbEntry->ClusterCount ); if (clusterCount < mcbEntry->ClusterCount) { FatAddMcbEntry ( vcb, &fcb->Mcb, (VBO)mcbEntry->Vcn, ((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector, (ULONG)mcbEntry->ClusterCount ); lookupResut = FatLookupMcbEntry( vcb, &fcb->Mcb, vcn, &lcn, &clusterCount, NULL ); ASSERT( lookupResut == TRUE ); //ASSERT( startingLcn == lcn ); ASSERT( vcn == mcbEntry->Vcn ); ASSERT( lcn == (((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector) ); ASSERT( clusterCount == mcbEntry->ClusterCount ); } } else { ASSERT( lookupResut == FALSE || lcn == 0 ); FatAddMcbEntry ( vcb, &fcb->Mcb, (VBO)mcbEntry->Vcn, ((LBO)mcbEntry->Lcn) << vcb->AllocationSupport.LogOfBytesPerSector, (ULONG)mcbEntry->ClusterCount ); } vcn += (ULONG)mcbEntry->ClusterCount; } ASSERT( vcn == ndfsWinxpReplytHeader->AllocationSize ); fcb->Header.AllocationSize.QuadPart = ndfsWinxpReplytHeader->AllocationSize; SetFlag( fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE ); if (CcIsFileCached(fileObject)) { ASSERT( fileObject->SectionObjectPointer->SharedCacheMap != NULL ); CcSetFileSizes( fileObject, (PCC_FILE_SIZES)&fcb->Header.AllocationSize ); } } DebugTrace2(0, Dbg, ("write scb->Header.FileSize.LowPart = %I64x, scb->Header.ValidDataLength.QuadPart = %I64x\n", fcb->Header.FileSize.LowPart, fcb->Header.ValidDataLength.QuadPart) ); } #if DBG { BOOLEAN lookupResut; VBO vcn; LBO lcn; //LCN startingLcn; ULONG clusterCount; vcn = 0; while (1) { lookupResut = FatLookupMcbEntry( vcb, &fcb->Mcb, vcn, &lcn, &clusterCount, NULL ); if (lookupResut == FALSE || lcn == 0) break; vcn += clusterCount; } ASSERT( vcn == fcb->Header.AllocationSize.QuadPart ); } #endif } finally { if (secondarySessionResourceAcquired == TRUE) SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); if (fcbAcquired) { FatReleaseFcb( IrpContext, fcb ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } return status; }
/* Last handle to a file object is closed */ NTSTATUS NTAPI FatiCleanup(PFAT_IRP_CONTEXT IrpContext, PIRP Irp) { PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PSHARE_ACCESS ShareAccess; BOOLEAN SendUnlockNotification = FALSE; PLARGE_INTEGER TruncateSize = NULL; //LARGE_INTEGER LocalTruncateSize; BOOLEAN AcquiredVcb = FALSE, AcquiredFcb = FALSE; NTSTATUS Status; PVCB Vcb; PFCB Fcb; PCCB Ccb; IrpSp = IoGetCurrentIrpStackLocation( Irp ); DPRINT("FatiCleanup\n"); DPRINT("\tIrp = %p\n", Irp); DPRINT("\t->FileObject = %p\n", IrpSp->FileObject); FileObject = IrpSp->FileObject; TypeOfOpen = FatDecodeFileObject(FileObject, &Vcb, &Fcb, &Ccb); if (TypeOfOpen == UnopenedFileObject) { DPRINT1("Unopened File Object\n"); FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); return STATUS_SUCCESS; } if (FlagOn( FileObject->Flags, FO_CLEANUP_COMPLETE )) { /* Just flush the file */ if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) && FlagOn(FileObject->Flags, FO_FILE_MODIFIED) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED) && (TypeOfOpen == UserFileOpen)) { //Status = FatFlushFile(IrpContext, Fcb, Flush); //if (!NT_SUCCESS(Status)) FatNormalizeAndRaiseStatus(IrpContext, Status); UNIMPLEMENTED; } FatCompleteRequest(IrpContext, Irp, STATUS_SUCCESS); return STATUS_SUCCESS; } if (TypeOfOpen == UserFileOpen || TypeOfOpen == UserDirectoryOpen) { ASSERT(Fcb != NULL); (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); AcquiredFcb = TRUE; /* Set FCB flags according to DELETE_ON_CLOSE */ if (FlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE)) { ASSERT(FatNodeType(Fcb) != FAT_NTC_ROOT_DCB); SetFlag(Fcb->State, FCB_STATE_DELETE_ON_CLOSE); /* Issue a notification */ if (TypeOfOpen == UserDirectoryOpen) { FsRtlNotifyFullChangeDirectory(Vcb->NotifySync, &Vcb->NotifyList, FileObject->FsContext, NULL, FALSE, FALSE, 0, NULL, NULL, NULL); } } /* If file should be deleted, acquire locks */ if ((Fcb->UncleanCount == 1) && FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && (Fcb->Condition != FcbBad) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { FatReleaseFcb(IrpContext, Fcb); AcquiredFcb = FALSE; (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb); AcquiredVcb = TRUE; (VOID)FatAcquireExclusiveFcb(IrpContext, Fcb); AcquiredFcb = TRUE; } } /* Acquire VCB lock if it was a volume open */ if (TypeOfOpen == UserVolumeOpen) { (VOID)FatAcquireExclusiveVcb(IrpContext, Vcb); AcquiredVcb = TRUE; } /* Cleanup all notifications */ if (TypeOfOpen == UserDirectoryOpen) { FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb); } if (Fcb) { //TODO: FatVerifyFcb } switch (TypeOfOpen) { case DirectoryFile: case VirtualVolumeFile: DPRINT1("Cleanup VirtualVolumeFile/DirectoryFile\n"); ShareAccess = NULL; break; case UserVolumeOpen: DPRINT("Cleanup UserVolumeOpen\n"); if (FlagOn(Ccb->Flags, CCB_COMPLETE_DISMOUNT)) { FatCheckForDismount( IrpContext, Vcb, TRUE ); } else if (FileObject->WriteAccess && FlagOn(FileObject->Flags, FO_FILE_MODIFIED)) { UNIMPLEMENTED; } /* Release the volume and send notification */ if (FlagOn(Vcb->State, VCB_STATE_FLAG_LOCKED) && (Vcb->FileObjectWithVcbLocked == FileObject)) { UNIMPLEMENTED; SendUnlockNotification = TRUE; } ShareAccess = &Vcb->ShareAccess; break; case EaFile: DPRINT1("Cleanup EaFileObject\n"); ShareAccess = NULL; break; case UserDirectoryOpen: DPRINT("Cleanup UserDirectoryOpen\n"); ShareAccess = &Fcb->ShareAccess; /* Should it be a delayed close? */ if ((Fcb->UncleanCount == 1) && (Fcb->OpenCount == 1) && (Fcb->Dcb.DirectoryFileOpenCount == 0) && !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && Fcb->Condition == FcbGood) { /* Yes, a delayed one */ SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); } if (VcbGood == Vcb->Condition) { //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); //TODO: Actually update dirent } if ((Fcb->UncleanCount == 1) && (FatNodeType(Fcb) == FAT_NTC_DCB) && (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) && (Fcb->Condition != FcbBad) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { UNIMPLEMENTED; } /* Decrement unclean counter */ ASSERT(Fcb->UncleanCount != 0); Fcb->UncleanCount--; break; case UserFileOpen: DPRINT("Cleanup UserFileOpen\n"); ShareAccess = &Fcb->ShareAccess; /* Should it be a delayed close? */ if ((FileObject->SectionObjectPointer->DataSectionObject == NULL) && (FileObject->SectionObjectPointer->ImageSectionObject == NULL) && (Fcb->UncleanCount == 1) && (Fcb->OpenCount == 1) && !FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && Fcb->Condition == FcbGood) { /* Yes, a delayed one */ //SetFlag(Fcb->State, FCB_STATE_DELAY_CLOSE); DPRINT1("Setting a delay on close for some reason for FCB %p, FF handle %p, file name '%wZ'\n", Fcb, Fcb->FatHandle, &Fcb->FullFileName); } /* Unlock all file locks */ FsRtlFastUnlockAll(&Fcb->Fcb.Lock, FileObject, IoGetRequestorProcess(Irp), NULL); if (Vcb->Condition == VcbGood) { if (Fcb->Condition != FcbBad) { //FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); // TODO: Update on-disk structures } if (Fcb->UncleanCount == 1 && Fcb->Condition != FcbBad) { //DELETE_CONTEXT DeleteContext; /* Should this file be deleted on close? */ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { UNIMPLEMENTED; } else { if (!FlagOn(Fcb->State, FCB_STATE_PAGEFILE) && (Fcb->Header.ValidDataLength.LowPart < Fcb->Header.FileSize.LowPart)) { #if 0 ULONG ValidDataLength; ValidDataLength = Fcb->Header.ValidDataLength.LowPart; if (ValidDataLength < Fcb->ValidDataToDisk) { ValidDataLength = Fcb->ValidDataToDisk; } if (ValidDataLength < Fcb->Header.FileSize.LowPart) { FatZeroData( IrpContext, Vcb, FileObject, ValidDataLength, Fcb->Header.FileSize.LowPart - ValidDataLength ); Fcb->ValidDataToDisk = Fcb->Header.ValidDataLength.LowPart = Fcb->Header.FileSize.LowPart; if (CcIsFileCached(FileObject)) { CcSetFileSizes(FileObject, (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); } } #endif DPRINT1("Zeroing out data is not implemented\n"); } } /* Should the file be truncated on close? */ if (FlagOn(Fcb->State, FCB_STATE_TRUNCATE_ON_CLOSE)) { if (Vcb->Condition == VcbGood) { // TODO: Actually truncate the file allocation UNIMPLEMENTED; } /* Remove truncation flag */ Fcb->State &= ~FCB_STATE_TRUNCATE_ON_CLOSE; } /* Check again if it should be deleted */ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE) && Fcb->Header.AllocationSize.LowPart == 0) { FatNotifyReportChange(IrpContext, Vcb, Fcb, FILE_NOTIFY_CHANGE_FILE_NAME, FILE_ACTION_REMOVED); } /* Remove the entry from the splay table if the file was deleted */ if (FlagOn(Fcb->State, FCB_STATE_DELETE_ON_CLOSE)) { FatRemoveNames(IrpContext, Fcb); } } } ASSERT(Fcb->UncleanCount != 0); Fcb->UncleanCount--; if (!FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) { ASSERT(Fcb->NonCachedUncleanCount != 0); Fcb->NonCachedUncleanCount--; } if (FlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) && (Fcb->NonCachedUncleanCount != 0) && (Fcb->NonCachedUncleanCount == Fcb->UncleanCount) && (Fcb->SectionObjectPointers.DataSectionObject != NULL)) { CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL); /* Acquire and release PagingIo to get in sync with lazy writer */ ExAcquireResourceExclusiveLite(Fcb->Header.PagingIoResource, TRUE); ExReleaseResourceLite(Fcb->Header.PagingIoResource); CcPurgeCacheSection(&Fcb->SectionObjectPointers, NULL, 0, FALSE); } if (Fcb->Condition == FcbBad) { //TruncateSize = &FatLargeZero; UNIMPLEMENTED; } /* Cleanup the cache map */ CcUninitializeCacheMap(FileObject, TruncateSize, NULL); break; default: KeBugCheckEx(FAT_FILE_SYSTEM, __LINE__, (ULONG_PTR)TypeOfOpen, 0, 0); } /* Cleanup the share access */ if (ShareAccess) { DPRINT("Cleaning up the share access\n"); IoRemoveShareAccess(FileObject, ShareAccess); } if (TypeOfOpen == UserFileOpen) { /* Update oplocks */ FsRtlCheckOplock(&Fcb->Fcb.Oplock, Irp, IrpContext, NULL, NULL); Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb); } /* Set the FO_CLEANUP_COMPLETE flag */ SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE); Status = STATUS_SUCCESS; // TODO: Unpin repinned BCBs //FatUnpinRepinnedBcbs(IrpContext); /* Flush the volume if necessary */ if (FlagOn(Vcb->State, VCB_STATE_FLAG_DEFERRED_FLUSH) && !FlagOn(Vcb->State, VCB_STATE_FLAG_WRITE_PROTECTED)) { UNIMPLEMENTED; } /* Cleanup */ if (AcquiredFcb) FatReleaseFcb(IrpContext, Fcb); if (AcquiredVcb) FatReleaseVcb(IrpContext, Vcb); /* Send volume notification */ if (SendUnlockNotification) FsRtlNotifyVolumeEvent(FileObject, FSRTL_VOLUME_UNLOCK); return Status; }
NTSTATUS NdFatSecondaryUserFsCtrl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for implementing the user's requests made through NtFsControlFile. Arguments: Irp - Supplies the Irp being processed Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; ULONG FsControlCode; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp ); PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; PCCB ccb; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; _U8 *ndfsWinxpRequestData; LARGE_INTEGER timeOut; struct FileSystemControl fileSystemControl; PVOID inputBuffer = NULL; ULONG inputBufferLength; PVOID outputBuffer = NULL; ULONG outputBufferLength; ULONG bufferLength; // // Save some references to make our life a little easier // FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; DebugTrace(+1, Dbg,"FatUserFsCtrl...\n", 0); DebugTrace( 0, Dbg,"FsControlCode = %08lx\n", FsControlCode); // // Some of these Fs Controls use METHOD_NEITHER buffering. If the previous mode // of the caller was userspace and this is a METHOD_NEITHER, we have the choice // of realy buffering the request through so we can possibly post, or making the // request synchronous. Since the former was not done by design, do the latter. // if (Irp->RequestorMode != KernelMode && (FsControlCode & 3) == METHOD_NEITHER) { SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); } // // Case on the control code. // switch ( FsControlCode ) { case FSCTL_REQUEST_OPLOCK_LEVEL_1: case FSCTL_REQUEST_OPLOCK_LEVEL_2: case FSCTL_REQUEST_BATCH_OPLOCK: case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: case FSCTL_OPBATCH_ACK_CLOSE_PENDING: case FSCTL_OPLOCK_BREAK_NOTIFY: case FSCTL_OPLOCK_BREAK_ACK_NO_2: case FSCTL_REQUEST_FILTER_OPLOCK : //ASSERT( FALSE ); //Status = STATUS_SUCCESS; //break; Status = FatOplockRequest( IrpContext, Irp ); return Status; case FSCTL_LOCK_VOLUME: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatLockVolume( IrpContext, Irp ); break; case FSCTL_UNLOCK_VOLUME: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatUnlockVolume( IrpContext, Irp ); break; case FSCTL_DISMOUNT_VOLUME: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatDismountVolume( IrpContext, Irp ); break; case FSCTL_MARK_VOLUME_DIRTY: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NdFatSecondaryUserFsCtrl -> %08lx\n", Status) ); return Status; //Status = FatDirtyVolume( IrpContext, Irp ); break; case FSCTL_IS_VOLUME_DIRTY: Status = FatIsVolumeDirty( IrpContext, Irp ); break; case FSCTL_IS_VOLUME_MOUNTED: Status = FatIsVolumeMounted( IrpContext, Irp ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_IS_PATHNAME_VALID: Status = FatIsPathnameValid( IrpContext, Irp ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_QUERY_RETRIEVAL_POINTERS: Status = FatQueryRetrievalPointers( IrpContext, Irp ); break; case FSCTL_QUERY_FAT_BPB: Status = FatQueryBpb( IrpContext, Irp ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; break; case FSCTL_FILESYSTEM_GET_STATISTICS: Status = FatGetStatistics( IrpContext, Irp ); break; case FSCTL_GET_VOLUME_BITMAP: Status = FatGetVolumeBitmap( IrpContext, Irp ); break; case FSCTL_GET_RETRIEVAL_POINTERS: Status = FatGetRetrievalPointers( IrpContext, Irp ); break; case FSCTL_MOVE_FILE: FatCompleteRequest( IrpContext, Irp, Status = STATUS_ACCESS_DENIED ); DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; //Status = FatMoveFile( IrpContext, Irp ); break; case FSCTL_ALLOW_EXTENDED_DASD_IO: Status = FatAllowExtendedDasdIo( IrpContext, Irp ); break; default : DebugTrace(0, Dbg, "Invalid control code -> %08lx\n", FsControlCode ); FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST ); Status = STATUS_INVALID_DEVICE_REQUEST; break; } ASSERT( !ExIsResourceAcquiredSharedLite(&volDo->Vcb.Resource) ); if (Status != STATUS_SUCCESS) { DebugTrace2( -1, Dbg, ("NtfsUserFsRequest -> %08lx\n", Status) ); return Status; } inputBuffer = IrpContext->InputBuffer; outputBuffer = IrpContext->outputBuffer; ASSERT( IrpSp->Parameters.FileSystemControl.InputBufferLength ? (inputBuffer != NULL) : (inputBuffer == NULL) ); ASSERT( IrpSp->Parameters.FileSystemControl.OutputBufferLength ? (outputBuffer != NULL) : (outputBuffer == NULL) ); ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL ); if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) { return FatFsdPostRequest( IrpContext, Irp ); } try { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->Secondary->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ASSERT( IS_SECONDARY_FILEOBJECT(IrpSp->FileObject) ); typeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &vcb, &fcb, &ccb ); if (FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { ASSERT( FlagOn(ccb->NdFatFlags, ND_FAT_CCB_FLAG_CORRUPTED) ); try_return( Status = STATUS_FILE_CORRUPT_ERROR ); } fileSystemControl.FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode; fileSystemControl.InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; fileSystemControl.OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; if (inputBuffer == NULL) fileSystemControl.InputBufferLength = 0; if (outputBuffer == NULL) fileSystemControl.OutputBufferLength = 0; outputBufferLength = fileSystemControl.OutputBufferLength; if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 inputBufferLength = 0; } else if (fileSystemControl.FsControlCode == FSCTL_MARK_HANDLE) { // 63 inputBufferLength = 0; } else { inputBufferLength = fileSystemControl.InputBufferLength; } bufferLength = (inputBufferLength >= outputBufferLength) ? inputBufferLength : outputBufferLength; secondaryRequest = ALLOC_WINXP_SECONDARY_REQUEST( volDo->Secondary, IRP_MJ_FILE_SYSTEM_CONTROL, bufferLength ); if (secondaryRequest == NULL) { Status = Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; Irp->IoStatus.Information = 0; try_return( Status ); } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FILE_SYSTEM_CONTROL, inputBufferLength ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, Irp, IrpSp, ccb->PrimaryFileHandle ); ndfsWinxpRequestHeader->FileSystemControl.OutputBufferLength = fileSystemControl.OutputBufferLength; ndfsWinxpRequestHeader->FileSystemControl.InputBufferLength = fileSystemControl.InputBufferLength; ndfsWinxpRequestHeader->FileSystemControl.FsControlCode = fileSystemControl.FsControlCode; #if 0 if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 PMOVE_FILE_DATA moveFileData = inputBuffer; PFILE_OBJECT moveFileObject; PCCB moveCcb; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if (Status != STATUS_SUCCESS) { ASSERT( FALSE ); try_return( Status ); } ObDereferenceObject( moveFileObject ); moveCcb = moveFileObject->FsContext2; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.FileHandle = moveCcb->PrimaryFileHandle; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.StartingVcn = moveFileData->StartingVcn.QuadPart; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.StartingLcn = moveFileData->StartingLcn.QuadPart; ndfsWinxpRequestHeader->FileSystemControl.FscMoveFileData.ClusterCount = moveFileData->ClusterCount; } else #endif if (fileSystemControl.FsControlCode == FSCTL_MARK_HANDLE) { // 63 PMARK_HANDLE_INFO markHandleInfo = inputBuffer; PFILE_OBJECT volumeFileObject; PCCB volumeCcb; Status = ObReferenceObjectByHandle( markHandleInfo->VolumeHandle, FILE_READ_DATA, 0, KernelMode, &volumeFileObject, NULL ); if (Status != STATUS_SUCCESS) { try_return( Status ); } ObDereferenceObject( volumeFileObject ); volumeCcb = volumeFileObject->FsContext2; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.UsnSourceInfo = markHandleInfo->UsnSourceInfo; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.VolumeHandle = volumeCcb->PrimaryFileHandle; ndfsWinxpRequestHeader->FileSystemControl.FscMarkHandleInfo.HandleInfo = markHandleInfo->HandleInfo; } else { ndfsWinxpRequestData = (_U8 *)(ndfsWinxpRequestHeader+1); if (inputBufferLength) RtlCopyMemory( ndfsWinxpRequestData, inputBuffer, inputBufferLength ); } ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { secondaryRequest = NULL; try_return( Status = STATUS_IO_DEVICE_ERROR ); } KeClearEvent( &secondaryRequest->CompleteEvent ); if (secondaryRequest->ExecuteStatus != STATUS_SUCCESS) { if (IrpContext->OriginatingIrp) PrintIrp( Dbg2, "secondaryRequest->ExecuteStatus != STATUS_SUCCESS", NULL, IrpContext->OriginatingIrp ); DebugTrace2( 0, Dbg2, ("secondaryRequest->ExecuteStatus != STATUS_SUCCESS file = %s, line = %d\n", __FILE__, __LINE__) ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; Status = Irp->IoStatus.Status = ndfsWinxpReplytHeader->Status; Irp->IoStatus.Information = ndfsWinxpReplytHeader->Information; if (FsControlCode == FSCTL_GET_NTFS_VOLUME_DATA && Status != STATUS_SUCCESS) DebugTrace2( 0, Dbg2, ("FSCTL_GET_NTFS_VOLUME_DATA: Status = %x, Irp->IoStatus.Information = %d\n", Status, Irp->IoStatus.Information) ); if (secondaryRequest->NdfsReplyHeader.MessageSize - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REPLY_HEADER)) { ASSERT( Irp->IoStatus.Status == STATUS_SUCCESS || Irp->IoStatus.Status == STATUS_BUFFER_OVERFLOW ); ASSERT( Irp->IoStatus.Information ); ASSERT( Irp->IoStatus.Information <= outputBufferLength ); ASSERT( outputBuffer ); RtlCopyMemory( outputBuffer, (_U8 *)(ndfsWinxpReplytHeader+1), Irp->IoStatus.Information ); } if (fileSystemControl.FsControlCode == FSCTL_MOVE_FILE && Status != STATUS_SUCCESS) DebugTrace2( 0, Dbg2, ("NtfsDefragFile: status = %x\n", Status) ); #if 0 if (Status == STATUS_SUCCESS && fileSystemControl.FsControlCode == FSCTL_MOVE_FILE) { // 29 PMOVE_FILE_DATA moveFileData = inputBuffer; PFILE_OBJECT moveFileObject; TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB moveFcb; PSCB moveScb; PCCB moveCcb; Status = ObReferenceObjectByHandle( moveFileData->FileHandle, FILE_READ_DATA, 0, KernelMode, &moveFileObject, NULL ); if (Status != STATUS_SUCCESS) { try_return( Status ); } ObDereferenceObject( moveFileObject ); typeOfOpen = NtfsDecodeFileObject( IrpContext, moveFileObject, &vcb, &moveFcb, &moveScb, &moveCcb, TRUE ); if (typeOfOpen == UserFileOpen && FlagOn(volDo->NdFatFlags, ND_FAT_DEVICE_FLAG_DIRECT_RW) && ndfsWinxpReplytHeader->FileInformationSet && ndfsWinxpReplytHeader->AllocationSize) { PNDFS_FAT_MCB_ENTRY mcbEntry; ULONG index; VCN testVcn; SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ); NtfsAcquireFcbWithPaging( IrpContext, moveFcb, 0 ); NtfsAcquireNtfsMcbMutex( &moveScb->Mcb ); mcbEntry = (PNDFS_FAT_MCB_ENTRY)( ndfsWinxpReplytHeader+1 ); if (moveScb->Header.AllocationSize.QuadPart) { NtfsRemoveNtfsMcbEntry( &moveScb->Mcb, 0, 0xFFFFFFFF ); } for (index=0, testVcn=0; index < ndfsWinxpReplytHeader->NumberOfMcbEntry; index++) { ASSERT( mcbEntry[index].Vcn == testVcn ); testVcn += (LONGLONG)mcbEntry[index].ClusterCount; NtfsAddNtfsMcbEntry( &moveScb->Mcb, mcbEntry[index].Vcn, (mcbEntry[index].Lcn << vcb->AllocationSupport.LogOfBytesPerSector), (LONGLONG)mcbEntry[index].ClusterCount, TRUE ); } ASSERT( LlBytesFromClusters(vcb, testVcn) == ndfsWinxpReplytHeader->AllocationSize ); if (moveScb->Header.AllocationSize.QuadPart != ndfsWinxpReplytHeader->AllocationSize) SetFlag( moveScb->ScbState, SCB_STATE_TRUNCATE_ON_CLOSE ); moveScb->Header.FileSize.LowPart = ndfsWinxpReplytHeader->FileSize; moveScb->Header.AllocationSize.QuadPart = ndfsWinxpReplytHeader->AllocationSize; ASSERT( moveScb->Header.AllocationSize.QuadPart >= moveScb->Header.FileSize.LowPart ); if (moveFileObject->SectionObjectPointer->DataSectionObject != NULL && moveFileObject->PrivateCacheMap == NULL) { CcInitializeCacheMap( moveFileObject, (PCC_FILE_SIZES)&moveScb->Header.AllocationSize, FALSE, &NtfsData.CacheManagerCallbacks, moveScb ); //CcSetAdditionalCacheAttributes( fileObject, TRUE, TRUE ); } if (CcIsFileCached(moveFileObject)) { NtfsSetBothCacheSizes( moveFileObject, (PCC_FILE_SIZES)&scb->Header.AllocationSize, moveScb ); } NtfsReleaseNtfsMcbMutex( &moveScb->Mcb ); NtfsReleaseFcb( IrpContext, moveFcb ); } } #endif try_exit: NOTHING; } finally { if (secondarySessionResourceAcquired == TRUE) { SecondaryReleaseResourceLite( IrpContext, &volDo->Secondary->SessionResource ); } if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); } FatCompleteRequest( IrpContext, Irp, Status ); DebugTrace(-1, Dbg, "FatUserFsCtrl -> %08lx\n", Status ); return Status; }
NTSTATUS FatFsdClose ( IN PVOLUME_DEVICE_OBJECT VolumeDeviceObject, IN PIRP Irp ) /*++ Routine Description: This routine implements the FSD part of Close. Arguments: VolumeDeviceObject - Supplies the volume device object where the file exists Irp - Supplies the Irp being processed Return Value: NTSTATUS - The FSD status for the IRP --*/ { NTSTATUS Status = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; PVCB Vcb; PFCB Fcb; PCCB Ccb; TYPE_OF_OPEN TypeOfOpen; BOOLEAN TopLevel; BOOLEAN VcbDeleted; #ifdef __ND_FAT__ if ((PVOID)FatControlDeviceObject == VolumeDeviceObject) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } #endif // // If we were called with our file system device object instead of a // volume device object, just complete this request with STATUS_SUCCESS // if (FatDeviceIsFatFsdo( VolumeDeviceObject)) { Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = FILE_OPENED; IoCompleteRequest( Irp, IO_DISK_INCREMENT ); return STATUS_SUCCESS; } DebugTrace(+1, Dbg, "FatFsdClose\n", 0); // // Call the common Close routine // FsRtlEnterFileSystem(); TopLevel = FatIsIrpTopLevel( Irp ); // // Get a pointer to the current stack location and the file object // IrpSp = IoGetCurrentIrpStackLocation( Irp ); FileObject = IrpSp->FileObject; // // Decode the file object and set the read-only bit in the Ccb. // TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); if (Ccb && IsFileObjectReadOnly(FileObject)) { SetFlag( Ccb->Flags, CCB_FLAG_READ_ONLY ); } try { PCLOSE_CONTEXT CloseContext; // // If we are top level, WAIT can be TRUE, otherwise make it FALSE // to avoid deadlocks, unless this is a top // level request not originating from the system process. // BOOLEAN Wait = TopLevel && (PsGetCurrentProcess() != FatData.OurProcess); #ifdef __ND_FAT__ if (Ccb) { SetFlag( Ccb->NdFatFlags, ND_FAT_CCB_FLAG_CLOSE ); ((PCCB)(FileObject->FsContext2))->FileObject = NULL; FileObject->FsContext = NULL; FileObject->FsContext2 = NULL; } #endif // // Call the common Close routine if we are not delaying this close. // if ((((TypeOfOpen == UserFileOpen) || (TypeOfOpen == UserDirectoryOpen)) && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE) && !FatData.ShutdownStarted) || (FatCommonClose( Vcb, Fcb, Ccb, TypeOfOpen, Wait, &VcbDeleted ) == STATUS_PENDING)) { // // Metadata streams have had close contexts preallocated. // if (TypeOfOpen == VirtualVolumeFile || TypeOfOpen == DirectoryFile || TypeOfOpen == EaFile) { CloseContext = FatAllocateCloseContext(); ASSERT( CloseContext != NULL ); CloseContext->Free = TRUE; } else { // // Free up any query template strings before using the close context fields, // which overlap (union) // FatDeallocateCcbStrings( Ccb); CloseContext = &Ccb->CloseContext; CloseContext->Free = FALSE; SetFlag( Ccb->Flags, CCB_FLAG_CLOSE_CONTEXT ); } // // If the status is pending, then let's get the information we // need into the close context we already have bagged, complete // the request, and post it. It is important we allocate nothing // in the close path. // CloseContext->Vcb = Vcb; CloseContext->Fcb = Fcb; CloseContext->TypeOfOpen = TypeOfOpen; // // Send it off, either to an ExWorkerThread or to the async // close list. // FatQueueClose( CloseContext, (BOOLEAN)(Fcb && FlagOn(Fcb->FcbState, FCB_STATE_DELAY_CLOSE))); } else { // // The close proceeded synchronously, so for the metadata objects we // can now drop the close context we preallocated. // if (TypeOfOpen == VirtualVolumeFile || TypeOfOpen == DirectoryFile || TypeOfOpen == EaFile) { CloseContext = FatAllocateCloseContext(); ASSERT( CloseContext != NULL ); ExFreePool( CloseContext ); } } FatCompleteRequest( FatNull, Irp, Status ); } except(FatExceptionFilter( NULL, GetExceptionInformation() )) { // // We had some trouble trying to perform the requested // operation, so we'll abort the I/O request with the // error status that we get back from the execption code. // Status = FatProcessException( NULL, Irp, GetExceptionCode() ); } if (TopLevel) { IoSetTopLevelIrp( NULL ); } FsRtlExitFileSystem(); // // And return to our caller // DebugTrace(-1, Dbg, "FatFsdClose -> %08lx\n", Status); UNREFERENCED_PARAMETER( VolumeDeviceObject ); return Status; }
VOID CloseOpenFiles ( IN PPRIMARY_SESSION PrimarySession, IN BOOLEAN Remove ) { PLIST_ENTRY openFileEntry; for (openFileEntry = PrimarySession->Thread.OpenedFileQueue.Flink; openFileEntry != &PrimarySession->Thread.OpenedFileQueue; ) { POPEN_FILE openFile; NTSTATUS closeStatus; openFile = CONTAINING_RECORD( openFileEntry, OPEN_FILE, ListEntry ); openFileEntry = openFileEntry->Flink; //ASSERT( FALSE ); if (openFile->CleanUp == FALSE) { TYPE_OF_OPEN typeOfOpen; PVCB vcb; PFCB fcb; //PSCB scb; PCCB ccb; typeOfOpen = FatDecodeFileObject( openFile->FileObject, &vcb, &fcb, &ccb ); if (typeOfOpen == UserFileOpen) { PIRP irp; PFILE_OBJECT fileObject; PDEVICE_OBJECT deviceObject; KPROCESSOR_MODE requestorMode; PIO_STACK_LOCATION irpSp; BOOLEAN synchronousIo; PKEVENT eventObject = (PKEVENT) NULL; ULONG keyValue = 0; LARGE_INTEGER fileOffset = {0,0}; PULONG majorFunction; PETHREAD currentThread; KEVENT event; NDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PIRP topLevelIrp; PRIMARY_REQUEST_INFO primaryRequestInfo; NTSTATUS cleanupStatus; do { synchronousIo = openFile->FileObject ? BooleanFlagOn(openFile->FileObject->Flags, FO_SYNCHRONOUS_IO) : TRUE; ASSERT( synchronousIo == TRUE ); deviceObject = &PrimarySession->VolDo->DeviceObject; fileObject = openFile->FileObject; currentThread = PsGetCurrentThread (); ASSERT( deviceObject->StackSize >= 1 ); irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); requestorMode = KernelMode; if (!irp) { ASSERT( NDASFAT_INSUFFICIENT_RESOURCES ); break; } irp->Tail.Overlay.OriginalFileObject = fileObject; irp->Tail.Overlay.Thread = currentThread; irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL; irp->RequestorMode = requestorMode; irp->PendingReturned = FALSE; irp->Cancel = FALSE; irp->CancelRoutine = (PDRIVER_CANCEL) NULL; irp->UserEvent = eventObject; irp->UserIosb = NULL; //&ioStatusBlock; irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL; //ApcRoutine; irp->Overlay.AsynchronousParameters.UserApcContext = NULL; //ApcContext; KeInitializeEvent( &event, NotificationEvent, FALSE ); IoSetCompletionRoutine( irp, PrimaryCompletionRoutine, &event, TRUE, TRUE, TRUE ); IoSetNextIrpStackLocation( irp ); irpSp = IoGetCurrentIrpStackLocation( irp ); // = ¤tIrpSp; // = IoGetNextIrpStackLocation( irp ); majorFunction = (PULONG) (&irpSp->MajorFunction); *majorFunction = IRP_MJ_CLEANUP; irpSp->Control = (SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL); irpSp->MinorFunction = IRP_MJ_CLEANUP; irpSp->FileObject = fileObject; irpSp->DeviceObject = deviceObject; irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; irp->MdlAddress = (PMDL) NULL; ndfsWinxpRequestHeader.CleanUp.AllocationSize = fcb->Header.AllocationSize.QuadPart; ndfsWinxpRequestHeader.CleanUp.FileSize = fcb->Header.FileSize.LowPart; ndfsWinxpRequestHeader.CleanUp.ValidDataLength = fcb->Header.FileSize.LowPart; ndfsWinxpRequestHeader.CleanUp.VaildDataToDisk = fcb->Header.FileSize.LowPart; primaryRequestInfo.PrimaryTag = 0xe2027482; primaryRequestInfo.PrimarySession = PrimarySession; primaryRequestInfo.NdfsWinxpRequestHeader = &ndfsWinxpRequestHeader; topLevelIrp = IoGetTopLevelIrp(); ASSERT( topLevelIrp == NULL ); IoSetTopLevelIrp( (PIRP)&primaryRequestInfo ); cleanupStatus = FatFsdCleanup( PrimarySession->VolDo, irp ); if (cleanupStatus == STATUS_PENDING) { KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); } IoSetTopLevelIrp( topLevelIrp ); cleanupStatus = irp->IoStatus.Status; ASSERT( cleanupStatus == STATUS_SUCCESS ); if (irp->MdlAddress != NULL) { MmUnlockPages( irp->MdlAddress ); IoFreeMdl( irp->MdlAddress ); } IoFreeIrp( irp ); } while (0); } openFile->CleanUp = TRUE; } if (openFile->FileObject) { ObDereferenceObject( openFile->FileObject ); openFile->FileObject = NULL; } if (openFile->FileHandle) { closeStatus = ZwClose( openFile->FileHandle ); openFile->FileHandle = NULL; ASSERT( closeStatus == STATUS_SUCCESS ); } if (openFile->EventHandle) { closeStatus = ZwClose( openFile->EventHandle ); openFile->EventHandle = NULL; ASSERT(closeStatus == STATUS_SUCCESS); } if (Remove) { RemoveEntryList( &openFile->ListEntry ); InitializeListHead( &openFile->ListEntry ); PrimarySession_FreeOpenFile( PrimarySession, openFile ); } } return; }
NTSTATUS FatCommonDeviceControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing Device control operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process InFsp - Indicates if this is the fsp thread or someother thread Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; KEVENT WaitEvent; PVOID CompletionContext = NULL; PVCB Vcb; PFCB Fcb; PCCB Ccb; #if __NDAS_FAT_PRIMARY__ if (IrpContext->MajorFunction == IRP_MJ_DEVICE_CONTROL && IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode == IOCTL_INSERT_PRIMARY_SESSION) { PVOLUME_DEVICE_OBJECT VolDo = CONTAINING_RECORD( IoGetCurrentIrpStackLocation(Irp)->DeviceObject, VOLUME_DEVICE_OBJECT, DeviceObject ); PSESSION_INFORMATION inputBuffer = (PSESSION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ULONG inputBufferLength = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.InputBufferLength; ULONG outputBufferLength; PULONG outputBuffer; PPRIMARY_SESSION primarySession; if (inputBufferLength != sizeof(SESSION_INFORMATION)) { FatCompleteRequest( IrpContext, Irp, Status = STATUS_INVALID_PARAMETER ); return Status; } outputBufferLength = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.OutputBufferLength; outputBuffer = (PULONG)Irp->AssociatedIrp.SystemBuffer; #if 1 primarySession = PrimarySession_Create( IrpContext, VolDo, inputBuffer, NULL ); ASSERT( primarySession ); Irp->IoStatus.Information = sizeof( primarySession ); FatCompleteRequest( IrpContext, Irp, Status = STATUS_SUCCESS ); #else IoMarkIrpPending (Irp); primarySession = PrimarySession_Create( IrpContext, VolDo, inputBuffer, Irp ); ASSERT( primarySession ); FatCompleteRequest( IrpContext, NULL, 0 ); Status = STATUS_PENDING; #endif return Status; } #endif // // Get a pointer to the current Irp stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); // // Decode the file object, the only type of opens we accept are // user volume opens. // if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace(-1, Dbg2, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER); return STATUS_INVALID_PARAMETER; } #define IOCTL_VOLUME_BASE ((ULONG) 'V') #define MOUNTDEVCONTROLTYPE ((ULONG) 'M') DebugTrace2( 0, Dbg2, ("FatCommonDeviceControl: deviceType = %d, function = %d IOCTL_VOLUME_BASE = %d, MOUNTDEVCONTROLTYPE = %d\n", DEVICE_TYPE_FROM_CTL_CODE(IrpSp->Parameters.DeviceIoControl.IoControlCode), (UCHAR)((IrpSp->Parameters.DeviceIoControl.IoControlCode & 0x00003FFC) >> 2), IOCTL_VOLUME_BASE, MOUNTDEVCONTROLTYPE) ); #if __NDAS_FAT__ if (CONTAINING_RECORD(Vcb, VOLUME_DEVICE_OBJECT, Vcb)->NetdiskEnableMode == NETDISK_SECONDARY) SetFlag( IrpContext->NdFatFlags, ND_FAT_IRP_CONTEXT_FLAG_SECONDARY_CONTEXT ); #endif // // A few IOCTLs actually require some intervention on our part // switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES: #if __NDAS_FAT_WIN2K_SUPPORT__ if (!IS_WINDOWSXP_OR_LATER()) { ASSERT( FALSE ); IoSkipCurrentIrpStackLocation( Irp ); break; } #endif // // This is sent by the Volume Snapshot driver (Lovelace). // We flush the volume, and hold all file resources // to make sure that nothing more gets dirty. Then we wait // for the IRP to complete or cancel. // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); FatAcquireExclusiveVolume( IrpContext, Vcb ); FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushWithoutPurge ); KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE ); CompletionContext = &WaitEvent; // // Get the next stack location, and copy over the stack location // IoCopyCurrentIrpStackLocationToNext( Irp ); // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatDeviceControlCompletionRoutine, CompletionContext, TRUE, TRUE, TRUE ); break; default: // // FAT doesn't need to see this on the way back, so skip ourselves. // IoSkipCurrentIrpStackLocation( Irp ); break; } // // Send the request. // Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); if (Status == STATUS_PENDING && CompletionContext) { KeWaitForSingleObject( &WaitEvent, Executive, KernelMode, FALSE, NULL ); Status = Irp->IoStatus.Status; } //DebugTrace(-1, Dbg2, "FatCommonDeviceControl -> Information %08lx\n", Irp->IoStatus.Information); // // If we had a context, the IRP remains for us and we will complete it. // Handle it appropriately. // if (CompletionContext) { // // Release all the resources that we held because of a // VOLSNAP_FLUSH_AND_HOLD. // ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES ); FatReleaseVolume( IrpContext, Vcb ); // // If we had no context, the IRP will complete asynchronously. // } else { Irp = NULL; } FatCompleteRequest( IrpContext, Irp, Status ); DebugTrace(-1, Dbg2, "FatCommonDeviceControl -> %08lx\n", Status); return Status; }
NTSTATUS FatCommonDeviceControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing Device control operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process InFsp - Indicates if this is the fsp thread or someother thread Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; KEVENT WaitEvent; PVOID CompletionContext = NULL; PVCB Vcb; PFCB Fcb; PCCB Ccb; PAGED_CODE(); // // Get a pointer to the current Irp stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonDeviceControl\n", 0); DebugTrace( 0, Dbg, "Irp = %p\n", Irp); DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); // // Decode the file object, the only type of opens we accept are // user volume opens. // if (FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ) != UserVolumeOpen) { FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_INVALID_PARAMETER); return STATUS_INVALID_PARAMETER; } // // A few IOCTLs actually require some intervention on our part // switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES: // // This is sent by the Volume Snapshot driver (Lovelace). // We flush the volume, and hold all file resources // to make sure that nothing more gets dirty. Then we wait // for the IRP to complete or cancel. // SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); FatAcquireExclusiveVolume( IrpContext, Vcb ); FatFlushAndCleanVolume( IrpContext, Irp, Vcb, FlushWithoutPurge ); KeInitializeEvent( &WaitEvent, NotificationEvent, FALSE ); CompletionContext = &WaitEvent; // // Get the next stack location, and copy over the stack location // IoCopyCurrentIrpStackLocationToNext( Irp ); // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatDeviceControlCompletionRoutine, CompletionContext, TRUE, TRUE, TRUE ); break; case IOCTL_DISK_COPY_DATA: // // We cannot allow this IOCTL to be sent unless the volume is locked, // since this IOCTL allows direct writing of data to the volume. // We do allow kernel callers to force access via a flag. A handle that // issued a dismount can send this IOCTL as well. // if (!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) && !FlagOn( IrpSp->Flags, SL_FORCE_DIRECT_WRITE ) && !FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) { FatCompleteRequest( IrpContext, Irp, STATUS_ACCESS_DENIED ); DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", STATUS_ACCESS_DENIED); return STATUS_ACCESS_DENIED; } break; case IOCTL_SCSI_PASS_THROUGH: case IOCTL_SCSI_PASS_THROUGH_DIRECT: case IOCTL_SCSI_PASS_THROUGH_EX: case IOCTL_SCSI_PASS_THROUGH_DIRECT_EX: // // If someone is issuing a format unit command underneath us, then make // sure we mark the device as needing verification when they close their // handle. // if ((!FlagOn( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ) || !FlagOn( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT )) && (Irp->AssociatedIrp.SystemBuffer != NULL)) { PCDB Cdb = NULL; // // If this is a 32 bit application running on 64 bit then thunk the // input structures to grab the Cdb. // #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) if (IoIs32bitProcess(Irp)) { if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32 )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH32)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } else { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH32_EX )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH32_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } } else { #endif if ( (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH) || (IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT )) { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } else { if (IrpSp->Parameters.DeviceIoControl.InputBufferLength >= sizeof( SCSI_PASS_THROUGH_EX )) { Cdb = (PCDB)((PSCSI_PASS_THROUGH_EX)(Irp->AssociatedIrp.SystemBuffer))->Cdb; } } #if defined (_WIN64) && defined(BUILD_WOW64_ENABLED) } #endif if ((Cdb != NULL) && (Cdb->AsByte[0] == SCSIOP_FORMAT_UNIT)) { SetFlag( Ccb->Flags, CCB_FLAG_SENT_FORMAT_UNIT ); SetFlag( IrpSp->FileObject->Flags, FO_FILE_MODIFIED ); } } // // Fall through as we do not need to know the outcome of this operation. // default: // // FAT doesn't need to see this on the way back, so skip ourselves. // IoSkipCurrentIrpStackLocation( Irp ); break; } // // Send the request. // Status = IoCallDriver(Vcb->TargetDeviceObject, Irp); if (Status == STATUS_PENDING && CompletionContext) { KeWaitForSingleObject( &WaitEvent, Executive, KernelMode, FALSE, NULL ); Status = Irp->IoStatus.Status; } // // If we had a context, the IRP remains for us and we will complete it. // Handle it appropriately. // if (CompletionContext) { // // Release all the resources that we held because of a // VOLSNAP_FLUSH_AND_HOLD. // NT_ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES ); FatReleaseVolume( IrpContext, Vcb ); // // If we had no context, the IRP will complete asynchronously. // } else { Irp = NULL; } FatCompleteRequest( IrpContext, Irp, Status ); DebugTrace(-1, Dbg, "FatCommonDeviceControl -> %08lx\n", Status); return Status; }
NTSTATUS NdasFatCommonFlushBuffers ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for flushing a buffer. Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; BOOLEAN VcbAcquired = FALSE; BOOLEAN FcbAcquired = FALSE; PDIRENT Dirent; PBCB DirentBcb = NULL; PVOLUME_DEVICE_OBJECT volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb ); BOOLEAN secondarySessionResourceAcquired = FALSE; PSECONDARY_REQUEST secondaryRequest = NULL; PNDFS_REQUEST_HEADER ndfsRequestHeader; PNDFS_WINXP_REQUEST_HEADER ndfsWinxpRequestHeader; PNDFS_WINXP_REPLY_HEADER ndfsWinxpReplytHeader; LARGE_INTEGER timeOut; PAGED_CODE(); IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject); // // Extract and decode the file object // FileObject = IrpSp->FileObject; TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ); // // CcFlushCache is always synchronous, so if we can't wait enqueue // the irp to the Fsp. // if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) { Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status ); return Status; } Status = STATUS_SUCCESS; try { if (!FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) { do { secondarySessionResourceAcquired = SecondaryAcquireResourceExclusiveLite( IrpContext, &volDo->SessionResource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) { PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp ); NDAS_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); if (secondaryRequest == NULL) { NDAS_ASSERT( NDAS_ASSERT_INSUFFICIENT_RESOURCES ); Status = STATUS_INSUFFICIENT_RESOURCES; break; } ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader; INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 ); ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1); ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData ); INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, IrpContext->OriginatingIrp, IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), Ccb->PrimaryFileHandle ); ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) ); secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE; QueueingSecondaryRequest( volDo->Secondary, secondaryRequest ); timeOut.QuadPart = -NDASFAT_TIME_OUT; Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut ); if (Status != STATUS_SUCCESS) { ASSERT( NDASFAT_BUG ); break; } KeClearEvent (&secondaryRequest->CompleteEvent); if (BooleanFlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) { NDAS_ASSERT( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST ); FatRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) { ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData; ASSERT(NTOHL(ndfsWinxpReplytHeader->Status4) == STATUS_SUCCESS); } if (secondaryRequest) { DereferenceSecondaryRequest( secondaryRequest ); secondaryRequest = NULL; } if ( secondarySessionResourceAcquired == TRUE ) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); secondarySessionResourceAcquired = FALSE; } break; } while(0); } Status = STATUS_SUCCESS; // // Case on the type of open that we are trying to flush // switch (TypeOfOpen) { case VirtualVolumeFile: case EaFile: case DirectoryFile: DebugTrace(0, Dbg, "Flush that does nothing\n", 0); break; case UserFileOpen: DebugTrace(0, Dbg, "Flush User File Open\n", 0); (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); FcbAcquired = TRUE; FatVerifyFcb( IrpContext, Fcb ); // // If the file is cached then flush its cache // Status = FatFlushFile( IrpContext, Fcb, Flush ); // // Also update and flush the file's dirent in the parent directory if the // file flush worked. // if (NT_SUCCESS( Status )) { // // Insure that we get the filesize to disk correctly. This is // benign if it was already good. // // (why do we need to do this?) // SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED); #if 0 FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb ); #endif // // Flush the volume file to get any allocation information // updates to disk. // if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) { Status = FatFlushFat( IrpContext, Vcb ); ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT); } // // Set the write through bit so that these modifications // will be completed with the request. // SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH); } break; case UserDirectoryOpen: // // If the user had opened the root directory then we'll // oblige by flushing the volume. // if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) { DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0); break; } case UserVolumeOpen: DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0); // // Acquire exclusive access to the Vcb. // { BOOLEAN Finished; Finished = FatAcquireExclusiveVcb( IrpContext, Vcb ); ASSERT( Finished ); } VcbAcquired = TRUE; // // Mark the volume clean and then flush the volume file, // and then all directories // Status = FatFlushVolume( IrpContext, Vcb, Flush ); // // If the volume was dirty, do the processing that the delayed // callback would have done. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) { // // Cancel any pending clean volumes. // (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc ); // // The volume is now clean, note it. // if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) { FatMarkVolume( IrpContext, Vcb, VolumeClean ); ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); } // // Unlock the volume if it is removable. // if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); } } break; default: FatBugCheck( TypeOfOpen, 0, 0 ); } FatUnpinBcb( IrpContext, DirentBcb ); FatUnpinRepinnedBcbs( IrpContext ); } finally { DebugUnwind( FatCommonFlushBuffers ); if (secondaryRequest) DereferenceSecondaryRequest( secondaryRequest ); if (secondarySessionResourceAcquired) { SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource ); } FatUnpinBcb( IrpContext, DirentBcb ); if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); } if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); } // // If this is a normal termination then pass the request on // to the target device object. // if (!AbnormalTermination()) { NTSTATUS DriverStatus; PIO_STACK_LOCATION NextIrpSp; // // Get the next stack location, and copy over the stack location // NextIrpSp = IoGetNextIrpStackLocation( Irp ); *NextIrpSp = *IrpSp; // // Set up the completion routine // IoSetCompletionRoutine( Irp, FatFlushCompletionRoutine, ULongToPtr( Status ), TRUE, TRUE, TRUE ); // // Send the request. // DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp); Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ? Status : DriverStatus; // // Free the IrpContext and return to the caller. // FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS ); } DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status); } return Status; }