ReactOS 0.4.15-dev-7928-g68a8619
notify.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for notify.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr)
 

Functions

FORCEINLINE VOID FsRtlNotifyAcquireFastMutex (IN PREAL_NOTIFY_SYNC RealNotifySync)
 
FORCEINLINE VOID FsRtlNotifyReleaseFastMutex (IN PREAL_NOTIFY_SYNC RealNotifySync)
 
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)
 
VOID FsRtlCheckNotifyForDelete (IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
 
PNOTIFY_CHANGE FsRtlIsNotifyOnList (IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
 
VOID FsRtlNotifyCompleteIrp (IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange, IN ULONG DataLength, IN NTSTATUS Status, IN BOOLEAN SkipCompletion)
 
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)
 
VOID NTAPI FsRtlNotifyChangeDirectory (IN PNOTIFY_SYNC NotifySync, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN PLIST_ENTRY NotifyList, IN BOOLEAN WatchTree, IN ULONG CompletionFilter, IN PIRP NotifyIrp)
 
VOID NTAPI FsRtlNotifyCleanup (IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
 
VOID NTAPI FsRtlNotifyFilterChangeDirectory (IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL, IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL)
 
VOID NTAPI FsRtlNotifyFilterReportChange (IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN USHORT TargetNameOffset, IN PSTRING StreamName OPTIONAL, IN PSTRING NormalizedParentName OPTIONAL, IN ULONG FilterMatch, IN ULONG Action, IN PVOID TargetContext, IN PVOID FilterContext)
 
VOID NTAPI FsRtlNotifyFullChangeDirectory (IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
 
VOID NTAPI FsRtlNotifyFullReportChange (IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN USHORT TargetNameOffset, IN PSTRING StreamName OPTIONAL, IN PSTRING NormalizedParentName OPTIONAL, IN ULONG FilterMatch, IN ULONG Action, IN PVOID TargetContext)
 
VOID NTAPI FsRtlNotifyInitializeSync (IN PNOTIFY_SYNC *NotifySync)
 
VOID NTAPI FsRtlNotifyReportChange (IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN PUSHORT FileNamePartLength, IN ULONG FilterMatch)
 
VOID NTAPI FsRtlNotifyUninitializeSync (IN PNOTIFY_SYNC *NotifySync)
 

Macro Definition Documentation

◆ FsRtlNotifyGetLastPartOffset

#define FsRtlNotifyGetLastPartOffset (   FullLen,
  TargLen,
  Type,
  Chr 
)
Value:
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; \
} \
}
Type
Definition: Type.h:7

Definition at line 52 of file notify.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file notify.c.

Function Documentation

◆ FsRtlCancelNotify()

VOID NTAPI FsRtlCancelNotify ( IN PDEVICE_OBJECT  DeviceObject,
IN PIRP  Irp 
)

Definition at line 79 of file notify.c.

81{
86 PNOTIFY_CHANGE NotifyChange;
87 PREAL_NOTIFY_SYNC RealNotifySync;
88 BOOLEAN PoolQuotaCharged;
90
91 /* Get the NOTIFY_CHANGE struct and reset it */
92 NotifyChange = (PNOTIFY_CHANGE)Irp->IoStatus.Information;
93 Irp->IoStatus.Information = 0;
94 /* Reset the cancel routine */
96 /* And release lock */
97 IoReleaseCancelSpinLock(Irp->CancelIrql);
98 /* Get REAL_NOTIFY_SYNC struct */
99 RealNotifySync = NotifyChange->NotifySync;
100
101 FsRtlNotifyAcquireFastMutex(RealNotifySync);
102
104 {
105 /* Remove the IRP from the notifications list and mark it pending */
106 RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
108
109 /* Now, the tricky part - let's find a buffer big enough to hold the return data */
110 if (NotifyChange->Buffer && NotifyChange->AllocatedBuffer == NULL &&
111 ((Irp->MdlAddress && MmGetSystemAddressForMdl(Irp->MdlAddress) == NotifyChange->Buffer) ||
112 NotifyChange->Buffer == Irp->AssociatedIrp.SystemBuffer))
113 {
114 /* Assume we didn't find any */
115 Buffer = NULL;
116 BufferLength = 0;
117
118 /* If we don't have IRPs, check if current buffer is big enough */
119 if (IsListEmpty(&NotifyChange->NotifyIrps))
120 {
121 if (NotifyChange->BufferLength >= NotifyChange->DataLength)
122 {
123 BufferLength = NotifyChange->BufferLength;
124 }
125 }
126 else
127 {
128 /* Otherwise, try to look at next IRP available */
129 NotifyIrp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);
131
132 /* If its buffer is big enough, get it */
133 if (Stack->Parameters.NotifyDirectory.Length >= NotifyChange->BufferLength)
134 {
135 /* Is it MDL? */
136 if (NotifyIrp->AssociatedIrp.SystemBuffer == NULL)
137 {
138 if (NotifyIrp->MdlAddress != NULL)
139 {
141 }
142 }
143 else
144 {
145 Buffer = NotifyIrp->AssociatedIrp.MasterIrp;
146 }
147
148 /* Backup our accepted buffer length */
149 BufferLength = Stack->Parameters.NotifyDirectory.Length;
150 if (BufferLength > NotifyChange->BufferLength)
151 {
152 BufferLength = NotifyChange->BufferLength;
153 }
154 }
155 }
156
157 /* At that point, we *may* have a buffer */
158
159 /* If it has null length, then note that we won't use it */
160 if (BufferLength == 0)
161 {
162 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
163 }
164 else
165 {
166 /* If we have a buffer length, but no buffer then allocate one */
167 if (Buffer == NULL)
168 {
169 /* Assume we haven't charged quotas */
170 PoolQuotaCharged = FALSE;
171
173 {
174 /* Charge quotas */
176 PoolQuotaCharged = TRUE;
177
178 /* Allocate buffer */
180 NotifyChange->AllocatedBuffer = Buffer;
181
182 /* Copy data in that buffer */
183 RtlCopyMemory(Buffer, NotifyChange->Buffer, NotifyChange->DataLength);
184 NotifyChange->ThisBufferLength = BufferLength;
185 NotifyChange->Buffer = Buffer;
186 }
188 {
189 /* Something went wrong, have we charged quotas? */
190 if (PoolQuotaCharged)
191 {
192 /* We did, return quotas */
194 }
195
196 /* And notify immediately */
197 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
198 }
199 _SEH2_END;
200 }
201 }
202
203 /* If we have to notify immediately, ensure that any buffer is 0-ed out */
204 if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
205 {
206 NotifyChange->Buffer = 0;
207 NotifyChange->AllocatedBuffer = 0;
208 NotifyChange->LastEntry = 0;
209 NotifyChange->DataLength = 0;
210 NotifyChange->ThisBufferLength = 0;
211 }
212 }
213
214 /* It's now time to complete - data are ready */
215
216 /* Set appropriate status and complete */
217 Irp->IoStatus.Status = STATUS_CANCELLED;
219
220 /* If that notification isn't referenced any longer, drop it */
221 if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
222 {
223 /* If it had an allocated buffer, delete */
224 if (NotifyChange->AllocatedBuffer)
225 {
228 }
229
230 /* In case of full name, remember subject context for later deletion */
231 if (NotifyChange->FullDirectoryName)
232 {
233 SubjectContext = NotifyChange->SubjectContext;
234 }
235
236 /* We mustn't have ANY change left anymore */
237 ASSERT(NotifyChange->NotifyList.Flink == NULL);
238 ExFreePoolWithTag(NotifyChange, 0);
239 }
240 }
242 {
243 FsRtlNotifyReleaseFastMutex(RealNotifySync);
244
245 /* If the subject security context was captured, release and free it */
246 if (SubjectContext)
247 {
250 }
251 }
252 _SEH2_END;
253}
static PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(PIRP Irp)
unsigned char BOOLEAN
#define InterlockedDecrement
Definition: armddk.h:52
Definition: bufpool.h:45
_In_ PIRP Irp
Definition: csq.h:116
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define PagedPool
Definition: env_spec_w32.h:308
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS _In_opt_ PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fltkernel.h:2246
#define NOTIFY_IMMEDIATELY
Definition: fsrtl.h:56
struct _NOTIFY_CHANGE * PNOTIFY_CHANGE
_In_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_opt_ PIRP NotifyIrp
Definition: fsrtlfuncs.h:728
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
IoMarkIrpPending(Irp)
IoSetCancelRoutine(Irp, CancelRoutine)
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
FORCEINLINE VOID FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
Definition: notify.c:41
FORCEINLINE VOID FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
Definition: notify.c:22
#define IoCompleteRequest
Definition: irp.c:1240
VOID NTAPI IoReleaseCancelSpinLock(IN KIRQL Irql)
Definition: util.c:150
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_VOLATILE
Definition: pseh2_64.h:163
VOID NTAPI PsReturnProcessPagedPoolQuota(_In_ PEPROCESS Process, _In_ SIZE_T Amount)
Returns the paged pool quota that the process was taking up.
Definition: quota.c:965
VOID NTAPI PsChargePoolQuota(_In_ PEPROCESS Process, _In_ POOL_TYPE PoolType, _In_ SIZE_T Amount)
Charges the pool quota of a given process. The kind of pool quota to charge is determined by the Pool...
Definition: quota.c:775
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PSTRING FullDirectoryName
Definition: fsrtl.h:82
ULONG BufferLength
Definition: fsrtl.h:91
PVOID Buffer
Definition: fsrtl.h:90
PVOID AllocatedBuffer
Definition: fsrtl.h:89
USHORT Flags
Definition: fsrtl.h:86
LIST_ENTRY NotifyIrps
Definition: fsrtl.h:84
PSECURITY_SUBJECT_CONTEXT SubjectContext
Definition: fsrtl.h:81
PEPROCESS OwningProcess
Definition: fsrtl.h:96
ULONG DataLength
Definition: fsrtl.h:93
ULONG LastEntry
Definition: fsrtl.h:94
ULONG ReferenceCount
Definition: fsrtl.h:95
PREAL_NOTIFY_SYNC NotifySync
Definition: fsrtl.h:77
LIST_ENTRY NotifyList
Definition: fsrtl.h:83
ULONG ThisBufferLength
Definition: fsrtl.h:92
VOID NTAPI SeReleaseSubjectContext(_In_ PSECURITY_SUBJECT_CONTEXT SubjectContext)
Releases both the primary and client tokens of a security subject context.
Definition: subject.c:171
#define TAG_FS_NOTIFICATIONS
Definition: tag.h:68
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
int32_t * PLONG
Definition: typedefs.h:58
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_CANCELLED
Definition: udferr_usr.h:170
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639
#define IO_DISK_INCREMENT
Definition: iotypes.h:600
#define POOL_RAISE_IF_ALLOCATION_FAILURE
#define MmGetSystemAddressForMdl(Mdl)

