2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/notify.c
5 * PURPOSE: Change Notifications and Sync for File System Drivers
6 * PROGRAMMERS: Pierre Schweitzer
9 /* INCLUDES ******************************************************************/
15 /* PRIVATE FUNCTIONS *********************************************************/
18 FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList
,
21 PLIST_ENTRY NextEntry
;
22 PNOTIFY_CHANGE NotifyChange
;
24 if (!IsListEmpty(NotifyList
))
26 /* Browse the notifications list to find the matching entry */
27 for (NextEntry
= NotifyList
->Flink
;
28 NextEntry
!= NotifyList
;
29 NextEntry
= NextEntry
->Flink
)
31 NotifyChange
= CONTAINING_RECORD(NextEntry
, NOTIFY_CHANGE
, NotifyList
);
32 /* If the current record matches with the given context, it's the good one */
33 if (NotifyChange
->FsContext
== FsContext
)
44 FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync
)
46 ULONG_PTR CurrentThread
= (ULONG_PTR
)KeGetCurrentThread();
48 /* Only acquire fast mutex if it's not already acquired by the current thread */
49 if (RealNotifySync
->OwningThread
!= CurrentThread
)
51 ExAcquireFastMutexUnsafe(&(RealNotifySync
->FastMutex
));
52 RealNotifySync
->OwningThread
= CurrentThread
;
54 /* Whatever the case, keep trace of the attempt to acquire fast mutex */
55 RealNotifySync
->OwnerCount
++;
59 FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange
,
66 FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync
)
68 RealNotifySync
->OwnerCount
--;
69 /* Release the fast mutex only if no other instance needs it */
70 if (!RealNotifySync
->OwnerCount
)
72 ExReleaseFastMutexUnsafe(&(RealNotifySync
->FastMutex
));
73 RealNotifySync
->OwningThread
= (ULONG_PTR
)0;
77 /* PUBLIC FUNCTIONS **********************************************************/
80 * @name FsRtlNotifyChangeDirectory
83 * Lets FSD know if changes occures in the specified directory.
84 * Directory will be reenumerated.
87 * Synchronization object pointer
90 * Used to identify the notify structure
92 * @param FullDirectoryName
93 * String (A or W) containing the full directory name
96 * Notify list pointer (to head)
99 * True to notify changes in subdirectories too
101 * @param CompletionFilter
102 * Used to define types of changes to notify
105 * IRP pointer to complete notify operation. It can be null
109 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
114 FsRtlNotifyChangeDirectory(IN PNOTIFY_SYNC NotifySync
,
116 IN PSTRING FullDirectoryName
,
117 IN PLIST_ENTRY NotifyList
,
118 IN BOOLEAN WatchTree
,
119 IN ULONG CompletionFilter
,
122 FsRtlNotifyFilterChangeDirectory(NotifySync
,
136 * @name FsRtlNotifyCleanup
139 * Called by FSD when all handles to FileObject (identified by FsContext) are closed
142 * Synchronization object pointer
145 * Notify list pointer (to head)
148 * Used to identify the notify structure
157 FsRtlNotifyCleanup(IN PNOTIFY_SYNC NotifySync
,
158 IN PLIST_ENTRY NotifyList
,
161 PNOTIFY_CHANGE NotifyChange
;
162 PREAL_NOTIFY_SYNC RealNotifySync
;
163 PSECURITY_SUBJECT_CONTEXT SubjectContext
= NULL
;
165 /* Get real structure hidden behind the opaque pointer */
166 RealNotifySync
= (PREAL_NOTIFY_SYNC
)NotifySync
;
168 /* Acquire the fast mutex */
169 FsRtlNotifyAcquireFastMutex(RealNotifySync
);
173 /* Find if there's a matching notification with the FsContext */
174 NotifyChange
= FsRtlIsNotifyOnList(NotifyList
, FsContext
);
177 /* Mark it as to know that cleanup is in process */
178 NotifyChange
->Flags
|= CLEANUP_IN_PROCESS
;
180 /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP status */
181 if (!IsListEmpty(NotifyChange
->NotifyIrps
))
183 FsRtlNotifyCompleteIrpList(NotifyChange
, STATUS_NOTIFY_CLEANUP
);
185 /* Remove from the list */
186 RemoveEntryList(NotifyChange
->NotifyList
);
188 /* Downcrease reference number and if 0 is reached, it's time to do complete cleanup */
189 if (!InterlockedDecrement((PLONG
)&(NotifyChange
->ReferenceCount
)))
191 /* In case there was an allocated buffer, free it */
192 if (NotifyChange
->AllocatedBuffer
)
194 PsReturnProcessPagedPoolQuota(NotifyChange
->OwningProcess
, NotifyChange
->ThisBufferLength
);
195 ExFreePool(NotifyChange
->AllocatedBuffer
);
198 /* In case there the string was set, get the captured subject security context */
199 if (NotifyChange
->FullDirectoryName
)
201 SubjectContext
= NotifyChange
->SubjectContext
;
204 /* Finally, free the notification, as it's not needed anymore */
205 ExFreePool(NotifyChange
);
211 /* Release fast mutex */
212 FsRtlNotifyReleaseFastMutex(RealNotifySync
);
214 /* If the subject security context was captured, release and free it */
217 SeReleaseSubjectContext(SubjectContext
);
218 ExFreePool(SubjectContext
);
225 * @name FsRtlNotifyFilterChangeDirectory
239 * @param FullDirectoryName
245 * @param IgnoreBuffer
248 * @param CompletionFilter
254 * @param TraverseCallback
257 * @param SubjectContext
260 * @param FilterCallback
270 FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync
,
271 IN PLIST_ENTRY NotifyList
,
273 IN PSTRING FullDirectoryName
,
274 IN BOOLEAN WatchTree
,
275 IN BOOLEAN IgnoreBuffer
,
276 IN ULONG CompletionFilter
,
278 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
279 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
,
280 IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL
)
282 KeBugCheck(FILE_SYSTEM
);
286 * @name FsRtlNotifyFilterReportChange
297 * @param FullTargetName
300 * @param TargetNameOffset
306 * @param NormalizedParentName
315 * @param TargetContext
318 * @param FilterContext
328 FsRtlNotifyFilterReportChange(IN PNOTIFY_SYNC NotifySync
,
329 IN PLIST_ENTRY NotifyList
,
330 IN PSTRING FullTargetName
,
331 IN USHORT TargetNameOffset
,
332 IN PSTRING StreamName OPTIONAL
,
333 IN PSTRING NormalizedParentName OPTIONAL
,
334 IN ULONG FilterMatch
,
336 IN PVOID TargetContext
,
337 IN PVOID FilterContext
)
339 KeBugCheck(FILE_SYSTEM
);
343 * @name FsRtlNotifyFullChangeDirectory
346 * Lets FSD know if changes occures in the specified directory.
349 * Synchronization object pointer
352 * Notify list pointer (to head)
355 * Used to identify the notify structure
357 * @param FullDirectoryName
358 * String (A or W) containing the full directory name
361 * True to notify changes in subdirectories too
363 * @param IgnoreBuffer
364 * True to reenumerate directory. It's ignored it NotifyIrp is null
366 * @param CompletionFilter
367 * Used to define types of changes to notify
370 * IRP pointer to complete notify operation. It can be null
372 * @param TraverseCallback
373 * Pointer to a callback function. It's called each time a change is
374 * done in a subdirectory of the main directory. It's ignored it NotifyIrp
377 * @param SubjectContext
378 * Pointer to pass to SubjectContext member of TraverseCallback.
379 * It's freed after use. It's ignored it NotifyIrp is null
383 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
388 FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync
,
389 IN PLIST_ENTRY NotifyList
,
391 IN PSTRING FullDirectoryName
,
392 IN BOOLEAN WatchTree
,
393 IN BOOLEAN IgnoreBuffer
,
394 IN ULONG CompletionFilter
,
396 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
397 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
)
399 FsRtlNotifyFilterChangeDirectory(NotifySync
,
413 * @name FsRtlNotifyFullReportChange
416 * Complets the pending notify IRPs.
419 * Synchronization object pointer
422 * Notify list pointer (to head)
424 * @param FullTargetName
425 * String (A or W) containing the full directory name that changed
427 * @param TargetNameOffset
428 * Offset, in FullTargetName, of the final component that is in the changed directory
431 * String (A or W) containing a stream name
433 * @param NormalizedParentName
434 * String (A or W) containing the full directory name that changed with long names
437 * Flags that will be compared to the completion filter
440 * Action code to store in user's buffer
442 * @param TargetContext
443 * Pointer to a callback function. It's called each time a change is
444 * done in a subdirectory of the main directory.
448 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
453 FsRtlNotifyFullReportChange(IN PNOTIFY_SYNC NotifySync
,
454 IN PLIST_ENTRY NotifyList
,
455 IN PSTRING FullTargetName
,
456 IN USHORT TargetNameOffset
,
457 IN PSTRING StreamName OPTIONAL
,
458 IN PSTRING NormalizedParentName OPTIONAL
,
459 IN ULONG FilterMatch
,
461 IN PVOID TargetContext
)
463 FsRtlNotifyFilterReportChange(NotifySync
,
468 NormalizedParentName
,
476 * @name FsRtlNotifyInitializeSync
479 * Allocates the internal structure associated with notifications.
482 * Opaque pointer. It will receive the address of the allocated internal structure.
486 * @remarks This function raise an exception in case of a failure.
491 FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC
*NotifySync
)
493 PREAL_NOTIFY_SYNC RealNotifySync
;
497 RealNotifySync
= ExAllocatePoolWithTag(NonPagedPool
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
498 sizeof(REAL_NOTIFY_SYNC
), TAG('F', 'S', 'N', 'S'));
499 ExInitializeFastMutex(&(RealNotifySync
->FastMutex
));
500 RealNotifySync
->OwningThread
= 0;
501 RealNotifySync
->OwnerCount
= 0;
503 *NotifySync
= RealNotifySync
;
507 * @name FsRtlNotifyReportChange
510 * Complets the pending notify IRPs.
513 * Synchronization object pointer
516 * Notify list pointer (to head)
518 * @param FullTargetName
519 * String (A or W) containing the full directory name that changed
521 * @param FileNamePartLength
522 * Length of the final component that is in the changed directory
525 * Flags that will be compared to the completion filter
529 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
534 FsRtlNotifyReportChange(IN PNOTIFY_SYNC NotifySync
,
535 IN PLIST_ENTRY NotifyList
,
536 IN PSTRING FullTargetName
,
537 IN PUSHORT FileNamePartLength
,
538 IN ULONG FilterMatch
)
540 FsRtlNotifyFilterReportChange(NotifySync
,
543 FullTargetName
->Length
- *FileNamePartLength
,
553 * @name FsRtlNotifyUninitializeSync
556 * Uninitialize a NOTIFY_SYNC object
559 * Address of a pointer to a PNOTIFY_SYNC object previously
560 * initialized by FsRtlNotifyInitializeSync()
569 FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC
*NotifySync
)
573 ExFreePoolWithTag(*NotifySync
, TAG('F', 'S', 'N', 'S'));