\o/! -----Message d'origine----- De : ros-dev-boun...@reactos.org [mailto:ros-dev-boun...@reactos.org] De la part de Jérôme Gardou Envoyé : vendredi 7 mars 2014 20:38 À : ros-dev@reactos.org Objet : Re: [ros-dev] [ros-diffs] [pschweitzer] 62442: [NTOSKRNL] - Implement FsRtlNotifyFilterReportChange - Implement FsRtlNotifyUpdateBuffer - Implement FsRtlCancelNotify - Implement FsRtlNotifyGetLastPartOffset - Fix implementa...
Awesomeness, in its purest art. Le 07.03.2014 20:33, pschweit...@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=62442&r1=62441&r2=62442&view=diff > ============================================================================== > --- 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/inte > rnal/fsrtl.h?rev=62442&r1=62441&r2=62442&view=diff > ============================================================================== > --- 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 > > > _______________________________________________ Ros-dev mailing list Ros-dev@reactos.org http://www.reactos.org/mailman/listinfo/ros-dev _______________________________________________ Ros-dev mailing list Ros-dev@reactos.org http://www.reactos.org/mailman/listinfo/ros-dev