[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / fsrtl / notify.c
1 /*
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
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* PRIVATE FUNCTIONS *********************************************************/
16
17 PNOTIFY_CHANGE
18 FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList,
19 IN PVOID FsContext)
20 {
21 PLIST_ENTRY NextEntry;
22 PNOTIFY_CHANGE NotifyChange;
23
24 if (!IsListEmpty(NotifyList))
25 {
26 /* Browse the notifications list to find the matching entry */
27 for (NextEntry = NotifyList->Flink;
28 NextEntry != NotifyList;
29 NextEntry = NextEntry->Flink)
30 {
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)
34 {
35 return NotifyChange;
36 }
37 }
38 }
39 return NULL;
40 }
41
42 VOID
43 FORCEINLINE
44 FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
45 {
46 ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread();
47
48 /* Only acquire fast mutex if it's not already acquired by the current thread */
49 if (RealNotifySync->OwningThread != CurrentThread)
50 {
51 ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex));
52 RealNotifySync->OwningThread = CurrentThread;
53 }
54 /* Whatever the case, keep trace of the attempt to acquire fast mutex */
55 RealNotifySync->OwnerCount++;
56 }
57
58 VOID
59 FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange,
60 IN NTSTATUS Status)
61 {
62 }
63
64 VOID
65 FORCEINLINE
66 FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync)
67 {
68 RealNotifySync->OwnerCount--;
69 /* Release the fast mutex only if no other instance needs it */
70 if (!RealNotifySync->OwnerCount)
71 {
72 ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex));
73 RealNotifySync->OwningThread = (ULONG_PTR)0;
74 }
75 }
76
77 /* PUBLIC FUNCTIONS **********************************************************/
78
79 /*++
80 * @name FsRtlNotifyChangeDirectory
81 * @implemented
82 *
83 * Lets FSD know if changes occures in the specified directory.
84 * Directory will be reenumerated.
85 *
86 * @param NotifySync
87 * Synchronization object pointer
88 *
89 * @param FsContext
90 * Used to identify the notify structure
91 *
92 * @param FullDirectoryName
93 * String (A or W) containing the full directory name
94 *
95 * @param NotifyList
96 * Notify list pointer (to head)
97 *
98 * @param WatchTree
99 * True to notify changes in subdirectories too
100 *
101 * @param CompletionFilter
102 * Used to define types of changes to notify
103 *
104 * @param NotifyIrp
105 * IRP pointer to complete notify operation. It can be null
106 *
107 * @return None
108 *
109 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
110 *
111 *--*/
112 VOID
113 NTAPI
114 FsRtlNotifyChangeDirectory(IN PNOTIFY_SYNC NotifySync,
115 IN PVOID FsContext,
116 IN PSTRING FullDirectoryName,
117 IN PLIST_ENTRY NotifyList,
118 IN BOOLEAN WatchTree,
119 IN ULONG CompletionFilter,
120 IN PIRP NotifyIrp)
121 {
122 FsRtlNotifyFilterChangeDirectory(NotifySync,
123 NotifyList,
124 FsContext,
125 FullDirectoryName,
126 WatchTree,
127 TRUE,
128 CompletionFilter,
129 NotifyIrp,
130 NULL,
131 NULL,
132 NULL);
133 }
134
135 /*++
136 * @name FsRtlNotifyCleanup
137 * @implemented
138 *
139 * Called by FSD when all handles to FileObject (identified by FsContext) are closed
140 *
141 * @param NotifySync
142 * Synchronization object pointer
143 *
144 * @param NotifyList
145 * Notify list pointer (to head)
146 *
147 * @param FsContext
148 * Used to identify the notify structure
149 *
150 * @return None
151 *
152 * @remarks None
153 *
154 *--*/
155 VOID
156 NTAPI
157 FsRtlNotifyCleanup(IN PNOTIFY_SYNC NotifySync,
158 IN PLIST_ENTRY NotifyList,
159 IN PVOID FsContext)
160 {
161 PNOTIFY_CHANGE NotifyChange;
162 PREAL_NOTIFY_SYNC RealNotifySync;
163 PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL;
164
165 /* Get real structure hidden behind the opaque pointer */
166 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync;
167
168 /* Acquire the fast mutex */
169 FsRtlNotifyAcquireFastMutex(RealNotifySync);
170
171 _SEH2_TRY
172 {
173 /* Find if there's a matching notification with the FsContext */
174 NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext);
175 if (NotifyChange)
176 {
177 /* Mark it as to know that cleanup is in process */
178 NotifyChange->Flags |= CLEANUP_IN_PROCESS;
179
180 /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP status */
181 if (!IsListEmpty(&NotifyChange->NotifyIrps))
182 {
183 FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_NOTIFY_CLEANUP);
184 }
185
186 /* Decrease reference number and if 0 is reached, it's time to do complete cleanup */
187 if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount)))
188 {
189 /* Remove it from the notifications list */
190 RemoveEntryList(&NotifyChange->NotifyList);
191
192 /* In case there was an allocated buffer, free it */
193 if (NotifyChange->AllocatedBuffer)
194 {
195 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength);
196 ExFreePool(NotifyChange->AllocatedBuffer);
197 }
198
199 /* In case there the string was set, get the captured subject security context */
200 if (NotifyChange->FullDirectoryName)
201 {
202 SubjectContext = NotifyChange->SubjectContext;
203 }
204
205 /* Finally, free the notification, as it's not needed anymore */
206 ExFreePool(NotifyChange);
207 }
208 }
209 }
210 _SEH2_FINALLY
211 {
212 /* Release fast mutex */
213 FsRtlNotifyReleaseFastMutex(RealNotifySync);
214
215 /* If the subject security context was captured, release and free it */
216 if (SubjectContext)
217 {
218 SeReleaseSubjectContext(SubjectContext);
219 ExFreePool(SubjectContext);
220 }
221 }
222 _SEH2_END;
223 }
224
225 /*++
226 * @name FsRtlNotifyFilterChangeDirectory
227 * @unimplemented
228 *
229 * FILLME
230 *
231 * @param NotifySync
232 * FILLME
233 *
234 * @param NotifyList
235 * FILLME
236 *
237 * @param FsContext
238 * FILLME
239 *
240 * @param FullDirectoryName
241 * FILLME
242 *
243 * @param WatchTree
244 * FILLME
245 *
246 * @param IgnoreBuffer
247 * FILLME
248 *
249 * @param CompletionFilter
250 * FILLME
251 *
252 * @param NotifyIrp
253 * FILLME
254 *
255 * @param TraverseCallback
256 * FILLME
257 *
258 * @param SubjectContext
259 * FILLME
260 *
261 * @param FilterCallback
262 * FILLME
263 *
264 * @return None
265 *
266 * @remarks None
267 *
268 *--*/
269 VOID
270 NTAPI
271 FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync,
272 IN PLIST_ENTRY NotifyList,
273 IN PVOID FsContext,
274 IN PSTRING FullDirectoryName,
275 IN BOOLEAN WatchTree,
276 IN BOOLEAN IgnoreBuffer,
277 IN ULONG CompletionFilter,
278 IN PIRP NotifyIrp,
279 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL,
280 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL,
281 IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL)
282 {
283 KeBugCheck(FILE_SYSTEM);
284 }
285
286 /*++
287 * @name FsRtlNotifyFilterReportChange
288 * @unimplemented
289 *
290 * FILLME
291 *
292 * @param NotifySync
293 * FILLME
294 *
295 * @param NotifyList
296 * FILLME
297 *
298 * @param FullTargetName
299 * FILLME
300 *
301 * @param TargetNameOffset
302 * FILLME
303 *
304 * @param StreamName
305 * FILLME
306 *
307 * @param NormalizedParentName
308 * FILLME
309 *
310 * @param FilterMatch
311 * FILLME
312 *
313 * @param Action
314 * FILLME
315 *
316 * @param TargetContext
317 * FILLME
318 *
319 * @param FilterContext
320 * FILLME
321 *
322 * @return None
323 *
324 * @remarks None
325 *
326 *--*/
327 VOID
328 NTAPI
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,
336 IN ULONG Action,
337 IN PVOID TargetContext,
338 IN PVOID FilterContext)
339 {
340 KeBugCheck(FILE_SYSTEM);
341 }
342
343 /*++
344 * @name FsRtlNotifyFullChangeDirectory
345 * @implemented
346 *
347 * Lets FSD know if changes occures in the specified directory.
348 *
349 * @param NotifySync
350 * Synchronization object pointer
351 *
352 * @param NotifyList
353 * Notify list pointer (to head)
354 *
355 * @param FsContext
356 * Used to identify the notify structure
357 *
358 * @param FullDirectoryName
359 * String (A or W) containing the full directory name
360 *
361 * @param WatchTree
362 * True to notify changes in subdirectories too
363 *
364 * @param IgnoreBuffer
365 * True to reenumerate directory. It's ignored it NotifyIrp is null
366 *
367 * @param CompletionFilter
368 * Used to define types of changes to notify
369 *
370 * @param NotifyIrp
371 * IRP pointer to complete notify operation. It can be null
372 *
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
376 * is null
377 *
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
381 *
382 * @return None
383 *
384 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory.
385 *
386 *--*/
387 VOID
388 NTAPI
389 FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync,
390 IN PLIST_ENTRY NotifyList,
391 IN PVOID FsContext,
392 IN PSTRING FullDirectoryName,
393 IN BOOLEAN WatchTree,
394 IN BOOLEAN IgnoreBuffer,
395 IN ULONG CompletionFilter,
396 IN PIRP NotifyIrp,
397 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL,
398 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL)
399 {
400 FsRtlNotifyFilterChangeDirectory(NotifySync,
401 NotifyList,
402 FsContext,
403 FullDirectoryName,
404 WatchTree,
405 IgnoreBuffer,
406 CompletionFilter,
407 NotifyIrp,
408 TraverseCallback,
409 SubjectContext,
410 NULL);
411 }
412
413 /*++
414 * @name FsRtlNotifyFullReportChange
415 * @implemented
416 *
417 * Complets the pending notify IRPs.
418 *
419 * @param NotifySync
420 * Synchronization object pointer
421 *
422 * @param NotifyList
423 * Notify list pointer (to head)
424 *
425 * @param FullTargetName
426 * String (A or W) containing the full directory name that changed
427 *
428 * @param TargetNameOffset
429 * Offset, in FullTargetName, of the final component that is in the changed directory
430 *
431 * @param StreamName
432 * String (A or W) containing a stream name
433 *
434 * @param NormalizedParentName
435 * String (A or W) containing the full directory name that changed with long names
436 *
437 * @param FilterMatch
438 * Flags that will be compared to the completion filter
439 *
440 * @param Action
441 * Action code to store in user's buffer
442 *
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.
446 *
447 * @return None
448 *
449 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
450 *
451 *--*/
452 VOID
453 NTAPI
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,
461 IN ULONG Action,
462 IN PVOID TargetContext)
463 {
464 FsRtlNotifyFilterReportChange(NotifySync,
465 NotifyList,
466 FullTargetName,
467 TargetNameOffset,
468 StreamName,
469 NormalizedParentName,
470 FilterMatch,
471 Action,
472 TargetContext,
473 NULL);
474 }
475
476 /*++
477 * @name FsRtlNotifyInitializeSync
478 * @implemented
479 *
480 * Allocates the internal structure associated with notifications.
481 *
482 * @param NotifySync
483 * Opaque pointer. It will receive the address of the allocated internal structure.
484 *
485 * @return None
486 *
487 * @remarks This function raise an exception in case of a failure.
488 *
489 *--*/
490 VOID
491 NTAPI
492 FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC *NotifySync)
493 {
494 PREAL_NOTIFY_SYNC RealNotifySync;
495
496 *NotifySync = NULL;
497
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;
503
504 *NotifySync = RealNotifySync;
505 }
506
507 /*++
508 * @name FsRtlNotifyReportChange
509 * @implemented
510 *
511 * Complets the pending notify IRPs.
512 *
513 * @param NotifySync
514 * Synchronization object pointer
515 *
516 * @param NotifyList
517 * Notify list pointer (to head)
518 *
519 * @param FullTargetName
520 * String (A or W) containing the full directory name that changed
521 *
522 * @param FileNamePartLength
523 * Length of the final component that is in the changed directory
524 *
525 * @param FilterMatch
526 * Flags that will be compared to the completion filter
527 *
528 * @return None
529 *
530 * @remarks This function only redirects to FsRtlNotifyFilterReportChange.
531 *
532 *--*/
533 VOID
534 NTAPI
535 FsRtlNotifyReportChange(IN PNOTIFY_SYNC NotifySync,
536 IN PLIST_ENTRY NotifyList,
537 IN PSTRING FullTargetName,
538 IN PUSHORT FileNamePartLength,
539 IN ULONG FilterMatch)
540 {
541 FsRtlNotifyFilterReportChange(NotifySync,
542 NotifyList,
543 FullTargetName,
544 FullTargetName->Length - *FileNamePartLength,
545 NULL,
546 NULL,
547 FilterMatch,
548 0,
549 NULL,
550 NULL);
551 }
552
553 /*++
554 * @name FsRtlNotifyUninitializeSync
555 * @implemented
556 *
557 * Uninitialize a NOTIFY_SYNC object
558 *
559 * @param NotifySync
560 * Address of a pointer to a PNOTIFY_SYNC object previously
561 * initialized by FsRtlNotifyInitializeSync()
562 *
563 * @return None
564 *
565 * @remarks None
566 *
567 *--*/
568 VOID
569 NTAPI
570 FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC *NotifySync)
571 {
572 if (*NotifySync)
573 {
574 ExFreePoolWithTag(*NotifySync, 'FSNS');
575 *NotifySync = NULL;
576 }
577 }
578