Referenced by FsRtlNotifySetCancelRoutine().

◆ FsRtlCheckNotifyForDelete()

VOID FsRtlCheckNotifyForDelete ( IN PLIST_ENTRY  NotifyList,
IN PVOID  FsContext 
)

Definition at line 259 of file notify.c.

261{
262 PLIST_ENTRY NextEntry;
263 PNOTIFY_CHANGE NotifyChange;
264
266 {
267 /* Browse the notifications list to find the matching entry */
268 for (NextEntry = NotifyList->Flink;
269 NextEntry != NotifyList;
270 NextEntry = NextEntry->Flink)
271 {
272 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
273 /* If the current record matches with the given context, it's the good one */
274 if (NotifyChange->FsContext == FsContext && !IsListEmpty(&(NotifyChange->NotifyIrps)))
275 {
277 }
278 }
279 }
280}
_Inout_ PLIST_ENTRY NotifyList
Definition: fltkernel.h:2238
_Inout_ PLIST_ENTRY _In_ PVOID FsContext
Definition: fltkernel.h:2239
VOID FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, IN NTSTATUS Status)
Definition: notify.c:418
#define STATUS_DELETE_PENDING
Definition: ntstatus.h:322
Definition: typedefs.h:120
PVOID FsContext
Definition: fsrtl.h:78

Referenced by FsRtlNotifyFilterChangeDirectory().

◆ FsRtlIsNotifyOnList()

PNOTIFY_CHANGE FsRtlIsNotifyOnList ( IN PLIST_ENTRY  NotifyList,
IN PVOID  FsContext 
)

Definition at line 286 of file notify.c.

288{
289 PLIST_ENTRY NextEntry;
290 PNOTIFY_CHANGE NotifyChange;
291
293 {
294 /* Browse the notifications list to find the matching entry */
295 for (NextEntry = NotifyList->Flink;
296 NextEntry != NotifyList;
297 NextEntry = NextEntry->Flink)
298 {
299 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
300 /* If the current record matches with the given context, it's the good one */
301 if (NotifyChange->FsContext == FsContext)
302 {
303 return NotifyChange;
304 }
305 }
306 }
307 return NULL;
308}

Referenced by FsRtlNotifyCleanup(), and FsRtlNotifyFilterChangeDirectory().

◆ FsRtlNotifyAcquireFastMutex()

FORCEINLINE VOID FsRtlNotifyAcquireFastMutex ( IN PREAL_NOTIFY_SYNC  RealNotifySync)

Definition at line 22 of file notify.c.

23{
24 ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
25
26 /* Only acquire fast mutex if it's not already acquired by the current thread */
27 if (RealNotifySync->OwningThread != CurrentThread)
28 {
29 ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));
30 RealNotifySync->OwningThread = CurrentThread;
31 }
32 /* Whatever the case, keep trace of the attempt to acquire fast mutex */
33 RealNotifySync->OwnerCount++;
34}
#define ULONG_PTR
Definition: config.h:101
#define KeGetCurrentThread
Definition: hal.h:55
VOID FASTCALL ExAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:75
uint32_t ULONG_PTR
Definition: typedefs.h:65

Referenced by FsRtlCancelNotify(), FsRtlNotifyCleanup(), FsRtlNotifyFilterChangeDirectory(), and FsRtlNotifyFilterReportChange().

◆ FsRtlNotifyChangeDirectory()

VOID NTAPI FsRtlNotifyChangeDirectory ( IN PNOTIFY_SYNC  NotifySync,
IN PVOID  FsContext,
IN PSTRING  FullDirectoryName,
IN PLIST_ENTRY  NotifyList,
IN BOOLEAN  WatchTree,
IN ULONG  CompletionFilter,
IN PIRP  NotifyIrp 
)

