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 = STATUS_SUCCESS; PIO_STACK_LOCATION IrpSp; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; BOOLEAN OplockPostIrp = FALSE; PAGED_CODE(); // // 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. // #if (NTDDI_VERSION >= NTDDI_WIN8) if (((IRP_MN_LOCK == IrpSp->MinorFunction) && ((ULONGLONG)IrpSp->Parameters.LockControl.ByteOffset.QuadPart < (ULONGLONG)Fcb->Header.AllocationSize.QuadPart)) || ((IRP_MN_LOCK != IrpSp->MinorFunction) && FsRtlAreThereWaitingFileLocks( &Fcb->Specific.Fcb.FileLock ))) { // // Check whether we can proceed based on the state of file oplocks if doing // an operation that interferes with oplocks. Those operations are: // // 1. Lock a range within the file's AllocationSize. // 2. Unlock a range when there are waiting locks on the file. This one // is not guaranteed to interfere with oplocks, but it could, as // unlocking this range might cause a waiting lock to be granted // within AllocationSize! // #endif Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), Irp, IrpContext, FatOplockComplete, NULL ); #if (NTDDI_VERSION >= NTDDI_WIN8) } #endif 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; }
NTSTATUS DokanCommonLockControl(__in PIRP Irp) { NTSTATUS Status = STATUS_SUCCESS; PDokanFCB Fcb; PDokanCCB Ccb; PFILE_OBJECT fileObject; PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp); DDbgPrint("==> DokanCommonLockControl\n"); PAGED_CODE(); fileObject = irpSp->FileObject; DokanPrintFileName(fileObject); Ccb = fileObject->FsContext2; if (Ccb == NULL || Ccb->Identifier.Type != CCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } Fcb = Ccb->Fcb; if (Fcb == NULL || Fcb->Identifier.Type != FCB) { DDbgPrint(" DokanOplockRequest STATUS_INVALID_PARAMETER\n"); return STATUS_INVALID_PARAMETER; } DokanFCBLockRW(Fcb); // // If the file is not a user file open then we reject the request // as an invalid parameter // if (FlagOn(Fcb->Flags, DOKAN_FILE_DIRECTORY)) { DDbgPrint(" DokanCommonLockControl -> STATUS_INVALID_PARAMETER\n", 0); DokanFCBUnlock(Fcb); return STATUS_INVALID_PARAMETER; } try { // // We check whether we can proceed // based on the state of the file oplocks. // #if (NTDDI_VERSION >= NTDDI_WIN8) if (((IRP_MN_LOCK == irpSp->MinorFunction) && ((ULONGLONG)irpSp->Parameters.LockControl.ByteOffset.QuadPart < (ULONGLONG)Fcb->AdvancedFCBHeader.AllocationSize.QuadPart)) || ((IRP_MN_LOCK != irpSp->MinorFunction) && FsRtlAreThereWaitingFileLocks(&Fcb->FileLock))) { // // Check whether we can proceed based on the state of file oplocks if doing // an operation that interferes with oplocks. Those operations are: // // 1. Lock a range within the file's AllocationSize. // 2. Unlock a range when there are waiting locks on the file. This one // is not guaranteed to interfere with oplocks, but it could, as // unlocking this range might cause a waiting lock to be granted // within AllocationSize! // #endif // Dokan DokanOplockComplete sends the operation to user mode, which isn't // what we want to do // so now wait for the oplock to be broken (pass in NULL for the callback) Status = FsRtlCheckOplock(DokanGetFcbOplock(Fcb), Irp, NULL /* EventContext */, NULL /*DokanOplockComplete*/, NULL); #if (NTDDI_VERSION >= NTDDI_WIN8) } #endif // If we were waiting for the callback, then STATUS_PENDING would be ok too if (Status != STATUS_SUCCESS) { __leave; } // // Now call the FsRtl routine to do the actual processing of the // Lock request // Status = FsRtlProcessFileLock(&Fcb->FileLock, Irp, NULL); } finally { DokanFCBUnlock(Fcb); } DDbgPrint("<== DokanCommonLockControl\n"); return Status; }