Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygennotify.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/fsrtl/notify.c 00005 * PURPOSE: Change Notifications and Sync for File System Drivers 00006 * PROGRAMMERS: Pierre Schweitzer 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* PRIVATE FUNCTIONS *********************************************************/ 00016 00017 VOID 00018 FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, 00019 IN NTSTATUS Status); 00020 00021 BOOLEAN 00022 FsRtlNotifySetCancelRoutine(IN PIRP Irp, 00023 IN PNOTIFY_CHANGE NotifyChange OPTIONAL); 00024 00025 VOID 00026 NTAPI 00027 FsRtlCancelNotify(IN PDEVICE_OBJECT DeviceObject, 00028 IN PIRP Irp) 00029 { 00030 IoReleaseCancelSpinLock(Irp->CancelIrql); 00031 UNIMPLEMENTED; 00032 } 00033 00034 /* 00035 * @implemented 00036 */ 00037 VOID 00038 FsRtlCheckNotifyForDelete(IN PLIST_ENTRY NotifyList, 00039 IN PVOID FsContext) 00040 { 00041 PLIST_ENTRY NextEntry; 00042 PNOTIFY_CHANGE NotifyChange; 00043 00044 if (!IsListEmpty(NotifyList)) 00045 { 00046 /* Browse the notifications list to find the matching entry */ 00047 for (NextEntry = NotifyList->Flink; 00048 NextEntry != NotifyList; 00049 NextEntry = NextEntry->Flink) 00050 { 00051 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList); 00052 /* If the current record matches with the given context, it's the good one */ 00053 if (NotifyChange->FsContext == FsContext && !IsListEmpty(&(NotifyChange->NotifyIrps))) 00054 { 00055 FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_DELETE_PENDING); 00056 } 00057 } 00058 } 00059 } 00060 00061 PNOTIFY_CHANGE 00062 FsRtlIsNotifyOnList(IN PLIST_ENTRY NotifyList, 00063 IN PVOID FsContext) 00064 { 00065 PLIST_ENTRY NextEntry; 00066 PNOTIFY_CHANGE NotifyChange; 00067 00068 if (!IsListEmpty(NotifyList)) 00069 { 00070 /* Browse the notifications list to find the matching entry */ 00071 for (NextEntry = NotifyList->Flink; 00072 NextEntry != NotifyList; 00073 NextEntry = NextEntry->Flink) 00074 { 00075 NotifyChange = CONTAINING_RECORD(NextEntry, NOTIFY_CHANGE, NotifyList); 00076 /* If the current record matches with the given context, it's the good one */ 00077 if (NotifyChange->FsContext == FsContext) 00078 { 00079 return NotifyChange; 00080 } 00081 } 00082 } 00083 return NULL; 00084 } 00085 00086 VOID 00087 FORCEINLINE 00088 FsRtlNotifyAcquireFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) 00089 { 00090 ULONG_PTR CurrentThread = (ULONG_PTR)KeGetCurrentThread(); 00091 00092 /* Only acquire fast mutex if it's not already acquired by the current thread */ 00093 if (RealNotifySync->OwningThread != CurrentThread) 00094 { 00095 ExAcquireFastMutexUnsafe(&(RealNotifySync->FastMutex)); 00096 RealNotifySync->OwningThread = CurrentThread; 00097 } 00098 /* Whatever the case, keep trace of the attempt to acquire fast mutex */ 00099 RealNotifySync->OwnerCount++; 00100 } 00101 00102 /* 00103 * @implemented 00104 */ 00105 VOID 00106 FsRtlNotifyCompleteIrp(IN PIRP Irp, 00107 IN PNOTIFY_CHANGE NotifyChange, 00108 IN ULONG DataLength, 00109 IN NTSTATUS Status, 00110 IN BOOLEAN SkipCompletion) 00111 { 00112 PVOID Buffer; 00113 PIO_STACK_LOCATION Stack; 00114 00115 PAGED_CODE(); 00116 00117 /* Check if we need to complete */ 00118 if (!FsRtlNotifySetCancelRoutine(Irp, NotifyChange) && SkipCompletion) 00119 { 00120 return; 00121 } 00122 00123 /* No succes => no data to return just complete */ 00124 if (Status != STATUS_SUCCESS) 00125 { 00126 goto Completion; 00127 } 00128 00129 /* Ensure there's something to return */ 00130 Stack = IoGetCurrentIrpStackLocation(Irp); 00131 if (!DataLength || Stack->Parameters.NotifyDirectory.Length < DataLength) 00132 { 00133 Status = STATUS_NOTIFY_ENUM_DIR; 00134 goto Completion; 00135 } 00136 00137 /* Ensture there's a buffer where to find data */ 00138 if (!NotifyChange->AllocatedBuffer) 00139 { 00140 Irp->IoStatus.Information = DataLength; 00141 NotifyChange->Buffer = NULL; 00142 goto Completion; 00143 } 00144 00145 /* Now, browse all the way to return data 00146 * and find the one that will work. We will 00147 * return data whatever happens 00148 */ 00149 if (Irp->AssociatedIrp.SystemBuffer) 00150 { 00151 Buffer = Irp->AssociatedIrp.SystemBuffer; 00152 goto CopyAndComplete; 00153 } 00154 00155 if (Irp->MdlAddress) 00156 { 00157 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress); 00158 goto CopyAndComplete; 00159 } 00160 00161 if (!(Stack->Control & SL_PENDING_RETURNED)) 00162 { 00163 Buffer = Irp->UserBuffer; 00164 goto CopyAndComplete; 00165 } 00166 00167 Irp->Flags |= (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_SYNCHRONOUS_PAGING_IO); 00168 Irp->AssociatedIrp.SystemBuffer = NotifyChange->AllocatedBuffer; 00169 /* Nothing to copy */ 00170 goto ReleaseAndComplete; 00171 00172 CopyAndComplete: 00173 _SEH2_TRY 00174 { 00175 RtlCopyMemory(Buffer, NotifyChange->AllocatedBuffer, DataLength); 00176 } 00177 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00178 { 00179 /* Do nothing */ 00180 } 00181 _SEH2_END; 00182 00183 ReleaseAndComplete: 00184 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength); 00185 00186 /* Release buffer UNLESS it's used */ 00187 if (NotifyChange->AllocatedBuffer != Irp->AssociatedIrp.SystemBuffer && 00188 NotifyChange->AllocatedBuffer) 00189 { 00190 ExFreePoolWithTag(NotifyChange->AllocatedBuffer, 0); 00191 } 00192 00193 /* Prepare for return */ 00194 NotifyChange->AllocatedBuffer = 0; 00195 NotifyChange->ThisBufferLength = 0; 00196 Irp->IoStatus.Information = DataLength; 00197 NotifyChange->Buffer = NULL; 00198 00199 /* Finally complete */ 00200 Completion: 00201 IoMarkIrpPending(Irp); 00202 Irp->IoStatus.Status = Status; 00203 IoCompleteRequest(Irp, EVENT_INCREMENT); 00204 } 00205 00206 /* 00207 * @implemented 00208 */ 00209 VOID 00210 FsRtlNotifyCompleteIrpList(IN PNOTIFY_CHANGE NotifyChange, 00211 IN NTSTATUS Status) 00212 { 00213 PIRP Irp; 00214 ULONG DataLength; 00215 PLIST_ENTRY NextEntry; 00216 00217 DataLength = NotifyChange->DataLength; 00218 00219 NotifyChange->Flags &= (INVALIDATE_BUFFERS | WATCH_TREE); 00220 NotifyChange->DataLength = 0; 00221 NotifyChange->LastEntry = 0; 00222 00223 while (!IsListEmpty(&(NotifyChange->NotifyIrps))) 00224 { 00225 /* We take the first entry */ 00226 NextEntry = RemoveHeadList(&(NotifyChange->NotifyIrps)); 00227 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); 00228 /* We complete it */ 00229 FsRtlNotifyCompleteIrp(Irp, NotifyChange, DataLength, Status, TRUE); 00230 /* If we're notifying success, just notify first one */ 00231 if (Status == STATUS_SUCCESS) 00232 break; 00233 } 00234 } 00235 00236 VOID 00237 FORCEINLINE 00238 FsRtlNotifyReleaseFastMutex(IN PREAL_NOTIFY_SYNC RealNotifySync) 00239 { 00240 RealNotifySync->OwnerCount--; 00241 /* Release the fast mutex only if no other instance needs it */ 00242 if (!RealNotifySync->OwnerCount) 00243 { 00244 ExReleaseFastMutexUnsafe(&(RealNotifySync->FastMutex)); 00245 RealNotifySync->OwningThread = (ULONG_PTR)0; 00246 } 00247 } 00248 00249 /* 00250 * @implemented 00251 */ 00252 BOOLEAN 00253 FsRtlNotifySetCancelRoutine(IN PIRP Irp, 00254 IN PNOTIFY_CHANGE NotifyChange OPTIONAL) 00255 { 00256 PDRIVER_CANCEL CancelRoutine; 00257 00258 /* Acquire cancel lock */ 00259 IoAcquireCancelSpinLock(&Irp->CancelIrql); 00260 00261 /* If NotifyChange was given */ 00262 if (NotifyChange) 00263 { 00264 /* First get cancel routine */ 00265 CancelRoutine = IoSetCancelRoutine(Irp, NULL); 00266 Irp->IoStatus.Information = 0; 00267 /* Release cancel lock */ 00268 IoReleaseCancelSpinLock(Irp->CancelIrql); 00269 /* If there was a cancel routine */ 00270 if (CancelRoutine) 00271 { 00272 /* Decrease reference count */ 00273 InterlockedDecrement((PLONG)&NotifyChange->ReferenceCount); 00274 /* Notify that we removed cancel routine */ 00275 return TRUE; 00276 } 00277 } 00278 else 00279 { 00280 /* If IRP is cancel, call FsRtl cancel routine */ 00281 if (Irp->Cancel) 00282 { 00283 FsRtlCancelNotify(NULL, Irp); 00284 } 00285 else 00286 { 00287 /* Otherwise, define FsRtl cancel routine as IRP cancel routine */ 00288 IoSetCancelRoutine(Irp, FsRtlCancelNotify); 00289 /* Release lock */ 00290 IoReleaseCancelSpinLock(Irp->CancelIrql); 00291 } 00292 } 00293 00294 /* Return that we didn't removed cancel routine */ 00295 return FALSE; 00296 } 00297 00298 /* PUBLIC FUNCTIONS **********************************************************/ 00299 00300 /*++ 00301 * @name FsRtlNotifyChangeDirectory 00302 * @implemented 00303 * 00304 * Lets FSD know if changes occures in the specified directory. 00305 * Directory will be reenumerated. 00306 * 00307 * @param NotifySync 00308 * Synchronization object pointer 00309 * 00310 * @param FsContext 00311 * Used to identify the notify structure 00312 * 00313 * @param FullDirectoryName 00314 * String (A or W) containing the full directory name 00315 * 00316 * @param NotifyList 00317 * Notify list pointer (to head) 00318 * 00319 * @param WatchTree 00320 * True to notify changes in subdirectories too 00321 * 00322 * @param CompletionFilter 00323 * Used to define types of changes to notify 00324 * 00325 * @param NotifyIrp 00326 * IRP pointer to complete notify operation. It can be null 00327 * 00328 * @return None 00329 * 00330 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory. 00331 * 00332 *--*/ 00333 VOID 00334 NTAPI 00335 FsRtlNotifyChangeDirectory(IN PNOTIFY_SYNC NotifySync, 00336 IN PVOID FsContext, 00337 IN PSTRING FullDirectoryName, 00338 IN PLIST_ENTRY NotifyList, 00339 IN BOOLEAN WatchTree, 00340 IN ULONG CompletionFilter, 00341 IN PIRP NotifyIrp) 00342 { 00343 FsRtlNotifyFilterChangeDirectory(NotifySync, 00344 NotifyList, 00345 FsContext, 00346 FullDirectoryName, 00347 WatchTree, 00348 TRUE, 00349 CompletionFilter, 00350 NotifyIrp, 00351 NULL, 00352 NULL, 00353 NULL); 00354 } 00355 00356 /*++ 00357 * @name FsRtlNotifyCleanup 00358 * @implemented 00359 * 00360 * Called by FSD when all handles to FileObject (identified by FsContext) are closed 00361 * 00362 * @param NotifySync 00363 * Synchronization object pointer 00364 * 00365 * @param NotifyList 00366 * Notify list pointer (to head) 00367 * 00368 * @param FsContext 00369 * Used to identify the notify structure 00370 * 00371 * @return None 00372 * 00373 * @remarks None 00374 * 00375 *--*/ 00376 VOID 00377 NTAPI 00378 FsRtlNotifyCleanup(IN PNOTIFY_SYNC NotifySync, 00379 IN PLIST_ENTRY NotifyList, 00380 IN PVOID FsContext) 00381 { 00382 PNOTIFY_CHANGE NotifyChange; 00383 PREAL_NOTIFY_SYNC RealNotifySync; 00384 PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; 00385 00386 /* Get real structure hidden behind the opaque pointer */ 00387 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync; 00388 00389 /* Acquire the fast mutex */ 00390 FsRtlNotifyAcquireFastMutex(RealNotifySync); 00391 00392 _SEH2_TRY 00393 { 00394 /* Find if there's a matching notification with the FsContext */ 00395 NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext); 00396 if (NotifyChange) 00397 { 00398 /* Mark it as to know that cleanup is in process */ 00399 NotifyChange->Flags |= CLEANUP_IN_PROCESS; 00400 00401 /* If there are pending IRPs, complete them using the STATUS_NOTIFY_CLEANUP status */ 00402 if (!IsListEmpty(&NotifyChange->NotifyIrps)) 00403 { 00404 FsRtlNotifyCompleteIrpList(NotifyChange, STATUS_NOTIFY_CLEANUP); 00405 } 00406 00407 /* Decrease reference number and if 0 is reached, it's time to do complete cleanup */ 00408 if (!InterlockedDecrement((PLONG)&(NotifyChange->ReferenceCount))) 00409 { 00410 /* Remove it from the notifications list */ 00411 RemoveEntryList(&NotifyChange->NotifyList); 00412 00413 /* In case there was an allocated buffer, free it */ 00414 if (NotifyChange->AllocatedBuffer) 00415 { 00416 PsReturnProcessPagedPoolQuota(NotifyChange->OwningProcess, NotifyChange->ThisBufferLength); 00417 ExFreePool(NotifyChange->AllocatedBuffer); 00418 } 00419 00420 /* In case there the string was set, get the captured subject security context */ 00421 if (NotifyChange->FullDirectoryName) 00422 { 00423 SubjectContext = NotifyChange->SubjectContext; 00424 } 00425 00426 /* Finally, free the notification, as it's not needed anymore */ 00427 ExFreePool(NotifyChange); 00428 } 00429 } 00430 } 00431 _SEH2_FINALLY 00432 { 00433 /* Release fast mutex */ 00434 FsRtlNotifyReleaseFastMutex(RealNotifySync); 00435 00436 /* If the subject security context was captured, release and free it */ 00437 if (SubjectContext) 00438 { 00439 SeReleaseSubjectContext(SubjectContext); 00440 ExFreePool(SubjectContext); 00441 } 00442 } 00443 _SEH2_END; 00444 } 00445 00446 /*++ 00447 * @name FsRtlNotifyFilterChangeDirectory 00448 * @unimplemented 00449 * 00450 * FILLME 00451 * 00452 * @param NotifySync 00453 * FILLME 00454 * 00455 * @param NotifyList 00456 * FILLME 00457 * 00458 * @param FsContext 00459 * FILLME 00460 * 00461 * @param FullDirectoryName 00462 * FILLME 00463 * 00464 * @param WatchTree 00465 * FILLME 00466 * 00467 * @param IgnoreBuffer 00468 * FILLME 00469 * 00470 * @param CompletionFilter 00471 * FILLME 00472 * 00473 * @param NotifyIrp 00474 * FILLME 00475 * 00476 * @param TraverseCallback 00477 * FILLME 00478 * 00479 * @param SubjectContext 00480 * FILLME 00481 * 00482 * @param FilterCallback 00483 * FILLME 00484 * 00485 * @return None 00486 * 00487 * @remarks None 00488 * 00489 *--*/ 00490 VOID 00491 NTAPI 00492 FsRtlNotifyFilterChangeDirectory(IN PNOTIFY_SYNC NotifySync, 00493 IN PLIST_ENTRY NotifyList, 00494 IN PVOID FsContext, 00495 IN PSTRING FullDirectoryName, 00496 IN BOOLEAN WatchTree, 00497 IN BOOLEAN IgnoreBuffer, 00498 IN ULONG CompletionFilter, 00499 IN PIRP NotifyIrp, 00500 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, 00501 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL, 00502 IN PFILTER_REPORT_CHANGE FilterCallback OPTIONAL) 00503 { 00504 ULONG SavedLength; 00505 PIO_STACK_LOCATION Stack; 00506 PNOTIFY_CHANGE NotifyChange; 00507 PREAL_NOTIFY_SYNC RealNotifySync; 00508 00509 PAGED_CODE(); 00510 00511 DPRINT("FsRtlNotifyFilterChangeDirectory(): %p, %p, %p, %wZ, %d, %d, %u, %p, %p, %p, %p\n", 00512 NotifySync, NotifyList, FsContext, FullDirectoryName, WatchTree, IgnoreBuffer, CompletionFilter, NotifyIrp, 00513 TraverseCallback, SubjectContext, FilterCallback); 00514 00515 /* Get real structure hidden behind the opaque pointer */ 00516 RealNotifySync = (PREAL_NOTIFY_SYNC)NotifySync; 00517 00518 /* Acquire the fast mutex */ 00519 FsRtlNotifyAcquireFastMutex(RealNotifySync); 00520 00521 _SEH2_TRY 00522 { 00523 /* If we have no IRP, FSD is performing a cleanup */ 00524 if (!NotifyIrp) 00525 { 00526 /* So, we delete */ 00527 FsRtlCheckNotifyForDelete(NotifyList, FsContext); 00528 _SEH2_LEAVE; 00529 } 00530 00531 NotifyIrp->IoStatus.Status = STATUS_SUCCESS; 00532 NotifyIrp->IoStatus.Information = (ULONG_PTR)NULL; 00533 00534 Stack = IoGetCurrentIrpStackLocation(NotifyIrp); 00535 /* If FileObject's been cleaned up, just return */ 00536 if (Stack->FileObject->Flags & FO_CLEANUP_COMPLETE) 00537 { 00538 IoMarkIrpPending(NotifyIrp); 00539 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP; 00540 IoCompleteRequest(NotifyIrp, EVENT_INCREMENT); 00541 _SEH2_LEAVE; 00542 } 00543 00544 /* Try to find a matching notification has been already registered */ 00545 NotifyChange = FsRtlIsNotifyOnList(NotifyList, FsContext); 00546 if (NotifyChange) 00547 { 00548 /* If it's been found, and is cleaned up, immediatly complete */ 00549 if (NotifyChange->Flags & CLEANUP_IN_PROCESS) 00550 { 00551 IoMarkIrpPending(NotifyIrp); 00552 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_CLEANUP; 00553 IoCompleteRequest(NotifyIrp, EVENT_INCREMENT); 00554 } 00555 /* Or if it's about to be deleted, complete */ 00556 else if (NotifyChange->Flags & DELETE_IN_PROCESS) 00557 { 00558 IoMarkIrpPending(NotifyIrp); 00559 NotifyIrp->IoStatus.Status = STATUS_DELETE_PENDING; 00560 IoCompleteRequest(NotifyIrp, EVENT_INCREMENT); 00561 } 00562 /* Complete if there is directory enumeration and no buffer available any more */ 00563 if ((NotifyChange->Flags & INVALIDATE_BUFFERS) && (NotifyChange->Flags & ENUMERATE_DIR)) 00564 { 00565 NotifyChange->Flags &= ~INVALIDATE_BUFFERS; 00566 IoMarkIrpPending(NotifyIrp); 00567 NotifyIrp->IoStatus.Status = STATUS_NOTIFY_ENUM_DIR; 00568 IoCompleteRequest(NotifyIrp, EVENT_INCREMENT); 00569 } 00570 /* If no data yet, or directory enumeration, handle */ 00571 else if (NotifyChange->DataLength == 0 || (NotifyChange->Flags & ENUMERATE_DIR)) 00572 { 00573 goto HandleIRP; 00574 } 00575 /* Else, just complete with we have */ 00576 else 00577 { 00578 SavedLength = NotifyChange->DataLength; 00579 NotifyChange->DataLength = 0; 00580 FsRtlNotifyCompleteIrp(NotifyIrp, NotifyChange, SavedLength, STATUS_SUCCESS, FALSE); 00581 } 00582 00583 _SEH2_LEAVE; 00584 } 00585 00586 /* Allocate new notification */ 00587 NotifyChange = ExAllocatePoolWithTag(PagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, 00588 sizeof(NOTIFY_CHANGE), 'FSrN'); 00589 RtlZeroMemory(NotifyChange, sizeof(NOTIFY_CHANGE)); 00590 00591 /* Set basic information */ 00592 NotifyChange->NotifySync = NotifySync; 00593 NotifyChange->FsContext = FsContext; 00594 NotifyChange->StreamID = Stack->FileObject->FsContext; 00595 NotifyChange->TraverseCallback = TraverseCallback; 00596 NotifyChange->SubjectContext = SubjectContext; 00597 NotifyChange->FullDirectoryName = FullDirectoryName; 00598 NotifyChange->FilterCallback = FilterCallback; 00599 InitializeListHead(&(NotifyChange->NotifyIrps)); 00600 00601 /* Keep trace of WatchTree */ 00602 if (WatchTree) 00603 { 00604 NotifyChange->Flags |= WATCH_TREE; 00605 } 00606 00607 /* If string is empty, faulty to ANSI */ 00608 if (FullDirectoryName->Length == 0) 00609 { 00610 NotifyChange->CharacterSize = sizeof(CHAR); 00611 } 00612 else 00613 { 00614 /* If it can't contain WCHAR, it's ANSI */ 00615 if (FullDirectoryName->Length < sizeof(WCHAR)) 00616 { 00617 NotifyChange->CharacterSize = sizeof(CHAR); 00618 } 00619 /* First char is \, so in unicode, right part is 0 00620 * whereas in ANSI it contains next char 00621 */ 00622 else if (((CHAR*)FullDirectoryName->Buffer)[1] == 0) 00623 { 00624 NotifyChange->CharacterSize = sizeof(WCHAR); 00625 } 00626 else 00627 { 00628 NotifyChange->CharacterSize = sizeof(CHAR); 00629 } 00630 00631 /* Now, check is user is willing to watch root */ 00632 if (FullDirectoryName->Length == NotifyChange->CharacterSize) 00633 { 00634 NotifyChange->Flags |= WATCH_ROOT; 00635 } 00636 } 00637 00638 NotifyChange->CompletionFilter = CompletionFilter; 00639 00640 /* In case we have not to ignore buffer , keep its length */ 00641 if (!IgnoreBuffer) 00642 { 00643 NotifyChange->BufferLength = Stack->Parameters.NotifyDirectory.Length; 00644 } 00645 00646 NotifyChange->OwningProcess = NotifyIrp->Tail.Overlay.Thread->ThreadsProcess; 00647 00648 /* Insert the notification into the notification list */ 00649 InsertTailList(NotifyList, &(NotifyChange->NotifyList)); 00650 00651 NotifyChange->ReferenceCount = 1; 00652 00653 HandleIRP: 00654 /* Associate the notification to the IRP */ 00655 NotifyIrp->IoStatus.Information = (ULONG_PTR)NotifyChange; 00656 /* The IRP is pending */ 00657 IoMarkIrpPending(NotifyIrp); 00658 /* Insert the IRP in the IRP list */ 00659 InsertTailList(&(NotifyChange->NotifyIrps), &(NotifyIrp->Tail.Overlay.ListEntry)); 00660 /* Increment reference count */ 00661 InterlockedIncrement((PLONG)&(NotifyChange->ReferenceCount)); 00662 /* Set cancel routine to FsRtl one */ 00663 FsRtlNotifySetCancelRoutine(NotifyIrp, NULL); 00664 } 00665 _SEH2_FINALLY 00666 { 00667 /* Release fast mutex */ 00668 FsRtlNotifyReleaseFastMutex(RealNotifySync); 00669 00670 /* If the subject security context was captured and there's no notify */ 00671 if (SubjectContext && (!NotifyChange || FullDirectoryName)) 00672 { 00673 SeReleaseSubjectContext(SubjectContext); 00674 ExFreePool(SubjectContext); 00675 } 00676 } 00677 _SEH2_END; 00678 } 00679 00680 /*++ 00681 * @name FsRtlNotifyFilterReportChange 00682 * @unimplemented 00683 * 00684 * FILLME 00685 * 00686 * @param NotifySync 00687 * FILLME 00688 * 00689 * @param NotifyList 00690 * FILLME 00691 * 00692 * @param FullTargetName 00693 * FILLME 00694 * 00695 * @param TargetNameOffset 00696 * FILLME 00697 * 00698 * @param StreamName 00699 * FILLME 00700 * 00701 * @param NormalizedParentName 00702 * FILLME 00703 * 00704 * @param FilterMatch 00705 * FILLME 00706 * 00707 * @param Action 00708 * FILLME 00709 * 00710 * @param TargetContext 00711 * FILLME 00712 * 00713 * @param FilterContext 00714 * FILLME 00715 * 00716 * @return None 00717 * 00718 * @remarks None 00719 * 00720 *--*/ 00721 VOID 00722 NTAPI 00723 FsRtlNotifyFilterReportChange(IN PNOTIFY_SYNC NotifySync, 00724 IN PLIST_ENTRY NotifyList, 00725 IN PSTRING FullTargetName, 00726 IN USHORT TargetNameOffset, 00727 IN PSTRING StreamName OPTIONAL, 00728 IN PSTRING NormalizedParentName OPTIONAL, 00729 IN ULONG FilterMatch, 00730 IN ULONG Action, 00731 IN PVOID TargetContext, 00732 IN PVOID FilterContext) 00733 { 00734 KeBugCheck(FILE_SYSTEM); 00735 } 00736 00737 /*++ 00738 * @name FsRtlNotifyFullChangeDirectory 00739 * @implemented 00740 * 00741 * Lets FSD know if changes occures in the specified directory. 00742 * 00743 * @param NotifySync 00744 * Synchronization object pointer 00745 * 00746 * @param NotifyList 00747 * Notify list pointer (to head) 00748 * 00749 * @param FsContext 00750 * Used to identify the notify structure 00751 * 00752 * @param FullDirectoryName 00753 * String (A or W) containing the full directory name 00754 * 00755 * @param WatchTree 00756 * True to notify changes in subdirectories too 00757 * 00758 * @param IgnoreBuffer 00759 * True to reenumerate directory. It's ignored it NotifyIrp is null 00760 * 00761 * @param CompletionFilter 00762 * Used to define types of changes to notify 00763 * 00764 * @param NotifyIrp 00765 * IRP pointer to complete notify operation. It can be null 00766 * 00767 * @param TraverseCallback 00768 * Pointer to a callback function. It's called each time a change is 00769 * done in a subdirectory of the main directory. It's ignored it NotifyIrp 00770 * is null 00771 * 00772 * @param SubjectContext 00773 * Pointer to pass to SubjectContext member of TraverseCallback. 00774 * It's freed after use. It's ignored it NotifyIrp is null 00775 * 00776 * @return None 00777 * 00778 * @remarks This function only redirects to FsRtlNotifyFilterChangeDirectory. 00779 * 00780 *--*/ 00781 VOID 00782 NTAPI 00783 FsRtlNotifyFullChangeDirectory(IN PNOTIFY_SYNC NotifySync, 00784 IN PLIST_ENTRY NotifyList, 00785 IN PVOID FsContext, 00786 IN PSTRING FullDirectoryName, 00787 IN BOOLEAN WatchTree, 00788 IN BOOLEAN IgnoreBuffer, 00789 IN ULONG CompletionFilter, 00790 IN PIRP NotifyIrp, 00791 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, 00792 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL) 00793 { 00794 FsRtlNotifyFilterChangeDirectory(NotifySync, 00795 NotifyList, 00796 FsContext, 00797 FullDirectoryName, 00798 WatchTree, 00799 IgnoreBuffer, 00800 CompletionFilter, 00801 NotifyIrp, 00802 TraverseCallback, 00803 SubjectContext, 00804 NULL); 00805 } 00806 00807 /*++ 00808 * @name FsRtlNotifyFullReportChange 00809 * @implemented 00810 * 00811 * Complets the pending notify IRPs. 00812 * 00813 * @param NotifySync 00814 * Synchronization object pointer 00815 * 00816 * @param NotifyList 00817 * Notify list pointer (to head) 00818 * 00819 * @param FullTargetName 00820 * String (A or W) containing the full directory name that changed 00821 * 00822 * @param TargetNameOffset 00823 * Offset, in FullTargetName, of the final component that is in the changed directory 00824 * 00825 * @param StreamName 00826 * String (A or W) containing a stream name 00827 * 00828 * @param NormalizedParentName 00829 * String (A or W) containing the full directory name that changed with long names 00830 * 00831 * @param FilterMatch 00832 * Flags that will be compared to the completion filter 00833 * 00834 * @param Action 00835 * Action code to store in user's buffer 00836 * 00837 * @param TargetContext 00838 * Pointer to a callback function. It's called each time a change is 00839 * done in a subdirectory of the main directory. 00840 * 00841 * @return None 00842 * 00843 * @remarks This function only redirects to FsRtlNotifyFilterReportChange. 00844 * 00845 *--*/ 00846 VOID 00847 NTAPI 00848 FsRtlNotifyFullReportChange(IN PNOTIFY_SYNC NotifySync, 00849 IN PLIST_ENTRY NotifyList, 00850 IN PSTRING FullTargetName, 00851 IN USHORT TargetNameOffset, 00852 IN PSTRING StreamName OPTIONAL, 00853 IN PSTRING NormalizedParentName OPTIONAL, 00854 IN ULONG FilterMatch, 00855 IN ULONG Action, 00856 IN PVOID TargetContext) 00857 { 00858 FsRtlNotifyFilterReportChange(NotifySync, 00859 NotifyList, 00860 FullTargetName, 00861 TargetNameOffset, 00862 StreamName, 00863 NormalizedParentName, 00864 FilterMatch, 00865 Action, 00866 TargetContext, 00867 NULL); 00868 } 00869 00870 /*++ 00871 * @name FsRtlNotifyInitializeSync 00872 * @implemented 00873 * 00874 * Allocates the internal structure associated with notifications. 00875 * 00876 * @param NotifySync 00877 * Opaque pointer. It will receive the address of the allocated internal structure. 00878 * 00879 * @return None 00880 * 00881 * @remarks This function raise an exception in case of a failure. 00882 * 00883 *--*/ 00884 VOID 00885 NTAPI 00886 FsRtlNotifyInitializeSync(IN PNOTIFY_SYNC *NotifySync) 00887 { 00888 PREAL_NOTIFY_SYNC RealNotifySync; 00889 00890 *NotifySync = NULL; 00891 00892 RealNotifySync = ExAllocatePoolWithTag(NonPagedPool | POOL_RAISE_IF_ALLOCATION_FAILURE, 00893 sizeof(REAL_NOTIFY_SYNC), 'FSNS'); 00894 ExInitializeFastMutex(&(RealNotifySync->FastMutex)); 00895 RealNotifySync->OwningThread = 0; 00896 RealNotifySync->OwnerCount = 0; 00897 00898 *NotifySync = RealNotifySync; 00899 } 00900 00901 /*++ 00902 * @name FsRtlNotifyReportChange 00903 * @implemented 00904 * 00905 * Complets the pending notify IRPs. 00906 * 00907 * @param NotifySync 00908 * Synchronization object pointer 00909 * 00910 * @param NotifyList 00911 * Notify list pointer (to head) 00912 * 00913 * @param FullTargetName 00914 * String (A or W) containing the full directory name that changed 00915 * 00916 * @param FileNamePartLength 00917 * Length of the final component that is in the changed directory 00918 * 00919 * @param FilterMatch 00920 * Flags that will be compared to the completion filter 00921 * 00922 * @return None 00923 * 00924 * @remarks This function only redirects to FsRtlNotifyFilterReportChange. 00925 * 00926 *--*/ 00927 VOID 00928 NTAPI 00929 FsRtlNotifyReportChange(IN PNOTIFY_SYNC NotifySync, 00930 IN PLIST_ENTRY NotifyList, 00931 IN PSTRING FullTargetName, 00932 IN PUSHORT FileNamePartLength, 00933 IN ULONG FilterMatch) 00934 { 00935 FsRtlNotifyFilterReportChange(NotifySync, 00936 NotifyList, 00937 FullTargetName, 00938 FullTargetName->Length - *FileNamePartLength, 00939 NULL, 00940 NULL, 00941 FilterMatch, 00942 0, 00943 NULL, 00944 NULL); 00945 } 00946 00947 /*++ 00948 * @name FsRtlNotifyUninitializeSync 00949 * @implemented 00950 * 00951 * Uninitialize a NOTIFY_SYNC object 00952 * 00953 * @param NotifySync 00954 * Address of a pointer to a PNOTIFY_SYNC object previously 00955 * initialized by FsRtlNotifyInitializeSync() 00956 * 00957 * @return None 00958 * 00959 * @remarks None 00960 * 00961 *--*/ 00962 VOID 00963 NTAPI 00964 FsRtlNotifyUninitializeSync(IN PNOTIFY_SYNC *NotifySync) 00965 { 00966 if (*NotifySync) 00967 { 00968 ExFreePoolWithTag(*NotifySync, 'FSNS'); 00969 *NotifySync = NULL; 00970 } 00971 } 00972 Generated on Sat May 26 2012 04:20:16 for ReactOS by
1.7.6.1
|