NTSTATUS FatCommonLockControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for doing Lock control operations called by both the fsd and fsp threads Arguments: Irp - Supplies the Irp to process Return Value: NTSTATUS - The return status for the operation --*/ { NTSTATUS Status; PIO_STACK_LOCATION IrpSp; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; BOOLEAN OplockPostIrp = FALSE; // // Get a pointer to the current Irp stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace(+1, Dbg, "FatCommonLockControl\n", 0); DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp); DebugTrace( 0, Dbg, "MinorFunction = %08lx\n", IrpSp->MinorFunction); // // Decode the type of file object we're being asked to process // TypeOfOpen = FatDecodeFileObject( IrpSp->FileObject, &Vcb, &Fcb, &Ccb ); // // If the file is not a user file open then we reject the request // as an invalid parameter // if (TypeOfOpen != UserFileOpen) { FatCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); DebugTrace(-1, Dbg, "FatCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0); return STATUS_INVALID_PARAMETER; } // // Acquire exclusive access to the Fcb and enqueue the Irp if we didn't // get access // if (!FatAcquireSharedFcb( IrpContext, Fcb )) { Status = FatFsdPostRequest( IrpContext, Irp ); DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status); return Status; } try { // // We check whether we can proceed // based on the state of the file oplocks. // Status = FsRtlCheckOplock( &Fcb->Specific.Fcb.Oplock, Irp, IrpContext, FatOplockComplete, NULL ); if (Status != STATUS_SUCCESS) { OplockPostIrp = TRUE; try_return( NOTHING ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request // Status = FsRtlProcessFileLock( &Fcb->Specific.Fcb.FileLock, Irp, NULL ); // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); try_exit: NOTHING; } finally { DebugUnwind( FatCommonLockControl ); // // Only if this is not an abnormal termination do we delete the // irp context // if (!AbnormalTermination() && !OplockPostIrp) { FatCompleteRequest( IrpContext, FatNull, 0 ); } // // Release the Fcb, and return to our caller // FatReleaseFcb( IrpContext, Fcb ); DebugTrace(-1, Dbg, "FatCommonLockControl -> %08lx\n", Status); } return Status; }
BOOLEAN FatFastLock ( IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, PEPROCESS ProcessId, ULONG Key, BOOLEAN FailImmediately, BOOLEAN ExclusiveLock, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast lock call. Arguments: FileObject - Supplies the file object used in this operation FileOffset - Supplies the file offset used in this operation Length - Supplies the length used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation FailImmediately - Indicates if the request should fail immediately if the lock cannot be granted. ExclusiveLock - Indicates if this is a request for an exclusive or shared lock IoStatus - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PVCB Vcb; PFCB Fcb; PCCB Ccb; DebugTrace(+1, Dbg, "FatFastLock\n", 0); // // Decode the type of file object we're being asked to process and make // sure it is only a user file open. // if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; IoStatus->Information = 0; DebugTrace(-1, Dbg, "FatFastLock -> TRUE (STATUS_INVALID_PARAMETER)\n", 0); return TRUE; } // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); // BUGBUG: kenr // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); try { // // We check whether we can proceed // based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &(Fcb)->Specific.Fcb.Oplock )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request // if (Results = FsRtlFastLock( &Fcb->Specific.Fcb.FileLock, FileObject, FileOffset, Length, ProcessId, Key, FailImmediately, ExclusiveLock, IoStatus, NULL, FALSE )) { // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); } try_exit: NOTHING; } finally { DebugUnwind( FatFastLock ); // // Release the Fcb, and return to our caller // // BUGBUG: kenr // ExReleaseResource( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); DebugTrace(-1, Dbg, "FatFastLock -> %08lx\n", Results); } return Results; }
BOOLEAN FatFastUnlockAllByKey ( IN PFILE_OBJECT FileObject, PVOID ProcessId, ULONG Key, OUT PIO_STATUS_BLOCK IoStatus, IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This is a call back routine for doing the fast unlock all by key call. Arguments: FileObject - Supplies the file object used in this operation ProcessId - Supplies the process ID used in this operation Key - Supplies the key used in this operation Status - Receives the Status if this operation is successful Return Value: BOOLEAN - TRUE if this operation completed and FALSE if caller needs to take the long route. --*/ { BOOLEAN Results; PVCB Vcb; PFCB Fcb; PCCB Ccb; DebugTrace(+1, Dbg, "FatFastUnlockAllByKey\n", 0); IoStatus->Information = 0; // // Decode the type of file object we're being asked to process and make sure // it is only a user file open. // if (FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb ) != UserFileOpen) { IoStatus->Status = STATUS_INVALID_PARAMETER; DebugTrace(-1, Dbg, "FatFastUnlockAll -> TRUE (STATUS_INVALID_PARAMETER)\n", 0); return TRUE; } // // Acquire exclusive access to the Fcb this operation can always wait // FsRtlEnterFileSystem(); (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE ); try { // // We check whether we can proceed based on the state of the file oplocks. // if (!FsRtlOplockIsFastIoPossible( &(Fcb)->Specific.Fcb.Oplock )) { try_return( Results = FALSE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request. The call will always succeed. // Results = TRUE; IoStatus->Status = FsRtlFastUnlockAllByKey( &Fcb->Specific.Fcb.FileLock, FileObject, ProcessId, Key, NULL ); // // Set the flag indicating if Fast I/O is possible // Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); try_exit: NOTHING; } finally { DebugUnwind( FatFastUnlockAllByKey ); // // Release the Fcb, and return to our caller // ExReleaseResource( (Fcb)->Header.Resource ); FsRtlExitFileSystem(); DebugTrace(-1, Dbg, "FatFastUnlockAllByKey -> %08lx\n", Results); } return Results; }
/* 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; }