Definition at line 616 of file notify.c.

623{
626 FsContext,
628 WatchTree,
629 TRUE,
631 NotifyIrp,
632 NULL,
633 NULL,
634 NULL);
635}
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING FullDirectoryName
Definition: fltkernel.h:2240
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG CompletionFilter
Definition: fltkernel.h:2243
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN WatchTree
Definition: fltkernel.h:2241
VOID NTAPI FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PVOID FsContext, IN PSTRING FullDirectoryName, IN BOOLEAN WatchTree, IN BOOLEAN IgnoreBuffer, IN ULONG CompletionFilter, IN PIRP NotifyIrp, IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL, IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL)
Definition: notify.c:773

◆ FsRtlNotifyCleanup()

VOID NTAPI FsRtlNotifyCleanup ( IN PNOTIFY_SYNC  NotifySync,
IN PLIST_ENTRY  NotifyList,
IN PVOID  FsContext 
)

Definition at line 659 of file notify.c.

662{
663 PNOTIFY_CHANGE NotifyChange;
664 PREAL_NOTIFY_SYNC RealNotifySync;
666
667 /* Get real structure hidden behind the opaque pointer */
668 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
669
670 /* Acquire the fast mutex */
671 FsRtlNotifyAcquireFastMutex(RealNotifySync);
672
674 {
675 /* Find if there's a matching notification with the FsContext */
677 if (NotifyChange)
678 {
679 /* Mark it as to know that cleanup is in process */
680 NotifyChange->Flags |= CLEANUP_IN_PROCESS;
681
682 /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP status */
683 if (!IsListEmpty(&NotifyChange->NotifyIrps))
684 {
686 }
687
688 /* Decrease reference number and if 0 is reached, it's time to do complete cleanup */
689 if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
690 {
691 /* Remove it from the notifications list */
692 RemoveEntryList(&NotifyChange->NotifyList);
693
694 /* In case there was an allocated buffer, free it */
695 if (NotifyChange->AllocatedBuffer)
696 {
698 ExFreePool(NotifyChange->AllocatedBuffer);
699 }
700
701 /* In case there the string was set, get the captured subject security context */
702 if (NotifyChange->FullDirectoryName)
703 {
704 SubjectContext = NotifyChange->SubjectContext;
705 }
706
707 /* Finally, free the notification, as it's not needed anymore */
708 ExFreePoolWithTag(NotifyChange, 'NrSF');
709 }
710 }
711 }
713 {
714 /* Release fast mutex */
715 FsRtlNotifyReleaseFastMutex(RealNotifySync);
716
717 /* If the subject security context was captured, release and free it */
718 if (SubjectContext)
719 {
722 }
723 }
724 _SEH2_END;
725}
#define CLEANUP_IN_PROCESS
Definition: fsrtl.h:57
struct _REAL_NOTIFY_SYNC * PREAL_NOTIFY_SYNC
PNOTIFY_CHANGE FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:286
#define STATUS_NOTIFY_CLEANUP
Definition: ntstatus.h:90

Referenced by _Dispatch_type_(), _Requires_lock_held_(), Ext2Cleanup(), UDFCommonCleanup(), and VfatCleanupFile().

◆ FsRtlNotifyCompleteIrp()

VOID FsRtlNotifyCompleteIrp ( IN PIRP  Irp,
IN PNOTIFY_CHANGE  NotifyChange,
IN ULONG  DataLength,
IN NTSTATUS  Status,
IN BOOLEAN  SkipCompletion 
)

Definition at line 314 of file notify.c.

319{
322
323 PAGED_CODE();
324
325 /* Check if we need to complete */
326 if (!FsRtlNotifySetCancelRoutine(Irp, NotifyChange) && SkipCompletion)
327 {
328 return;
329 }
330
331 /* No succes => no data to return just complete */
332 if (Status != STATUS_SUCCESS)
333 {
334 goto Completion;
335 }
336
337 /* Ensure there's something to return */
339 if (!DataLength || Stack->Parameters.NotifyDirectory.Length < DataLength)
340 {
342 goto Completion;
343 }
344
345 /* Ensture there's a buffer where to find data */
346 if (!NotifyChange->AllocatedBuffer)
347 {
348 Irp->IoStatus.Information = DataLength;
349 NotifyChange->Buffer = NULL;
350 goto Completion;
351 }
352
353 /* Now, browse all the way to return data
354 * and find the one that will work. We will
355 * return data whatever happens
356 */
357 if (Irp->AssociatedIrp.SystemBuffer)
358 {
359 Buffer = Irp->AssociatedIrp.SystemBuffer;
360 goto CopyAndComplete;
361 }
362
363 if (Irp->MdlAddress)
364 {
365 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
366 goto CopyAndComplete;
367 }
368
369 if (!(Stack->Control & SL_PENDING_RETURNED))
370 {
371 Buffer = Irp->UserBuffer;
372 goto CopyAndComplete;
373 }
374
376 Irp->AssociatedIrp.SystemBuffer = NotifyChange->AllocatedBuffer;
377 /* Nothing to copy */
378 goto ReleaseAndComplete;
379
380CopyAndComplete:
382 {
383 RtlCopyMemory(Buffer, NotifyChange->AllocatedBuffer, DataLength);
384 }
386 {
387 /* Do nothing */
388 }
389 _SEH2_END;
390
391ReleaseAndComplete:
392 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
393
394 /* Release buffer UNLESS it's used */
395 if (NotifyChange->AllocatedBuffer != Irp->AssociatedIrp.SystemBuffer &&
396 NotifyChange->AllocatedBuffer)
397 {
398 ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 0);
399 }
400
401 /* Prepare for return */
402 NotifyChange->AllocatedBuffer = 0;
403 NotifyChange->ThisBufferLength = 0;
404 Irp->IoStatus.Information = DataLength;
405 NotifyChange->Buffer = NULL;
406
407 /* Finally complete */
408Completion:
410 Irp->IoStatus.Status = Status;
412}
#define PAGED_CODE()
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1444
Status
Definition: gdiplustypes.h:25
BOOLEAN FsRtlNotifySetCancelRoutine(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange OPTIONAL)
Definition: notify.c:448
#define STATUS_NOTIFY_ENUM_DIR
Definition: ntstatus.h:91
#define STATUS_SUCCESS
Definition: shellext.h:65
#define SL_PENDING_RETURNED
Definition: iotypes.h:3325
#define IRP_DEALLOCATE_BUFFER
#define IRP_BUFFERED_IO
#define IRP_SYNCHRONOUS_PAGING_IO

Referenced by FsRtlNotifyCompleteIrpList(), and FsRtlNotifyFilterChangeDirectory().

◆ FsRtlNotifyCompleteIrpList()

VOID FsRtlNotifyCompleteIrpList ( IN PNOTIFY_CHANGE  NotifyChange,
IN NTSTATUS  Status 
)

Definition at line 418 of file notify.c.

