PAGED_LOOKASIDE_LIST FsRtlFileLockLookasideList;
+/* Note: this aligns the two types of lock entry structs so we can access the
+ FILE_LOCK_INFO part in common. Add elements after Shared if new stuff is needed.
+*/
+typedef union _COMBINED_LOCK_ELEMENT
+{
+ struct
+ {
+ LIST_ENTRY dummy;
+ FILE_SHARED_LOCK_ENTRY Shared;
+ };
+ FILE_EXCLUSIVE_LOCK_ENTRY Exclusive;
+}
+ COMBINED_LOCK_ELEMENT, *PCOMBINED_LOCK_ELEMENT;
+
+typedef struct _LOCK_INFORMATION
+{
+ RTL_GENERIC_TABLE RangeTable;
+ IO_CSQ Csq;
+ KSPIN_LOCK CsqLock;
+ LIST_ENTRY CsqList;
+ PFILE_LOCK BelongsTo;
+ LIST_ENTRY SharedLocks;
+ ULONG Generation;
+}
+ LOCK_INFORMATION, *PLOCK_INFORMATION;
+
+typedef struct _LOCK_SHARED_RANGE
+{
+ LIST_ENTRY Entry;
+ LARGE_INTEGER Start, End;
+ ULONG Key;
+ PVOID ProcessId;
+}
+ LOCK_SHARED_RANGE, *PLOCK_SHARED_RANGE;
+
+#define TAG_TABLE 'LTAB'
+#define TAG_RANGE 'FSRA'
+#define TAG_FLOCK 'FLCK'
+
/* PRIVATE FUNCTIONS *********************************************************/
+VOID
+NTAPI
+FsRtlCompleteLockIrpReal(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteRoutine,
+ IN PVOID Context,
+ IN PIRP Irp,
+ IN NTSTATUS Status,
+ OUT PNTSTATUS NewStatus,
+ IN PFILE_OBJECT FileObject OPTIONAL);
+
+/* Generic table methods */
+
+static PVOID NTAPI LockAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
+{
+ PVOID Result;
+ Result = ExAllocatePoolWithTag(NonPagedPool, Bytes, TAG_TABLE);
+ DPRINT("LockAllocate(%lu) => %p\n", Bytes, Result);
+ return Result;
+}
+
+static VOID NTAPI LockFree(PRTL_GENERIC_TABLE Table, PVOID Buffer)
+{
+ DPRINT("LockFree(%p)\n", Buffer);
+ ExFreePoolWithTag(Buffer, TAG_TABLE);
+}
+
+static RTL_GENERIC_COMPARE_RESULTS NTAPI LockCompare
+(PRTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
+{
+ PCOMBINED_LOCK_ELEMENT A = PtrA, B = PtrB;
+ RTL_GENERIC_COMPARE_RESULTS Result;
+#if 0
+ DPRINT("Starting to compare element %x to element %x\n", PtrA, PtrB);
+#endif
+ /* Match if we overlap */
+ if (((A->Exclusive.FileLock.StartingByte.QuadPart <
+ B->Exclusive.FileLock.EndingByte.QuadPart) &&
+ (A->Exclusive.FileLock.StartingByte.QuadPart >=
+ B->Exclusive.FileLock.StartingByte.QuadPart)) ||
+ ((B->Exclusive.FileLock.StartingByte.QuadPart <
+ A->Exclusive.FileLock.EndingByte.QuadPart) &&
+ (B->Exclusive.FileLock.StartingByte.QuadPart >=
+ A->Exclusive.FileLock.StartingByte.QuadPart)))
+ return GenericEqual;
+ /* Otherwise, key on the starting byte */
+ Result =
+ (A->Exclusive.FileLock.StartingByte.QuadPart <
+ B->Exclusive.FileLock.StartingByte.QuadPart) ? GenericLessThan :
+ (A->Exclusive.FileLock.StartingByte.QuadPart >
+ B->Exclusive.FileLock.StartingByte.QuadPart) ? GenericGreaterThan :
+ GenericEqual;
+#if 0
+ DPRINT("Compare(%x:%x) %x-%x to %x-%x => %d\n",
+ A,B,
+ A->Exclusive.FileLock.StartingByte.LowPart,
+ A->Exclusive.FileLock.EndingByte.LowPart,
+ B->Exclusive.FileLock.StartingByte.LowPart,
+ B->Exclusive.FileLock.EndingByte.LowPart,
+ Result);
+#endif
+ return Result;
+}
+
+/* CSQ methods */
+
+static NTSTATUS NTAPI LockInsertIrpEx
+(PIO_CSQ Csq,
+ PIRP Irp,
+ PVOID InsertContext)
+{
+ PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq);
+ InsertTailList(&LockInfo->CsqList, &Irp->Tail.Overlay.ListEntry);
+ return STATUS_SUCCESS;
+}
+
+static VOID NTAPI LockRemoveIrp(PIO_CSQ Csq, PIRP Irp)
+{
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+static PIRP NTAPI LockPeekNextIrp(PIO_CSQ Csq, PIRP Irp, PVOID PeekContext)
+{
+ // Context will be a COMBINED_LOCK_ELEMENT. We're looking for a
+ // lock that can be acquired, now that the lock matching PeekContext
+ // has been removed.
+ COMBINED_LOCK_ELEMENT LockElement;
+ PCOMBINED_LOCK_ELEMENT WhereUnlock = PeekContext;
+ PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq);
+ PLIST_ENTRY Following;
+ DPRINT("PeekNextIrp(IRP %p, Context %p)\n", Irp, PeekContext);
+ if (!Irp)
+ {
+ Following = LockInfo->CsqList.Flink;
+ }
+ else
+ Following = Irp->Tail.Overlay.ListEntry.Flink;
+
+ DPRINT("ListEntry %p Head %p\n", Following, &LockInfo->CsqList);
+ for (;
+ Following != &LockInfo->CsqList;
+ Following = Following->Flink)
+ {
+ PIO_STACK_LOCATION IoStack;
+ BOOLEAN Matching;
+ Irp = CONTAINING_RECORD(Following, IRP, Tail.Overlay.ListEntry);
+ DPRINT("Irp %p\n", Irp);
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+ LockElement.Exclusive.FileLock.StartingByte =
+ IoStack->Parameters.LockControl.ByteOffset;
+ LockElement.Exclusive.FileLock.EndingByte.QuadPart =
+ LockElement.Exclusive.FileLock.StartingByte.QuadPart +
+ IoStack->Parameters.LockControl.Length->QuadPart;
+ /* If a context was specified, it's a range to check to unlock */
+ if (WhereUnlock)
+ {
+ Matching = LockCompare
+ (&LockInfo->RangeTable, &LockElement, WhereUnlock) != GenericEqual;
+ }
+ /* Else get any completable IRP */
+ else
+ {
+ Matching = FALSE;
+ }
+ if (!Matching)
+ {
+ // This IRP is fine...
+ DPRINT("Returning the IRP %p\n", Irp);
+ return Irp;
+ }
+ }
+ DPRINT("Return NULL\n");
+ return NULL;
+}
+
+static VOID NTAPI
+LockAcquireQueueLock(PIO_CSQ Csq, PKIRQL Irql)
+{
+ PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq);
+ KeAcquireSpinLock(&LockInfo->CsqLock, Irql);
+}
+
+static VOID NTAPI
+LockReleaseQueueLock(PIO_CSQ Csq, KIRQL Irql)
+{
+ PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq);
+ KeReleaseSpinLock(&LockInfo->CsqLock, Irql);
+}
+
+static VOID NTAPI
+LockCompleteCanceledIrp(PIO_CSQ Csq, PIRP Irp)
+{
+ NTSTATUS Status;
+ PLOCK_INFORMATION LockInfo = CONTAINING_RECORD(Csq, LOCK_INFORMATION, Csq);
+ DPRINT("Complete cancelled IRP %p Status %x\n", Irp, STATUS_CANCELLED);
+ FsRtlCompleteLockIrpReal
+ (LockInfo->BelongsTo->CompleteLockIrpRoutine,
+ NULL,
+ Irp,
+ STATUS_CANCELLED,
+ &Status,
+ NULL);
+}
+
VOID
NTAPI
FsRtlCompleteLockIrpReal(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteRoutine,
IN PFILE_OBJECT FileObject OPTIONAL)
{
/* Check if we have a complete routine */
+ Irp->IoStatus.Information = 0;
if (CompleteRoutine)
{
/* Check if we have a file object */
if (FileObject) FileObject->LastLock = NULL;
-
+
/* Set the I/O Status and do completion */
Irp->IoStatus.Status = Status;
+ DPRINT("Calling completion routine %p Status %x\n", Irp, Status);
*NewStatus = CompleteRoutine(Context, Irp);
}
else
{
/* Otherwise do a normal I/O complete request */
+ DPRINT("Completing IRP %p Status %x\n", Irp, Status);
FsRtlCompleteRequest(Irp, Status);
*NewStatus = Status;
}
FsRtlGetNextFileLock(IN PFILE_LOCK FileLock,
IN BOOLEAN Restart)
{
- KeBugCheck(FILE_SYSTEM);
- return NULL;
+ PCOMBINED_LOCK_ELEMENT Entry;
+ if (!FileLock->LockInformation) return NULL;
+ Entry = RtlEnumerateGenericTable(FileLock->LockInformation, Restart);
+ if (!Entry) return NULL;
+ else return &Entry->Exclusive.FileLock;
+}
+
+VOID
+NTAPI
+FsRtlpExpandLockElement
+(PCOMBINED_LOCK_ELEMENT ToExpand,
+ PCOMBINED_LOCK_ELEMENT Conflict)
+{
+ if (ToExpand->Exclusive.FileLock.StartingByte.QuadPart >
+ Conflict->Exclusive.FileLock.StartingByte.QuadPart)
+ {
+ ToExpand->Exclusive.FileLock.StartingByte =
+ Conflict->Exclusive.FileLock.StartingByte;
+ }
+ if (ToExpand->Exclusive.FileLock.EndingByte.QuadPart <
+ Conflict->Exclusive.FileLock.EndingByte.QuadPart)
+ {
+ ToExpand->Exclusive.FileLock.EndingByte =
+ Conflict->Exclusive.FileLock.EndingByte;
+ }
+}
+
+/* This function expands the conflicting range Conflict by removing and reinserting it,
+ then adds a shared range of the same size */
+PCOMBINED_LOCK_ELEMENT
+NTAPI
+FsRtlpRebuildSharedLockRange
+(PFILE_LOCK FileLock,
+ PLOCK_INFORMATION LockInfo,
+ PCOMBINED_LOCK_ELEMENT Conflict)
+{
+ /* Starting at Conflict->StartingByte and going to Conflict->EndingByte
+ * capture and expand a shared range from the shared range list.
+ * Finish when we've incorporated all overlapping shared regions.
+ */
+ BOOLEAN InsertedNew = FALSE, RemovedOld;
+ COMBINED_LOCK_ELEMENT NewElement = *Conflict;
+ PCOMBINED_LOCK_ELEMENT Entry;
+ while ((Entry = RtlLookupElementGenericTable
+ (FileLock->LockInformation, &NewElement)))
+ {
+ FsRtlpExpandLockElement(&NewElement, Entry);
+ RemovedOld = RtlDeleteElementGenericTable
+ (&LockInfo->RangeTable,
+ Entry);
+ ASSERT(RemovedOld);
+ }
+ Conflict = RtlInsertElementGenericTable
+ (&LockInfo->RangeTable,
+ &NewElement,
+ sizeof(NewElement),
+ &InsertedNew);
+ ASSERT(InsertedNew);
+ return Conflict;
}
/*
IN BOOLEAN AlreadySynchronized)
{
NTSTATUS Status;
+ COMBINED_LOCK_ELEMENT ToInsert;
+ PCOMBINED_LOCK_ELEMENT Conflict;
+ PLOCK_INFORMATION LockInfo;
+ PLOCK_SHARED_RANGE NewSharedRange;
+ BOOLEAN InsertedNew;
+ ULARGE_INTEGER UnsignedStart;
+ ULARGE_INTEGER UnsignedEnd;
+
+ DPRINT("FsRtlPrivateLock(%wZ, Offset %08x%08x (%d), Length %08x%08x (%d), Key %x, FailImmediately %u, Exclusive %u)\n",
+ &FileObject->FileName,
+ FileOffset->HighPart,
+ FileOffset->LowPart,
+ (int)FileOffset->QuadPart,
+ Length->HighPart,
+ Length->LowPart,
+ (int)Length->QuadPart,
+ Key,
+ FailImmediately,
+ ExclusiveLock);
+
+ UnsignedStart.QuadPart = FileOffset->QuadPart;
+ UnsignedEnd.QuadPart = FileOffset->QuadPart + Length->QuadPart;
- static BOOLEAN Warn;
- if (!Warn++) DPRINT1("FsRtlPrivateLock() is stubplemented!\n");
-
+ if (UnsignedEnd.QuadPart < UnsignedStart.QuadPart)
+ {
+ DPRINT("File offset out of range\n");
+ IoStatus->Status = STATUS_INVALID_PARAMETER;
+ if (Irp)
+ {
+ DPRINT("Complete lock %p Status %x\n", Irp, IoStatus->Status);
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ return FALSE;
+ }
+
/* Initialize the lock, if necessary */
if (!FileLock->LockInformation)
{
- DPRINT("LockInformation is uninitialized!\n");
+ LockInfo = ExAllocatePoolWithTag(NonPagedPool, sizeof(LOCK_INFORMATION), TAG_FLOCK);
+ if (!LockInfo)
+ {
+ IoStatus->Status = STATUS_NO_MEMORY;
+ return FALSE;
+ }
+ FileLock->LockInformation = LockInfo;
+
+ LockInfo->BelongsTo = FileLock;
+ InitializeListHead(&LockInfo->SharedLocks);
+
+ RtlInitializeGenericTable
+ (&LockInfo->RangeTable,
+ LockCompare,
+ LockAllocate,
+ LockFree,
+ NULL);
+
+ KeInitializeSpinLock(&LockInfo->CsqLock);
+ InitializeListHead(&LockInfo->CsqList);
+
+ IoCsqInitializeEx
+ (&LockInfo->Csq,
+ LockInsertIrpEx,
+ LockRemoveIrp,
+ LockPeekNextIrp,
+ LockAcquireQueueLock,
+ LockReleaseQueueLock,
+ LockCompleteCanceledIrp);
}
+
+ LockInfo = FileLock->LockInformation;
+ ToInsert.Exclusive.FileLock.FileObject = FileObject;
+ ToInsert.Exclusive.FileLock.StartingByte = *FileOffset;
+ ToInsert.Exclusive.FileLock.EndingByte.QuadPart = FileOffset->QuadPart + Length->QuadPart;
+ ToInsert.Exclusive.FileLock.ProcessId = Process->UniqueProcessId;
+ ToInsert.Exclusive.FileLock.Key = Key;
+ ToInsert.Exclusive.FileLock.ExclusiveLock = ExclusiveLock;
- /* Assume all is cool, and lock is set */
- IoStatus->Status = STATUS_SUCCESS;
+ Conflict = RtlInsertElementGenericTable
+ (FileLock->LockInformation,
+ &ToInsert,
+ sizeof(ToInsert),
+ &InsertedNew);
- if (Irp)
+ if (Conflict && !InsertedNew)
{
- /* Complete the request */
- FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
- Context,
- Irp,
- IoStatus->Status,
- &Status,
- FileObject);
+ if (Conflict->Exclusive.FileLock.ExclusiveLock || ExclusiveLock)
+ {
+ DPRINT("Conflict %08x%08x:%08x%08x Exc %u (Want Exc %u)\n",
+ Conflict->Exclusive.FileLock.StartingByte.HighPart,
+ Conflict->Exclusive.FileLock.StartingByte.LowPart,
+ Conflict->Exclusive.FileLock.EndingByte.HighPart,
+ Conflict->Exclusive.FileLock.EndingByte.LowPart,
+ Conflict->Exclusive.FileLock.ExclusiveLock,
+ ExclusiveLock);
+ if (FailImmediately)
+ {
+ DPRINT("STATUS_FILE_LOCK_CONFLICT\n");
+ IoStatus->Status = STATUS_FILE_LOCK_CONFLICT;
+ if (Irp)
+ {
+ DPRINT("STATUS_FILE_LOCK_CONFLICT: Complete\n");
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ return FALSE;
+ }
+ else
+ {
+ IoStatus->Status = STATUS_PENDING;
+ if (Irp)
+ {
+ Irp->IoStatus.Information = LockInfo->Generation;
+ IoMarkIrpPending(Irp);
+ IoCsqInsertIrpEx
+ (&LockInfo->Csq,
+ Irp,
+ NULL,
+ NULL);
+ }
+ }
+ return FALSE;
+ }
+ else
+ {
+ ULONG i;
+ /* We know of at least one lock in range that's shared. We need to
+ * find out if any more exist and any are exclusive. */
+ for (i = 0; i < RtlNumberGenericTableElements(&LockInfo->RangeTable); i++)
+ {
+ Conflict = RtlGetElementGenericTable(&LockInfo->RangeTable, i);
- /* Update the status */
- IoStatus->Status = Status;
- }
+ /* The first argument will be inserted as a shared range */
+ if (Conflict && (LockCompare(&LockInfo->RangeTable, Conflict, &ToInsert) == GenericEqual))
+ {
+ if (Conflict->Exclusive.FileLock.ExclusiveLock)
+ {
+ /* Found an exclusive match */
+ if (FailImmediately)
+ {
+ IoStatus->Status = STATUS_FILE_LOCK_CONFLICT;
+ DPRINT("STATUS_FILE_LOCK_CONFLICT\n");
+ if (Irp)
+ {
+ DPRINT("STATUS_FILE_LOCK_CONFLICT: Complete\n");
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ }
+ else
+ {
+ IoStatus->Status = STATUS_PENDING;
+ if (Irp)
+ {
+ IoMarkIrpPending(Irp);
+ IoCsqInsertIrpEx
+ (&LockInfo->Csq,
+ Irp,
+ NULL,
+ NULL);
+ }
+ }
+ return FALSE;
+ }
+ }
+ }
+
+ DPRINT("Overlapping shared lock %wZ %08x%08x %08x%08x\n",
+ &FileObject->FileName,
+ Conflict->Exclusive.FileLock.StartingByte.HighPart,
+ Conflict->Exclusive.FileLock.StartingByte.LowPart,
+ Conflict->Exclusive.FileLock.EndingByte.HighPart,
+ Conflict->Exclusive.FileLock.EndingByte.LowPart);
+ Conflict = FsRtlpRebuildSharedLockRange(FileLock,
+ LockInfo,
+ &ToInsert);
+ if (!Conflict)
+ {
+ IoStatus->Status = STATUS_NO_MEMORY;
+ if (Irp)
+ {
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ }
+ /* We got here because there were only overlapping shared locks */
+ /* A shared lock is both a range *and* a list entry. Insert the
+ entry here. */
+
+ DPRINT("Adding shared lock %wZ\n", &FileObject->FileName);
+ NewSharedRange =
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), TAG_RANGE);
+ if (!NewSharedRange)
+ {
+ IoStatus->Status = STATUS_NO_MEMORY;
+ if (Irp)
+ {
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ return FALSE;
+ }
+ DPRINT("Adding shared lock %wZ\n", &FileObject->FileName);
+ NewSharedRange->Start = *FileOffset;
+ NewSharedRange->End.QuadPart = FileOffset->QuadPart + Length->QuadPart;
+ NewSharedRange->Key = Key;
+ NewSharedRange->ProcessId = ToInsert.Exclusive.FileLock.ProcessId;
+ InsertTailList(&LockInfo->SharedLocks, &NewSharedRange->Entry);
+
+ DPRINT("Acquired shared lock %wZ %08x%08x %08x%08x\n",
+ &FileObject->FileName,
+ Conflict->Exclusive.FileLock.StartingByte.HighPart,
+ Conflict->Exclusive.FileLock.StartingByte.LowPart,
+ Conflict->Exclusive.FileLock.EndingByte.HighPart,
+ Conflict->Exclusive.FileLock.EndingByte.LowPart);
+ IoStatus->Status = STATUS_SUCCESS;
+ if (Irp)
+ {
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ return TRUE;
+ }
+ }
+ else if (!Conflict)
+ {
+ /* Conflict here is (or would be) the newly inserted element, but we ran
+ * out of space probably. */
+ IoStatus->Status = STATUS_NO_MEMORY;
+ if (Irp)
+ {
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ return FALSE;
+ }
+ else
+ {
+ DPRINT("Inserted new lock %wZ %08x%08x %08x%08x exclusive %u\n",
+ &FileObject->FileName,
+ Conflict->Exclusive.FileLock.StartingByte.HighPart,
+ Conflict->Exclusive.FileLock.StartingByte.LowPart,
+ Conflict->Exclusive.FileLock.EndingByte.HighPart,
+ Conflict->Exclusive.FileLock.EndingByte.LowPart,
+ Conflict->Exclusive.FileLock.ExclusiveLock);
+ if (!ExclusiveLock)
+ {
+ NewSharedRange =
+ ExAllocatePoolWithTag(NonPagedPool, sizeof(*NewSharedRange), TAG_RANGE);
+ if (!NewSharedRange)
+ {
+ IoStatus->Status = STATUS_NO_MEMORY;
+ if (Irp)
+ {
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+ }
+ return FALSE;
+ }
+ DPRINT("Adding shared lock %wZ\n", &FileObject->FileName);
+ NewSharedRange->Start = *FileOffset;
+ NewSharedRange->End.QuadPart = FileOffset->QuadPart + Length->QuadPart;
+ NewSharedRange->Key = Key;
+ NewSharedRange->ProcessId = Process->UniqueProcessId;
+ InsertTailList(&LockInfo->SharedLocks, &NewSharedRange->Entry);
+ }
+
+ /* Assume all is cool, and lock is set */
+ IoStatus->Status = STATUS_SUCCESS;
+
+ if (Irp)
+ {
+ /* Complete the request */
+ FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatus->Status,
+ &Status,
+ FileObject);
+
+ /* Update the status */
+ IoStatus->Status = Status;
+ }
+ }
+
return TRUE;
}
FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock,
IN PIRP Irp)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ BOOLEAN Result;
+ PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
+ COMBINED_LOCK_ELEMENT ToFind;
+ PCOMBINED_LOCK_ELEMENT Found;
+ DPRINT("CheckLockForReadAccess(%wZ, Offset %08x%08x, Length %x)\n",
+ &IoStack->FileObject->FileName,
+ IoStack->Parameters.Read.ByteOffset.HighPart,
+ IoStack->Parameters.Read.ByteOffset.LowPart,
+ IoStack->Parameters.Read.Length);
+ if (!FileLock->LockInformation) {
+ DPRINT("CheckLockForReadAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName);
+ return TRUE;
+ }
+ ToFind.Exclusive.FileLock.StartingByte = IoStack->Parameters.Read.ByteOffset;
+ ToFind.Exclusive.FileLock.EndingByte.QuadPart =
+ ToFind.Exclusive.FileLock.StartingByte.QuadPart +
+ IoStack->Parameters.Read.Length;
+ Found = RtlLookupElementGenericTable
+ (FileLock->LockInformation,
+ &ToFind);
+ if (!Found) {
+ DPRINT("CheckLockForReadAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName);
+ return TRUE;
+ }
+ Result = !Found->Exclusive.FileLock.ExclusiveLock ||
+ IoStack->Parameters.Read.Key == Found->Exclusive.FileLock.Key;
+ DPRINT("CheckLockForReadAccess(%wZ) => %s\n", &IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE");
+ return Result;
}
/*
FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock,
IN PIRP Irp)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ BOOLEAN Result;
+ PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
+ COMBINED_LOCK_ELEMENT ToFind;
+ PCOMBINED_LOCK_ELEMENT Found;
+ PEPROCESS Process = Irp->Tail.Overlay.Thread->ThreadsProcess;
+ DPRINT("CheckLockForWriteAccess(%wZ, Offset %08x%08x, Length %x)\n",
+ &IoStack->FileObject->FileName,
+ IoStack->Parameters.Write.ByteOffset.HighPart,
+ IoStack->Parameters.Write.ByteOffset.LowPart,
+ IoStack->Parameters.Write.Length);
+ if (!FileLock->LockInformation) {
+ DPRINT("CheckLockForWriteAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName);
+ return TRUE;
+ }
+ ToFind.Exclusive.FileLock.StartingByte = IoStack->Parameters.Write.ByteOffset;
+ ToFind.Exclusive.FileLock.EndingByte.QuadPart =
+ ToFind.Exclusive.FileLock.StartingByte.QuadPart +
+ IoStack->Parameters.Write.Length;
+ Found = RtlLookupElementGenericTable
+ (FileLock->LockInformation,
+ &ToFind);
+ if (!Found) {
+ DPRINT("CheckLockForWriteAccess(%wZ) => TRUE\n", &IoStack->FileObject->FileName);
+ return TRUE;
+ }
+ Result = Process->UniqueProcessId == Found->Exclusive.FileLock.ProcessId;
+ DPRINT("CheckLockForWriteAccess(%wZ) => %s\n", &IoStack->FileObject->FileName, Result ? "TRUE" : "FALSE");
+ return Result;
}
/*
IN PFILE_OBJECT FileObject,
IN PVOID Process)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ PEPROCESS EProcess = Process;
+ COMBINED_LOCK_ELEMENT ToFind;
+ PCOMBINED_LOCK_ELEMENT Found;
+ DPRINT("FsRtlFastCheckLockForRead(%wZ, Offset %08x%08x, Length %08x%08x, Key %x)\n",
+ &FileObject->FileName,
+ FileOffset->HighPart,
+ FileOffset->LowPart,
+ Length->HighPart,
+ Length->LowPart,
+ Key);
+ ToFind.Exclusive.FileLock.StartingByte = *FileOffset;
+ ToFind.Exclusive.FileLock.EndingByte.QuadPart =
+ FileOffset->QuadPart + Length->QuadPart;
+ if (!FileLock->LockInformation) return TRUE;
+ Found = RtlLookupElementGenericTable
+ (FileLock->LockInformation,
+ &ToFind);
+ if (!Found || !Found->Exclusive.FileLock.ExclusiveLock) return TRUE;
+ return Found->Exclusive.FileLock.Key == Key &&
+ Found->Exclusive.FileLock.ProcessId == EProcess->UniqueProcessId;
}
/*
IN PFILE_OBJECT FileObject,
IN PVOID Process)
{
- KeBugCheck(FILE_SYSTEM);
- return FALSE;
+ BOOLEAN Result;
+ PEPROCESS EProcess = Process;
+ COMBINED_LOCK_ELEMENT ToFind;
+ PCOMBINED_LOCK_ELEMENT Found;
+ DPRINT("FsRtlFastCheckLockForWrite(%wZ, Offset %08x%08x, Length %08x%08x, Key %x)\n",
+ &FileObject->FileName,
+ FileOffset->HighPart,
+ FileOffset->LowPart,
+ Length->HighPart,
+ Length->LowPart,
+ Key);
+ ToFind.Exclusive.FileLock.StartingByte = *FileOffset;
+ ToFind.Exclusive.FileLock.EndingByte.QuadPart =
+ FileOffset->QuadPart + Length->QuadPart;
+ if (!FileLock->LockInformation) {
+ DPRINT("CheckForWrite(%wZ) => TRUE\n", &FileObject->FileName);
+ return TRUE;
+ }
+ Found = RtlLookupElementGenericTable
+ (FileLock->LockInformation,
+ &ToFind);
+ if (!Found) {
+ DPRINT("CheckForWrite(%wZ) => TRUE\n", &FileObject->FileName);
+ return TRUE;
+ }
+ Result = Found->Exclusive.FileLock.Key == Key &&
+ Found->Exclusive.FileLock.ProcessId == EProcess->UniqueProcessId;
+ DPRINT("CheckForWrite(%wZ) => %s\n", &FileObject->FileName, Result ? "TRUE" : "FALSE");
+ return Result;
}
/*
IN PVOID Context OPTIONAL,
IN BOOLEAN AlreadySynchronized)
{
- static BOOLEAN Warn;
- if (!Warn++) DPRINT1("FsRtlFastUnlockSingle() is stubplemented!\n");
+ 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;
}
IN PEPROCESS Process,
IN PVOID Context OPTIONAL)
{
- KeBugCheck(FILE_SYSTEM);
- return STATUS_UNSUCCESSFUL;
+ PLIST_ENTRY ListEntry;
+ PCOMBINED_LOCK_ELEMENT Entry;
+ PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
+ DPRINT("FsRtlFastUnlockAll(%wZ)\n", &FileObject->FileName);
+ // XXX Synchronize somehow
+ if (!FileLock->LockInformation) {
+ DPRINT("Not locked %wZ\n", &FileObject->FileName);
+ return STATUS_RANGE_NOT_LOCKED; // no locks
+ }
+ for (ListEntry = InternalInfo->SharedLocks.Flink;
+ ListEntry != &InternalInfo->SharedLocks;)
+ {
+ LARGE_INTEGER Length;
+ PLOCK_SHARED_RANGE Range = CONTAINING_RECORD(ListEntry, LOCK_SHARED_RANGE, Entry);
+ Length.QuadPart = Range->End.QuadPart - Range->Start.QuadPart;
+ ListEntry = ListEntry->Flink;
+ if (Range->ProcessId != Process->UniqueProcessId)
+ continue;
+ FsRtlFastUnlockSingle
+ (FileLock,
+ FileObject,
+ &Range->Start,
+ &Length,
+ Range->ProcessId,
+ Range->Key,
+ Context,
+ TRUE);
+ }
+ for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE);
+ Entry;
+ Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE))
+ {
+ LARGE_INTEGER Length;
+ // We'll take the first one to be the list head, and free the others first...
+ Length.QuadPart =
+ Entry->Exclusive.FileLock.EndingByte.QuadPart -
+ Entry->Exclusive.FileLock.StartingByte.QuadPart;
+ FsRtlFastUnlockSingle
+ (FileLock,
+ Entry->Exclusive.FileLock.FileObject,
+ &Entry->Exclusive.FileLock.StartingByte,
+ &Length,
+ Entry->Exclusive.FileLock.ProcessId,
+ Entry->Exclusive.FileLock.Key,
+ Context,
+ TRUE);
+ }
+ DPRINT("Done %wZ\n", &FileObject->FileName);
+ return STATUS_SUCCESS;
}
/*
IN ULONG Key,
IN PVOID Context OPTIONAL)
{
- KeBugCheck(FILE_SYSTEM);
- return STATUS_UNSUCCESSFUL;
+ PLIST_ENTRY ListEntry;
+ PCOMBINED_LOCK_ELEMENT Entry;
+ PLOCK_INFORMATION InternalInfo = FileLock->LockInformation;
+
+ DPRINT("FsRtlFastUnlockAllByKey(%wZ,Key %x)\n", &FileObject->FileName, Key);
+
+ // XXX Synchronize somehow
+ if (!FileLock->LockInformation) return STATUS_RANGE_NOT_LOCKED; // no locks
+ for (ListEntry = InternalInfo->SharedLocks.Flink;
+ ListEntry != &InternalInfo->SharedLocks;)
+ {
+ PLOCK_SHARED_RANGE Range = CONTAINING_RECORD(ListEntry, LOCK_SHARED_RANGE, Entry);
+ LARGE_INTEGER Length;
+ Length.QuadPart = Range->End.QuadPart - Range->Start.QuadPart;
+ ListEntry = ListEntry->Flink;
+ if (Range->ProcessId != Process->UniqueProcessId ||
+ Range->Key != Key)
+ continue;
+ FsRtlFastUnlockSingle
+ (FileLock,
+ FileObject,
+ &Range->Start,
+ &Length,
+ Range->ProcessId,
+ Range->Key,
+ Context,
+ TRUE);
+ }
+ for (Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, TRUE);
+ Entry;
+ Entry = RtlEnumerateGenericTable(&InternalInfo->RangeTable, FALSE))
+ {
+ LARGE_INTEGER Length;
+ // We'll take the first one to be the list head, and free the others first...
+ Length.QuadPart =
+ Entry->Exclusive.FileLock.EndingByte.QuadPart -
+ Entry->Exclusive.FileLock.StartingByte.QuadPart;
+ if (Entry->Exclusive.FileLock.Key == Key &&
+ Entry->Exclusive.FileLock.ProcessId == Process->UniqueProcessId)
+ {
+ FsRtlFastUnlockSingle
+ (FileLock,
+ Entry->Exclusive.FileLock.FileObject,
+ &Entry->Exclusive.FileLock.StartingByte,
+ &Length,
+ Entry->Exclusive.FileLock.ProcessId,
+ Entry->Exclusive.FileLock.Key,
+ Context,
+ TRUE);
+ }
+ }
+
+ return STATUS_SUCCESS;
}
/*
PIO_STACK_LOCATION IoStackLocation;
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
-
+
/* Get the I/O Stack location */
IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
ASSERT(IoStackLocation->MajorFunction == IRP_MJ_LOCK_CONTROL);
-
+
/* Clear the I/O status block and check what function this is */
IoStatusBlock.Information = 0;
+
+ DPRINT("FsRtlProcessFileLock(%wZ, MinorFunction %x)\n",
+ &IoStackLocation->FileObject->FileName,
+ IoStackLocation->MinorFunction);
+
switch(IoStackLocation->MinorFunction)
{
/* A lock */
- case IRP_MN_LOCK:
-
- /* Call the private lock routine */
- FsRtlPrivateLock(FileLock,
- IoStackLocation->FileObject,
- &IoStackLocation->
- Parameters.LockControl.ByteOffset,
- IoStackLocation->Parameters.LockControl.Length,
- IoGetRequestorProcess(Irp),
- IoStackLocation->Parameters.LockControl.Key,
- IoStackLocation->Flags & SL_FAIL_IMMEDIATELY,
- IoStackLocation->Flags & SL_EXCLUSIVE_LOCK,
- &IoStatusBlock,
- Irp,
- Context,
- FALSE);
- break;
-
+ case IRP_MN_LOCK:
+
+ /* Call the private lock routine */
+ FsRtlPrivateLock(FileLock,
+ IoStackLocation->FileObject,
+ &IoStackLocation->
+ Parameters.LockControl.ByteOffset,
+ IoStackLocation->Parameters.LockControl.Length,
+ IoGetRequestorProcess(Irp),
+ IoStackLocation->Parameters.LockControl.Key,
+ IoStackLocation->Flags & SL_FAIL_IMMEDIATELY,
+ IoStackLocation->Flags & SL_EXCLUSIVE_LOCK,
+ &IoStatusBlock,
+ Irp,
+ Context,
+ FALSE);
+ return IoStatusBlock.Status;
+
/* A single unlock */
- case IRP_MN_UNLOCK_SINGLE:
-
- /* Call fast unlock */
- IoStatusBlock.Status =
- FsRtlFastUnlockSingle(FileLock,
- IoStackLocation->FileObject,
- &IoStackLocation->Parameters.LockControl.
- ByteOffset,
- IoStackLocation->Parameters.LockControl.
- Length,
- IoGetRequestorProcess(Irp),
- IoStackLocation->Parameters.LockControl.
- Key,
- Context,
- FALSE);
-
- /* Complete the IRP */
- FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
- Context,
- Irp,
- IoStatusBlock.Status,
- &Status,
- NULL);
- break;
-
+ case IRP_MN_UNLOCK_SINGLE:
+
+ /* Call fast unlock */
+ IoStatusBlock.Status =
+ FsRtlFastUnlockSingle(FileLock,
+ IoStackLocation->FileObject,
+ &IoStackLocation->Parameters.LockControl.
+ ByteOffset,
+ IoStackLocation->Parameters.LockControl.
+ Length,
+ IoGetRequestorProcess(Irp),
+ IoStackLocation->Parameters.LockControl.
+ Key,
+ Context,
+ FALSE);
+ break;
+
/* Total unlock */
- case IRP_MN_UNLOCK_ALL:
-
- /* Do a fast unlock */
- IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock,
- IoStackLocation->
- FileObject,
- IoGetRequestorProcess(Irp),
- Context);
-
- /* Complete the IRP */
- FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
- Context,
- Irp,
- IoStatusBlock.Status,
- &Status,
- NULL);
- break;
-
+ case IRP_MN_UNLOCK_ALL:
+
+ /* Do a fast unlock */
+ IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock,
+ IoStackLocation->
+ FileObject,
+ IoGetRequestorProcess(Irp),
+ Context);
+ break;
+
/* Unlock by key */
- case IRP_MN_UNLOCK_ALL_BY_KEY:
-
- /* Do it */
- IoStatusBlock.Status =
- FsRtlFastUnlockAllByKey(FileLock,
- IoStackLocation->FileObject,
- IoGetRequestorProcess(Irp),
- IoStackLocation->Parameters.
- LockControl.Key,
- Context);
-
- /* Complete the IRP */
- FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
- Context,
- Irp,
- IoStatusBlock.Status,
- &Status,
- NULL);
- break;
-
+ case IRP_MN_UNLOCK_ALL_BY_KEY:
+
+ /* Do it */
+ IoStatusBlock.Status =
+ FsRtlFastUnlockAllByKey(FileLock,
+ IoStackLocation->FileObject,
+ IoGetRequestorProcess(Irp),
+ IoStackLocation->Parameters.
+ LockControl.Key,
+ Context);
+ break;
+
/* Invalid request */
- default:
-
- /* Complete it */
- FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST);
- IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST;
- break;
+ default:
+
+ /* Complete it */
+ FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST);
+ IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST;
+ return STATUS_INVALID_DEVICE_REQUEST;
}
-
+
/* Return the status */
+ DPRINT("Lock IRP %p %x\n", Irp, IoStatusBlock.Status);
+ FsRtlCompleteLockIrpReal
+ (FileLock->CompleteLockIrpRoutine,
+ Context,
+ Irp,
+ IoStatusBlock.Status,
+ &Status,
+ NULL);
return IoStatusBlock.Status;
}
IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL)
{
/* Setup the lock */
+ RtlZeroMemory(FileLock, sizeof(*FileLock));
FileLock->FastIoIsQuestionable = FALSE;
FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine;
FileLock->UnlockRoutine = UnlockRoutine;
NTAPI
FsRtlUninitializeFileLock(IN PFILE_LOCK FileLock)
{
- return;
+ 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;
+ }
}
/*
IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL)
{
PFILE_LOCK FileLock;
-
+
/* Try to allocate it */
FileLock = ExAllocateFromPagedLookasideList(&FsRtlFileLockLookasideList);
if (FileLock)
CompleteLockIrpRoutine,
UnlockRoutine);
}
-
+
/* Return the lock */
return FileLock;
}
FsRtlUninitializeFileLock(FileLock);
ExFreeToPagedLookasideList(&FsRtlFileLockLookasideList, FileLock);
}
-