Awesomeness, in its purest art.
Le 07.03.2014 20:33, pschweitzer@svn.reactos.org a écrit :
Author: pschweitzer Date: Fri Mar 7 19:33:38 2014 New Revision: 62442
URL: http://svn.reactos.org/svn/reactos?rev=62442&view=rev Log: [NTOSKRNL]
- Implement FsRtlNotifyFilterReportChange
- Implement FsRtlNotifyUpdateBuffer
- Implement FsRtlCancelNotify
- Implement FsRtlNotifyGetLastPartOffset
- Fix implementation of FsRtlNotifyFilterChangeDirectory
This finishes the implementation of file system notifications inside the kernel. Data are properly returned to the caller on changes.
CORE-2582
Modified: trunk/reactos/ntoskrnl/fsrtl/notify.c trunk/reactos/ntoskrnl/include/internal/fsrtl.h
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] Fri Mar 7 19:33:38 2014 @@ -12,6 +12,55 @@ #define NDEBUG #include <debug.h>
+/* INLINED FUNCTIONS *********************************************************/
+/*
- @implemented
- */
+FORCEINLINE +VOID +FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) +{
- ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
- /* Only acquire fast mutex if it's not already acquired by the current thread */
- if (RealNotifySync->OwningThread != CurrentThread)
- {
ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));RealNotifySync->OwningThread = CurrentThread;- }
- /* Whatever the case, keep trace of the attempt to acquire fast mutex */
- RealNotifySync->OwnerCount++;
+}
+/*
- @implemented
- */
+FORCEINLINE +VOID +FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) +{
- RealNotifySync->OwnerCount--;
- /* Release the fast mutex only if no other instance needs it */
- if (!RealNotifySync->OwnerCount)
- {
ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));RealNotifySync->OwningThread = (ULONG_PTR)0;- }
+}
+#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr) \
for (FullPosition = 0; FullPosition < FullLen; ++FullPosition) \
if (((Type)NotifyChange->FullDirectoryName->Buffer)[FullPosition] == Chr) \++FullNumberOfParts; \for (LastPartOffset = 0; LastPartOffset < TargLen; ++LastPartOffset) { \
if ( ((Type)TargetDirectory.Buffer)[LastPartOffset] == Chr) { \++TargetNumberOfParts; \if (TargetNumberOfParts == FullNumberOfParts) \break; \} \}
/* PRIVATE FUNCTIONS *********************************************************/
VOID
@@ -22,13 +71,161 @@ FsRtlNotifySetCancelRoutine(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange OPTIONAL);
+/*
- @implemented
- */ VOID NTAPI FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
- PVOID Buffer;
- PIRP NotifyIrp;
- ULONG BufferLength;
- PIO_STACK_LOCATION Stack;
- PNOTIFY_CHANGE NotifyChange;
- PREAL_NOTIFY_SYNC RealNotifySync;
- PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL;
- /* Get the NOTIFY_CHANGE struct and reset it */
- NotifyChange = (PNOTIFY_CHANGE)Irp->IoStatus.Information;
- Irp->IoStatus.Information = 0;
- /* Reset the cancel routine */
- IoSetCancelRoutine(Irp, NULL);
- /* And release lock */ IoReleaseCancelSpinLock(Irp->CancelIrql);
- UNIMPLEMENTED;
/* Get REAL_NOTIFY_SYNC struct */
RealNotifySync = NotifyChange->NotifySync;
FsRtlNotifyAcquireFastMutex(RealNotifySync);
_SEH2_TRY
{
/* Remove the IRP from the notifications list and mark it pending */RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));IoMarkIrpPending(Irp);/* Now, the tricky part - let's find a buffer big enough to hold the return data */if (NotifyChange->Buffer && NotifyChange->AllocatedBuffer == NULL &&((Irp->MdlAddress && MmGetSystemAddressForMdl(Irp->MdlAddress) == NotifyChange->Buffer) ||NotifyChange->Buffer == Irp->AssociatedIrp.SystemBuffer)){/* Assume we didn't find any */Buffer = NULL;BufferLength = 0;/* If we don't have IRPs, check if current buffer is big enough */if (IsListEmpty(&NotifyChange->NotifyIrps)){if (NotifyChange->BufferLength >= NotifyChange->DataLength){BufferLength = NotifyChange->BufferLength;}}else{/* Otherwise, try to look at next IRP available */NotifyIrp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);Stack = IoGetCurrentIrpStackLocation(NotifyIrp);/* If its buffer is big enough, get it */if (Stack->Parameters.NotifyDirectory.Length >= NotifyChange->BufferLength){/* Is it MDL? */if (NotifyIrp->AssociatedIrp.SystemBuffer == NULL){if (NotifyIrp->MdlAddress != NULL){Buffer = MmGetSystemAddressForMdl(NotifyIrp->MdlAddress);}}else{Buffer = NotifyIrp->AssociatedIrp.MasterIrp;}/* Backup our accepted buffer length */BufferLength = Stack->Parameters.NotifyDirectory.Length;if (BufferLength > NotifyChange->BufferLength){BufferLength = NotifyChange->BufferLength;}}}/* At that point, we *may* have a buffer *//* If it has null length, then note that we won't use it */if (BufferLength == 0){NotifyChange->Flags |= NOTIFY_IMMEDIATELY;}else{/* If we have a buffer length, but no buffer then allocate one */if (Buffer == NULL){PsChargePoolQuota(NotifyChange->OwningProcess, PagedPool, BufferLength);Buffer = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, BufferLength, 'NrSF');NotifyChange->AllocatedBuffer = Buffer;}/* Copy data in that buffer */RtlCopyMemory(Buffer, NotifyChange->Buffer, NotifyChange->DataLength);NotifyChange->ThisBufferLength = BufferLength;NotifyChange->Buffer = Buffer;}/* If we don't have valide buffer, ensure everything is 0-ed out */if (NotifyChange->Flags & NOTIFY_IMMEDIATELY){NotifyChange->Buffer = 0;NotifyChange->AllocatedBuffer = 0;NotifyChange->LastEntry = 0;NotifyChange->DataLength = 0;NotifyChange->ThisBufferLength = 0;}}/* It's now time to complete - data are ready *//* Set appropriate status and complete */Irp->IoStatus.Status = STATUS_CANCELLED;IofCompleteRequest(Irp, EVENT_INCREMENT);/* If that notification isn't referenced any longer, drop it */if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount))){/* If it had an allocated buffer, delete */if (NotifyChange->AllocatedBuffer){PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 'NrSF');}/* In case of full name, remember subject context for later deletion */if (NotifyChange->FullDirectoryName){SubjectContext = NotifyChange->SubjectContext;}/* We mustn't have ANY change left anymore */ASSERT(NotifyChange->NotifyList.Flink == NULL);ExFreePoolWithTag(NotifyChange, 0);}}
_SEH2_FINALLY
{
FsRtlNotifyReleaseFastMutex(RealNotifySync);/* If the subject security context was captured, release and free it */if (SubjectContext){SeReleaseSubjectContext(SubjectContext);ExFreePool(SubjectContext);}}
_SEH2_END; }
/*
@@ -58,6 +255,9 @@ } }
+/*
- *@implemented
- */ PNOTIFY_CHANGE FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
@@ -81,22 +281,6 @@ } } return NULL; -}
-FORCEINLINE -VOID -FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) -{
ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
/* Only acquire fast mutex if it's not already acquired by the current thread */
if (RealNotifySync->OwningThread != CurrentThread)
{
ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));RealNotifySync->OwningThread = CurrentThread;}
/* Whatever the case, keep trace of the attempt to acquire fast mutex */
RealNotifySync->OwnerCount++; }
/*
@@ -216,7 +400,7 @@
DataLength = NotifyChange->DataLength;
- NotifyChange->Flags &= (INVALIDATE_BUFFERS | WATCH_TREE);
- NotifyChange->Flags &= (NOTIFY_IMMEDIATELY | WATCH_TREE); NotifyChange->DataLength = 0; NotifyChange->LastEntry = 0;
@@ -233,19 +417,6 @@ } }
-FORCEINLINE -VOID -FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) -{
- RealNotifySync->OwnerCount--;
- /* Release the fast mutex only if no other instance needs it */
- if (!RealNotifySync->OwnerCount)
- {
ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));RealNotifySync->OwningThread = (ULONG_PTR)0;- }
-}
- /*
*/
- @implemented
@@ -293,6 +464,91 @@
/* Return that we didn't removed cancel routine */ return FALSE;+}
+/*
- @implemented
- */
+BOOLEAN +FsRtlNotifyUpdateBuffer(OUT PFILE_NOTIFY_INFORMATION OutputBuffer,
IN ULONG Action,IN PSTRING ParentName,IN PSTRING TargetName,IN PSTRING StreamName,IN BOOLEAN IsUnicode,IN ULONG DataLength)+{
/* Unless there's an issue with buffers, there's no reason to fail */
BOOLEAN Succeed = TRUE;
ULONG AlreadyWritten = 0, ResultSize;
PAGED_CODE();
/* Update user buffer with the change that occured
* First copy parent name if any* Then copy target name, there's always one* And finally, copy stream name if any* If these names aren't unicode, then convert first*/_SEH2_TRY
{
OutputBuffer->NextEntryOffset = 0;OutputBuffer->Action = Action;OutputBuffer->FileNameLength = DataLength - sizeof(FILE_NOTIFY_INFORMATION);if (IsUnicode){if (ParentName->Length){RtlCopyMemory(OutputBuffer->FileName, ParentName->Buffer, ParentName->Length);OutputBuffer->FileName[ParentName->Length / sizeof(WCHAR)] = L'\\';AlreadyWritten = ParentName->Length + sizeof(WCHAR);}RtlCopyMemory(OutputBuffer->FileName + AlreadyWritten, TargetName->Buffer, TargetName->Length);if (StreamName){AlreadyWritten += TargetName->Length;OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';RtlCopyMemory(OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR),StreamName->Buffer, StreamName->Length);}}else{if (!ParentName->Length){ASSERT(StreamName);RtlCopyMemory(OutputBuffer->FileName, StreamName->Buffer, StreamName->Length);}else{RtlOemToUnicodeN(OutputBuffer->FileName, OutputBuffer->FileNameLength,&ResultSize, ParentName->Buffer,ParentName->Length);OutputBuffer->FileName[ResultSize / sizeof(WCHAR)] = L'\\';AlreadyWritten = ResultSize + sizeof(WCHAR);RtlOemToUnicodeN(OutputBuffer->FileName + AlreadyWritten,OutputBuffer->FileNameLength, &ResultSize,TargetName->Buffer, TargetName->Length);if (StreamName){AlreadyWritten += ResultSize;OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';RtlOemToUnicodeN(OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR),OutputBuffer->FileNameLength, &ResultSize,StreamName->Buffer, StreamName->Length);}}}}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Succeed = FALSE;}
_SEH2_END;
return Succeed; }
/* PUBLIC FUNCTIONS **********************************************************/
@@ -445,7 +701,7 @@
/*++
- @name FsRtlNotifyFilterChangeDirectory
- @unimplemented
- @implemented
- FILLME
@@ -559,16 +815,16 @@ NotifyIrp->IoStatus.Status = STATUS_DELETE_PENDING; IoCompleteRequest(NotifyIrp, EVENT_INCREMENT); }
/* Complete if there is directory enumeration and no buffer available any more */if ((NotifyChange->Flags & INVALIDATE_BUFFERS) && (NotifyChange->Flags & ENUMERATE_DIR)){NotifyChange->Flags &= ~INVALIDATE_BUFFERS;
/* Complete now if asked to (and not asked to notify later on) */if ((NotifyChange->Flags & NOTIFY_IMMEDIATELY) && !(NotifyChange->Flags & NOTIFY_LATER)){NotifyChange->Flags &= ~NOTIFY_IMMEDIATELY; IoMarkIrpPending(NotifyIrp); NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR; IoCompleteRequest(NotifyIrp, EVENT_INCREMENT); }
/* If no data yet, or directory enumeration, handle */else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & ENUMERATE_DIR))
/* If no data yet, or asked to notify later on, handle */else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & NOTIFY_LATER)) { goto HandleIRP; }@@ -612,20 +868,13 @@ else { /* If it can't contain WCHAR, it's ANSI */
if (FullDirectoryName->Length < sizeof(WCHAR))
if (FullDirectoryName->Length < sizeof(WCHAR) || ((CHAR*)FullDirectoryName->Buffer)[1] != 0) { NotifyChange->CharacterSize = sizeof(CHAR); }
/* First char is \, so in unicode, right part is 0* whereas in ANSI it contains next char*/else if (((CHAR*)FullDirectoryName->Buffer)[1] == 0)
else { NotifyChange->CharacterSize = sizeof(WCHAR);
}else{NotifyChange->CharacterSize = sizeof(CHAR); } /* Now, check is user is willing to watch root */@@ -668,7 +917,7 @@ FsRtlNotifyReleaseFastMutex(RealNotifySync);
/* If the subject security context was captured and there's no notify */
if (SubjectContext && (!NotifyChange || FullDirectoryName))
if (SubjectContext && (!NotifyChange || NotifyChange->FullDirectoryName)) { SeReleaseSubjectContext(SubjectContext); ExFreePool(SubjectContext);@@ -679,7 +928,7 @@
/*++
- @name FsRtlNotifyFilterReportChange
- @unimplemented
- @implemented
- FILLME
@@ -731,7 +980,437 @@ IN PVOID TargetContext, IN PVOID FilterContext) {
- KeBugCheck(FILE_SYSTEM);
PIRP Irp;
PVOID OutputBuffer;
USHORT FullPosition;
PLIST_ENTRY NextEntry;
PIO_STACK_LOCATION Stack;
PNOTIFY_CHANGE NotifyChange;
PREAL_NOTIFY_SYNC RealNotifySync;
PFILE_NOTIFY_INFORMATION FileNotifyInfo;
BOOLEAN IsStream, IsParent, PoolQuotaCharged;
STRING TargetDirectory, TargetName, ParentName, IntNormalizedParentName;
ULONG NumberOfBytes, TargetNumberOfParts, FullNumberOfParts, LastPartOffset, ParentNameOffset, ParentNameLength;
ULONG DataLength, TargetNameLength, AlignedDataLength;
TargetDirectory.Length = 0;
TargetDirectory.MaximumLength = 0;
TargetDirectory.Buffer = NULL;
TargetName.Length = 0;
TargetName.MaximumLength = 0;
TargetName.Buffer = NULL;
ParentName.Length = 0;
ParentName.MaximumLength = 0;
ParentName.Buffer = NULL;
IsStream = FALSE;
PAGED_CODE();
DPRINT("FsRtlNotifyFilterReportChange(%p, %p, %p, %u, %p, %p, %p, %x, %x, %p, %p)\n",
NotifySync, NotifyList, FullTargetName, TargetNameOffset, StreamName, NormalizedParentName,FilterMatch, Action, TargetContext, FilterContext);/* We need offset in name */
if (!TargetNameOffset && FullTargetName)
{
return;}
/* Get real structure hidden behind the opaque pointer */
RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
/* Acquire lock - will be released in finally block */
FsRtlNotifyAcquireFastMutex(RealNotifySync);
_SEH2_TRY
{
/* Browse all the registered notifications we have */for (NextEntry = NotifyList->Flink; NextEntry != NotifyList;NextEntry = NextEntry->Flink){/* Try to find an entry matching our change */NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);if (FullTargetName != NULL){ASSERT(NotifyChange->FullDirectoryName != NULL);if (!NotifyChange->FullDirectoryName->Length){continue;}if (!(FilterMatch & NotifyChange->CompletionFilter)){continue;}/* If no normalized name provided, construct it from full target name */if (NormalizedParentName == NULL){IntNormalizedParentName.Buffer = FullTargetName->Buffer;if (TargetNameOffset != NotifyChange->CharacterSize){IntNormalizedParentName.MaximumLength =IntNormalizedParentName.Length = TargetNameOffset - NotifyChange->CharacterSize;}else{IntNormalizedParentName.MaximumLength =IntNormalizedParentName.Length = TargetNameOffset;}NormalizedParentName = &IntNormalizedParentName;}/* heh? Watched directory bigger than changed file? */if (NormalizedParentName->Length < NotifyChange->FullDirectoryName->Length){continue;}/* Same len => parent */if (NormalizedParentName->Length == NotifyChange->FullDirectoryName->Length){IsParent = TRUE;}/* If not, then, we have to be watching the tree, otherwise we don't have to report such changes */else if (!(NotifyChange->Flags & WATCH_TREE)){continue;}/* And finally, we've to check we're properly \-terminated */else{if (!(NotifyChange->Flags & WATCH_ROOT)){if (NotifyChange->CharacterSize == sizeof(CHAR)){if (((PSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length] != '\\'){continue;}}else{if (((PWSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length / sizeof (WCHAR)] != L'\\'){continue;}}}IsParent = FALSE;}/* If len matches, then check that both name are equal */if (!RtlEqualMemory(NormalizedParentName->Buffer, NotifyChange->FullDirectoryName->Buffer,NotifyChange->FullDirectoryName->Length)){continue;}/* Call traverse callback (only if we have to traverse ;-)) */if (!IsParent&& NotifyChange->TraverseCallback != NULL&& !NotifyChange->TraverseCallback(NotifyChange->FsContext,TargetContext,NotifyChange->SubjectContext)){continue;}/* And then, filter callback if provided */if (NotifyChange->FilterCallback != NULL&& FilterContext != NULL&& !NotifyChange->FilterCallback(NotifyChange->FsContext, FilterContext)){continue;}}/* We have a stream! */else{ASSERT(NotifyChange->FullDirectoryName == NULL);if (TargetContext != NotifyChange->SubjectContext){continue;}ParentName.Buffer = NULL;ParentName.Length = 0;IsStream = TRUE;IsParent = FALSE;}/* If we don't have to notify immediately, prepare for output */if (!(NotifyChange->Flags & NOTIFY_IMMEDIATELY)){/* If we have something to output... */if (NotifyChange->BufferLength){/* Get size of the output */NumberOfBytes = 0;Irp = NULL;if (!NotifyChange->ThisBufferLength){if (IsListEmpty(&NotifyChange->NotifyIrps)){NumberOfBytes = NotifyChange->BufferLength;}else{Irp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);Stack = IoGetCurrentIrpStackLocation(Irp);NumberOfBytes = Stack->Parameters.NotifyDirectory.Length;}}else{NumberOfBytes = NotifyChange->ThisBufferLength;}/* If we're matching parent, we don't care about parent (redundant) */if (IsParent){ParentName.Length = 0;}else{/* If we don't deal with streams, some more work is required */if (!IsStream){if (NotifyChange->Flags & WATCH_ROOT ||(NormalizedParentName->Buffer != FullTargetName->Buffer)){/* Construct TargetDirectory if we don't have it yet */if (TargetDirectory.Buffer == NULL){TargetDirectory.Buffer = FullTargetName->Buffer;TargetDirectory.Length = TargetNameOffset;if (TargetNameOffset != NotifyChange->CharacterSize){TargetDirectory.Length = TargetNameOffset - NotifyChange->CharacterSize;}TargetDirectory.MaximumLength = TargetDirectory.Length;}/* Now, we start looking for matching parts (unless we watch root) */TargetNumberOfParts = 0;if (!(NotifyChange->Flags & WATCH_ROOT)){FullNumberOfParts = 1;if (NotifyChange->CharacterSize == sizeof(CHAR)){FsRtlNotifyGetLastPartOffset(NotifyChange->FullDirectoryName->Length,TargetDirectory.Length, PSTR, '\\');}else{FsRtlNotifyGetLastPartOffset(NotifyChange->FullDirectoryName->Length / sizeof(WCHAR),TargetDirectory.Length / sizeof(WCHAR), PWSTR, L'\\');LastPartOffset *= NotifyChange->CharacterSize;}}/* Then, we can construct proper parent name */ParentNameOffset = NotifyChange->CharacterSize + LastPartOffset;ParentName.Buffer = &TargetDirectory.Buffer[ParentNameOffset];ParentNameLength = TargetDirectory.Length;}else{/* Construct parent name even for streams */ParentName.Buffer = &NormalizedParentName->Buffer[NotifyChange->FullDirectoryName->Length] + NotifyChange->CharacterSize;ParentNameLength = NormalizedParentName->Length - NotifyChange->FullDirectoryName->Length;ParentNameOffset = NotifyChange->CharacterSize;}ParentNameLength -= ParentNameOffset;ParentName.Length = ParentNameLength;ParentName.MaximumLength = ParentNameLength;}}/* Start to count amount of data to write, we've first the structure itself */DataLength = FIELD_OFFSET(FILE_NOTIFY_INFORMATION, FileName);/* If stream, we'll just append stream name */if (IsStream){ASSERT(StreamName != NULL);DataLength += StreamName->Length;}else{/* If not parent, we've to append parent name */if (!IsParent){if (NotifyChange->CharacterSize == sizeof(CHAR)){DataLength += RtlOemStringToCountedUnicodeSize(&ParentName);}else{DataLength += ParentName.Length;}DataLength += sizeof(WCHAR);}/* Look for target name & construct it, if required */if (TargetName.Buffer){TargetNameLength = TargetName.Length;}else{TargetName.Buffer = &FullTargetName->Buffer[TargetNameOffset];TargetNameLength = FullTargetName->Length - TargetNameOffset;TargetName.Length = TargetNameLength;TargetName.MaximumLength = TargetNameLength;}/* Then, we will append it as well */if (NotifyChange->CharacterSize == sizeof(CHAR)){DataLength += RtlOemStringToCountedUnicodeSize(&TargetName);}else{DataLength += TargetName.Length;}/* If we also had a stream name, then we can append it as well */if (StreamName != NULL){if (NotifyChange->CharacterSize == sizeof(WCHAR)){DataLength += StreamName->Length + sizeof(WCHAR);}else{DataLength = DataLength + RtlOemStringToCountedUnicodeSize(&TargetName) + sizeof(CHAR);}}}/* Get the position where we can put our data (aligned!) */AlignedDataLength = ROUND_UP(NotifyChange->DataLength, sizeof(ULONG));/* If it's higher than buffer length, then, bail out without outputing */if (DataLength > NumberOfBytes || AlignedDataLength + DataLength > NumberOfBytes){NotifyChange->Flags |= NOTIFY_IMMEDIATELY;}else{OutputBuffer = 0;FileNotifyInfo = 0;/* If we already had a buffer, update last entry position */if (NotifyChange->Buffer != NULL){FileNotifyInfo = (PVOID)((ULONG_PTR)NotifyChange->Buffer + NotifyChange->LastEntry);FileNotifyInfo->NextEntryOffset = AlignedDataLength - NotifyChange->LastEntry;NotifyChange->LastEntry = AlignedDataLength;/* And get our output buffer */OutputBuffer = (PVOID)((ULONG_PTR)NotifyChange->Buffer + AlignedDataLength);}/* If we hadn't buffer, try to find one */else if (Irp != NULL){if (Irp->AssociatedIrp.SystemBuffer != NULL){OutputBuffer = Irp->AssociatedIrp.SystemBuffer;}else if (Irp->MdlAddress != NULL){OutputBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);}NotifyChange->Buffer = OutputBuffer;NotifyChange->ThisBufferLength = NumberOfBytes;}/* If we couldn't find one, then allocate one */if (NotifyChange->Buffer == NULL){PoolQuotaCharged = FALSE;_SEH2_TRY{PsChargePoolQuota(NotifyChange->OwningProcess, PagedPool, NumberOfBytes);PoolQuotaCharged = TRUE;OutputBuffer = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE,NumberOfBytes, 'NrSF');NotifyChange->Buffer = OutputBuffer;NotifyChange->AllocatedBuffer = OutputBuffer;}/* If something went wrong during allocation, notify immediately instead of outputing */_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER){if (PoolQuotaCharged){PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NumberOfBytes);}NotifyChange->Flags |= NOTIFY_IMMEDIATELY;}_SEH2_END;}/* Finally, if we have a buffer, fill it in! */if (OutputBuffer != NULL){if (FsRtlNotifyUpdateBuffer((FILE_NOTIFY_INFORMATION *)OutputBuffer,Action, &ParentName, &TargetName,StreamName, NotifyChange->CharacterSize == sizeof(WCHAR),DataLength)){NotifyChange->DataLength = DataLength + AlignedDataLength;}/* If it failed, notify immediately */else{NotifyChange->Flags |= NOTIFY_IMMEDIATELY;}}}/* If we have to notify right now (something went wrong?) */if (NotifyChange->Flags & NOTIFY_IMMEDIATELY){/* Ensure that all our buffers are NULL */if (NotifyChange->Buffer != NULL){if (NotifyChange->AllocatedBuffer != NULL){PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 'NrSF');}NotifyChange->Buffer = NULL;NotifyChange->AllocatedBuffer = NULL;NotifyChange->LastEntry = 0;NotifyChange->DataLength = 0;NotifyChange->ThisBufferLength = 0;}}}}/* If asking for old name in case of a rename, notify later on,* so that we can wait for new name.* http://msdn.microsoft.com/en-us/library/dn392331.aspx*/if (Action == FILE_ACTION_RENAMED_OLD_NAME){NotifyChange->Flags |= NOTIFY_LATER;}else{NotifyChange->Flags &= ~NOTIFY_LATER;if (!IsListEmpty(&NotifyChange->NotifyIrps)){FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_SUCCESS);}}}}
_SEH2_FINALLY
{
FsRtlNotifyReleaseFastMutex(RealNotifySync);}
_SEH2_END; }
/*++
Modified: trunk/reactos/ntoskrnl/include/internal/fsrtl.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/f... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/fsrtl.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/fsrtl.h [iso-8859-1] Fri Mar 7 19:33:38 2014 @@ -53,9 +53,9 @@ // Notifications flags // #define WATCH_TREE 0x01 -#define INVALIDATE_BUFFERS 0x02 +#define NOTIFY_IMMEDIATELY 0x02 #define CLEANUP_IN_PROCESS 0x04 -#define ENUMERATE_DIR 0x08 +#define NOTIFY_LATER 0x08 #define WATCH_ROOT 0x10 #define DELETE_IN_PROCESS 0x20