420{
421 PIRP Irp;
423 PLIST_ENTRY NextEntry;
424
425 DataLength = NotifyChange->DataLength;
426
427 NotifyChange->Flags &= (NOTIFY_IMMEDIATELY | WATCH_TREE);
428 NotifyChange->DataLength = 0;
429 NotifyChange->LastEntry = 0;
430
431 while (!IsListEmpty(&(NotifyChange->NotifyIrps)))
432 {
433 /* We take the first entry */
434 NextEntry = RemoveHeadList(&(NotifyChange->NotifyIrps));
435 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
436 /* We complete it */
438 /* If we're notifying success, just notify first one */
439 if (Status == STATUS_SUCCESS)
440 break;
441 }
442}
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define WATCH_TREE
Definition: fsrtl.h:55
VOID FsRtlNotifyCompleteIrp(IN PIRP Irp, IN PNOTIFY_CHANGE NotifyChange, IN ULONG DataLength, IN NTSTATUS Status, IN BOOLEAN SkipCompletion)
Definition: notify.c:314

Referenced by FsRtlCheckNotifyForDelete(), FsRtlNotifyCleanup(), and FsRtlNotifyFilterReportChange().

◆ FsRtlNotifyFilterChangeDirectory()

VOID NTAPI FsRtlNotifyFilterChangeDirectory ( IN PNOTIFY_SYNC  NotifySync,
IN PLIST_ENTRY  NotifyList,
IN PVOID  FsContext,
IN PSTRING  FullDirectoryName,
IN BOOLEAN  WatchTree,
IN BOOLEAN  IgnoreBuffer,
IN ULONG  CompletionFilter,
IN PIRP  NotifyIrp,
IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback  OPTIONAL,
IN PSECURITY_SUBJECT_CONTEXT SubjectContext  OPTIONAL,
IN PFILTER_REPORT_CHANGE FilterCallback  OPTIONAL 
)

Definition at line 773 of file notify.c.

784{
785 ULONG SavedLength;
787 PNOTIFY_CHANGE NotifyChange = NULL;
788 PREAL_NOTIFY_SYNC RealNotifySync;
789
790 PAGED_CODE();
791
792 DPRINT("FsRtlNotifyFilterChangeDirectory(): %p, %p, %p, %wZ, %u, %u, %u, %p, %p, %p, %p\n",
795
796 /* Get real structure hidden behind the opaque pointer */
797 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
798
799 /* Acquire the fast mutex */
800 FsRtlNotifyAcquireFastMutex(RealNotifySync);
801
803 {
804 /* If we have no IRP, FSD is performing a cleanup */
805 if (!NotifyIrp)
806 {
807 /* So, we delete */
810 }
811
812 NotifyIrp->IoStatus.Status = STATUS_SUCCESS;
813 NotifyIrp->IoStatus.Information = (ULONG_PTR)NULL;
814
816 /* If FileObject's been cleaned up, just return */
817 if (Stack->FileObject->Flags & FO_CLEANUP_COMPLETE)
818 {
820 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP;
823 }
824
825 /* Try to find a matching notification has been already registered */
827 if (NotifyChange)
828 {
829 /* If it's been found, and is cleaned up, immediatly complete */
830 if (NotifyChange->Flags & CLEANUP_IN_PROCESS)
831 {
833 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP;
835 }
836 /* Or if it's about to be deleted, complete */
837 else if (NotifyChange->Flags & DELETE_IN_PROCESS)
838 {
840 NotifyIrp->IoStatus.Status = STATUS_DELETE_PENDING;
842 }
843 /* Complete now if asked to (and not asked to notify later on) */
844 if ((NotifyChange->Flags & NOTIFY_IMMEDIATELY) && !(NotifyChange->Flags & NOTIFY_LATER))
845 {
846 NotifyChange->Flags &= ~NOTIFY_IMMEDIATELY;
848 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR;
850 }
851 /* If no data yet, or asked to notify later on, handle */
852 else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & NOTIFY_LATER))
853 {
854 goto HandleIRP;
855 }
856 /* Else, just complete with we have */
857 else
858 {
859 SavedLength = NotifyChange->DataLength;
860 NotifyChange->DataLength = 0;
861 FsRtlNotifyCompleteIrp(NotifyIrp, NotifyChange, SavedLength, STATUS_SUCCESS, FALSE);
862 }
863
865 }
866
867 /* Allocate new notification */
869 sizeof(NOTIFY_CHANGE), 'NrSF');
870 RtlZeroMemory(NotifyChange, sizeof(NOTIFY_CHANGE));
871
872 /* Set basic information */
873 NotifyChange->NotifySync = NotifySync;
874 NotifyChange->FsContext = FsContext;
875 NotifyChange->StreamID = Stack->FileObject->FsContext;
876 NotifyChange->TraverseCallback = TraverseCallback;
877 NotifyChange->SubjectContext = SubjectContext;
878 NotifyChange->FullDirectoryName = FullDirectoryName;
879 NotifyChange->FilterCallback = FilterCallback;
880 InitializeListHead(&(NotifyChange->NotifyIrps));
881
882 /* Keep trace of WatchTree */
883 if (WatchTree)
884 {
885 NotifyChange->Flags |= WATCH_TREE;
886 }
887
888 /* If string is empty, faulty to ANSI */
889 if (FullDirectoryName->Length == 0)
890 {
891 NotifyChange->CharacterSize = sizeof(CHAR);
892 }
893 else
894 {
895 /* If it can't contain WCHAR, it's ANSI */
896 if (FullDirectoryName->Length < sizeof(WCHAR) || ((CHAR*)FullDirectoryName->Buffer)[1] != 0)
897 {
898 NotifyChange->CharacterSize = sizeof(CHAR);
899 }
900 else
901 {
902 NotifyChange->CharacterSize = sizeof(WCHAR);
903 }
904
905 /* Now, check is user is willing to watch root */
906 if (FullDirectoryName->Length == NotifyChange->CharacterSize)
907 {
908 NotifyChange->Flags |= WATCH_ROOT;
909 }
910 }
911
912 NotifyChange->CompletionFilter = CompletionFilter;
913
914 /* In case we have not to ignore buffer , keep its length */
915 if (!IgnoreBuffer)
916 {
917 NotifyChange->BufferLength = Stack->Parameters.NotifyDirectory.Length;
918 }
919
920 NotifyChange->OwningProcess = NotifyIrp->Tail.Overlay.Thread->ThreadsProcess;
921
922 /* Insert the notification into the notification list */
923 InsertTailList(NotifyList, &(NotifyChange->NotifyList));
924
925 NotifyChange->ReferenceCount = 1;
926
927HandleIRP:
928 /* Associate the notification to the IRP */
929 NotifyIrp->IoStatus.Information = (ULONG_PTR)NotifyChange;
930 /* The IRP is pending */
932 /* Insert the IRP in the IRP list */
933 InsertTailList(&(NotifyChange->NotifyIrps), &(NotifyIrp->Tail.Overlay.ListEntry));
934 /* Increment reference count */
935 InterlockedIncrement((PLONG)&(NotifyChange->ReferenceCount));
936 /* Set cancel routine to FsRtl one */
938 }
940 {
941 /* Release fast mutex */
942 FsRtlNotifyReleaseFastMutex(RealNotifySync);
943
944 /* If the subject security context was captured and there's no notify */
945 if (SubjectContext && (!NotifyChange || NotifyChange->FullDirectoryName))
946 {
949 }
950 }
951 _SEH2_END;
952}
#define InterlockedIncrement
Definition: armddk.h:53
#define CHAR(Char)
#define InsertTailList(ListHead, Entry)
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define _SEH2_LEAVE
Definition: filesup.c:20
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
Definition: fltkernel.h:2245
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN _In_ ULONG _In_ PFLT_CALLBACK_DATA _In_opt_ PCHECK_FOR_TRAVERSE_ACCESS _In_opt_ PSECURITY_SUBJECT_CONTEXT _In_opt_ PFILTER_REPORT_CHANGE FilterCallback
Definition: fltkernel.h:2247
_Inout_ PLIST_ENTRY _In_ PVOID _In_ PSTRING _In_ BOOLEAN _In_ BOOLEAN IgnoreBuffer
Definition: fltkernel.h:2242
#define DELETE_IN_PROCESS
Definition: fsrtl.h:60
#define WATCH_ROOT
Definition: fsrtl.h:59
#define NOTIFY_LATER
Definition: fsrtl.h:58
VOID FsRtlCheckNotifyForDelete(IN PLIST_ENTRY NotifyList, IN PVOID FsContext)
Definition: notify.c:259
#define DPRINT
Definition: sndvol32.h:71
ULONG CompletionFilter
Definition: fsrtl.h:88
PVOID StreamID
Definition: fsrtl.h:79
UCHAR CharacterSize
Definition: fsrtl.h:87
PFILTER_REPORT_CHANGE FilterCallback
Definition: fsrtl.h:85
PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback
Definition: fsrtl.h:80
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define FO_CLEANUP_COMPLETE
Definition: iotypes.h:1790
__wchar_t WCHAR
Definition: xmlstorage.h:180
char CHAR
Definition: xmlstorage.h:175

