/* * @implemented */ VOID NTAPI FsRtlUninitializeFileLock(IN PFILE_LOCK FileLock) { if (FileLock->LockInformation) { PIRP Irp; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; PCOMBINED_LOCK_ELEMENT Entry; PLIST_ENTRY SharedEntry; PLOCK_SHARED_RANGE SharedRange; // MSDN: this completes any remaining lock IRPs for (SharedEntry = InternalInfo->SharedLocks.Flink; SharedEntry != &InternalInfo->SharedLocks;) { SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); SharedEntry = SharedEntry->Flink; RemoveEntryList(&SharedRange->Entry); ExFreePoolWithTag(SharedRange, TAG_RANGE); } while ((Entry = RtlGetElementGenericTable(&InternalInfo->RangeTable, 0)) != NULL) { RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); } while ((Irp = IoCsqRemoveNextIrp(&InternalInfo->Csq, NULL)) != NULL) { FsRtlProcessFileLock(FileLock, Irp, NULL); } ExFreePoolWithTag(InternalInfo, TAG_FLOCK); FileLock->LockInformation = NULL; } }
NTSTATUS FspFileNodeProcessLockIrp(FSP_FILE_NODE *FileNode, PIRP Irp) { PAGED_CODE(); IoMarkIrpPending(Irp); FspFileNodeSetOwnerF(FileNode, FspIrpFlags(Irp), Irp); try { FsRtlProcessFileLock(&FileNode->FileLock, Irp, FileNode); } except (EXCEPTION_EXECUTE_HANDLER) { Irp->IoStatus.Status = GetExceptionCode(); Irp->IoStatus.Information = 0; FspFileNodeCompleteLockIrp(FileNode, Irp); } return STATUS_PENDING; }
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; }
NTSTATUS CdCommonLockControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for Lock Control 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 = IoGetCurrentIrpStackLocation( Irp ); TYPE_OF_OPEN TypeOfOpen; PFCB Fcb; PCCB Ccb; PAGED_CODE(); // // Extract and decode the type of file object we're being asked to process // TypeOfOpen = CdDecodeFileObject( IrpContext, IrpSp->FileObject, &Fcb, &Ccb ); // // If the file is not a user file open then we reject the request // as an invalid parameter // if (TypeOfOpen != UserFileOpen) { CdCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER ); return STATUS_INVALID_PARAMETER; } // // We check whether we can proceed based on the state of the file oplocks. // This call might post the irp for us. // Status = FsRtlCheckOplock( &Fcb->Oplock, Irp, IrpContext, CdOplockComplete, NULL ); // // If we don't get success then the oplock package completed the request. // if (Status != STATUS_SUCCESS) { return Status; } // // Verify the Fcb. // CdVerifyFcbOperation( IrpContext, Fcb ); // // If we don't have a file lock, then get one now. // if (Fcb->FileLock == NULL) { CdCreateFileLock( IrpContext, Fcb, TRUE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request // Status = FsRtlProcessFileLock( Fcb->FileLock, Irp, NULL ); // // Set the flag indicating if Fast I/O is possible // CdLockFcb( IrpContext, Fcb ); Fcb->IsFastIoPossible = CdIsFastIoPossible( Fcb ); CdUnlockFcb( IrpContext, Fcb ); // // Complete the request. // CdCompleteRequest( IrpContext, NULL, Status ); return Status; }
NTSTATUS XixFsdCommonLockControl( IN PXIFS_IRPCONTEXT pIrpContext ) { NTSTATUS RC = STATUS_SUCCESS; PIRP pIrp = NULL; PIO_STACK_LOCATION pIrpSp = NULL; PFILE_OBJECT pFileObject = NULL; PXIFS_FCB pFCB = NULL; PXIFS_CCB pCCB = NULL; PXIFS_VCB pVCB = NULL; TYPE_OF_OPEN TypeOfOpen = UnopenedFileObject; PAGED_CODE(); DebugTrace(DEBUG_LEVEL_CRITICAL, DEBUG_TARGET_ALL, ("!!!!Enter XixFsdCommonLockControl \n")); DebugTrace(DEBUG_LEVEL_TRACE,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB), ("Enter XixFsdCommonLockControl\n")); ASSERT(pIrpContext); pIrp = pIrpContext->Irp; ASSERT(pIrp); pIrpSp = IoGetCurrentIrpStackLocation(pIrp); ASSERT(pIrpSp); pFileObject = pIrpSp->FileObject; ASSERT(pFileObject); TypeOfOpen = XixFsdDecodeFileObject(pFileObject, &pFCB, &pCCB); ASSERT_FCB(pFCB); if(TypeOfOpen != UserFileOpen){ RC = STATUS_INVALID_PARAMETER; XixFsdCompleteRequest(pIrpContext, RC, 0); return RC; } if(pFCB->FCBType != FCB_TYPE_FILE) { RC = STATUS_INVALID_PARAMETER; XixFsdCompleteRequest(pIrpContext, RC, 0); return RC; } if(pFCB->HasLock != FCB_FILE_LOCK_HAS){ RC = STATUS_ACCESS_DENIED; XixFsdCompleteRequest(pIrpContext, RC, 0); return RC; } pVCB = pFCB->PtrVCB; ASSERT_VCB(pVCB); DebugTrace(DEBUG_LEVEL_TRACE|DEBUG_LEVEL_ALL,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB), ("CALL FsRtlCheckOplock : XixFsdCommonLockControl\n")); RC = FsRtlCheckOplock(&pFCB->FCBOplock, pIrp, pIrpContext, XixFsdOplockComplete, NULL); if(!NT_SUCCESS(RC)){ DebugTrace(DEBUG_LEVEL_TRACE|DEBUG_LEVEL_ALL,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB), ("return PENDING FsRtlCheckOplock : XixFsdCommonLockControl\n")); return RC; } if(!XixFsdVerifyFcbOperation(pIrpContext, pFCB)){ RC = STATUS_INVALID_PARAMETER; XixFsdCompleteRequest(pIrpContext, RC, 0); return RC; } try{ if(pFCB->FCBFileLock == NULL){ pFCB->FCBFileLock = FsRtlAllocateFileLock(NULL, NULL); if(!pFCB->FCBFileLock){ RC = STATUS_INSUFFICIENT_RESOURCES; try_return(RC); } } RC = FsRtlProcessFileLock(pFCB->FCBFileLock, pIrp, NULL); XifsdLockFcb(pIrpContext, pFCB); pFCB->IsFastIoPossible = XixFsdCheckFastIoPossible(pFCB); XifsdUnlockFcb(pIrpContext, pFCB); }finally{ } XixFsdCompleteRequest(pIrpContext, RC, 0); DebugTrace(DEBUG_LEVEL_TRACE|DEBUG_LEVEL_ALL,(DEBUG_TARGET_FILEINFO|DEBUG_TARGET_FCB), ("Exit XixFsdCommonLockControl\n")); return RC; }
NTSTATUS NtfsCommonLockControl ( IN PIRP_CONTEXT IrpContext, IN PIRP Irp ) /*++ Routine Description: This is the common routine for Lock Control 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; PFILE_OBJECT FileObject; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PSCB Scb; PCCB Ccb; BOOLEAN FcbAcquired = FALSE; BOOLEAN OplockPostIrp; ASSERT_IRP_CONTEXT( IrpContext ); ASSERT_IRP( Irp ); PAGED_CODE(); // // Get a pointer to the current Irp stack location // IrpSp = IoGetCurrentIrpStackLocation( Irp ); DebugTrace( +1, Dbg, ("NtfsCommonLockControl\n") ); DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) ); DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) ); DebugTrace( 0, Dbg, ("MinorFunction = %08lx\n", IrpSp->MinorFunction) ); // // Extract and decode the type of file object we're being asked to process // FileObject = IrpSp->FileObject; TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE ); // // If the file is not a user file open then we reject the request // as an invalid parameter // if (TypeOfOpen != UserFileOpen) { NtfsCompleteRequest( &IrpContext, &Irp, STATUS_INVALID_PARAMETER ); DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> STATUS_INVALID_PARAMETER\n") ); return STATUS_INVALID_PARAMETER; } // // Acquire exclusive access to the Fcb // if (Scb->ScbType.Data.FileLock == NULL) { NtfsAcquireExclusiveFcb( IrpContext, Fcb, Scb, FALSE, FALSE ); FcbAcquired = TRUE; } else { //NtfsAcquireSharedFcb( IrpContext, Fcb, Scb ); } OplockPostIrp = FALSE; try { // // We check whether we can proceed based on the state of the file oplocks. // This call might post the irp for us. // Status = FsRtlCheckOplock( &Scb->ScbType.Data.Oplock, Irp, IrpContext, NtfsOplockComplete, NULL ); if (Status != STATUS_SUCCESS) { OplockPostIrp = TRUE; try_return( NOTHING ); } // // If we don't have a file lock, then get one now. // if (Scb->ScbType.Data.FileLock == NULL) { NtfsCreateFileLock( Scb, TRUE ); } // // Now call the FsRtl routine to do the actual processing of the // Lock request // Status = FsRtlProcessFileLock( Scb->ScbType.Data.FileLock, Irp, NULL ); // // Set the flag indicating if Fast I/O is possible // NtfsAcquireFsrtlHeader( Scb ); Scb->Header.IsFastIoPossible = NtfsIsFastIoPossible( Scb ); NtfsReleaseFsrtlHeader( Scb ); try_exit: NOTHING; } finally { DebugUnwind( NtfsCommonLockControl ); // // Release the Fcb, and return to our caller // if (FcbAcquired) { NtfsReleaseFcb( IrpContext, Fcb ); } // // Only if this is not an abnormal termination and we did not post the irp // do we delete the irp context // if (!AbnormalTermination() && !OplockPostIrp) { NtfsCompleteRequest( &IrpContext, NULL, 0 ); } DebugTrace( -1, Dbg, ("NtfsCommonLockControl -> %08lx\n", Status) ); } return Status; }
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 NTAPI FatiLockControl(PFAT_IRP_CONTEXT IrpContext, PIRP Irp) { PIO_STACK_LOCATION IrpSp; TYPE_OF_OPEN TypeOfOpen; PVCB Vcb; PFCB Fcb; PCCB Ccb; NTSTATUS Status; /* Get IRP stack location */ IrpSp = IoGetCurrentIrpStackLocation(Irp); /* Determine type of open */ TypeOfOpen = FatDecodeFileObject(IrpSp->FileObject, &Vcb, &Fcb, &Ccb); /* Only user file open is allowed */ if (TypeOfOpen != UserFileOpen) { FatCompleteRequest(IrpContext, Irp, STATUS_INVALID_PARAMETER); return STATUS_INVALID_PARAMETER; } /* Acquire shared FCB lock */ if (!FatAcquireSharedFcb(IrpContext, Fcb)) { UNIMPLEMENTED; //Status = FatFsdPostRequest(IrpContext, Irp); Status = STATUS_NOT_IMPLEMENTED; return Status; } /* Check oplock state */ Status = FsRtlCheckOplock(&Fcb->Fcb.Oplock, Irp, IrpContext, FatOplockComplete, NULL); if (Status != STATUS_SUCCESS) { /* Release FCB lock */ FatReleaseFcb(IrpContext, Fcb); return Status; } /* Process the lock */ Status = FsRtlProcessFileLock(&Fcb->Fcb.Lock, Irp, NULL); /* Update Fast I/O state */ Fcb->Header.IsFastIoPossible = FatIsFastIoPossible(Fcb); /* Complete the request */ FatCompleteRequest(IrpContext, NULL, 0); /* Release FCB lock */ FatReleaseFcb(IrpContext, Fcb); return Status; }
/* * @implemented */ NTSTATUS NTAPI FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock, IN PFILE_OBJECT FileObject, IN PLARGE_INTEGER FileOffset, IN PLARGE_INTEGER Length, IN PEPROCESS Process, IN ULONG Key, IN PVOID Context OPTIONAL, IN BOOLEAN AlreadySynchronized) { BOOLEAN FoundShared = FALSE; PLIST_ENTRY SharedEntry; PLOCK_SHARED_RANGE SharedRange = NULL; COMBINED_LOCK_ELEMENT Find; PCOMBINED_LOCK_ELEMENT Entry; PIRP NextMatchingLockIrp; PLOCK_INFORMATION InternalInfo = FileLock->LockInformation; DPRINT("FsRtlFastUnlockSingle(%wZ, Offset %08x%08x (%d), Length %08x%08x (%d), Key %x)\n", &FileObject->FileName, FileOffset->HighPart, FileOffset->LowPart, (int)FileOffset->QuadPart, Length->HighPart, Length->LowPart, (int)Length->QuadPart, Key); // The region to unlock must correspond exactly to a previously locked region // -- msdn // But Windows 2003 doesn't assert on it and simply ignores that parameter // ASSERT(AlreadySynchronized); Find.Exclusive.FileLock.StartingByte = *FileOffset; Find.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart; if (!InternalInfo) { DPRINT("File not previously locked (ever)\n"); return STATUS_RANGE_NOT_LOCKED; } Entry = RtlLookupElementGenericTable(&InternalInfo->RangeTable, &Find); if (!Entry) { DPRINT("Range not locked %wZ\n", &FileObject->FileName); return STATUS_RANGE_NOT_LOCKED; } DPRINT("Found lock entry: Exclusive %u %08x%08x:%08x%08x %wZ\n", Entry->Exclusive.FileLock.ExclusiveLock, Entry->Exclusive.FileLock.StartingByte.HighPart, Entry->Exclusive.FileLock.StartingByte.LowPart, Entry->Exclusive.FileLock.EndingByte.HighPart, Entry->Exclusive.FileLock.EndingByte.LowPart, &FileObject->FileName); if (Entry->Exclusive.FileLock.ExclusiveLock) { if (Entry->Exclusive.FileLock.Key != Key || Entry->Exclusive.FileLock.ProcessId != Process->UniqueProcessId || Entry->Exclusive.FileLock.StartingByte.QuadPart != FileOffset->QuadPart || Entry->Exclusive.FileLock.EndingByte.QuadPart != FileOffset->QuadPart + Length->QuadPart) { DPRINT("Range not locked %wZ\n", &FileObject->FileName); return STATUS_RANGE_NOT_LOCKED; } RtlCopyMemory(&Find, Entry, sizeof(Find)); // Remove the old exclusive lock region RtlDeleteElementGenericTable(&InternalInfo->RangeTable, Entry); } else { DPRINT("Shared lock %wZ Start %08x%08x End %08x%08x\n", &FileObject->FileName, Entry->Exclusive.FileLock.StartingByte.HighPart, Entry->Exclusive.FileLock.StartingByte.LowPart, Entry->Exclusive.FileLock.EndingByte.HighPart, Entry->Exclusive.FileLock.EndingByte.LowPart); for (SharedEntry = InternalInfo->SharedLocks.Flink; SharedEntry != &InternalInfo->SharedLocks; SharedEntry = SharedEntry->Flink) { SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); if (SharedRange->Start.QuadPart == FileOffset->QuadPart && SharedRange->End.QuadPart == FileOffset->QuadPart + Length->QuadPart && SharedRange->Key == Key && SharedRange->ProcessId == Process->UniqueProcessId) { FoundShared = TRUE; DPRINT("Found shared element to delete %wZ Start %08x%08x End %08x%08x Key %x\n", &FileObject->FileName, SharedRange->Start.HighPart, SharedRange->Start.LowPart, SharedRange->End.HighPart, SharedRange->End.LowPart, SharedRange->Key); break; } } if (FoundShared) { /* Remove the found range from the shared range lists */ RemoveEntryList(&SharedRange->Entry); ExFreePoolWithTag(SharedRange, TAG_RANGE); /* We need to rebuild the list of shared ranges. */ DPRINT("Removing the lock entry %wZ (%08x%08x:%08x%08x)\n", &FileObject->FileName, Entry->Exclusive.FileLock.StartingByte.HighPart, Entry->Exclusive.FileLock.StartingByte.LowPart, Entry->Exclusive.FileLock.EndingByte.HighPart, Entry->Exclusive.FileLock.EndingByte.LowPart); /* Remember what was in there and remove it from the table */ Find = *Entry; RtlDeleteElementGenericTable(&InternalInfo->RangeTable, &Find); /* Put shared locks back in place */ for (SharedEntry = InternalInfo->SharedLocks.Flink; SharedEntry != &InternalInfo->SharedLocks; SharedEntry = SharedEntry->Flink) { COMBINED_LOCK_ELEMENT LockElement; SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); LockElement.Exclusive.FileLock.FileObject = FileObject; LockElement.Exclusive.FileLock.StartingByte = SharedRange->Start; LockElement.Exclusive.FileLock.EndingByte = SharedRange->End; LockElement.Exclusive.FileLock.ProcessId = SharedRange->ProcessId; LockElement.Exclusive.FileLock.Key = SharedRange->Key; LockElement.Exclusive.FileLock.ExclusiveLock = FALSE; if (LockCompare(&InternalInfo->RangeTable, &Find, &LockElement) != GenericEqual) { DPRINT("Skipping range %08x%08x:%08x%08x\n", LockElement.Exclusive.FileLock.StartingByte.HighPart, LockElement.Exclusive.FileLock.StartingByte.LowPart, LockElement.Exclusive.FileLock.EndingByte.HighPart, LockElement.Exclusive.FileLock.EndingByte.LowPart); continue; } DPRINT("Re-creating range %08x%08x:%08x%08x\n", LockElement.Exclusive.FileLock.StartingByte.HighPart, LockElement.Exclusive.FileLock.StartingByte.LowPart, LockElement.Exclusive.FileLock.EndingByte.HighPart, LockElement.Exclusive.FileLock.EndingByte.LowPart); FsRtlpRebuildSharedLockRange(FileLock, InternalInfo, &LockElement); } } else { return STATUS_RANGE_NOT_LOCKED; } } #ifndef NDEBUG DPRINT("Lock still has:\n"); for (SharedEntry = InternalInfo->SharedLocks.Flink; SharedEntry != &InternalInfo->SharedLocks; SharedEntry = SharedEntry->Flink) { SharedRange = CONTAINING_RECORD(SharedEntry, LOCK_SHARED_RANGE, Entry); DPRINT("Shared element %wZ Offset %08x%08x Length %08x%08x Key %x\n", &FileObject->FileName, SharedRange->Start.HighPart, SharedRange->Start.LowPart, SharedRange->End.HighPart, SharedRange->End.LowPart, SharedRange->Key); } #endif // this is definitely the thing we want InternalInfo->Generation++; while ((NextMatchingLockIrp = IoCsqRemoveNextIrp(&InternalInfo->Csq, &Find))) { if (NextMatchingLockIrp->IoStatus.Information == InternalInfo->Generation) { // We've already looked at this one, meaning that we looped. // Put it back and exit. IoCsqInsertIrpEx (&InternalInfo->Csq, NextMatchingLockIrp, NULL, NULL); break; } // Got a new lock irp... try to do the new lock operation // Note that we pick an operation that would succeed at the time // we looked, but can't guarantee that it won't just be re-queued // because somebody else snatched part of the range in a new thread. DPRINT("Locking another IRP %p for %p %wZ\n", &FileObject->FileName, FileLock, NextMatchingLockIrp); FsRtlProcessFileLock(InternalInfo->BelongsTo, NextMatchingLockIrp, NULL); } DPRINT("Success %wZ\n", &FileObject->FileName); return STATUS_SUCCESS; }
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; }