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
);
186 /* Decrease reference number and if 0 is reached, it's time to do complete cleanup */
187 if (!InterlockedDecrement((PLONG
)&(NotifyChange
->ReferenceCount
)))
189 /* Remove it from the notifications list */
190 RemoveEntryList(&NotifyChange
->NotifyList
);
192 /* In case there was an allocated buffer, free it */
193 if (NotifyChange
->AllocatedBuffer
)
195 PsReturnProcessPagedPoolQuota(NotifyChange
->OwningProcess
, NotifyChange
->ThisBufferLength
);
196 ExFreePool(NotifyChange
->AllocatedBuffer
);
199 /* In case there the string was set, get the captured subject security context */
200 if (NotifyChange
->FullDirectoryName
)
202 SubjectContext
= NotifyChange
->SubjectContext
;
205 /* Finally, free the notification, as it's not needed anymore */
206 ExFreePool(NotifyChange
);
212 /* Release fast mutex */
213 FsRtlNotifyReleaseFastMutex(RealNotifySync
);
215 /* If the subject security context was captured, release and free it */
218 SeReleaseSubjectContext(SubjectContext
);
219 ExFreePool(SubjectContext
);
226 * @name FsRtlNotifyFilterChangeDirectory
240 * @param FullDirectoryName
246 * @param IgnoreBuffer
249 * @param CompletionFilter
255 * @param TraverseCallback
258 * @param SubjectContext
261 * @param FilterCallback
271 FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync
,
272 IN PLIST_ENTRY NotifyList
,
274 IN PSTRING FullDirectoryName
,
275 IN BOOLEAN WatchTree
,
276 IN BOOLEAN IgnoreBuffer
,
277 IN ULONG CompletionFilter
,
279 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
280 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
,
281 IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL
)
283 KeBugCheck(FILE_SYSTEM
);
287 * @name FsRtlNotifyFilterReportChange
298 * @param FullTargetName
301 * @param TargetNameOffset
307 * @param NormalizedParentName
316 * @param TargetContext
319 * @param FilterContext
329 FsRtlNotifyFilterReportChange(IN PNOTIFY_SYNC NotifySync
,
330 IN PLIST_ENTRY NotifyList
,
331 IN PSTRING FullTargetName
,
332 IN USHORT TargetNameOffset
,
333 IN PSTRING StreamName OPTIONAL
,
334 IN PSTRING NormalizedParentName OPTIONAL
,
335 IN ULONG FilterMatch
,
337 IN PVOID TargetContext
,
338 IN PVOID FilterContext
)
340 KeBugCheck(FILE_SYSTEM
);
344 * @name FsRtlNotifyFullChangeDirectory
347 * Lets FSD know if changes occures in the specified directory.
350 * Synchronization object pointer
353 * Notify list pointer (to head)
356 * Used to identify the notify structure
358 * @param FullDirectoryName
359 * String (A or W) containing the full directory name
362 * True to notify changes in subdirectories too
364 * @param IgnoreBuffer
365 * True to reenumerate directory. It's ignored it NotifyIrp is null
367 * @param CompletionFilter
368 * Used to define types of changes to notify
371 * IRP pointer to complete notify operation. It can be null
373 * @param TraverseCallback
374 * Pointer to a callback function. It's called each time a change is
375 * done in a subdirectory of the main directory. It's ignored it NotifyIrp
378 * @param SubjectContext
379 * Pointer to pass to SubjectContext member of TraverseCallback.
380 * It's freed after use. It's ignored it NotifyIrp is null
384 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
389 FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync
,
390 IN PLIST_ENTRY NotifyList
,
392 IN PSTRING FullDirectoryName
,
393 IN BOOLEAN WatchTree
,
394 IN BOOLEAN IgnoreBuffer
,
395 IN ULONG CompletionFilter
,
397 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL
,
398 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL
)
400 FsRtlNotifyFilterChangeDirectory(NotifySync
,
414 * @name FsRtlNotifyFullReportChange
417 * Complets the pending notify IRPs.
420 * Synchronization object pointer
423 * Notify list pointer (to head)
425 * @param FullTargetName
426 * String (A or W) containing the full directory name that changed
428 * @param TargetNameOffset
429 * Offset, in FullTargetName, of the final component that is in the changed directory
432 * String (A or W) containing a stream name
434 * @param NormalizedParentName
435 * String (A or W) containing the full directory name that changed with long names
438 * Flags that will be compared to the completion filter
441 * Action code to store in user's buffer
443 * @param TargetContext
444 * Pointer to a callback function. It's called each time a change is
445 * done in a subdirectory of the main directory.
449 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
454 FsRtlNotifyFullReportChange(IN PNOTIFY_SYNC NotifySync
,
455 IN PLIST_ENTRY NotifyList
,
456 IN PSTRING FullTargetName
,
457 IN USHORT TargetNameOffset
,
458 IN PSTRING StreamName OPTIONAL
,
459 IN PSTRING NormalizedParentName OPTIONAL
,
460 IN ULONG FilterMatch
,
462 IN PVOID TargetContext
)
464 FsRtlNotifyFilterReportChange(NotifySync
,
469 NormalizedParentName
,
477 * @name FsRtlNotifyInitializeSync
480 * Allocates the internal structure associated with notifications.
483 * Opaque pointer. It will receive the address of the allocated internal structure.
487 * @remarks This function raise an exception in case of a failure.
492 FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC
*NotifySync
)
494 PREAL_NOTIFY_SYNC RealNotifySync
;
498 RealNotifySync
= ExAllocatePoolWithTag(NonPagedPool
| POOL_RAISE_IF_ALLOCATION_FAILURE
,
499 sizeof(REAL_NOTIFY_SYNC
), 'FSNS');
500 ExInitializeFastMutex(&(RealNotifySync
->FastMutex
));
501 RealNotifySync
->OwningThread
= 0;
502 RealNotifySync
->OwnerCount
= 0;
504 *NotifySync
= RealNotifySync
;
508 * @name FsRtlNotifyReportChange
511 * Complets the pending notify IRPs.
514 * Synchronization object pointer
517 * Notify list pointer (to head)
519 * @param FullTargetName
520 * String (A or W) containing the full directory name that changed
522 * @param FileNamePartLength
523 * Length of the final component that is in the changed directory
526 * Flags that will be compared to the completion filter
530 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
535 FsRtlNotifyReportChange(IN PNOTIFY_SYNC NotifySync
,
536 IN PLIST_ENTRY NotifyList
,
537 IN PSTRING FullTargetName
,
538 IN PUSHORT FileNamePartLength
,
539 IN ULONG FilterMatch
)
541 FsRtlNotifyFilterReportChange(NotifySync
,
544 FullTargetName
->Length
- *FileNamePartLength
,
554 * @name FsRtlNotifyUninitializeSync
557 * Uninitialize a NOTIFY_SYNC object
560 * Address of a pointer to a PNOTIFY_SYNC object previously
561 * initialized by FsRtlNotifyInitializeSync()
570 FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC
*NotifySync
)
574 ExFreePoolWithTag(*NotifySync
, 'FSNS');