Referenced by FsRtlNotifyChangeDirectory(), FsRtlNotifyFullChangeDirectory(), and notify_change_directory().

◆ FsRtlNotifyFilterReportChange()

VOID NTAPI FsRtlNotifyFilterReportChange ( IN PNOTIFY_SYNC  NotifySync,
IN PLIST_ENTRY  NotifyList,
IN PSTRING  FullTargetName,
IN USHORT  TargetNameOffset,
IN PSTRING StreamName  OPTIONAL,
IN PSTRING NormalizedParentName  OPTIONAL,
IN ULONG  FilterMatch,
IN ULONG  Action,
IN PVOID  TargetContext,
IN PVOID  FilterContext 
)

Definition at line 997 of file notify.c.

1007{
1008 PIRP Irp;
1010 USHORT FullPosition;
1011 PLIST_ENTRY NextEntry;
1013 PNOTIFY_CHANGE NotifyChange;
1014 PREAL_NOTIFY_SYNC RealNotifySync;
1015 PFILE_NOTIFY_INFORMATION FileNotifyInfo;
1016 BOOLEAN IsStream, IsParent, PoolQuotaCharged;
1017 STRING TargetDirectory, TargetName, ParentName, IntNormalizedParentName;
1018 ULONG NumberOfBytes, TargetNumberOfParts, FullNumberOfParts, LastPartOffset, ParentNameOffset, ParentNameLength;
1019 ULONG DataLength, AlignedDataLength;
1020
1021 TargetDirectory.Length = 0;
1022 TargetDirectory.MaximumLength = 0;
1023 TargetDirectory.Buffer = NULL;
1024 TargetName.Length = 0;
1025 TargetName.MaximumLength = 0;
1026 TargetName.Buffer = NULL;
1027 ParentName.Length = 0;
1028 ParentName.MaximumLength = 0;
1029 ParentName.Buffer = NULL;
1030 IsStream = FALSE;
1031
1032 PAGED_CODE();
1033
1034 DPRINT("FsRtlNotifyFilterReportChange(%p, %p, %p, %u, %p, %p, %p, %x, %x, %p, %p)\n",
1037
1038 /* We need offset in name */
1040 {
1041 return;
1042 }
1043
1044 /* Get real structure hidden behind the opaque pointer */
1045 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
1046 /* Acquire lock - will be released in finally block */
1047 FsRtlNotifyAcquireFastMutex(RealNotifySync);
1048 _SEH2_TRY
1049 {
1050 /* Browse all the registered notifications we have */
1051 for (NextEntry = NotifyList->Flink; NextEntry != NotifyList;
1052 NextEntry = NextEntry->Flink)
1053 {
1054 /* Try to find an entry matching our change */
1055 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList);
1056 if (FullTargetName != NULL)
1057 {
1058 ASSERT(NotifyChange->FullDirectoryName != NULL);
1059 if (!NotifyChange->FullDirectoryName->Length)
1060 {
1061 continue;
1062 }
1063
1064 if (!(FilterMatch & NotifyChange->CompletionFilter))
1065 {
1066 continue;
1067 }
1068
1069 /* If no normalized name provided, construct it from full target name */
1071 {
1072 IntNormalizedParentName.Buffer = FullTargetName->Buffer;
1073 if (TargetNameOffset != NotifyChange->CharacterSize)
1074 {
1075 IntNormalizedParentName.MaximumLength =
1076 IntNormalizedParentName.Length = TargetNameOffset - NotifyChange->CharacterSize;
1077 }
1078 else
1079 {
1080 IntNormalizedParentName.MaximumLength =
1081 IntNormalizedParentName.Length = TargetNameOffset;
1082 }
1083 NormalizedParentName = &IntNormalizedParentName;
1084 }
1085
1086 /* heh? Watched directory bigger than changed file? */
1087 if (NormalizedParentName->Length < NotifyChange->FullDirectoryName->Length)
1088 {
1089 continue;
1090 }
1091
1092 /* Same len => parent */
1093 if (NormalizedParentName->Length == NotifyChange->FullDirectoryName->Length)
1094 {
1095 IsParent = TRUE;
1096 }
1097 /* If not, then, we have to be watching the tree, otherwise we don't have to report such changes */
1098 else if (!(NotifyChange->Flags & WATCH_TREE))
1099 {
1100 continue;
1101 }
1102 /* And finally, we've to check we're properly \-terminated */
1103 else
1104 {
1105 if (!(NotifyChange->Flags & WATCH_ROOT))
1106 {
1107 if (NotifyChange->CharacterSize == sizeof(CHAR))
1108 {
1109 if (((PSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length] != '\\')
1110 {
1111 continue;
1112 }
1113 }
1114 else
1115 {
1116 if (((PWSTR)NormalizedParentName->Buffer)[NotifyChange->FullDirectoryName->Length / sizeof (WCHAR)] != L'\\')
1117 {
1118 continue;
1119 }
1120 }
1121 }
1122
1123 IsParent = FALSE;
1124 }
1125
1126 /* If len matches, then check that both name are equal */
1127 if (!RtlEqualMemory(NormalizedParentName->Buffer, NotifyChange->FullDirectoryName->Buffer,
1128 NotifyChange->FullDirectoryName->Length))
1129 {
1130 continue;
1131 }
1132
1133 /* Call traverse callback (only if we have to traverse ;-)) */
1134 if (!IsParent
1135 && NotifyChange->TraverseCallback != NULL
1136 && !NotifyChange->TraverseCallback(NotifyChange->FsContext,
1138 NotifyChange->SubjectContext))
1139 {
1140 continue;
1141 }
1142
1143 /* And then, filter callback if provided */
1144 if (NotifyChange->FilterCallback != NULL
1145 && FilterContext != NULL
1146 && !NotifyChange->FilterCallback(NotifyChange->FsContext, FilterContext))
1147 {
1148 continue;
1149 }
1150 }
1151 /* We have a stream! */
1152 else
1153 {
1154 ASSERT(NotifyChange->FullDirectoryName == NULL);
1155 if (TargetContext != NotifyChange->SubjectContext)
1156 {
1157 continue;
1158 }
1159
1160 ParentName.Buffer = NULL;
1161 ParentName.Length = 0;
1162 IsStream = TRUE;
1163 IsParent = FALSE;
1164 }
1165
1166 /* If we don't have to notify immediately, prepare for output */
1167 if (!(NotifyChange->Flags & NOTIFY_IMMEDIATELY))
1168 {
1169 /* If we have something to output... */
1170 if (NotifyChange->BufferLength)
1171 {
1172 /* Get size of the output */
1173 NumberOfBytes = 0;
1174 Irp = NULL;
1175 if (!NotifyChange->ThisBufferLength)
1176 {
1177 if (IsListEmpty(&NotifyChange->NotifyIrps))
1178 {
1179 NumberOfBytes = NotifyChange->BufferLength;
1180 }
1181 else
1182 {
1183 Irp = CONTAINING_RECORD(NotifyChange->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry);
1185 NumberOfBytes = Stack->Parameters.NotifyDirectory.Length;
1186 }
1187 }
1188 else
1189 {
1190 NumberOfBytes = NotifyChange->ThisBufferLength;
1191 }
1192
1193 /* If we're matching parent, we don't care about parent (redundant) */
1194 if (IsParent)
1195 {
1196 ParentName.Length = 0;
1197 }
1198 else
1199 {
1200 /* If we don't deal with streams, some more work is required */
1201 if (!IsStream)
1202 {
1203 if (NotifyChange->Flags & WATCH_ROOT ||
1204 (NormalizedParentName->Buffer != FullTargetName->Buffer))
1205 {
1206 /* Construct TargetDirectory if we don't have it yet */
1207 if (TargetDirectory.Buffer == NULL)
1208 {
1209 TargetDirectory.Buffer = FullTargetName->Buffer;
1210 TargetDirectory.Length = TargetNameOffset;
1211 if (TargetNameOffset != NotifyChange->CharacterSize)
1212 {
1213 TargetDirectory.Length = TargetNameOffset - NotifyChange->CharacterSize;
1214 }
1215 TargetDirectory.MaximumLength = TargetDirectory.Length;
1216 }
1217 /* Now, we start looking for matching parts (unless we watch root) */
1218 TargetNumberOfParts = 0;
1219 if (!(NotifyChange->Flags & WATCH_ROOT))
1220 {
1221 FullNumberOfParts = 1;
1222 if (NotifyChange->CharacterSize == sizeof(CHAR))
1223 {
1225 TargetDirectory.Length, PSTR, '\\');
1226 }
1227 else
1228 {
1230 TargetDirectory.Length / sizeof(WCHAR), PWSTR, L'\\');
1231 LastPartOffset *= NotifyChange->CharacterSize;
1232 }
1233 }
1234
1235 /* Then, we can construct proper parent name */
1236 ParentNameOffset = NotifyChange->CharacterSize + LastPartOffset;
1237 ParentName.Buffer = &TargetDirectory.Buffer[ParentNameOffset];
1238 ParentNameLength = TargetDirectory.Length;
1239 }
1240 else
1241 {
1242 /* Construct parent name even for streams */
1243 ParentName.Buffer = &NormalizedParentName->Buffer[NotifyChange->FullDirectoryName->Length] + NotifyChange->CharacterSize;
1244 ParentNameLength = NormalizedParentName->Length - NotifyChange->FullDirectoryName->Length;
1245 ParentNameOffset = NotifyChange->CharacterSize;
1246 }
1247 ParentNameLength -= ParentNameOffset;
1248 ParentName.Length = ParentNameLength;
1249 ParentName.MaximumLength = ParentNameLength;
1250 }
1251 }
1252
1253 /* Start to count amount of data to write, we've first the structure itself */
1255
1256 /* If stream, we'll just append stream name */
1257 if (IsStream)
1258 {
1260 DataLength += StreamName->Length;
1261 }
1262 else
1263 {
1264 /* If not parent, we've to append parent name */
1265 if (!IsParent)
1266 {
1267 if (NotifyChange->CharacterSize == sizeof(CHAR))
1268 {
1270 }
1271 else
1272 {
1273 DataLength += ParentName.Length;
1274 }
1275 DataLength += sizeof(WCHAR);
1276 }
1277
1278 /* Look for target name & construct it, if required */
1279 if (TargetName.Buffer == NULL)
1280 {
1281 TargetName.Buffer = &FullTargetName->Buffer[TargetNameOffset];
1282 TargetName.Length =
1283 TargetName.MaximumLength = FullTargetName->Length - TargetNameOffset;
1284 }
1285
1286 /* Then, we will append it as well */
1287 if (NotifyChange->CharacterSize == sizeof(CHAR))
1288 {
1290 }
1291 else
1292 {
1293 DataLength += TargetName.Length;
1294 }
1295
1296 /* If we also had a stream name, then we can append it as well */
1297 if (StreamName != NULL)
1298 {
1299 if (NotifyChange->CharacterSize == sizeof(WCHAR))
1300 {
1301 DataLength += StreamName->Length + sizeof(WCHAR);
1302 }
1303 else
1304 {
1306 }
1307 }
1308 }
1309
1310 /* Get the position where we can put our data (aligned!) */
1311 AlignedDataLength = ROUND_UP(NotifyChange->DataLength, sizeof(ULONG));
1312 /* If it's higher than buffer length, then, bail out without outputing */
1313 if (DataLength > NumberOfBytes || AlignedDataLength + DataLength > NumberOfBytes)
1314 {
1315 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1316 }
1317 else
1318 {
1320 FileNotifyInfo = NULL;
1321 /* If we already had a buffer, update last entry position */
1322 if (NotifyChange->Buffer != NULL)
1323 {
1324 FileNotifyInfo = (PVOID)((ULONG_PTR)NotifyChange->Buffer + NotifyChange->LastEntry);
1325 FileNotifyInfo->NextEntryOffset = AlignedDataLength - NotifyChange->LastEntry;
1326 NotifyChange->LastEntry = AlignedDataLength;
1327 /* And get our output buffer */
1328 OutputBuffer = (PVOID)((ULONG_PTR)NotifyChange->Buffer + AlignedDataLength);
1329 }
1330 /* If we hadn't buffer, try to find one */
1331 else if (Irp != NULL)
1332 {
1333 if (Irp->AssociatedIrp.SystemBuffer != NULL)
1334 {
1335 OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1336 }
1337 else if (Irp->MdlAddress != NULL)
1338 {
1340 }
1341
1342 NotifyChange->Buffer = OutputBuffer;
1343 NotifyChange->ThisBufferLength = NumberOfBytes;
1344 }
1345
1346 /* If we couldn't find one, then allocate one */
1347 if (NotifyChange->Buffer == NULL)
1348 {
1349 /* Assign the length buffer */
1350 NotifyChange->ThisBufferLength = NumberOfBytes;
1351
1352 /* Assume we have not charged quotas */
1353 PoolQuotaCharged = FALSE;
1354 _SEH2_TRY
1355 {
1356 /* And charge quotas */
1357 PsChargePoolQuota(NotifyChange->OwningProcess, PagedPool, NotifyChange->ThisBufferLength);
1358 PoolQuotaCharged = TRUE;
1361 NotifyChange->Buffer = OutputBuffer;
1362 NotifyChange->AllocatedBuffer = OutputBuffer;
1363 }
1364 /* If something went wrong during allocation, notify immediately instead of outputing */
1366 {
1367 if (PoolQuotaCharged)
1368 {
1369 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
1370 }
1371 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1372 }
1373 _SEH2_END;
1374 }
1375
1376 /* Finally, if we have a buffer, fill it in! */
1377 if (OutputBuffer != NULL)
1378 {
1380 Action, &ParentName, &TargetName,
1381 StreamName, NotifyChange->CharacterSize == sizeof(WCHAR),
1382 DataLength))
1383 {
1384 NotifyChange->DataLength = DataLength + AlignedDataLength;
1385 }
1386 /* If it failed, notify immediately */
1387 else
1388 {
1389 NotifyChange->Flags |= NOTIFY_IMMEDIATELY;
1390 }
1391 }
1392 }
1393
1394 /* If we have to notify right now (something went wrong?) */
1395 if (NotifyChange->Flags & NOTIFY_IMMEDIATELY)
1396 {
1397 /* Ensure that all our buffers are NULL */
1398 if (NotifyChange->Buffer != NULL)
1399 {
1400 if (NotifyChange->AllocatedBuffer != NULL)
1401 {
1402 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
1404 }
1405
1406 NotifyChange->Buffer = NULL;
1407 NotifyChange->AllocatedBuffer = NULL;
1408 NotifyChange->LastEntry = 0;
1409 NotifyChange->DataLength = 0;
1410 NotifyChange->ThisBufferLength = 0;
1411 }
1412 }
1413 }
1414 }
1415
1416 /* If asking for old name in case of a rename, notify later on,
1417 * so that we can wait for new name.
1418 * http://msdn.microsoft.com/en-us/library/dn392331.aspx
1419 */
1421 {
1422 NotifyChange->Flags |= NOTIFY_LATER;
1423 }
1424 else
1425 {
1426 NotifyChange->Flags &= ~NOTIFY_LATER;
1427 if (!IsListEmpty(&NotifyChange->NotifyIrps))
1428 {
1430 }
1431 }
1432 }
1433 }
1435 {
1436 FsRtlNotifyReleaseFastMutex(RealNotifySync);
1437 }
1438 _SEH2_END;
1439}
#define ROUND_UP(n, align)
Definition: eventvwr.h:34
std::wstring STRING
Definition: fontsub.cpp:33
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG _In_ ULONG _In_opt_ PVOID TargetContext
Definition: fsrtlfuncs.h:745
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT TargetNameOffset
Definition: fsrtlfuncs.h:740
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING NormalizedParentName
Definition: fsrtlfuncs.h:742
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG _In_ ULONG _In_opt_ PVOID _In_opt_ PVOID FilterContext
Definition: fsrtlfuncs.h:746
_In_ PLIST_ENTRY _In_ PSTRING FullTargetName
Definition: fsrtlfuncs.h:739
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING StreamName
Definition: fsrtlfuncs.h:741
_In_ PLIST_ENTRY _In_ PSTRING _In_ USHORT _In_opt_ PSTRING _In_opt_ PSTRING _In_ ULONG FilterMatch
Definition: fsrtlfuncs.h:743
#define RtlEqualMemory(a, b, c)
Definition: kdvm.h:18
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)
Definition: notify.c:497
#define FsRtlNotifyGetLastPartOffset(FullLen, TargLen, Type, Chr)
Definition: notify.c:52
#define L(x)
Definition: ntvdm.h:50
unsigned short USHORT
Definition: pedump.c:61
static PCWSTR TargetName
Definition: ping.c:67
unsigned short Length
Definition: sprintf.c:451
void * Buffer
Definition: sprintf.c:453
uint16_t * PWSTR
Definition: typedefs.h:56
char * PSTR
Definition: typedefs.h:51
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
void * PVOID
Definition: typedefs.h:50
_Must_inspect_result_ _In_ WDFIOTARGET _In_opt_ WDFREQUEST _In_opt_ PWDF_MEMORY_DESCRIPTOR OutputBuffer
Definition: wdfiotarget.h:863
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:510
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
#define FILE_ACTION_RENAMED_OLD_NAME
_Must_inspect_result_ typedef _In_ PHYSICAL_ADDRESS _Inout_ PLARGE_INTEGER NumberOfBytes
Definition: iotypes.h:1036
#define RtlOemStringToCountedUnicodeSize(STRING)

