test: notify.c Source File

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 }