Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

notify.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 Notify.c 00008 00009 Abstract: 00010 00011 The Notify package provides support to filesystems which implement 00012 NotifyChangeDirectory. This package will manage a queue of notify 00013 blocks which are attached to some filesystem structure (i.e. Vcb 00014 in Fat, HPFS). The filesystems will allocate a fast mutex to be used 00015 by this package to synchronize access to the notify queue. 00016 00017 The following routines are provided by this package: 00018 00019 o FsRtlNotifyInitializeSync - Create and initializes the 00020 synchronization object. 00021 00022 o FsrtlNotifyUninitializeSync - Deallocates the synchronization 00023 object. 00024 00025 o FsRtlNotifyChangeDirectory - This routine is called whenever the 00026 filesystems receive a NotifyChangeDirectoryFile call. This 00027 routine allocates any neccessary structures and places the 00028 Irp in the NotifyQueue (or possibly completes or cancels it 00029 immediately). 00030 00031 o FsRtlNotifyFullChangeDirectory - This routine is called whenever the 00032 filesystems receive a NotifyChangeDirectoryFile call. This differs 00033 from the FsRtlNotifyChangeDirectory in that it expects to return 00034 the notify information in the user's buffer. 00035 00036 o FsRtlNotifyReportChange - This routine is called by the 00037 filesystems whenever they perform some operation that could 00038 cause the completion of a notify operation. This routine will 00039 walk through the notify queue to see if any Irps are affected 00040 by the indicated operation. 00041 00042 o FsRtlNotifyFullReportChange - This routine is called by the 00043 filesystems whenever they perform some operation that could 00044 cause the completion of a notify operation. This routine differs 00045 from the FsRtlNotifyReportChange call in that it returns more 00046 detailed information in the caller's buffer if present. 00047 00048 o FsRtlNotifyCleanup - This routine is called to remove any 00049 references to a particular FsContext structure from the notify 00050 queue. If the matching FsContext structure is found in the 00051 queue, then all associated Irps are completed. 00052 00053 Author: 00054 00055 Brian Andrew [BrianAn] 9-19-1991 00056 00057 Revision History: 00058 00059 --*/ 00060 00061 #include "FsRtlP.h" 00062 00063 // 00064 // Trace level for the module 00065 // 00066 00067 #define Dbg (0x04000000) 00068 00069 // 00070 // This is the synchronization object for the notify package. The caller 00071 // given a pointer to this structure. 00072 // 00073 00074 typedef struct _REAL_NOTIFY_SYNC { 00075 00076 FAST_MUTEX FastMutex; 00077 ERESOURCE_THREAD OwningThread; 00078 ULONG OwnerCount; 00079 00080 } REAL_NOTIFY_SYNC, *PREAL_NOTIFY_SYNC; 00081 00082 // 00083 // A list of the following structures is used to store the NotifyChange 00084 // requests. They are linked to a filesystem-defined list head. 00085 // 00086 00087 typedef struct _NOTIFY_CHANGE { 00088 00089 // 00090 // Fast Mutex. This fast mutex is used to access the list containing this 00091 // structure. 00092 // 00093 00094 PREAL_NOTIFY_SYNC NotifySync; 00095 00096 // 00097 // FsContext. This value is given by the filesystems to uniquely 00098 // identify this structure. The identification is on a 00099 // per-user file object basis. The expected value is the Ccb address 00100 // for this user file object. 00101 // 00102 00103 PVOID FsContext; 00104 00105 // 00106 // StreamID. This value matches the FsContext field in the file object for 00107 // the directory being watched. This is used to identify the directory stream 00108 // when the directory is being deleted. 00109 // 00110 00111 PVOID StreamID; 00112 00113 // 00114 // TraverseAccessCallback. This is the filesystem-supplied routine used 00115 // to call back into the filesystem to check whether the caller has traverse 00116 // access when watching a sub-directory. Only applies when watching a 00117 // sub-directory. 00118 // 00119 00120 PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback; 00121 00122 // 00123 // SubjectContext. If the caller specifies a traverse callback routine 00124 // we will need to pass the Security Context from the thread which 00125 // originated this call. The notify package will free this structure 00126 // on tearing down the notify package. We don't expect to need this 00127 // structure often. 00128 // 00129 00130 PSECURITY_SUBJECT_CONTEXT SubjectContext; 00131 00132 // 00133 // Full Directory Name. The following string is the full directory 00134 // name of the directory being watched. It is used during watch tree 00135 // operations to check whether this directory is an ancestor of 00136 // the modified file. The string could be in ANSI or UNICODE form. 00137 // 00138 00139 PSTRING FullDirectoryName; 00140 00141 // 00142 // Notify List. The following field links the notify structures for 00143 // a particular volume. 00144 // 00145 00146 LIST_ENTRY NotifyList; 00147 00148 // 00149 // Notify Irps. The following field links the Irps associated with 00150 // 00151 // 00152 00153 LIST_ENTRY NotifyIrps; 00154 00155 // 00156 // Flags. State of the notify for this volume. 00157 // 00158 00159 USHORT Flags; 00160 00161 // 00162 // Character size. Larger size indicates unicode characters. 00163 // unicode names. 00164 // 00165 00166 UCHAR CharacterSize; 00167 00168 // 00169 // Completion Filter. This field is used to mask the modification 00170 // actions to determine whether to complete the notify irp. 00171 // 00172 00173 ULONG CompletionFilter; 00174 00175 // 00176 // The following values are used to manage a buffer if there is no current 00177 // Irp to complete. The fields have the following meaning: 00178 // 00179 // AllocatedBuffer - Buffer we need to allocate 00180 // Buffer - Buffer to store data in 00181 // BufferLength - Length of original user buffer 00182 // ThisBufferLength - Length of the buffer we are using 00183 // DataLength - Current length of the data in the buffer 00184 // LastEntry - Offset of previous entry in the buffer 00185 // 00186 00187 PVOID AllocatedBuffer; 00188 PVOID Buffer; 00189 ULONG BufferLength; 00190 ULONG ThisBufferLength; 00191 ULONG DataLength; 00192 ULONG LastEntry; 00193 00194 // 00195 // Reference count which keeps the notify structure around. Such references include 00196 // 00197 // - Lifetime reference. Count set to one initially and removed on cleanup 00198 // - Cancel reference. Reference the notify struct when storing the cancel routine 00199 // in the Irp. The routine which actually clears the routine will decrement 00200 // this value. 00201 // 00202 00203 ULONG ReferenceCount; 00204 00205 // 00206 // This is the process on whose behalf the structure was allocated. We 00207 // charge any quota to this process. 00208 // 00209 00210 PEPROCESS OwningProcess; 00211 00212 } NOTIFY_CHANGE, *PNOTIFY_CHANGE; 00213 00214 #define NOTIFY_WATCH_TREE (0x0001) 00215 #define NOTIFY_IMMEDIATE_NOTIFY (0x0002) 00216 #define NOTIFY_CLEANUP_CALLED (0x0004) 00217 #define NOTIFY_DEFER_NOTIFY (0x0008) 00218 #define NOTIFY_DIR_IS_ROOT (0x0010) 00219 #define NOTIFY_STREAM_IS_DELETED (0x0020) 00220 00221 // 00222 // CAST 00223 // Add2Ptr ( 00224 // IN PVOID Pointer, 00225 // IN ULONG Increment 00226 // IN (CAST) 00227 // ); 00228 // 00229 // ULONG 00230 // PtrOffset ( 00231 // IN PVOID BasePtr, 00232 // IN PVOID OffsetPtr 00233 // ); 00234 // 00235 00236 #define Add2Ptr(PTR,INC,CAST) ((CAST)((PUCHAR)(PTR) + (INC))) 00237 00238 #define PtrOffset(BASE,OFFSET) ((ULONG)((PCHAR)(OFFSET) - (PCHAR)(BASE))) 00239 00240 // 00241 // VOID 00242 // SetFlag ( 00243 // IN ULONG Flags, 00244 // IN ULONG SingleFlag 00245 // ); 00246 // 00247 // VOID 00248 // ClearFlag ( 00249 // IN ULONG Flags, 00250 // IN ULONG SingleFlag 00251 // ); 00252 // 00253 00254 #define SetFlag(F,SF) { \ 00255 (F) |= (SF); \ 00256 } 00257 00258 #define ClearFlag(F,SF) { \ 00259 (F) &= ~(SF); \ 00260 } 00261 00262 // 00263 // VOID 00264 // AcquireNotifySync ( 00265 // IN PREAL_NOTIFY_SYNC NotifySync 00266 // ); 00267 // 00268 // VOID 00269 // ReleaseNotifySync ( 00270 // IN PREAL_NOTIFY_SYNC NotifySync 00271 // ); 00272 // 00273 00274 #define AcquireNotifySync(NS) { \ 00275 ERESOURCE_THREAD _CurrentThread; \ 00276 _CurrentThread = (ERESOURCE_THREAD) PsGetCurrentThread(); \ 00277 if (_CurrentThread != ((PREAL_NOTIFY_SYNC) (NS))->OwningThread) { \ 00278 ExAcquireFastMutexUnsafe( &((PREAL_NOTIFY_SYNC) (NS))->FastMutex ); \ 00279 ((PREAL_NOTIFY_SYNC) (NS))->OwningThread = _CurrentThread; \ 00280 } \ 00281 ((PREAL_NOTIFY_SYNC) (NS))->OwnerCount += 1; \ 00282 } 00283 00284 #define ReleaseNotifySync(NS) { \ 00285 ((PREAL_NOTIFY_SYNC) (NS))->OwnerCount -= 1; \ 00286 if (((PREAL_NOTIFY_SYNC) (NS))->OwnerCount == 0) { \ 00287 ((PREAL_NOTIFY_SYNC) (NS))->OwningThread = (ERESOURCE_THREAD) 0; \ 00288 ExReleaseFastMutexUnsafe(&((PREAL_NOTIFY_SYNC) (NS))->FastMutex); \ 00289 } \ 00290 } 00291 00292 // 00293 // Define a tag for general pool allocations from this module 00294 // 00295 00296 #undef MODULE_POOL_TAG 00297 #define MODULE_POOL_TAG ('NrSF') 00298 00299 00300 // 00301 // Local support routines 00302 // 00303 00304 PNOTIFY_CHANGE 00305 FsRtlIsNotifyOnList ( 00306 IN PLIST_ENTRY NotifyListHead, 00307 IN PVOID FsContext 00308 ); 00309 00310 VOID 00311 FsRtlNotifyCompleteIrp ( 00312 IN PIRP NotifyIrp, 00313 IN PNOTIFY_CHANGE Notify, 00314 IN ULONG DataLength, 00315 IN NTSTATUS Status, 00316 IN ULONG CheckCancel 00317 ); 00318 00319 BOOLEAN 00320 FsRtlNotifySetCancelRoutine ( 00321 IN PIRP NotifyIrp, 00322 IN PNOTIFY_CHANGE Notify OPTIONAL 00323 ); 00324 00325 BOOLEAN 00326 FsRtlNotifyUpdateBuffer ( 00327 IN PFILE_NOTIFY_INFORMATION NotifyInfo, 00328 IN ULONG FileAction, 00329 IN PSTRING ParentName, 00330 IN PSTRING TargetName, 00331 IN PSTRING StreamName OPTIONAL, 00332 IN BOOLEAN UnicodeName, 00333 IN ULONG SizeOfEntry 00334 ); 00335 00336 VOID 00337 FsRtlNotifyCompleteIrpList ( 00338 IN PNOTIFY_CHANGE Notify, 00339 IN NTSTATUS Status 00340 ); 00341 00342 VOID 00343 FsRtlCancelNotify ( 00344 IN PDEVICE_OBJECT DeviceObject, 00345 IN PIRP ThisIrp 00346 ); 00347 00348 VOID 00349 FsRtlCheckNotifyForDelete ( 00350 IN PLIST_ENTRY NotifyListHead, 00351 IN PVOID FsContext 00352 ); 00353 00354 #ifdef ALLOC_PRAGMA 00355 #pragma alloc_text(PAGE, FsRtlNotifyInitializeSync) 00356 #pragma alloc_text(PAGE, FsRtlNotifyUninitializeSync) 00357 #pragma alloc_text(PAGE, FsRtlNotifyFullChangeDirectory) 00358 #pragma alloc_text(PAGE, FsRtlNotifyFullReportChange) 00359 #pragma alloc_text(PAGE, FsRtlIsNotifyOnList) 00360 #pragma alloc_text(PAGE, FsRtlNotifyChangeDirectory) 00361 #pragma alloc_text(PAGE, FsRtlNotifyCleanup) 00362 #pragma alloc_text(PAGE, FsRtlNotifyCompleteIrp) 00363 #pragma alloc_text(PAGE, FsRtlNotifyReportChange) 00364 #pragma alloc_text(PAGE, FsRtlNotifyUpdateBuffer) 00365 #pragma alloc_text(PAGE, FsRtlCheckNotifyForDelete) 00366 #endif 00367 00368 00369 NTKERNELAPI 00370 VOID 00371 FsRtlNotifyInitializeSync ( 00372 IN PNOTIFY_SYNC *NotifySync 00373 ) 00374 00375 /*++ 00376 00377 Routine Description: 00378 00379 This routine is called to allocate and initialize the synchronization object 00380 for this notify list. 00381 00382 Arguments: 00383 00384 NotifySync - This is the address to store the structure we allocate. 00385 00386 Return Value: 00387 00388 None. 00389 00390 --*/ 00391 00392 { 00393 PREAL_NOTIFY_SYNC RealSync; 00394 00395 PAGED_CODE(); 00396 00397 DebugTrace( +1, Dbg, "FsRtlNotifyInitializeSync: Entered\n", 0 ); 00398 00399 // 00400 // Clear the pointer and then attempt to allocate a non-paged 00401 // structure. 00402 // 00403 00404 *NotifySync = NULL; 00405 00406 RealSync = (PREAL_NOTIFY_SYNC) FsRtlpAllocatePool( NonPagedPool, 00407 sizeof( REAL_NOTIFY_SYNC )); 00408 00409 // 00410 // Initialize the structure. 00411 // 00412 00413 ExInitializeFastMutex( &RealSync->FastMutex ); 00414 RealSync->OwningThread = (ERESOURCE_THREAD) 0; 00415 RealSync->OwnerCount = 0; 00416 00417 *NotifySync = (PNOTIFY_SYNC) RealSync; 00418 00419 DebugTrace( -1, Dbg, "FsRtlNotifyInitializeSync: Exit\n", 0 ); 00420 return; 00421 } 00422 00423 00424 NTKERNELAPI 00425 VOID 00426 FsRtlNotifyUninitializeSync ( 00427 IN PNOTIFY_SYNC *NotifySync 00428 ) 00429 00430 /*++ 00431 00432 Routine Description: 00433 00434 This routine is called to uninitialize the synchronization object 00435 for this notify list. 00436 00437 Arguments: 00438 00439 NotifySync - This is the address containing the pointer to our synchronization 00440 object. 00441 00442 Return Value: 00443 00444 None. 00445 00446 --*/ 00447 00448 { 00449 PAGED_CODE(); 00450 00451 DebugTrace( +1, Dbg, "FsRtlNotifyUninitializeSync: Entered\n", 0 ); 00452 00453 // 00454 // Free the structure if present and clear the pointer. 00455 // 00456 00457 if (*NotifySync != NULL) { 00458 00459 ExFreePool( *NotifySync ); 00460 *NotifySync = NULL; 00461 } 00462 00463 DebugTrace( -1, Dbg, "FsRtlNotifyUninitializeSync: Exit\n", 0 ); 00464 return; 00465 } 00466 00467 00468 VOID 00469 FsRtlNotifyChangeDirectory ( 00470 IN PNOTIFY_SYNC NotifySync, 00471 IN PVOID FsContext, 00472 IN PSTRING FullDirectoryName, 00473 IN PLIST_ENTRY NotifyList, 00474 IN BOOLEAN WatchTree, 00475 IN ULONG CompletionFilter, 00476 IN PIRP NotifyIrp 00477 ) 00478 00479 /*++ 00480 00481 Routine Description: 00482 00483 This routine is called by a file system which has received a NotifyChange 00484 request. This routine checks if there is already a notify structure and 00485 inserts one if not present. With a notify structure in hand, we check 00486 whether we already have a pending notify and report it if so. If there 00487 is no pending notify, we check if this Irp has already been cancelled and 00488 completes it if so. Otherwise we add this to the list of Irps waiting 00489 for notification. 00490 00491 Arguments: 00492 00493 NotifySync - This is the controlling fast mutex for this notify list. 00494 It is stored here so that it can be found for an Irp which is being 00495 cancelled. 00496 00497 FsContext - This is supplied by the file system so that this notify 00498 structure can be uniquely identified. 00499 00500 FullDirectoryName - Points to the full name for the directory associated 00501 with this notify structure. 00502 00503 NotifyList - This is the start of the notify list to add this 00504 structure to. 00505 00506 WatchTree - This indicates whether all subdirectories for this directory 00507 should be watched, or just the directory itself. 00508 00509 CompletionFilter - This provides the mask to determine which operations 00510 will trigger the notify operations. 00511 00512 NotifyIrp - This is the Irp to complete on notify change. 00513 00514 Return Value: 00515 00516 None. 00517 00518 --*/ 00519 00520 { 00521 PAGED_CODE(); 00522 00523 DebugTrace( +1, Dbg, "FsRtlNotifyChangeDirectory: Entered\n", 0 ); 00524 00525 // 00526 // We will simply call the full notify routine to do the real work. 00527 // 00528 00529 FsRtlNotifyFullChangeDirectory( NotifySync, 00530 NotifyList, 00531 FsContext, 00532 FullDirectoryName, 00533 WatchTree, 00534 TRUE, 00535 CompletionFilter, 00536 NotifyIrp, 00537 NULL, 00538 NULL ); 00539 00540 DebugTrace( -1, Dbg, "FsRtlNotifyChangeDirectory: Exit\n", 0 ); 00541 00542 return; 00543 } 00544 00545 00546 VOID 00547 FsRtlNotifyFullChangeDirectory ( 00548 IN PNOTIFY_SYNC NotifySync, 00549 IN PLIST_ENTRY NotifyList, 00550 IN PVOID FsContext, 00551 IN PSTRING FullDirectoryName, 00552 IN BOOLEAN WatchTree, 00553 IN BOOLEAN IgnoreBuffer, 00554 IN ULONG CompletionFilter, 00555 IN PIRP NotifyIrp, 00556 IN PCHECK_FOR_TRAVERSE_ACCESS TraverseCallback OPTIONAL, 00557 IN PSECURITY_SUBJECT_CONTEXT SubjectContext OPTIONAL 00558 ) 00559 00560 /*++ 00561 00562 Routine Description: 00563 00564 This routine is called by a file system which has received a NotifyChange 00565 request. This routine checks if there is already a notify structure and 00566 inserts one if not present. With a notify structure in hand, we check 00567 whether we already have a pending notify and report it if so. If there 00568 is no pending notify, we check if this Irp has already been cancelled and 00569 completes it if so. Otherwise we add this to the list of Irps waiting 00570 for notification. 00571 00572 This is the version of this routine which understands about the user's 00573 buffer and will fill it in on a reported change. 00574 00575 Arguments: 00576 00577 NotifySync - This is the controlling fast mutex for this notify list. 00578 It is stored here so that it can be found for an Irp which is being 00579 cancelled. 00580 00581 NotifyList - This is the start of the notify list to add this 00582 structure to. 00583 00584 FsContext - This is supplied by the file system so that this notify 00585 structure can be uniquely identified. If the NotifyIrp is not specified 00586 then this is used to identify the stream and it will match the FsContext 00587 field in the file object of a stream being deleted. 00588 00589 FullDirectoryName - Points to the full name for the directory associated 00590 with this notify structure. Ignored if the NotifyIrp is not specified. 00591 00592 WatchTree - This indicates whether all subdirectories for this directory 00593 should be watched, or just the directory itself. Ignored if the 00594 NotifyIrp is not specified. 00595 00596 IgnoreBuffer - Indicates whether we will always ignore any user buffer 00597 and force the directory to be reenumerated. This will speed up the 00598 operation. Ignored if the NotifyIrp is not specified. 00599 00600 CompletionFilter - This provides the mask to determine which operations 00601 will trigger the notify operations. Ignored if the NotifyIrp is not 00602 specified. 00603 00604 NotifyIrp - This is the Irp to complete on notify change. If this irp is 00605 not specified it means that the stream represented by this file object 00606 is being deleted. 00607 00608 TraverseCallback - If specified we must call this routine when a change 00609 has occurred in a subdirectory being watched in a tree. This will 00610 let the filesystem check if the watcher has traverse access to that 00611 directory. Ignored if the NotifyIrp is not specified. 00612 00613 SubjectContext - If there is a traverse callback routine then we will 00614 pass this subject context as a parameter to the call. We will release 00615 the context and free the structure when done with it. Ignored if the 00616 NotifyIrp is not specified. 00617 00618 Return Value: 00619 00620 None. 00621 00622 --*/ 00623 00624 { 00625 PNOTIFY_CHANGE Notify; 00626 PIO_STACK_LOCATION IrpSp; 00627 00628 PAGED_CODE(); 00629 00630 DebugTrace( +1, Dbg, "FsRtlNotifyFullChangeDirectory: Entered\n", 0 ); 00631 00632 // 00633 // Acquire exclusive access to the list by acquiring the mutex. 00634 // 00635 00636 AcquireNotifySync( NotifySync ); 00637 00638 // 00639 // Use a try-finally to facilitate cleanup. 00640 // 00641 00642 try { 00643 00644 // 00645 // If there is no Irp then find all of the pending Irps whose file objects 00646 // refer to the same stream and complete them with STATUS_DELETE_PENDING. 00647 // 00648 00649 if (NotifyIrp == NULL) { 00650 00651 FsRtlCheckNotifyForDelete( NotifyList, FsContext ); 00652 try_return( NOTHING ); 00653 } 00654 00655 // 00656 // Get the current Stack location 00657 // 00658 00659 IrpSp = IoGetCurrentIrpStackLocation( NotifyIrp ); 00660 00661 // 00662 // Clear the Iosb in the Irp. 00663 // 00664 00665 NotifyIrp->IoStatus.Status = STATUS_SUCCESS; 00666 NotifyIrp->IoStatus.Information = 0; 00667 00668 // 00669 // If the file object has already gone through cleanup, then complete 00670 // the request immediately. 00671 // 00672 00673 if (FlagOn( IrpSp->FileObject->Flags, FO_CLEANUP_COMPLETE )) { 00674 00675 // 00676 // Always mark this Irp as pending returned. 00677 // 00678 00679 IoMarkIrpPending( NotifyIrp ); 00680 00681 FsRtlCompleteRequest( NotifyIrp, STATUS_NOTIFY_CLEANUP ); 00682 try_return( NOTHING ); 00683 } 00684 00685 // 00686 // If the notify structure is not already in the list, add it 00687 // now. 00688 // 00689 00690 Notify = FsRtlIsNotifyOnList( NotifyList, FsContext ); 00691 00692 if (Notify == NULL) { 00693 00694 // 00695 // Allocate and initialize the structure. 00696 // 00697 00698 Notify = FsRtlpAllocatePool( PagedPool, sizeof( NOTIFY_CHANGE )); 00699 RtlZeroMemory( Notify, sizeof( NOTIFY_CHANGE )); 00700 00701 Notify->NotifySync = (PREAL_NOTIFY_SYNC) NotifySync; 00702 Notify->FsContext = FsContext; 00703 Notify->StreamID = IrpSp->FileObject->FsContext; 00704 00705 Notify->TraverseCallback = TraverseCallback; 00706 Notify->SubjectContext = SubjectContext; 00707 SubjectContext = NULL; 00708 00709 Notify->FullDirectoryName = FullDirectoryName; 00710 00711 InitializeListHead( &Notify->NotifyIrps ); 00712 00713 if (WatchTree) { 00714 00715 SetFlag( Notify->Flags, NOTIFY_WATCH_TREE ); 00716 } 00717 00718 if (FullDirectoryName == NULL) { 00719 00720 // 00721 // In the view index we aren't using this buffer to hold a 00722 // unicode string. 00723 // 00724 00725 Notify->CharacterSize = sizeof( CHAR ); 00726 00727 } else { 00728 00729 // 00730 // We look at the directory name to decide if we have a unicode 00731 // name. 00732 // 00733 00734 if (FullDirectoryName->Length >= 2 00735 && FullDirectoryName->Buffer[1] == '\0') { 00736 00737 Notify->CharacterSize = sizeof( WCHAR ); 00738 00739 } else { 00740 00741 Notify->CharacterSize = sizeof( CHAR ); 00742 } 00743 00744 if (FullDirectoryName->Length == Notify->CharacterSize) { 00745 00746 SetFlag( Notify->Flags, NOTIFY_DIR_IS_ROOT ); 00747 } 00748 } 00749 00750 Notify->CompletionFilter = CompletionFilter; 00751 00752 // 00753 // If we are to return data to the user then look for the length 00754 // of the original buffer in the IrpSp. 00755 // 00756 00757 if (!IgnoreBuffer) { 00758 00759 Notify->BufferLength = IrpSp->Parameters.NotifyDirectory.Length; 00760 } 00761 00762 Notify->OwningProcess = THREAD_TO_PROCESS( NotifyIrp->Tail.Overlay.Thread ); 00763 InsertTailList( NotifyList, &Notify->NotifyList ); 00764 00765 Notify->ReferenceCount = 1; 00766 00767 // 00768 // If we have already been called with cleanup then complete 00769 // the request immediately. 00770 // 00771 00772 } else if (FlagOn( Notify->Flags, NOTIFY_CLEANUP_CALLED )) { 00773 00774 // 00775 // Always mark this Irp as pending returned. 00776 // 00777 00778 IoMarkIrpPending( NotifyIrp ); 00779 00780 FsRtlCompleteRequest( NotifyIrp, STATUS_NOTIFY_CLEANUP ); 00781 try_return( NOTHING ); 00782 00783 // 00784 // If this file has been deleted then complete with STATUS_DELETE_PENDING. 00785 // 00786 00787 } else if (FlagOn( Notify->Flags, NOTIFY_STREAM_IS_DELETED )) { 00788 00789 // 00790 // Always mark this Irp as pending returned. 00791 // 00792 00793 IoMarkIrpPending( NotifyIrp ); 00794 00795 FsRtlCompleteRequest( NotifyIrp, STATUS_DELETE_PENDING ); 00796 try_return( NOTHING ); 00797 00798 // 00799 // If the notify pending flag is set or there is data in an internal buffer 00800 // we complete this Irp immediately and exit. 00801 // 00802 00803 } else if (FlagOn( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ) 00804 && !FlagOn( Notify->Flags, NOTIFY_DEFER_NOTIFY )) { 00805 00806 DebugTrace( 0, Dbg, "Notify has been pending\n", 0 ); 00807 00808 // 00809 // Clear the flag in our notify structure before completing the 00810 // Irp. This will prevent a caller who reposts in his completion 00811 // routine from looping in the completion routine. 00812 // 00813 00814 ClearFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 00815 00816 // 00817 // Always mark this Irp as pending returned. 00818 // 00819 00820 IoMarkIrpPending( NotifyIrp ); 00821 00822 FsRtlCompleteRequest( NotifyIrp, STATUS_NOTIFY_ENUM_DIR ); 00823 try_return( NOTHING ); 00824 00825 } else if (Notify->DataLength != 0 00826 && !FlagOn( Notify->Flags, NOTIFY_DEFER_NOTIFY )) { 00827 00828 ULONG ThisDataLength = Notify->DataLength; 00829 00830 // 00831 // Now set our buffer pointers back to indicate an empty buffer. 00832 // 00833 00834 Notify->DataLength = 0; 00835 Notify->LastEntry = 0; 00836 00837 FsRtlNotifyCompleteIrp( NotifyIrp, 00838 Notify, 00839 ThisDataLength, 00840 STATUS_SUCCESS, 00841 FALSE ); 00842 00843 try_return( NOTHING ); 00844 } 00845 00846 // 00847 // Add the Irp to the tail of the notify queue. 00848 // 00849 00850 NotifyIrp->IoStatus.Information = (ULONG_PTR) Notify; 00851 IoMarkIrpPending( NotifyIrp ); 00852 InsertTailList( &Notify->NotifyIrps, &NotifyIrp->Tail.Overlay.ListEntry ); 00853 00854 // 00855 // Increment the reference count to indicate that Irp might go through cancel. 00856 // 00857 00858 InterlockedIncrement( &Notify->ReferenceCount ); 00859 00860 // 00861 // Call the routine to set the cancel routine. 00862 // 00863 00864 FsRtlNotifySetCancelRoutine( NotifyIrp, NULL ); 00865 00866 try_exit: NOTHING; 00867 } finally { 00868 00869 // 00870 // Release the mutex. 00871 // 00872 00873 ReleaseNotifySync( NotifySync ); 00874 00875 // 00876 // If there is still a subject context then release it and deallocate 00877 // the structure. Remember that if FullDirectoryName is null, it means 00878 // this is a view index, not a directory index, and the SubjectContext 00879 // is really a piece of file system context information. 00880 // 00881 00882 if ((SubjectContext != NULL) && 00883 (Notify->FullDirectoryName != NULL)) { 00884 00885 SeReleaseSubjectContext( SubjectContext ); 00886 ExFreePool( SubjectContext ); 00887 } 00888 00889 DebugTrace( -1, Dbg, "FsRtlNotifyFullChangeDirectory: Exit\n", 0 ); 00890 } 00891 00892 return; 00893 } 00894 00895 00896 VOID 00897 FsRtlNotifyReportChange ( 00898 IN PNOTIFY_SYNC NotifySync, 00899 IN PLIST_ENTRY NotifyList, 00900 IN PSTRING FullTargetName, 00901 IN PSTRING TargetName, 00902 IN ULONG FilterMatch 00903 ) 00904 00905 /*++ 00906 00907 Routine Description: 00908 00909 This routine is called by a file system when a file has been modified in 00910 such a way that it will cause a notify change Irp to complete. We walk 00911 through all the notify structures looking for those structures which 00912 would be associated with an ancestor directory of the target file name. 00913 00914 We look for all the notify structures which have a filter match and 00915 then check that the directory name in the notify structure is a 00916 proper prefix of the full target name. 00917 00918 If we find a notify structure which matches the above conditions, we 00919 complete all the Irps for the notify structure. If the structure has 00920 no Irps, we mark the notify pending field. 00921 00922 Arguments: 00923 00924 NotifySync - This is the controlling fast mutex for this notify list. 00925 It is stored here so that it can be found for an Irp which is being 00926 cancelled. 00927 00928 NotifyList - This is the start of the notify list to add this 00929 structure to. 00930 00931 FullTargetName - This is the full name of the file which has been 00932 changed. 00933 00934 TargetName - This is the final component of the modified file. 00935 00936 FilterMatch - This flag field is compared with the completion filter 00937 in the notify structure. If any of the corresponding 00938 bits in the completion filter are set, then a notify 00939 condition exists. 00940 00941 Return Value: 00942 00943 None. 00944 00945 --*/ 00946 00947 { 00948 PAGED_CODE(); 00949 00950 DebugTrace( +1, Dbg, "FsRtlNotifyReportChange: Entered\n", 0 ); 00951 00952 // 00953 // Call the full notify routine to do the actual work. 00954 // 00955 00956 FsRtlNotifyFullReportChange( NotifySync, 00957 NotifyList, 00958 FullTargetName, 00959 (USHORT) (FullTargetName->Length - TargetName->Length), 00960 NULL, 00961 NULL, 00962 FilterMatch, 00963 0, 00964 NULL ); 00965 00966 DebugTrace( -1, Dbg, "FsRtlNotifyReportChange: Exit\n", 0 ); 00967 00968 return; 00969 } 00970 00971 00972 VOID 00973 FsRtlNotifyFullReportChange ( 00974 IN PNOTIFY_SYNC NotifySync, 00975 IN PLIST_ENTRY NotifyList, 00976 IN PSTRING FullTargetName, 00977 IN USHORT TargetNameOffset, 00978 IN PSTRING StreamName OPTIONAL, 00979 IN PSTRING NormalizedParentName OPTIONAL, 00980 IN ULONG FilterMatch, 00981 IN ULONG Action, 00982 IN PVOID TargetContext 00983 ) 00984 00985 /*++ 00986 00987 Routine Description: 00988 00989 This routine is called by a file system when a file has been modified in 00990 such a way that it will cause a notify change Irp to complete. We walk 00991 through all the notify structures looking for those structures which 00992 would be associated with an ancestor directory of the target file name. 00993 00994 We look for all the notify structures which have a filter match and 00995 then check that the directory name in the notify structure is a 00996 proper prefix of the full target name. 00997 00998 If we find a notify structure which matches the above conditions, we 00999 complete all the Irps for the notify structure. If the structure has 01000 no Irps, we mark the notify pending field. 01001 01002 Arguments: 01003 01004 NotifySync - This is the controlling fast mutex for this notify list. 01005 It is stored here so that it can be found for an Irp which is being 01006 cancelled. 01007 01008 NotifyList - This is the start of the notify list to add this 01009 structure to. 01010 01011 FullTargetName - This is the full name of the file from the root of the volume. 01012 01013 TargetNameOffset - This is the offset in the full name of the final component 01014 of the name. 01015 01016 StreamName - If present then this is the stream name to store with 01017 the filename. 01018 01019 NormalizedParentName - If present this is the same path as the parent name 01020 but the DOS-ONLY names have been replaced with the associated long name. 01021 01022 FilterMatch - This flag field is compared with the completion filter 01023 in the notify structure. If any of the corresponding bits in the 01024 completion filter are set, then a notify condition exists. 01025 01026 Action - This is the action code to store in the user's buffer if 01027 present. 01028 01029 TargetContext - This is one of the context pointers to pass to the file 01030 system if performing a traverse check in the case of a tree being 01031 watched. 01032 01033 Return Value: 01034 01035 None. 01036 01037 --*/ 01038 01039 { 01040 PLIST_ENTRY NotifyLinks; 01041 01042 STRING NormalizedParent; 01043 STRING ParentName; 01044 STRING TargetName; 01045 01046 PNOTIFY_CHANGE Notify; 01047 STRING TargetParent; 01048 PIRP NotifyIrp; 01049 01050 BOOLEAN NotifyIsParent; 01051 BOOLEAN ViewIndex = FALSE; 01052 UCHAR ComponentCount; 01053 ULONG SizeOfEntry; 01054 ULONG CurrentOffset; 01055 ULONG NextEntryOffset; 01056 ULONG ExceptionCode; 01057 01058 PAGED_CODE(); 01059 01060 DebugTrace( +1, Dbg, "FsRtlNotifyFullReportChange: Entered\n", 0 ); 01061 01062 // 01063 // If this is a change to the root directory then return immediately. 01064 // 01065 01066 if ((TargetNameOffset == 0) && (FullTargetName != NULL)) { 01067 01068 DebugTrace( -1, Dbg, "FsRtlNotifyFullReportChange: Exit\n", 0 ); 01069 return; 01070 } 01071 01072 ParentName.Buffer = NULL; 01073 TargetName.Buffer = NULL; 01074 01075 // 01076 // Acquire exclusive access to the list by acquiring the mutex. 01077 // 01078 01079 AcquireNotifySync( NotifySync ); 01080 01081 // 01082 // Use a try-finally to facilitate cleanup. 01083 // 01084 01085 try { 01086 01087 // 01088 // Walk through all the notify blocks. 01089 // 01090 01091 for (NotifyLinks = NotifyList->Flink; 01092 NotifyLinks != NotifyList; 01093 NotifyLinks = NotifyLinks->Flink) { 01094 01095 // 01096 // Obtain the Notify structure from the list entry. 01097 // 01098 01099 Notify = CONTAINING_RECORD( NotifyLinks, NOTIFY_CHANGE, NotifyList ); 01100 01101 // 01102 // The rules for deciding whether this notification applies are 01103 // different for view indices versus file name indices (directories). 01104 // 01105 01106 if (FullTargetName == NULL) { 01107 01108 ASSERTMSG( "Directory notify handle in view index notify list!", Notify->FullDirectoryName == NULL); 01109 01110 // 01111 // Make sure this is the Fcb being watched. 01112 // 01113 01114 if (TargetContext != Notify->SubjectContext) { 01115 01116 continue; 01117 } 01118 01119 TargetParent.Buffer = NULL; 01120 TargetParent.Length = 0; 01121 01122 ViewIndex = TRUE; 01123 01124 // 01125 // Handle the directory case. 01126 // 01127 01128 } else { 01129 01130 ASSERTMSG( "View index notify handle in directory notify list!", Notify->FullDirectoryName != NULL); 01131 01132 // 01133 // If the length of the name in the notify block is currently zero then 01134 // someone is doing a rename and we can skip this block. 01135 // 01136 01137 if (Notify->FullDirectoryName->Length == 0) { 01138 01139 continue; 01140 } 01141 01142 // 01143 // If this filter match is not part of the completion filter then continue. 01144 // 01145 01146 if (!(FilterMatch & Notify->CompletionFilter)) { 01147 01148 continue; 01149 } 01150 01151 // 01152 // If there is no normalized name then set its value from the full 01153 // file name. 01154 // 01155 01156 if (!ARGUMENT_PRESENT( NormalizedParentName )) { 01157 NormalizedParent.Buffer = FullTargetName->Buffer; 01158 NormalizedParent.Length = TargetNameOffset; 01159 01160 if (NormalizedParent.Length != Notify->CharacterSize) { 01161 01162 NormalizedParent.Length -= Notify->CharacterSize; 01163 } 01164 01165 NormalizedParent.MaximumLength = NormalizedParent.Length; 01166 01167 NormalizedParentName = &NormalizedParent; 01168 } 01169 01170 // 01171 // If the length of the directory being watched is longer than the 01172 // parent of the modified file then it can't be an ancestor of the 01173 // modified file. 01174 // 01175 01176 if (Notify->FullDirectoryName->Length > NormalizedParentName->Length) { 01177 01178 continue; 01179 } 01180 01181 // 01182 // If the lengths match exactly then this can only be the parent of 01183 // the modified file. 01184 // 01185 01186 if (NormalizedParentName->Length == Notify->FullDirectoryName->Length) { 01187 01188 NotifyIsParent = TRUE; 01189 01190 // 01191 // If we are not watching the subtree of this directory then continue. 01192 // 01193 01194 } else if (!FlagOn( Notify->Flags, NOTIFY_WATCH_TREE )) { 01195 01196 continue; 01197 01198 // 01199 // The watched directory can only be an ancestor of the modified 01200 // file. Make sure that there is legal pathname separator immediately 01201 // after the end of the watched directory name within the normalized name. 01202 // If the watched directory is the root then we know this condition is TRUE. 01203 // 01204 01205 } else { 01206 01207 if (!FlagOn( Notify->Flags, NOTIFY_DIR_IS_ROOT )) { 01208 01209 // 01210 // Check for the character size. 01211 // 01212 01213 if (Notify->CharacterSize == sizeof( CHAR )) { 01214 01215 if (*(Add2Ptr( NormalizedParentName->Buffer, 01216 Notify->FullDirectoryName->Length, 01217 PCHAR )) != '\\') { 01218 01219 continue; 01220 } 01221 01222 } else if (*(Add2Ptr( NormalizedParentName->Buffer, 01223 Notify->FullDirectoryName->Length, 01224 PWCHAR )) != L'\\') { 01225 01226 continue; 01227 } 01228 } 01229 01230 NotifyIsParent = FALSE; 01231 } 01232 01233 // 01234 // We now have a correct match of the name lengths. Now verify that the 01235 // characters match exactly. 01236 // 01237 01238 if (!RtlEqualMemory( Notify->FullDirectoryName->Buffer, 01239 NormalizedParentName->Buffer, 01240 Notify->FullDirectoryName->Length )) { 01241 01242 continue; 01243 } 01244 01245 // 01246 // The characters are correct. Now check in the case of a non-parent 01247 // notify that we have traverse callback. 01248 // 01249 01250 if (!NotifyIsParent && 01251 Notify->TraverseCallback != NULL && 01252 !Notify->TraverseCallback( Notify->FsContext, 01253 TargetContext, 01254 Notify->SubjectContext )) { 01255 01256 continue; 01257 } 01258 } 01259 01260 // 01261 // If this entry is going into a buffer then check that 01262 // it will fit. 01263 // 01264 01265 if (!FlagOn( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ) 01266 && Notify->BufferLength != 0) { 01267 01268 ULONG AllocationLength; 01269 01270 AllocationLength = 0; 01271 NotifyIrp = NULL; 01272 01273 // 01274 // If we don't already have a buffer then check to see 01275 // if we have any Irps in the list and use the buffer 01276 // length in the Irp. 01277 // 01278 01279 if (Notify->ThisBufferLength == 0) { 01280 01281 // 01282 // If there is an entry in the list then get the length. 01283 // 01284 01285 if (!IsListEmpty( &Notify->NotifyIrps )) { 01286 01287 PIO_STACK_LOCATION IrpSp; 01288 01289 NotifyIrp = CONTAINING_RECORD( Notify->NotifyIrps.Flink, 01290 IRP, 01291 Tail.Overlay.ListEntry ); 01292 01293 IrpSp = IoGetCurrentIrpStackLocation( NotifyIrp ); 01294 01295 AllocationLength = IrpSp->Parameters.NotifyDirectory.Length; 01296 01297 // 01298 // Otherwise use the caller's last buffer size. 01299 // 01300 01301 } else { 01302 01303 AllocationLength = Notify->BufferLength; 01304 } 01305 01306 // 01307 // Otherwise use the length of the current buffer. 01308 // 01309 01310 } else { 01311 01312 AllocationLength = Notify->ThisBufferLength; 01313 } 01314 01315 // 01316 // Build the strings for the relative name. This includes 01317 // the strings for the parent name, file name and stream 01318 // name. 01319 // 01320 01321 if (!NotifyIsParent) { 01322 01323 // 01324 // We need to find the string for the ancestor of this 01325 // file from the watched directory. If the normalized parent 01326 // name is the same as the parent name then we can use 01327 // the tail of the parent directly. Otherwise we need to 01328 // count the matching name components and capture the 01329 // final components. 01330 // 01331 01332 if (!ViewIndex) { 01333 01334 // 01335 // If the watched directory is the root then we just use the full 01336 // parent name. 01337 // 01338 01339 if (FlagOn( Notify->Flags, NOTIFY_DIR_IS_ROOT ) || 01340 NormalizedParentName->Buffer != FullTargetName->Buffer) { 01341 01342 // 01343 // If we don't have a string for the parent then construct 01344 // it now. 01345 // 01346 01347 if (ParentName.Buffer == NULL) { 01348 01349 ParentName.Buffer = FullTargetName->Buffer; 01350 ParentName.Length = TargetNameOffset; 01351 01352 if (ParentName.Length != Notify->CharacterSize) { 01353 01354 ParentName.Length -= Notify->CharacterSize; 01355 } 01356 01357 ParentName.MaximumLength = ParentName.Length; 01358 } 01359 01360 // 01361 // Count through the components of the parent until we have 01362 // swallowed the same number of name components as in the 01363 // watched directory name. We have the unicode version and 01364 // the Ansi version to watch for. 01365 // 01366 01367 ComponentCount = 0; 01368 CurrentOffset = 0; 01369 01370 // 01371 // If this is the root then there is no more to do. 01372 // 01373 01374 if (FlagOn( Notify->Flags, NOTIFY_DIR_IS_ROOT )) { 01375 01376 NOTHING; 01377 01378 } else { 01379 01380 ULONG ParentComponentCount; 01381 ULONG ParentOffset; 01382 01383 ParentComponentCount = 1; 01384 ParentOffset = 0; 01385 01386 if (Notify->CharacterSize == sizeof( CHAR )) { 01387 01388 // 01389 // Find the number of components in the parent. We 01390 // have to do this for each one because this name and 01391 // the number of components could have changed. 01392 // 01393 01394 while (ParentOffset < Notify->FullDirectoryName->Length) { 01395 01396 if (*((PCHAR) Notify->FullDirectoryName->Buffer + ParentOffset) == '\\') { 01397 01398 ParentComponentCount += 1; 01399 } 01400 01401 ParentOffset += 1; 01402 } 01403 01404 while (TRUE) { 01405 01406 if (*((PCHAR) ParentName.Buffer + CurrentOffset) == '\\') { 01407 01408 ComponentCount += 1; 01409 01410 if (ComponentCount == ParentComponentCount) { 01411 01412 break; 01413 } 01414 01415 } 01416 01417 CurrentOffset += 1; 01418 } 01419 01420 } else { 01421 01422 // 01423 // Find the number of components in the parent. We 01424 // have to do this for each one because this name and 01425 // the number of components could have changed. 01426 // 01427 01428 while (ParentOffset < Notify->FullDirectoryName->Length / sizeof( WCHAR )) { 01429 01430 if (*((PWCHAR) Notify->FullDirectoryName->Buffer + ParentOffset) == '\\') { 01431 01432 ParentComponentCount += 1; 01433 } 01434 01435 ParentOffset += 1; 01436 } 01437 01438 while (TRUE) { 01439 01440 if (*((PWCHAR) ParentName.Buffer + CurrentOffset) == L'\\') { 01441 01442 ComponentCount += 1; 01443 01444 if (ComponentCount == ParentComponentCount) { 01445 01446 break; 01447 } 01448 } 01449 01450 CurrentOffset += 1; 01451 } 01452 01453 // 01454 // Convert characters to bytes. 01455 // 01456 01457 CurrentOffset *= Notify->CharacterSize; 01458 } 01459 } 01460 01461 // 01462 // We now know the offset into the parent name of the separator 01463 // immediately preceding the relative parent name. Construct the 01464 // target parent name for the buffer. 01465 // 01466 01467 CurrentOffset += Notify->CharacterSize; 01468 01469 TargetParent.Buffer = Add2Ptr( ParentName.Buffer, 01470 CurrentOffset, 01471 PCHAR ); 01472 TargetParent.MaximumLength = 01473 TargetParent.Length = ParentName.Length - (USHORT) CurrentOffset; 01474 01475 // 01476 // If the normalized is the same as the parent name use the portion 01477 // after the match with the watched directory. 01478 // 01479 01480 } else { 01481 01482 TargetParent.Buffer = Add2Ptr( NormalizedParentName->Buffer, 01483 (Notify->FullDirectoryName->Length + 01484 Notify->CharacterSize), 01485 PCHAR ); 01486 01487 TargetParent.MaximumLength = 01488 TargetParent.Length = NormalizedParentName->Length - 01489 Notify->FullDirectoryName->Length - 01490 Notify->CharacterSize; 01491 01492 } 01493 } 01494 01495 } else { 01496 01497 // 01498 // The length of the target parent is zero. 01499 // 01500 01501 TargetParent.Length = 0; 01502 } 01503 01504 // 01505 // Compute how much buffer space this report will take. 01506 // 01507 01508 SizeOfEntry = FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileName ); 01509 01510 if (ViewIndex) { 01511 01512 // 01513 // In the view index case, the information to copy to the 01514 // buffer comes to us in the stream name, and that is all 01515 // the room we need to worry about having. 01516 // 01517 01518 ASSERT(ARGUMENT_PRESENT( StreamName )); 01519 01520 SizeOfEntry += StreamName->Length; 01521 01522 } else { 01523 01524 // 01525 // If there is a parent to report, find the size and include a separator 01526 // character. 01527 // 01528 01529 if (!NotifyIsParent) { 01530 01531 if (Notify->CharacterSize == sizeof( CHAR )) { 01532 01533 SizeOfEntry += RtlOemStringToCountedUnicodeSize( &TargetParent ); 01534 01535 } else { 01536 01537 SizeOfEntry += TargetParent.Length; 01538 } 01539 01540 // 01541 // Include the separator. This is always a unicode character. 01542 // 01543 01544 SizeOfEntry += sizeof( WCHAR ); 01545 } 01546 01547 // 01548 // If we don't have the string for the target then construct it now. 01549 // 01550 01551 if (TargetName.Buffer == NULL) { 01552 01553 TargetName.Buffer = Add2Ptr( FullTargetName->Buffer, TargetNameOffset, PCHAR ); 01554 TargetName.MaximumLength = 01555 TargetName.Length = FullTargetName->Length - TargetNameOffset; 01556 } 01557 01558 if (Notify->CharacterSize == sizeof( CHAR )) { 01559 01560 SizeOfEntry += RtlOemStringToCountedUnicodeSize( &TargetName ); 01561 01562 } else { 01563 01564 SizeOfEntry += TargetName.Length; 01565 } 01566 01567 // 01568 // If there is a stream name then add the bytes needed 01569 // for that. 01570 // 01571 01572 if (ARGUMENT_PRESENT( StreamName )) { 01573 01574 // 01575 // Add the space needed for the ':' separator. 01576 // 01577 01578 if (Notify->CharacterSize == sizeof( WCHAR )) { 01579 01580 SizeOfEntry += (StreamName->Length + sizeof( WCHAR )); 01581 01582 } else { 01583 01584 SizeOfEntry += (RtlOemStringToCountedUnicodeSize( StreamName ) 01585 + sizeof( CHAR )); 01586 } 01587 } 01588 } 01589 01590 // 01591 // Remember if this report would overflow the buffer. 01592 // 01593 01594 NextEntryOffset = (ULONG)LongAlign( Notify->DataLength ); 01595 01596 if (SizeOfEntry <= AllocationLength 01597 && (NextEntryOffset + SizeOfEntry) <= AllocationLength) { 01598 01599 PFILE_NOTIFY_INFORMATION NotifyInfo = NULL; 01600 01601 // 01602 // If there is already a notify buffer, we append this 01603 // data to it. 01604 // 01605 01606 if (Notify->Buffer != NULL) { 01607 01608 NotifyInfo = Add2Ptr( Notify->Buffer, 01609 Notify->LastEntry, 01610 PFILE_NOTIFY_INFORMATION ); 01611 01612 NotifyInfo->NextEntryOffset = NextEntryOffset - Notify->LastEntry; 01613 01614 Notify->LastEntry = NextEntryOffset; 01615 01616 NotifyInfo = Add2Ptr( Notify->Buffer, 01617 Notify->LastEntry, 01618 PFILE_NOTIFY_INFORMATION ); 01619 01620 // 01621 // If there is an Irp list we check whether we will need 01622 // to allocate a new buffer. 01623 // 01624 01625 } else if (NotifyIrp != NULL) { 01626 01627 if (NotifyIrp->AssociatedIrp.SystemBuffer != NULL) { 01628 01629 Notify->Buffer = 01630 NotifyInfo = NotifyIrp->AssociatedIrp.SystemBuffer; 01631 01632 Notify->ThisBufferLength = AllocationLength; 01633 01634 } else if (NotifyIrp->MdlAddress != NULL) { 01635 01636 Notify->Buffer = 01637 NotifyInfo = MmGetSystemAddressForMdl( NotifyIrp->MdlAddress ); 01638 01639 Notify->ThisBufferLength = AllocationLength; 01640 } 01641 } 01642 01643 // 01644 // If we need to allocate a buffer, we will charge quota 01645 // to the original process and allocate paged pool. 01646 // 01647 01648 if (Notify->Buffer == NULL) { 01649 01650 BOOLEAN ChargedQuota = FALSE; 01651 01652 try { 01653 01654 PsChargePoolQuota( Notify->OwningProcess, 01655 PagedPool, 01656 AllocationLength ); 01657 01658 ChargedQuota = TRUE; 01659 01660 Notify->AllocatedBuffer = 01661 Notify->Buffer = FsRtlpAllocatePool( PagedPool, 01662 AllocationLength ); 01663 01664 Notify->ThisBufferLength = AllocationLength; 01665 01666 NotifyInfo = Notify->Buffer; 01667 01668 } except(( ExceptionCode = GetExceptionCode(), FsRtlIsNtstatusExpected(ExceptionCode)) 01669 ? EXCEPTION_EXECUTE_HANDLER 01670 : EXCEPTION_CONTINUE_SEARCH ) { 01671 01672 01673 ASSERT( (ExceptionCode == STATUS_INSUFFICIENT_RESOURCES) || 01674 (ExceptionCode == STATUS_QUOTA_EXCEEDED) ); 01675 01676 // 01677 // Return quota if we allocated the buffer. 01678 // 01679 01680 if (ChargedQuota) { 01681 01682 PsReturnPoolQuota( Notify->OwningProcess, 01683 PagedPool, 01684 AllocationLength ); 01685 01686 } 01687 01688 // 01689 // Forget any current buffer and resort to immediate 01690 // notify. 01691 // 01692 01693 SetFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 01694 } 01695 } 01696 01697 // 01698 // If we have a buffer then fill in the results 01699 // from this operation. Otherwise we remember 01700 // to simply alert the caller. 01701 // 01702 01703 if (NotifyInfo != NULL) { 01704 01705 // 01706 // Update the buffer with the current data. 01707 // 01708 01709 if (FsRtlNotifyUpdateBuffer( NotifyInfo, 01710 Action, 01711 &TargetParent, 01712 &TargetName, 01713 StreamName, 01714 (BOOLEAN) (Notify->CharacterSize == sizeof( WCHAR )), 01715 SizeOfEntry )) { 01716 01717 // 01718 // Update the buffer data length. 01719 // 01720 01721 Notify->DataLength = NextEntryOffset + SizeOfEntry; 01722 01723 // 01724 // We couldn't copy the data into the buffer. Just 01725 // notify without any additional information. 01726 // 01727 01728 } else { 01729 01730 SetFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 01731 } 01732 } 01733 01734 } else { 01735 01736 SetFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 01737 } 01738 01739 // 01740 // If we have a buffer but can't use it then clear all of the 01741 // buffer related fields. Also deallocate any buffer allocated 01742 // by us. 01743 // 01744 01745 if (FlagOn( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ) 01746 && Notify->Buffer != NULL) { 01747 01748 if (Notify->AllocatedBuffer != NULL) { 01749 01750 PsReturnPoolQuota( Notify->OwningProcess, 01751 PagedPool, 01752 Notify->ThisBufferLength ); 01753 01754 ExFreePool( Notify->AllocatedBuffer ); 01755 } 01756 01757 Notify->AllocatedBuffer = Notify->Buffer = NULL; 01758 01759 Notify->ThisBufferLength = Notify->DataLength = Notify->LastEntry = 0; 01760 } 01761 } 01762 01763 // 01764 // Complete the next entry on the list if we aren't holding 01765 // up notification. 01766 // 01767 01768 if (Action == FILE_ACTION_RENAMED_OLD_NAME) { 01769 01770 SetFlag( Notify->Flags, NOTIFY_DEFER_NOTIFY ); 01771 01772 } else { 01773 01774 ClearFlag( Notify->Flags, NOTIFY_DEFER_NOTIFY ); 01775 01776 if (!IsListEmpty( &Notify->NotifyIrps )) { 01777 01778 FsRtlNotifyCompleteIrpList( Notify, STATUS_SUCCESS ); 01779 } 01780 } 01781 } 01782 01783 } finally { 01784 01785 ReleaseNotifySync( NotifySync ); 01786 01787 DebugTrace( -1, Dbg, "FsRtlNotifyFullReportChange: Exit\n", 0 ); 01788 } 01789 01790 return; 01791 } 01792 01793 01794 VOID 01795 FsRtlNotifyCleanup ( 01796 IN PNOTIFY_SYNC NotifySync, 01797 IN PLIST_ENTRY NotifyList, 01798 IN PVOID FsContext 01799 ) 01800 01801 /*++ 01802 01803 Routine Description: 01804 01805 This routine is called for a cleanup of a user directory handle. We 01806 walk through our notify structures looking for a matching context field. 01807 We complete all the pending notify Irps for this Notify structure, remove 01808 the notify structure and deallocate it. 01809 01810 Arguments: 01811 01812 NotifySync - This is the controlling fast mutex for this notify list. 01813 It is stored here so that it can be found for an Irp which is being 01814 cancelled. 01815 01816 NotifyList - This is the start of the notify list to add this 01817 structure to. 01818 01819 FsContext - This is a unique value assigned by the file system to 01820 identify a particular notify structure. 01821 01822 Return Value: 01823 01824 None. 01825 01826 --*/ 01827 01828 { 01829 PNOTIFY_CHANGE Notify; 01830 PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; 01831 01832 PAGED_CODE(); 01833 01834 DebugTrace( +1, Dbg, "FsRtlNotifyCleanup: Entered\n", 0 ); 01835 DebugTrace( 0, Dbg, "Mutex -> %08lx\n", Mutex ); 01836 DebugTrace( 0, Dbg, "Notify List -> %08lx\n", NotifyList ); 01837 DebugTrace( 0, Dbg, "FsContext -> %08lx\n", FsContext ); 01838 01839 // 01840 // Acquire exclusive access to the list by acquiring the mutex. 01841 // 01842 01843 AcquireNotifySync( NotifySync ); 01844 01845 // 01846 // Use a try-finally to facilitate cleanup. 01847 // 01848 01849 try { 01850 01851 // 01852 // Search for a match on the list. 01853 // 01854 01855 Notify = FsRtlIsNotifyOnList( NotifyList, FsContext ); 01856 01857 // 01858 // If found, then complete all the Irps with STATUS_NOTIFY_CLEANUP 01859 // 01860 01861 if (Notify != NULL) { 01862 01863 // 01864 // Set the flag to indicate that we have been called with cleanup. 01865 // 01866 01867 SetFlag( Notify->Flags, NOTIFY_CLEANUP_CALLED ); 01868 01869 if (!IsListEmpty( &Notify->NotifyIrps )) { 01870 01871 FsRtlNotifyCompleteIrpList( Notify, STATUS_NOTIFY_CLEANUP ); 01872 } 01873 01874 RemoveEntryList( &Notify->NotifyList ); 01875 01876 InterlockedDecrement( &Notify->ReferenceCount ); 01877 01878 if (Notify->ReferenceCount == 0) { 01879 01880 if (Notify->AllocatedBuffer != NULL) { 01881 01882 PsReturnPoolQuota( Notify->OwningProcess, 01883 PagedPool, 01884 Notify->ThisBufferLength ); 01885 01886 ExFreePool( Notify->AllocatedBuffer ); 01887 } 01888 01889 if (Notify->FullDirectoryName != NULL) { 01890 01891 SubjectContext = Notify->SubjectContext; 01892 } 01893 01894 ExFreePool( Notify ); 01895 } 01896 } 01897 01898 } finally { 01899 01900 ReleaseNotifySync( NotifySync ); 01901 01902 if (SubjectContext != NULL) { 01903 01904 SeReleaseSubjectContext( SubjectContext ); 01905 ExFreePool( SubjectContext ); 01906 } 01907 01908 DebugTrace( -1, Dbg, "FsRtlNotifyCleanup: Exit\n", 0 ); 01909 } 01910 01911 return; 01912 } 01913 01914 01915 // 01916 // Local support routine 01917 // 01918 01919 PNOTIFY_CHANGE 01920 FsRtlIsNotifyOnList ( 01921 IN PLIST_ENTRY NotifyListHead, 01922 IN PVOID FsContext 01923 ) 01924 01925 /*++ 01926 01927 Routine Description: 01928 01929 This routine is called to walk through a notify list searching for 01930 a member associated with the FsContext value. 01931 01932 Arguments: 01933 01934 NotifyListHead - This is the start of the notify list. 01935 01936 FsContext - This is supplied by the file system so that this notify 01937 structure can be uniquely identified. 01938 01939 Return Value: 01940 01941 PNOTIFY_CHANGE - A pointer to the matching structure is returned. NULL 01942 is returned if the structure isn't present. 01943 01944 --*/ 01945 01946 { 01947 PLIST_ENTRY Link; 01948 01949 PNOTIFY_CHANGE ThisNotify; 01950 PNOTIFY_CHANGE Notify; 01951 01952 PAGED_CODE(); 01953 01954 DebugTrace( +1, Dbg, "FsRtlIsNotifyOnList: Entered\n", 0 ); 01955 01956 // 01957 // Assume we won't have a match. 01958 // 01959 01960 Notify = NULL; 01961 01962 // 01963 // Walk through all the entries on the list looking for a match. 01964 // 01965 01966 for (Link = NotifyListHead->Flink; 01967 Link != NotifyListHead; 01968 Link = Link->Flink) { 01969 01970 // 01971 // Obtain the notify structure from the link. 01972 // 01973 01974 ThisNotify = CONTAINING_RECORD( Link, NOTIFY_CHANGE, NotifyList ); 01975 01976 // 01977 // If the context field matches, remember this structure and 01978 // exit. 01979 // 01980 01981 if (ThisNotify->FsContext == FsContext) { 01982 01983 Notify = ThisNotify; 01984 break; 01985 } 01986 } 01987 01988 DebugTrace( 0, Dbg, "Notify Structure -> %08lx\n", Notify ); 01989 DebugTrace( -1, Dbg, "FsRtlIsNotifyOnList: Exit\n", 0 ); 01990 01991 return Notify; 01992 } 01993 01994 01995 // 01996 // Local support routine 01997 // 01998 01999 VOID 02000 FsRtlNotifyCompleteIrp ( 02001 IN PIRP NotifyIrp, 02002 IN PNOTIFY_CHANGE Notify, 02003 IN ULONG DataLength, 02004 IN NTSTATUS Status, 02005 IN ULONG CheckCancel 02006 ) 02007 02008 /*++ 02009 02010 Routine Description: 02011 02012 This routine is called to complete an Irp with the data in the NOTIFY_CHANGE 02013 structure. 02014 02015 Arguments: 02016 02017 NotifyIrp - Irp to complete. 02018 02019 Notify - Notify structure which contains the data. 02020 02021 DataLength - This is the length of the data in the buffer in the notify 02022 structure. A value of zero indicates that we should complete the 02023 request with STATUS_NOTIFY_ENUM_DIR. 02024 02025 Status - Indicates the status to complete the Irp with. 02026 02027 CheckCancel - Indicates if we should only complete the irp if we clear the cancel routine 02028 ourselves. 02029 02030 Return Value: 02031 02032 None. 02033 02034 --*/ 02035 02036 { 02037 PIO_STACK_LOCATION IrpSp; 02038 02039 PAGED_CODE(); 02040 02041 DebugTrace( +1, Dbg, "FsRtlIsNotifyCompleteIrp: Entered\n", 0 ); 02042 02043 // 02044 // Attempt to clear the cancel routine. If this routine owns the cancel 02045 // routine then it can complete the irp. Otherwise there is a cancel underway 02046 // on this. 02047 // 02048 02049 if (FsRtlNotifySetCancelRoutine( NotifyIrp, Notify ) || !CheckCancel) { 02050 02051 // 02052 // We only process the buffer if the status is STATUS_SUCCESS. 02053 // 02054 02055 if (Status == STATUS_SUCCESS) { 02056 02057 // 02058 // Get the current Stack location 02059 // 02060 02061 IrpSp = IoGetCurrentIrpStackLocation( NotifyIrp ); 02062 02063 // 02064 // If the data won't fit in the user's buffer or there was already a 02065 // buffer overflow then return the alternate status code. If the data 02066 // was already stored in the Irp buffer then we know that we won't 02067 // take this path. Otherwise we wouldn't be cleaning up the Irp 02068 // correctly. 02069 // 02070 02071 if (DataLength == 0 02072 || IrpSp->Parameters.NotifyDirectory.Length < DataLength) { 02073 02074 Status = STATUS_NOTIFY_ENUM_DIR; 02075 02076 // 02077 // We have to carefully return the buffer to the user and handle all 02078 // of the different buffer cases. If there is no allocated buffer 02079 // in the notify structure it means that we have already used the 02080 // caller's buffer. 02081 // 02082 // 1 - If the system allocated an associated system buffer we 02083 // can simply fill that in. 02084 // 02085 // 2 - If there is an Mdl then we get a system address for the Mdl 02086 // and copy the data into it. 02087 // 02088 // 3 - If there is only a user's buffer and pending has not been 02089 // returned, we can fill the user's buffer in directly. 02090 // 02091 // 4 - If there is only a user's buffer and pending has been returned 02092 // then we are not in the user's address space. We dress up 02093 // the Irp with our system buffer and let the Io system 02094 // copy the data in. 02095 // 02096 02097 } else { 02098 02099 if (Notify->AllocatedBuffer != NULL) { 02100 02101 // 02102 // Protect the copy with a try-except and ignore the buffer 02103 // if we have some error in copying it to the buffer. 02104 // 02105 02106 try { 02107 02108 if (NotifyIrp->AssociatedIrp.SystemBuffer != NULL) { 02109 02110 RtlCopyMemory( NotifyIrp->AssociatedIrp.SystemBuffer, 02111 Notify->AllocatedBuffer, 02112 DataLength ); 02113 02114 } else if (NotifyIrp->MdlAddress != NULL) { 02115 02116 RtlCopyMemory( MmGetSystemAddressForMdl( NotifyIrp->MdlAddress ), 02117 Notify->AllocatedBuffer, 02118 DataLength ); 02119 02120 } else if (!FlagOn( IrpSp->Control, SL_PENDING_RETURNED )) { 02121 02122 RtlCopyMemory( NotifyIrp->UserBuffer, 02123 Notify->AllocatedBuffer, 02124 DataLength ); 02125 02126 } else { 02127 02128 NotifyIrp->Flags |= (IRP_BUFFERED_IO | IRP_INPUT_OPERATION | IRP_DEALLOCATE_BUFFER); 02129 NotifyIrp->AssociatedIrp.SystemBuffer = Notify->AllocatedBuffer; 02130 02131 } 02132 02133 } except( EXCEPTION_EXECUTE_HANDLER ) { 02134 02135 Status = STATUS_NOTIFY_ENUM_DIR; 02136 DataLength = 0; 02137 } 02138 02139 // 02140 // Return the quota and deallocate the buffer if we didn't pass it 02141 // back via the irp. 02142 // 02143 02144 PsReturnPoolQuota( Notify->OwningProcess, PagedPool, Notify->ThisBufferLength ); 02145 02146 if (Notify->AllocatedBuffer != NotifyIrp->AssociatedIrp.SystemBuffer 02147 && Notify->AllocatedBuffer != NULL) { 02148 02149 ExFreePool( Notify->AllocatedBuffer ); 02150 } 02151 02152 Notify->AllocatedBuffer = NULL; 02153 Notify->ThisBufferLength = 0; 02154 } 02155 02156 // 02157 // Update the data length in the Irp. 02158 // 02159 02160 NotifyIrp->IoStatus.Information = DataLength; 02161 02162 // 02163 // Show that there is no buffer in the notify package 02164 // anymore. 02165 // 02166 02167 Notify->Buffer = NULL; 02168 } 02169 } 02170 02171 // 02172 // Make sure the Irp is marked as pending returned. 02173 // 02174 02175 IoMarkIrpPending( NotifyIrp ); 02176 02177 // 02178 // Now complete the request. 02179 // 02180 02181 FsRtlCompleteRequest( NotifyIrp, Status ); 02182 } 02183 02184 DebugTrace( -1, Dbg, "FsRtlIsNotifyCompleteIrp: Exit\n", 0 ); 02185 02186 return; 02187 } 02188 02189 02190 // 02191 // Local support routine 02192 // 02193 02194 BOOLEAN 02195 FsRtlNotifySetCancelRoutine ( 02196 IN PIRP NotifyIrp, 02197 IN PNOTIFY_CHANGE Notify OPTIONAL 02198 ) 02199 02200 /*++ 02201 02202 Routine Description: 02203 02204 This is a separate routine because it cannot be paged. 02205 02206 Arguments: 02207 02208 NotifyIrp - Set the cancel routine in this Irp. 02209 02210 Notify - If NULL then we are setting the cancel routine. If not-NULL then we 02211 are clearing the cancel routine. If the cancel routine is not-null then 02212 we need to decrement the reference count on this Notify structure 02213 02214 Return Value: 02215 02216 BOOLEAN - Only meaningfull if Notify is specified. It indicates if this 02217 routine cleared the cancel routine. FALSE indicates that the cancel 02218 routine is processing the Irp. 02219 02220 --*/ 02221 02222 { 02223 BOOLEAN ClearedCancel = FALSE; 02224 PDRIVER_CANCEL CurrentCancel; 02225 02226 // 02227 // Grab the cancel spinlock and set our cancel routine in the Irp. 02228 // 02229 02230 IoAcquireCancelSpinLock( &NotifyIrp->CancelIrql ); 02231 02232 // 02233 // If we are completing an Irp then clear the cancel routine and 02234 // the information field. 02235 // 02236 02237 if (ARGUMENT_PRESENT( Notify )) { 02238 02239 CurrentCancel = IoSetCancelRoutine( NotifyIrp, NULL ); 02240 NotifyIrp->IoStatus.Information = 0; 02241 02242 IoReleaseCancelSpinLock( NotifyIrp->CancelIrql ); 02243 02244 // 02245 // If the current cancel routine is non-NULL then decrement the reference count 02246 // in the Notify. 02247 // 02248 02249 if (CurrentCancel != NULL) { 02250 02251 InterlockedDecrement( &Notify->ReferenceCount ); 02252 ClearedCancel = TRUE; 02253 } 02254 02255 // 02256 // If the cancel flag is set, we complete the Irp with cancelled 02257 // status and exit. 02258 // 02259 02260 } else if (NotifyIrp->Cancel) { 02261 02262 DebugTrace( 0, Dbg, "Irp has been cancelled\n", 0 ); 02263 02264 FsRtlCancelNotify( NULL, NotifyIrp ); 02265 02266 } else { 02267 02268 // 02269 // Set our cancel routine in the Irp. 02270 // 02271 02272 IoSetCancelRoutine( NotifyIrp, FsRtlCancelNotify ); 02273 02274 IoReleaseCancelSpinLock( NotifyIrp->CancelIrql ); 02275 } 02276 02277 return ClearedCancel; 02278 } 02279 02280 02281 // 02282 // Local support routine 02283 // 02284 02285 BOOLEAN 02286 FsRtlNotifyUpdateBuffer ( 02287 IN PFILE_NOTIFY_INFORMATION NotifyInfo, 02288 IN ULONG FileAction, 02289 IN PSTRING ParentName, 02290 IN PSTRING TargetName, 02291 IN PSTRING StreamName OPTIONAL, 02292 IN BOOLEAN UnicodeName, 02293 IN ULONG SizeOfEntry 02294 ) 02295 02296 /*++ 02297 02298 Routine Description: 02299 02300 This routine is called to fill in a FILE_NOTIFY_INFORMATION structure for a 02301 notify change event. The main work is in converting an OEM string to Unicode. 02302 02303 Arguments: 02304 02305 NotifyInfo - Information structure to complete. 02306 02307 FileAction - Action which triggered the notification event. 02308 02309 ParentName - Relative path to the parent of the changed file from the 02310 directory being watched. The length for this will be zero if the modified 02311 file is in the watched directory. 02312 02313 TargetName - This is the name of the modified file. 02314 02315 StreamName - If present there is a stream name to append to the filename. 02316 02317 UnicodeName - Indicates if the above name is Unicode or Oem. 02318 02319 SizeOfEntry - Indicates the number of bytes to be used in the buffer. 02320 02321 Return Value: 02322 02323 BOOLEAN - TRUE if we were able to update the buffer, FALSE otherwise. 02324 02325 --*/ 02326 02327 { 02328 BOOLEAN CopiedToBuffer; 02329 ULONG BufferOffset = 0; 02330 02331 PAGED_CODE(); 02332 02333 DebugTrace( +1, Dbg, "FsRtlNotifyUpdateBuffer: Entered\n", 0 ); 02334 02335 // 02336 // Protect the entire call with a try-except. If we had an error 02337 // we will assume that we have a bad buffer and we won't return 02338 // the data in the buffer. 02339 // 02340 02341 try { 02342 02343 // 02344 // Update the common fields in the notify information. 02345 // 02346 02347 NotifyInfo->NextEntryOffset = 0; 02348 NotifyInfo->Action = FileAction; 02349 02350 NotifyInfo->FileNameLength = SizeOfEntry - FIELD_OFFSET( FILE_NOTIFY_INFORMATION, FileName ); 02351 02352 // 02353 // If we have a unicode name, then copy the data directly into the output buffer. 02354 // 02355 02356 if (UnicodeName) { 02357 02358 if (ParentName->Length != 0) { 02359 02360 RtlCopyMemory( NotifyInfo->FileName, 02361 ParentName->Buffer, 02362 ParentName->Length ); 02363 02364 *(Add2Ptr( NotifyInfo->FileName, ParentName->Length, PWCHAR )) = L'\\'; 02365 BufferOffset = ParentName->Length + sizeof( WCHAR ); 02366 } 02367 02368 RtlCopyMemory( Add2Ptr( NotifyInfo->FileName, 02369 BufferOffset, 02370 PVOID ), 02371 TargetName->Buffer, 02372 TargetName->Length ); 02373 02374 if (ARGUMENT_PRESENT( StreamName )) { 02375 02376 BufferOffset += TargetName->Length; 02377 02378 *(Add2Ptr( NotifyInfo->FileName, BufferOffset, PWCHAR )) = L':'; 02379 02380 RtlCopyMemory( Add2Ptr( NotifyInfo->FileName, 02381 BufferOffset + sizeof( WCHAR ), 02382 PVOID ), 02383 StreamName->Buffer, 02384 StreamName->Length ); 02385 } 02386 02387 // 02388 // For a non-unicode name, use the conversion routines. 02389 // 02390 02391 } else { 02392 02393 ULONG BufferLength; 02394 02395 if (ParentName->Length != 0) { 02396 02397 RtlOemToUnicodeN( NotifyInfo->FileName, 02398 NotifyInfo->FileNameLength, 02399 &BufferLength, 02400 ParentName->Buffer, 02401 ParentName->Length ); 02402 02403 *(Add2Ptr( NotifyInfo->FileName, BufferLength, PWCHAR )) = L'\\'; 02404 02405 BufferOffset = BufferLength + sizeof( WCHAR ); 02406 } 02407 02408 // 02409 // For view indices, we do not have a parent name. 02410 // 02411 02412 if (ParentName->Length == 0) { 02413 02414 ASSERT(ARGUMENT_PRESENT( StreamName )); 02415 02416 RtlCopyMemory( Add2Ptr( NotifyInfo->FileName, 02417 BufferOffset, 02418 PCHAR ), 02419 StreamName->Buffer, 02420 StreamName->Length ); 02421 02422 } else { 02423 02424 RtlOemToUnicodeN( Add2Ptr( NotifyInfo->FileName, 02425 BufferOffset, 02426 PWCHAR ), 02427 NotifyInfo->FileNameLength, 02428 &BufferLength, 02429 TargetName->Buffer, 02430 TargetName->Length ); 02431 02432 if (ARGUMENT_PRESENT( StreamName )) { 02433 02434 BufferOffset += BufferLength; 02435 02436 *(Add2Ptr( NotifyInfo->FileName, BufferOffset, PWCHAR )) = L':'; 02437 02438 RtlOemToUnicodeN( Add2Ptr( NotifyInfo->FileName, 02439 BufferOffset + sizeof( WCHAR ), 02440 PWCHAR ), 02441 NotifyInfo->FileNameLength, 02442 &BufferLength, 02443 StreamName->Buffer, 02444 StreamName->Length ); 02445 } 02446 } 02447 } 02448 02449 CopiedToBuffer = TRUE; 02450 02451 } except( EXCEPTION_EXECUTE_HANDLER ) { 02452 02453 CopiedToBuffer = FALSE; 02454 } 02455 02456 DebugTrace( -1, Dbg, "FsRtlNotifyUpdateBuffer: Exit\n", 0 ); 02457 02458 return CopiedToBuffer; 02459 } 02460 02461 02462 // 02463 // Local support routine 02464 // 02465 02466 VOID 02467 FsRtlNotifyCompleteIrpList ( 02468 IN OUT PNOTIFY_CHANGE Notify, 02469 IN NTSTATUS Status 02470 ) 02471 02472 /*++ 02473 02474 Routine Description: 02475 02476 This routine walks through the Irps for a particular notify structure 02477 and completes the Irps with the indicated status. If the status is 02478 STATUS_SUCCESS then we are completing an Irp because of a notification event. 02479 In that case we look at the notify structure to decide if we can return the 02480 data to the user. 02481 02482 Arguments: 02483 02484 Notify - This is the notify change structure. 02485 02486 Status - Indicates the status used to complete the request. If this status 02487 is STATUS_SUCCESS then we only want to complete one Irp. Otherwise we 02488 want complete all the Irps in the list. 02489 02490 Return Value: 02491 02492 None. 02493 02494 --*/ 02495 02496 { 02497 PIRP Irp; 02498 ULONG DataLength; 02499 02500 DebugTrace( +1, Dbg, "FsRtlNotifyCompleteIrpList: Entered\n", 0 ); 02501 02502 DataLength = Notify->DataLength; 02503 02504 // 02505 // Clear the fields to indicate that there is no more data to return. 02506 // 02507 02508 ClearFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 02509 Notify->DataLength = 0; 02510 Notify->LastEntry = 0; 02511 02512 // 02513 // Walk through all the Irps in the list. We are never called unless 02514 // there is at least one irp. 02515 // 02516 02517 do { 02518 02519 Irp = CONTAINING_RECORD( Notify->NotifyIrps.Flink, IRP, Tail.Overlay.ListEntry ); 02520 02521 RemoveHeadList( &Notify->NotifyIrps ); 02522 02523 // 02524 // Call our completion routine to complete the request. 02525 // 02526 02527 FsRtlNotifyCompleteIrp( Irp, 02528 Notify, 02529 DataLength, 02530 Status, 02531 TRUE ); 02532 02533 // 02534 // If we were only to complete one Irp then break now. 02535 // 02536 02537 if (Status == STATUS_SUCCESS) { 02538 02539 break; 02540 } 02541 02542 } while (!IsListEmpty( &Notify->NotifyIrps )); 02543 02544 DebugTrace( -1, Dbg, "FsRtlNotifyCompleteIrpList: Exit\n", 0 ); 02545 02546 return; 02547 } 02548 02549 02550 // 02551 // Local support routine 02552 // 02553 02554 VOID 02555 FsRtlCancelNotify ( 02556 IN PDEVICE_OBJECT DeviceObject, 02557 IN PIRP ThisIrp 02558 ) 02559 02560 /*++ 02561 02562 Routine Description: 02563 02564 This routine is for an Irp which is being cancelled. We Null the cancel 02565 routine and then walk through the Irps for this notify structure and 02566 complete all cancelled Irps. It is possible there is pending notify 02567 stored in the buffer for this Irp. In this case we want to copy the 02568 data to a system buffer if possible. 02569 02570 Arguments: 02571 02572 DeviceObject - Ignored. 02573 02574 ThisIrp - This is the Irp to cancel. 02575 02576 Return Value: 02577 02578 None. 02579 02580 --*/ 02581 02582 { 02583 PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL; 02584 02585 PNOTIFY_CHANGE Notify; 02586 PNOTIFY_SYNC NotifySync; 02587 LONG ExceptionCode; 02588 02589 UNREFERENCED_PARAMETER( DeviceObject ); 02590 02591 DebugTrace( +1, Dbg, "FsRtlCancelNotify: Entered\n", 0 ); 02592 DebugTrace( 0, Dbg, "Irp -> %08lx\n", Irp ); 02593 02594 // 02595 // Capture the notify structure. 02596 // 02597 02598 Notify = (PNOTIFY_CHANGE) ThisIrp->IoStatus.Information; 02599 02600 // 02601 // Void the cancel routine and release the cancel spinlock. 02602 // 02603 02604 IoSetCancelRoutine( ThisIrp, NULL ); 02605 ThisIrp->IoStatus.Information = 0; 02606 IoReleaseCancelSpinLock( ThisIrp->CancelIrql ); 02607 02608 FsRtlEnterFileSystem(); 02609 02610 // 02611 // Grab the mutex for this structure. 02612 // 02613 02614 NotifySync = Notify->NotifySync; 02615 AcquireNotifySync( NotifySync ); 02616 02617 // 02618 // Use a try finally to faciltate cleanup. 02619 // 02620 02621 try { 02622 02623 // 02624 // Remove the Irp from the queue. 02625 // 02626 02627 RemoveEntryList( &ThisIrp->Tail.Overlay.ListEntry ); 02628 02629 IoMarkIrpPending( ThisIrp ); 02630 02631 // 02632 // We now have the Irp. Check to see if there is data stored 02633 // in the buffer for this Irp. 02634 // 02635 02636 if (Notify->Buffer != NULL 02637 && Notify->AllocatedBuffer == NULL 02638 02639 && ((ThisIrp->MdlAddress != NULL 02640 && MmGetSystemAddressForMdl( ThisIrp->MdlAddress ) == Notify->Buffer) 02641 02642 || (Notify->Buffer == ThisIrp->AssociatedIrp.SystemBuffer))) { 02643 02644 PIRP NextIrp; 02645 PVOID NewBuffer; 02646 ULONG NewBufferLength; 02647 PIO_STACK_LOCATION IrpSp; 02648 02649 // 02650 // Initialize the above values. 02651 // 02652 02653 NewBuffer = NULL; 02654 NewBufferLength = 0; 02655 02656 // 02657 // Remember the next Irp on the list. Find the length of any 02658 // buffer it might have. Also keep a pointer to the buffer 02659 // if present. 02660 // 02661 02662 if (!IsListEmpty( &Notify->NotifyIrps )) { 02663 02664 NextIrp = CONTAINING_RECORD( Notify->NotifyIrps.Flink, 02665 IRP, 02666 Tail.Overlay.ListEntry ); 02667 02668 IrpSp = IoGetCurrentIrpStackLocation( NextIrp ); 02669 02670 // 02671 // If the buffer here is large enough to hold the data we 02672 // can use that buffer. 02673 // 02674 02675 if (IrpSp->Parameters.NotifyDirectory.Length >= Notify->DataLength) { 02676 02677 // 02678 // If there is a system buffer or Mdl then get a new 02679 // buffer there. 02680 // 02681 02682 if (NextIrp->AssociatedIrp.SystemBuffer != NULL) { 02683 02684 NewBuffer = NextIrp->AssociatedIrp.SystemBuffer; 02685 02686 } else if (NextIrp->MdlAddress != NULL) { 02687 02688 NewBuffer = MmGetSystemAddressForMdl( NextIrp->MdlAddress ); 02689 } 02690 02691 NewBufferLength = IrpSp->Parameters.NotifyDirectory.Length; 02692 02693 if (NewBufferLength > Notify->BufferLength) { 02694 02695 NewBufferLength = Notify->BufferLength; 02696 } 02697 } 02698 02699 // 02700 // Otherwise check if the user's original buffer is larger than 02701 // the current buffer. 02702 // 02703 02704 } else if (Notify->BufferLength >= Notify->DataLength) { 02705 02706 NewBufferLength = Notify->BufferLength; 02707 } 02708 02709 // 02710 // If we have a new buffer length then we either have a new 02711 // buffer or need to allocate one. We will do this under 02712 // the protection of a try-except in order to continue in the 02713 // event of a failure. 02714 // 02715 02716 if (NewBufferLength != 0) { 02717 02718 BOOLEAN ChargedQuota; 02719 02720 try { 02721 02722 ChargedQuota = FALSE; 02723 02724 if (NewBuffer == NULL) { 02725 02726 PsChargePoolQuota( Notify->OwningProcess, 02727 PagedPool, 02728 NewBufferLength ); 02729 02730 ChargedQuota = TRUE; 02731 02732 // 02733 // If we didn't get an error then attempt to 02734 // allocate the pool. If there is an error 02735 // don't forget to release the quota. 02736 // 02737 02738 NewBuffer = FsRtlpAllocatePool( PagedPool, 02739 NewBufferLength ); 02740 02741 Notify->AllocatedBuffer = NewBuffer; 02742 } 02743 02744 // 02745 // Now copy the data over to the new buffer. 02746 // 02747 02748 RtlCopyMemory( NewBuffer, 02749 Notify->Buffer, 02750 Notify->DataLength ); 02751 02752 // 02753 // It is possible that the buffer size changed. 02754 // 02755 02756 Notify->ThisBufferLength = NewBufferLength; 02757 Notify->Buffer = NewBuffer; 02758 02759 } except( FsRtlIsNtstatusExpected( ExceptionCode = GetExceptionCode()) ? 02760 EXCEPTION_EXECUTE_HANDLER : 02761 EXCEPTION_CONTINUE_SEARCH ) { 02762 02763 ASSERT( (ExceptionCode == STATUS_INSUFFICIENT_RESOURCES) || 02764 (ExceptionCode == STATUS_QUOTA_EXCEEDED) ); 02765 02766 // 02767 // Return quota if we allocated the buffer. 02768 // 02769 02770 if (ChargedQuota) { 02771 02772 PsReturnPoolQuota( Notify->OwningProcess, 02773 PagedPool, 02774 NewBufferLength ); 02775 } 02776 02777 // 02778 // Forget any current buffer and resort to immediate 02779 // notify. 02780 // 02781 02782 SetFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 02783 } 02784 02785 // 02786 // Otherwise set the immediate notify flag. 02787 // 02788 02789 } else { 02790 02791 SetFlag( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY ); 02792 } 02793 02794 // 02795 // If the immediate notify flag is set then clear the other 02796 // values in the notify structures. 02797 // 02798 02799 if (FlagOn( Notify->Flags, NOTIFY_IMMEDIATE_NOTIFY )) { 02800 02801 // 02802 // Forget any current buffer and resort to immediate 02803 // notify. 02804 // 02805 02806 Notify->AllocatedBuffer = Notify->Buffer = NULL; 02807 02808 Notify->ThisBufferLength = 02809 Notify->DataLength = Notify->LastEntry = 0; 02810 } 02811 } 02812 02813 // 02814 // Complete the Irp with status cancelled. 02815 // 02816 02817 FsRtlCompleteRequest( ThisIrp, STATUS_CANCELLED ); 02818 02819 // 02820 // Decrement the count of Irps that might go through the cancel path. 02821 // 02822 02823 InterlockedDecrement( &Notify->ReferenceCount ); 02824 02825 if (Notify->ReferenceCount == 0) { 02826 02827 if (Notify->AllocatedBuffer != NULL) { 02828 02829 PsReturnPoolQuota( Notify->OwningProcess, 02830 PagedPool, 02831 Notify->ThisBufferLength ); 02832 02833 ExFreePool( Notify->AllocatedBuffer ); 02834 } 02835 02836 if (Notify->FullDirectoryName != NULL) { 02837 02838 SubjectContext = Notify->SubjectContext; 02839 } 02840 02841 ExFreePool( Notify ); 02842 Notify = NULL; 02843 } 02844 02845 } finally { 02846 02847 // 02848 // No matter how we exit, we release the mutex. 02849 // 02850 02851 ReleaseNotifySync( NotifySync ); 02852 02853 if (SubjectContext != NULL) { 02854 02855 SeReleaseSubjectContext( SubjectContext ); 02856 ExFreePool( SubjectContext ); 02857 } 02858 02859 FsRtlExitFileSystem(); 02860 02861 DebugTrace( -1, Dbg, "FsRtlCancelNotify: Exit\n", 0 ); 02862 } 02863 02864 return; 02865 } 02866 02867 02868 // 02869 // Local support routine 02870 // 02871 02872 VOID 02873 FsRtlCheckNotifyForDelete ( 02874 IN PLIST_ENTRY NotifyListHead, 02875 IN PVOID StreamID 02876 ) 02877 02878 /*++ 02879 02880 Routine Description: 02881 02882 This routine is called when a stream is being marked for delete. We will 02883 walk through the notify structures looking for an Irp for the same stream. 02884 We will complete these Irps with STATUS_DELETE_PENDING. 02885 02886 Arguments: 02887 02888 NotifyListHead - This is the start of the notify list. 02889 02890 StreamID - This is the Context ID used to identify the stream. 02891 02892 Return Value: 02893 02894 None. 02895 02896 --*/ 02897 02898 { 02899 PLIST_ENTRY Link; 02900 02901 PNOTIFY_CHANGE ThisNotify; 02902 02903 PAGED_CODE(); 02904 02905 // 02906 // Walk through all the entries on the list looking for a match. 02907 // 02908 02909 for (Link = NotifyListHead->Flink; 02910 Link != NotifyListHead; 02911 Link = Link->Flink) { 02912 02913 // 02914 // Obtain the notify structure from the link. 02915 // 02916 02917 ThisNotify = CONTAINING_RECORD( Link, NOTIFY_CHANGE, NotifyList ); 02918 02919 // 02920 // If the context field matches, then complete any waiting Irps. 02921 // 02922 02923 if (ThisNotify->StreamID == StreamID) { 02924 02925 // 02926 // Start by marking the notify structure as file deleted. 02927 // 02928 02929 SetFlag( ThisNotify->Flags, NOTIFY_STREAM_IS_DELETED ); 02930 02931 // 02932 // Now complete all of the Irps on this list. 02933 // 02934 02935 if (!IsListEmpty( &ThisNotify->NotifyIrps )) { 02936 02937 FsRtlNotifyCompleteIrpList( ThisNotify, STATUS_DELETE_PENDING ); 02938 } 02939 } 02940 } 02941 02942 return; 02943 }

Generated on Sat May 15 19:40:57 2004 for test by doxygen 1.3.7