Referenced by FsRtlNotifyFullReportChange(), FsRtlNotifyReportChange(), send_notification_fcb(), send_notification_fileref(), and set_rename_information().

◆ FsRtlNotifyFullChangeDirectory()

VOID NTAPI FsRtlNotifyFullChangeDirectory ( IN PNOTIFY_SYNC  NotifySync,
IN PLIST_ENTRY  NotifyList,
IN PVOID  FsContext,
IN PSTRING  FullDirectoryName,
IN BOOLEAN  WatchTree,
IN BOOLEAN  IgnoreBuffer,
IN ULONG  CompletionFilter,
IN PIRP  NotifyIrp,
IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback  OPTIONAL,
IN PSECURITY_SUBJECT_CONTEXT SubjectContext  OPTIONAL 
)

◆ FsRtlNotifyFullReportChange()

VOID NTAPI FsRtlNotifyFullReportChange ( IN PNOTIFY_SYNC  NotifySync,
IN PLIST_ENTRY  NotifyList,
IN PSTRING  FullTargetName,
IN USHORT  TargetNameOffset,
IN PSTRING StreamName  OPTIONAL,
IN PSTRING NormalizedParentName  OPTIONAL,
IN ULONG  FilterMatch,
IN ULONG  Action,
IN PVOID  TargetContext 
)

