Author: pschweitzer Date: Wed Feb 29 20:01:21 2012 New Revision: 55934
URL: http://svn.reactos.org/svn/reactos?rev=55934&view=rev Log: [NTOSKRNL] Stub FsRtlCancelNotify Implement FsRtlCheckNotifyForDelete, FsRtlNotifyCompleteIrp, FsRtlNotifyCompleteIrpList, FsRtlNotifySetCancelRoutine
Modified: trunk/reactos/ntoskrnl/fsrtl/notify.c
Modified: trunk/reactos/ntoskrnl/fsrtl/notify.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/fsrtl/notify.c?rev... ============================================================================== --- trunk/reactos/ntoskrnl/fsrtl/notify.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/fsrtl/notify.c [iso-8859-1] Wed Feb 29 20:01:21 2012 @@ -13,6 +13,50 @@ #include <debug.h>
/* PRIVATE FUNCTIONS *********************************************************/ + +VOID +FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, + IN NTSTATUS Status); + +BOOLEAN +FsRtlNotifySetCancelRoutine(IN PIRP Irp, + IN PNOTIFY_CHANGE NotifyChange OPTIONAL); + +VOID +NTAPI +FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + IoReleaseCancelSpinLock(Irp->CancelIrql); + UNIMPLEMENTED; +} + +/* + * @implemented + */ +VOID +FsRtlCheckNotifyForDelete(IN PLIST_ENTRY NotifyList, + IN PVOID FsContext) +{ + PLIST_ENTRY NextEntry; + PNOTIFY_CHANGE NotifyChange; + + if (!IsListEmpty(NotifyList)) + { + /* Browse the notifications list to find the matching entry */ + for (NextEntry = NotifyList->Flink; + NextEntry != NotifyList; + NextEntry = NextEntry->Flink) + { + NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList); + /* If the current record matches with the given context, it's the good one */ + if (NotifyChange->FsContext == FsContext && !IsListEmpty(&(NotifyChange->NotifyIrps))) + { + FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_DELETE_PENDING); + } + } + } +}
PNOTIFY_CHANGE FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, @@ -55,10 +99,138 @@ RealNotifySync->OwnerCount++; }
+/* + * @implemented + */ +VOID +FsRtlNotifyCompleteIrp(IN PIRP Irp, + IN PNOTIFY_CHANGE NotifyChange, + IN ULONG DataLength, + IN NTSTATUS Status, + IN BOOLEAN SkipCompletion) +{ + PVOID Buffer; + PIO_STACK_LOCATION Stack; + + PAGED_CODE(); + + /* Check if we need to complete */ + if (!FsRtlNotifySetCancelRoutine(Irp, NotifyChange) && SkipCompletion) + { + return; + } + + /* No succes => no data to return just complete */ + if (Status != STATUS_SUCCESS) + { + goto Completion; + } + + /* Ensure there's something to return */ + Stack = IoGetCurrentIrpStackLocation(Irp); + if (!DataLength || Stack->Parameters.NotifyDirectory.Length < DataLength) + { + Status = STATUS_NOTIFY_ENUM_DIR; + goto Completion; + } + + /* Ensture there's a buffer where to find data */ + if (!NotifyChange->AllocatedBuffer) + { + Irp->IoStatus.Information = DataLength; + NotifyChange->Buffer = NULL; + goto Completion; + } + + /* Now, browse all the way to return data + * and find the one that will work. We will + * return data whatever happens + */ + if (Irp->AssociatedIrp.SystemBuffer) + { + Buffer = Irp->AssociatedIrp.SystemBuffer; + goto CopyAndComplete; + } + + if (Irp->MdlAddress) + { + Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress); + goto CopyAndComplete; + } + + if (!(Stack->Control & SL_PENDING_RETURNED)) + { + Buffer = Irp->UserBuffer; + goto CopyAndComplete; + } + + Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_SYNCHRONOUS_PAGING_IO); + Irp->AssociatedIrp.SystemBuffer = NotifyChange->AllocatedBuffer; + /* Nothing to copy */ + goto ReleaseAndComplete; + +CopyAndComplete: + _SEH2_TRY + { + RtlCopyMemory(Buffer, NotifyChange->AllocatedBuffer, DataLength); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Do nothing */ + } + _SEH2_END; + +ReleaseAndComplete: + PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength); + + /* Release buffer UNLESS it's used */ + if (NotifyChange->AllocatedBuffer != Irp->AssociatedIrp.SystemBuffer && + NotifyChange->AllocatedBuffer) + { + ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 0); + } + + /* Prepare for return */ + NotifyChange->AllocatedBuffer = 0; + NotifyChange->ThisBufferLength = 0; + Irp->IoStatus.Information = DataLength; + NotifyChange->Buffer = NULL; + + /* Finally complete */ +Completion: + IoMarkIrpPending(Irp); + Irp->IoStatus.Status = Status; + IofCompleteRequest(Irp, EVENT_INCREMENT); +} + +/* + * @implemented + */ VOID FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, IN NTSTATUS Status) { + PIRP Irp; + ULONG DataLength; + PLIST_ENTRY NextEntry; + + DataLength = NotifyChange->DataLength; + + NotifyChange->Flags &= (INVALIDATE_BUFFERS | WATCH_TREE); + NotifyChange->DataLength = 0; + NotifyChange->LastEntry = 0; + + while (!IsListEmpty(&(NotifyChange->NotifyIrps))) + { + /* We take the first entry */ + NextEntry = RemoveHeadList(&(NotifyChange->NotifyIrps)); + Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); + /* We complete it */ + FsRtlNotifyCompleteIrp(Irp, NotifyChange, DataLength, Status, TRUE); + /* If we're notifying success, just notify first one */ + if (Status == STATUS_SUCCESS) + break; + } }
VOID @@ -72,6 +244,55 @@ ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex)); RealNotifySync->OwningThread = (ULONG_PTR)0; } +} + +/* + * @implemented + */ +BOOLEAN +FsRtlNotifySetCancelRoutine(IN PIRP Irp, + IN PNOTIFY_CHANGE NotifyChange OPTIONAL) +{ + PDRIVER_CANCEL CancelRoutine; + + /* Acquire cancel lock */ + IoAcquireCancelSpinLock(&Irp->CancelIrql); + + /* If NotifyChange was given */ + if (NotifyChange) + { + /* First get cancel routine */ + CancelRoutine = IoSetCancelRoutine(Irp, NULL); + Irp->IoStatus.Information = 0; + /* Release cancel lock */ + IoReleaseCancelSpinLock(Irp->CancelIrql); + /* If there was a cancel routine */ + if (CancelRoutine) + { + /* Decrease reference count */ + InterlockedDecrement((PLONG)&NotifyChange->ReferenceCount); + /* Notify that we removed cancel routine */ + return TRUE; + } + } + else + { + /* If IRP is cancel, call FsRtl cancel routine */ + if (Irp->Cancel) + { + FsRtlCancelNotify(NULL, Irp); + } + else + { + /* Otherwise, define FsRtl cancel routine as IRP cancel routine */ + IoSetCancelRoutine(Irp, FsRtlCancelNotify); + /* Release lock */ + IoReleaseCancelSpinLock(Irp->CancelIrql); + } + } + + /* Return that we didn't removed cancel routine */ + return FALSE; }
/* PUBLIC FUNCTIONS **********************************************************/