Definition at line 1552 of file notify.c.

1561{
1563 NotifyList,
1566 StreamName,
1569 Action,
1571 NULL);
1572}
VOID NTAPI FsRtlNotifyFilterReportChange(IN PNOTIFY_SYNC NotifySync, IN PLIST_ENTRY NotifyList, IN PSTRING FullTargetName, IN USHORT TargetNameOffset, IN PSTRING StreamName OPTIONAL, IN PSTRING NormalizedParentName OPTIONAL, IN ULONG FilterMatch, IN ULONG Action, IN PVOID TargetContext, IN PVOID FilterContext)
Definition: notify.c:997

Referenced by Ext2NotifyReportChange(), UDFHardLink(), UDFNotifyFullReportChange(), UDFRename(), and vfatReportChange().

◆ FsRtlNotifyInitializeSync()

VOID NTAPI FsRtlNotifyInitializeSync ( IN PNOTIFY_SYNC NotifySync)

Definition at line 1590 of file notify.c.

1591{
1592 PREAL_NOTIFY_SYNC RealNotifySync;
1593
1594 *NotifySync = NULL;
1595
1597 sizeof(REAL_NOTIFY_SYNC), 'SNSF');
1598 ExInitializeFastMutex(&(RealNotifySync->FastMutex));
1599 RealNotifySync->OwningThread = 0;
1600 RealNotifySync->OwnerCount = 0;
1601
1602 *NotifySync = RealNotifySync;
1603}
#define NonPagedPool
Definition: env_spec_w32.h:307
ULONG_PTR OwningThread
Definition: fsrtl.h:68
ULONG OwnerCount
Definition: fsrtl.h:69
FAST_MUTEX FastMutex
Definition: fsrtl.h:67
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274

Referenced by _Requires_lock_held_(), CdInitializeVcb(), Ext2InitializeVcb(), mount_vol(), UDFInitializeVCB(), and VfatMount().

◆ FsRtlNotifyReleaseFastMutex()

FORCEINLINE VOID FsRtlNotifyReleaseFastMutex ( IN PREAL_NOTIFY_SYNC  RealNotifySync)

Definition at line 41 of file notify.c.

42{
43 RealNotifySync->OwnerCount--;
44 /* Release the fast mutex only if no other instance needs it */
45 if (!RealNotifySync->OwnerCount)
46 {
47 ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));
48 RealNotifySync->OwningThread = (ULONG_PTR)0;
49 }
50}
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86

Referenced by FsRtlCancelNotify(), FsRtlNotifyCleanup(), FsRtlNotifyFilterChangeDirectory(), and FsRtlNotifyFilterReportChange().

◆ FsRtlNotifyReportChange()

VOID NTAPI FsRtlNotifyReportChange ( IN PNOTIFY_SYNC  NotifySync,
IN PLIST_ENTRY  NotifyList,
IN PSTRING  FullTargetName,
IN PUSHORT  FileNamePartLength,
IN ULONG  FilterMatch 
)

Definition at line 1633 of file notify.c.

1638{
1640 NotifyList,
1642 FullTargetName->Length - *FileNamePartLength,
1643 NULL,
1644 NULL,
1646 0,
1647 NULL,
1648 NULL);
1649}

◆ FsRtlNotifySetCancelRoutine()

BOOLEAN FsRtlNotifySetCancelRoutine ( IN PIRP  Irp,
IN PNOTIFY_CHANGE NotifyChange  OPTIONAL 
)

Definition at line 448 of file notify.c.

450{
452
453 /* Acquire cancel lock */
454 IoAcquireCancelSpinLock(&Irp->CancelIrql);
455
456 /* If NotifyChange was given */
457 if (NotifyChange)
458 {
459 /* First get cancel routine */
461 Irp->IoStatus.Information = 0;
462 /* Release cancel lock */
463 IoReleaseCancelSpinLock(Irp->CancelIrql);
464 /* If there was a cancel routine */
465 if (CancelRoutine)
466 {
467 /* Decrease reference count */
468 InterlockedDecrement((PLONG)&NotifyChange->ReferenceCount);
469 /* Notify that we removed cancel routine */
470 return TRUE;
471 }
472 }
473 else
474 {
475 /* If IRP is cancel, call FsRtl cancel routine */
476 if (Irp->Cancel)
477 {
479 }
480 else
481 {
482 /* Otherwise, define FsRtl cancel routine as IRP cancel routine */
484 /* Release lock */
485 IoReleaseCancelSpinLock(Irp->CancelIrql);
486 }
487 }
488
489 /* Return that we didn't removed cancel routine */
490 return FALSE;
491}
VOID NTAPI FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: notify.c:79
VOID NTAPI IoAcquireCancelSpinLock(OUT PKIRQL Irql)
Definition: util.c:56
_In_opt_ PDRIVER_CANCEL CancelRoutine
Definition: iofuncs.h:2744
DRIVER_CANCEL * PDRIVER_CANCEL
Definition: iotypes.h:2759

Referenced by FsRtlNotifyCompleteIrp(), and FsRtlNotifyFilterChangeDirectory().

◆ FsRtlNotifyUninitializeSync()

VOID NTAPI FsRtlNotifyUninitializeSync ( IN PNOTIFY_SYNC NotifySync)

Definition at line 1668 of file notify.c.

1669{
1670 if (*NotifySync)
1671 {
1672 ExFreePoolWithTag(*NotifySync, 'SNSF');
1673 *NotifySync = NULL;
1674 }
1675}

Referenced by CdDeleteVcb(), CdInitializeVcb(), Ext2DestroyVcb(), Ext2InitializeVcb(), FatDeleteVcb(), UDFReleaseVCB(), and VfatCheckForDismount().

◆ FsRtlNotifyUpdateBuffer()

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 
)

Definition at line 497 of file notify.c.

504{
505 /* Unless there's an issue with buffers, there's no reason to fail */
506 BOOLEAN Succeed = TRUE;
507 ULONG AlreadyWritten = 0, ResultSize;
508
509 PAGED_CODE();
510
511 /* Update user buffer with the change that occured
512 * First copy parent name if any
513 * Then copy target name, there's always one
514 * And finally, copy stream name if any
515 * If these names aren't unicode, then convert first
516 */
518 {
519 OutputBuffer->NextEntryOffset = 0;
520 OutputBuffer->Action = Action;
522 if (IsUnicode)
523 {
524 if (ParentName->Length)
525 {
526 RtlCopyMemory(OutputBuffer->FileName, ParentName->Buffer, ParentName->Length);
527 OutputBuffer->FileName[ParentName->Length / sizeof(WCHAR)] = L'\\';
528 AlreadyWritten = ParentName->Length + sizeof(WCHAR);
529 }
530 RtlCopyMemory((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten),
531 TargetName->Buffer, TargetName->Length);
532 if (StreamName)
533 {
534 AlreadyWritten += TargetName->Length;
535 OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';
536 RtlCopyMemory((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR)),
537 StreamName->Buffer, StreamName->Length);
538 }
539 }
540 else
541 {
542 if (!ParentName->Length)
543 {
545 RtlCopyMemory(OutputBuffer->FileName, StreamName->Buffer, StreamName->Length);
546 }
547 else
548 {
549 RtlOemToUnicodeN(OutputBuffer->FileName, OutputBuffer->FileNameLength,
550 &ResultSize, ParentName->Buffer,
551 ParentName->Length);
552 OutputBuffer->FileName[ResultSize / sizeof(WCHAR)] = L'\\';
553 AlreadyWritten = ResultSize + sizeof(WCHAR);
554
555 RtlOemToUnicodeN((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten),
556 OutputBuffer->FileNameLength, &ResultSize,
557 TargetName->Buffer, TargetName->Length);
558
559 if (StreamName)
560 {
561 AlreadyWritten += ResultSize;
562 OutputBuffer->FileName[AlreadyWritten / sizeof(WCHAR)] = L':';
563 RtlOemToUnicodeN((PVOID)((ULONG_PTR)OutputBuffer->FileName + AlreadyWritten + sizeof(WCHAR)),
564 OutputBuffer->FileNameLength, &ResultSize,
565 StreamName->Buffer, StreamName->Length);
566 }
567 }
568 }
569 }
571 {
572 Succeed = FALSE;
573 }
574 _SEH2_END;
575
576 return Succeed;
577}
_Use_decl_annotations_ NTSTATUS NTAPI RtlOemToUnicodeN(_Out_ PWCHAR UnicodeString, _In_ ULONG UnicodeSize, _Out_opt_ PULONG ResultSize, _In_ PCCH OemString, _In_ ULONG OemSize)
Definition: nlsboot.c:282

Referenced by FsRtlNotifyFilterReportChange().