ed426e367821c356b3240985cd80a42654a9d6c6
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSDirControl.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSDirControl.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSDirControl
43 //
44 // Description:
45 //
46 //      This function is the IRP_MJ_DIRECTORY_CONTROL dispatch handler
47 //
48 // Return:
49 //
50 //       A status is returned for the handling of this request
51 //
52
53 NTSTATUS
54 AFSDirControl( IN PDEVICE_OBJECT LibDeviceObject,
55                IN PIRP Irp)
56 {
57     UNREFERENCED_PARAMETER(LibDeviceObject);
58     NTSTATUS ntStatus = STATUS_SUCCESS;
59     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
60
61     __try
62     {
63
64         switch( pIrpSp->MinorFunction )
65         {
66
67             case IRP_MN_QUERY_DIRECTORY:
68             {
69
70                 ntStatus = AFSQueryDirectory( Irp);
71
72                 break;
73             }
74
75             case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
76             {
77
78                 ntStatus = AFSNotifyChangeDirectory( Irp);
79
80                 break;
81             }
82
83             default:
84
85                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
86
87                 break;
88         }
89     }
90     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
91     {
92
93         AFSDbgLogMsg( 0,
94                       0,
95                       "EXCEPTION - AFSDirControl\n");
96
97         AFSDumpTraceFilesFnc();
98     }
99
100     if( ntStatus != STATUS_PENDING)
101     {
102
103         AFSCompleteRequest( Irp,
104                             ntStatus);
105     }
106
107     return ntStatus;
108 }
109
110 NTSTATUS
111 AFSQueryDirectory( IN PIRP Irp)
112 {
113
114     NTSTATUS ntStatus = STATUS_SUCCESS;
115     NTSTATUS dStatus = STATUS_SUCCESS;
116     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
117     PIO_STACK_LOCATION pIrpSp;
118     AFSFcb *pFcb = NULL;
119     AFSCcb *pCcb = NULL;
120     BOOLEAN bInitialQuery = FALSE;
121     PUCHAR pBuffer;
122     ULONG ulUserBufferLength;
123     PUNICODE_STRING puniArgFileName = NULL;
124     UNICODE_STRING uniTmpMaskName;
125     WCHAR wchMaskBuffer[ 4];
126     FILE_INFORMATION_CLASS FileInformationClass;
127     ULONG ulFileIndex;
128     BOOLEAN bRestartScan;
129     BOOLEAN bReturnSingleEntry;
130     BOOLEAN bIndexSpecified;
131     ULONG ulNextEntry = 0;
132     ULONG ulLastEntry = 0;
133     PFILE_DIRECTORY_INFORMATION pDirInfo;
134     PFILE_FULL_DIR_INFORMATION pFullDirInfo;
135     PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
136     PFILE_NAMES_INFORMATION pNamesInfo;
137     ULONG ulBaseLength;
138     ULONG ulBytesConverted;
139     AFSDirectoryCB *pDirEntry = NULL;
140     BOOLEAN bReleaseMain = FALSE;
141     BOOLEAN bReleaseFcb = FALSE;
142     AFSFileInfoCB       stFileInfo;
143     AFSObjectInfoCB *pObjectInfo = NULL;
144     ULONG ulAdditionalAttributes = 0;
145     LONG lCount;
146
147     __Enter
148     {
149
150         //  Get the current Stack location
151         pIrpSp = IoGetCurrentIrpStackLocation( Irp);
152
153         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
154         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
155
156         if( pFcb == NULL)
157         {
158
159             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
160                           AFS_TRACE_LEVEL_ERROR,
161                           "AFSQueryDirectory Attempted access (%08lX) when pFcb == NULL\n",
162                           Irp);
163
164             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
165         }
166
167         if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
168             pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
169             pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
170         {
171
172             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
173                           AFS_TRACE_LEVEL_ERROR,
174                           "AFSQueryDirectory Attempted access (%08lX) to non-directory Fcb %08lX NodeType %u\n",
175                           Irp,
176                           pFcb,
177                           pFcb->Header.NodeTypeCode);
178
179             pFcb = NULL;
180
181             try_return( ntStatus = STATUS_INVALID_PARAMETER);
182         }
183
184         //
185         // Set the enumeration event ...
186         //
187
188         AFSSetEnumerationEvent( pFcb);
189
190         //  Reference our input parameters to make things easier
191         ulUserBufferLength = pIrpSp->Parameters.QueryDirectory.Length;
192
193         FileInformationClass = pIrpSp->Parameters.QueryDirectory.FileInformationClass;
194         ulFileIndex = pIrpSp->Parameters.QueryDirectory.FileIndex;
195
196         puniArgFileName = (PUNICODE_STRING)pIrpSp->Parameters.QueryDirectory.FileName;
197
198         bRestartScan       = BooleanFlagOn( pIrpSp->Flags, SL_RESTART_SCAN);
199         bReturnSingleEntry = BooleanFlagOn( pIrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
200         bIndexSpecified    = BooleanFlagOn( pIrpSp->Flags, SL_INDEX_SPECIFIED);
201
202         bInitialQuery = (BOOLEAN)( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED));
203
204         if( bInitialQuery)
205         {
206
207             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
208                           AFS_TRACE_LEVEL_VERBOSE,
209                           "AFSQueryDirectory Enumerating content for parent %wZ Initial Query\n",
210                           &pCcb->DirectoryCB->NameInformation.FileName);
211
212             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
213                           AFS_TRACE_LEVEL_VERBOSE,
214                           "AFSQueryDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
215                           &pFcb->NPFcb->Resource,
216                           PsGetCurrentThread());
217
218             AFSAcquireExcl( &pFcb->NPFcb->Resource,
219                             TRUE);
220
221             bReleaseFcb = TRUE;
222         }
223         else
224         {
225
226             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
227                           AFS_TRACE_LEVEL_VERBOSE,
228                           "AFSQueryDirectory Enumerating content for parent %wZ Subsequent\n",
229                           &pCcb->DirectoryCB->NameInformation.FileName);
230
231             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
232                           AFS_TRACE_LEVEL_VERBOSE,
233                           "AFSQueryDirectory Acquiring Dcb lock %08lX SHARED %08lX\n",
234                           &pFcb->NPFcb->Resource,
235                           PsGetCurrentThread());
236
237             AFSAcquireShared( &pFcb->NPFcb->Resource,
238                               TRUE);
239
240             bReleaseFcb = TRUE;
241         }
242
243         //
244         // Grab the directory node hdr tree lock while parsing the directory
245         // contents
246         //
247
248         AFSAcquireExcl( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
249                         TRUE);
250
251         bReleaseMain = TRUE;
252
253         //
254         // Before attempting to insert the new entry, check if we need to validate the parent
255         //
256
257         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
258         {
259
260             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
261                           AFS_TRACE_LEVEL_VERBOSE,
262                           "AFSQueryDirectory Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n",
263                           &pCcb->DirectoryCB->NameInformation.FileName,
264                           pFcb->ObjectInformation->FileId.Cell,
265                           pFcb->ObjectInformation->FileId.Volume,
266                           pFcb->ObjectInformation->FileId.Vnode,
267                           pFcb->ObjectInformation->FileId.Unique);
268
269             ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
270                                        pCcb->DirectoryCB);
271
272             if( !NT_SUCCESS( ntStatus))
273             {
274
275                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
276                               AFS_TRACE_LEVEL_ERROR,
277                               "AFSQueryDirectory Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
278                               &pCcb->DirectoryCB->NameInformation.FileName,
279                               pFcb->ObjectInformation->FileId.Cell,
280                               pFcb->ObjectInformation->FileId.Volume,
281                               pFcb->ObjectInformation->FileId.Vnode,
282                               pFcb->ObjectInformation->FileId.Unique,
283                               ntStatus);
284
285                 try_return( ntStatus);
286             }
287
288             //
289             // Perform a new snapshot of the directory
290             //
291
292             AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
293                             TRUE);
294
295             ntStatus = AFSSnapshotDirectory( pFcb,
296                                              pCcb,
297                                              FALSE);
298
299             AFSReleaseResource( &pCcb->NPCcb->CcbLock);
300
301             if( !NT_SUCCESS( ntStatus))
302             {
303
304                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
305                               AFS_TRACE_LEVEL_ERROR,
306                               "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
307                               &pCcb->DirectoryCB->NameInformation.FileName,
308                               &pCcb->MaskName,
309                               ntStatus);
310
311                 try_return( ntStatus);
312             }
313         }
314
315         AFSConvertToShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
316
317         //
318         // We can now safely drop the lock on the node
319         //
320
321         AFSReleaseResource( &pFcb->NPFcb->Resource);
322
323         bReleaseFcb = FALSE;
324
325         //
326         // Start processing the data
327         //
328
329         pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
330                                                ulUserBufferLength);
331
332         if( pBuffer == NULL)
333         {
334
335             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
336         }
337
338         AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
339                         TRUE);
340
341         // Check if initial on this map
342         if( bInitialQuery)
343         {
344
345             ntStatus = AFSSnapshotDirectory( pFcb,
346                                              pCcb,
347                                              TRUE);
348
349             if( !NT_SUCCESS( ntStatus))
350             {
351
352                 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
353
354                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
355                               AFS_TRACE_LEVEL_ERROR,
356                               "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
357                               &pCcb->DirectoryCB->NameInformation.FileName,
358                               &pCcb->MaskName,
359                               ntStatus);
360
361                 try_return( ntStatus);
362             }
363
364             SetFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED);
365
366             ClearFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
367
368             // build mask if none
369             if( puniArgFileName == NULL)
370             {
371                 puniArgFileName = &uniTmpMaskName;
372                 puniArgFileName->Length = 0;
373                 puniArgFileName->Buffer = NULL;
374             }
375
376             if( puniArgFileName->Length == 0)
377             {
378
379                 puniArgFileName->Length = sizeof(WCHAR);
380                 puniArgFileName->MaximumLength = (USHORT)4;
381             }
382
383             if( puniArgFileName->Buffer == NULL)
384             {
385
386                 puniArgFileName->Buffer = wchMaskBuffer;
387
388                 RtlZeroMemory( wchMaskBuffer,
389                                4);
390
391                 RtlCopyMemory( &puniArgFileName->Buffer[ 0],
392                                L"*",
393                                sizeof(WCHAR));
394             }
395
396             if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
397                  ( puniArgFileName->Buffer[0] == L'*')))
398             {
399
400                 SetFlag( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY);
401             }
402             else
403             {
404
405                 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
406                      ( puniArgFileName->Buffer[0] == L'<')) ||
407                     (( puniArgFileName->Length == 2*sizeof(WCHAR)) &&
408                     ( RtlEqualMemory( puniArgFileName->Buffer, L"*.", 2*sizeof(WCHAR) ))))
409                 {
410
411                     SetFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
412                 }
413
414                 //
415                 // Build the name for procesisng
416                 //
417
418                 pCcb->MaskName.Length = puniArgFileName->Length;
419                 pCcb->MaskName.MaximumLength = pCcb->MaskName.Length;
420
421                 pCcb->MaskName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
422                                                                            pCcb->MaskName.Length,
423                                                                            AFS_GENERIC_MEMORY_6_TAG);
424
425                 if( pCcb->MaskName.Buffer == NULL)
426                 {
427
428                     try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
429                 }
430
431                 if( FsRtlDoesNameContainWildCards( puniArgFileName))
432                 {
433
434                     RtlUpcaseUnicodeString( &pCcb->MaskName,
435                                             puniArgFileName,
436                                             FALSE);
437
438                     SetFlag( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS);
439
440                     if( FsRtlIsNameInExpression( &pCcb->MaskName,
441                                                  &AFSPIOCtlName,
442                                                  TRUE,
443                                                  NULL))
444                     {
445                         SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
446                     }
447                 }
448                 else
449                 {
450
451                     RtlCopyMemory( pCcb->MaskName.Buffer,
452                                    puniArgFileName->Buffer,
453                                    pCcb->MaskName.Length);
454
455                     if( RtlCompareUnicodeString( &AFSPIOCtlName,
456                                                  &pCcb->MaskName,
457                                                  TRUE) == 0)
458                     {
459                         SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
460                     }
461                 }
462
463                 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
464                 {
465                     if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
466                     {
467
468                         AFSReleaseResource( &pCcb->NPCcb->CcbLock);
469
470                         AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
471
472                         bReleaseMain = FALSE;
473
474                         AFSAcquireExcl( &pFcb->NPFcb->Resource,
475                                         TRUE);
476
477                         if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
478                         {
479
480                             ntStatus = AFSInitPIOCtlDirectoryCB( pFcb->ObjectInformation);
481
482                             if( !NT_SUCCESS( ntStatus))
483                             {
484
485                                 AFSReleaseResource( &pFcb->NPFcb->Resource);
486
487                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
488                                               AFS_TRACE_LEVEL_ERROR,
489                                               "AFSQueryDirectory Init PIOCtl directory failure for parent %wZ Mask %wZ Status %08lX\n",
490                                               &pCcb->DirectoryCB->NameInformation.FileName,
491                                               &pCcb->MaskName,
492                                               ntStatus);
493
494                                 try_return( ntStatus);
495                             }
496                         }
497
498                         AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
499                                           TRUE);
500
501                         bReleaseMain = TRUE;
502
503                         AFSReleaseResource( &pFcb->NPFcb->Resource);
504
505                         AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
506                                         TRUE);
507                     }
508                 }
509
510                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
511                               AFS_TRACE_LEVEL_VERBOSE,
512                               "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ\n",
513                               &pCcb->DirectoryCB->NameInformation.FileName,
514                               &pCcb->MaskName);
515             }
516         }
517
518         // Check if we need to start from index
519         if( bIndexSpecified)
520         {
521
522             //
523             // Need to set up the initial point for the query
524             //
525
526             pCcb->CurrentDirIndex = ulFileIndex - 1;
527         }
528
529         // Check if we need to restart the scan
530         else if( bRestartScan)
531         {
532
533             //
534             // Reset the current scan processing
535             //
536
537             if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
538             {
539
540                 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
541             }
542             else
543             {
544
545                 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
546             }
547         }
548
549         AFSReleaseResource( &pCcb->NPCcb->CcbLock);
550
551         AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
552
553         bReleaseMain = FALSE;
554
555         switch( FileInformationClass)
556         {
557
558             case FileDirectoryInformation:
559
560                 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
561                                              FileName[0] );
562                 break;
563
564             case FileFullDirectoryInformation:
565
566                 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
567                                              FileName[0] );
568                 break;
569
570             case FileNamesInformation:
571
572                 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
573                                              FileName[0] );
574                 break;
575
576             case FileBothDirectoryInformation:
577
578                 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
579                                              FileName[0] );
580                 break;
581
582             case FileIdBothDirectoryInformation:
583
584                 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
585                                              FileName[0] );
586
587                 break;
588
589             case FileIdFullDirectoryInformation:
590
591                 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
592                                              FileName[0] );
593
594                 break;
595
596             default:
597
598                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
599                               AFS_TRACE_LEVEL_ERROR,
600                               "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
601                               Irp,
602                               FileInformationClass);
603
604                 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
605         }
606
607         while( TRUE)
608         {
609
610             ULONG ulBytesRemainingInBuffer;
611
612             ulAdditionalAttributes = 0;
613
614             //
615             //  If the user had requested only a single match and we have
616             //  returned that, then we stop at this point.
617             //
618
619             if( bReturnSingleEntry && ulNextEntry != 0)
620             {
621
622                 try_return( ntStatus);
623             }
624
625             pDirEntry = AFSLocateNextDirEntry( pFcb->ObjectInformation,
626                                                pCcb);
627
628             if( pDirEntry == NULL)
629             {
630
631                 if( ulNextEntry == 0)
632                 {
633
634                     if( ( bInitialQuery ||
635                           bRestartScan) &&
636                         pCcb->MaskName.Buffer != NULL)
637                     {
638                         ntStatus = STATUS_NO_SUCH_FILE;
639                     }
640                     else
641                     {
642                         ntStatus = STATUS_NO_MORE_FILES;
643                     }
644                 }
645
646                 try_return( ntStatus);
647             }
648
649             //
650             // Skip the entry if it is pending delete or deleted
651             //
652
653             else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) ||
654                      BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED))
655             {
656
657                 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
658
659                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
660                               AFS_TRACE_LEVEL_VERBOSE,
661                               "AFSQueryDirectory Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
662                               &pDirEntry->NameInformation.FileName,
663                               pDirEntry,
664                               pCcb,
665                               lCount);
666
667                 ASSERT( lCount >= 0);
668
669                 continue;
670             }
671
672             pObjectInfo = pDirEntry->ObjectInformation;
673
674             //
675             // Apply the name filter if there is one
676             //
677
678             if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY))
679             {
680
681                 //
682                 // Only returning directories?
683                 //
684
685                 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY))
686                 {
687
688                     if( !FlagOn( pObjectInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))
689                     {
690
691                         lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
692
693                         AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
694                                       AFS_TRACE_LEVEL_VERBOSE,
695                                       "AFSQueryDirectory Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n",
696                                       &pDirEntry->NameInformation.FileName,
697                                       pDirEntry,
698                                       pCcb,
699                                       lCount);
700
701                         ASSERT( lCount >= 0);
702
703                         continue;
704                     }
705                 }
706                 else if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
707                 {
708
709                     //
710                     // Are we doing a wild card search?
711                     //
712
713                     if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS))
714                     {
715
716                         if( !FsRtlIsNameInExpression( &pCcb->MaskName,
717                                                       &pDirEntry->NameInformation.FileName,
718                                                       TRUE,
719                                                       NULL))
720                         {
721
722                             lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
723
724                             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
725                                           AFS_TRACE_LEVEL_VERBOSE,
726                                           "AFSQueryDirectory Decrement3 count on %wZ DE %p Ccb %p Cnt %d\n",
727                                           &pDirEntry->NameInformation.FileName,
728                                           pDirEntry,
729                                           pCcb,
730                                           lCount);
731
732                             ASSERT( lCount >= 0);
733
734                             continue;
735                         }
736                     }
737                     else
738                     {
739
740                         if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
741                                                      &pCcb->MaskName,
742                                                      FALSE))
743                         {
744
745                             //
746                             // See if this is a match for a case insensitive search
747                             //
748
749                             if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
750                                                          &pCcb->MaskName,
751                                                          TRUE))
752                             {
753
754                                 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
755
756                                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
757                                               AFS_TRACE_LEVEL_VERBOSE,
758                                               "AFSQueryDirectory Decrement4 count on %wZ DE %p Ccb %p Cnt %d\n",
759                                               &pDirEntry->NameInformation.FileName,
760                                               pDirEntry,
761                                               pCcb,
762                                               lCount);
763
764                                 ASSERT( lCount >= 0);
765
766                                 continue;
767                             }
768                         }
769                     }
770                 }
771             }
772
773             //
774             // Be sure the information is valid
775             // We don't worry about entries while enumerating the directory
776             //
777
778             if ( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
779             {
780
781                 ntStatus = AFSValidateEntry( pDirEntry,
782                                              &pCcb->AuthGroup,
783                                              FALSE,
784                                              FALSE);
785                 if ( NT_SUCCESS( ntStatus))
786                 {
787
788                     ClearFlag( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
789                 }
790                 else
791                 {
792
793                     ntStatus = STATUS_SUCCESS;
794                 }
795             }
796
797             pObjectInfo = pDirEntry->ObjectInformation;
798
799             //  Here are the rules concerning filling up the buffer:
800             //
801             //  1.  The Io system guarantees that there will always be
802             //      enough room for at least one base record.
803             //
804             //  2.  If the full first record (including file name) cannot
805             //      fit, as much of the name as possible is copied and
806             //      STATUS_BUFFER_OVERFLOW is returned.
807             //
808             //  3.  If a subsequent record cannot completely fit into the
809             //      buffer, none of it (as in 0 bytes) is copied, and
810             //      STATUS_SUCCESS is returned.  A subsequent query will
811             //      pick up with this record.
812
813             ulBytesRemainingInBuffer = ulUserBufferLength - ulNextEntry;
814
815             if( ( ulNextEntry != 0) &&
816                 ( ( ulBaseLength + pDirEntry->NameInformation.FileName.Length > ulBytesRemainingInBuffer) ||
817                   ( ulUserBufferLength < ulNextEntry) ) )
818             {
819
820                 //
821                 // Back off our current index
822                 //
823
824                 pCcb->CurrentDirIndex--;
825
826                 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
827
828                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
829                               AFS_TRACE_LEVEL_VERBOSE,
830                               "AFSQueryDirectory Decrement5 count on %wZ DE %p Ccb %p Cnt %d\n",
831                               &pDirEntry->NameInformation.FileName,
832                               pDirEntry,
833                               pCcb,
834                               lCount);
835
836                 ASSERT( lCount >= 0);
837
838                 try_return( ntStatus = STATUS_SUCCESS);
839             }
840
841
842             //
843             // For Symlinks and Mount Points the reparse point attribute
844             // must be associated with the directory entry.  In addition,
845             // for Symlinks it must be determined if the target object is
846             // a directory or not.  If so, the directory attribute must be
847             // specified.  Mount points always refer to directories and
848             // must have the directory attribute set.
849             //
850
851             switch( pObjectInfo->FileType)
852             {
853
854             case AFS_FILE_TYPE_MOUNTPOINT:
855             case AFS_FILE_TYPE_DFSLINK:
856             {
857
858                 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
859
860                 break;
861             }
862
863             case AFS_FILE_TYPE_SYMLINK:
864             {
865
866                 //
867                 // Go grab the file information for this entry
868                 // No worries on failures since we will just display
869                 // pseudo information
870                 //
871
872                 RtlZeroMemory( &stFileInfo,
873                                sizeof( AFSFileInfoCB));
874
875                 if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
876                                                            pDirEntry,
877                                                            &pCcb->FullFileName,
878                                                            pCcb->NameArray,
879                                                            &pCcb->AuthGroup,
880                                                            &stFileInfo)))
881                 {
882
883                     if ( stFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
884                     {
885
886                         ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY;
887                     }
888                 }
889
890                 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
891
892                 break;
893             }
894             }
895
896             //
897             // Check if the name begins with a . and we are hiding them
898             //
899
900             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
901                 pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
902                 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
903             {
904
905                 ulAdditionalAttributes |= FILE_ATTRIBUTE_HIDDEN;
906             }
907
908
909             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
910                           AFS_TRACE_LEVEL_VERBOSE,
911                           "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n",
912                           &pCcb->DirectoryCB->NameInformation.FileName,
913                           &pDirEntry->NameInformation.FileName);
914
915             //  Zero the base part of the structure.
916             RtlZeroMemory( &pBuffer[ ulNextEntry],
917                            ulBaseLength);
918
919             switch( FileInformationClass)
920             {
921
922                 //  Now fill the base parts of the structure that are applicable.
923                 case FileIdBothDirectoryInformation:
924                 case FileBothDirectoryInformation:
925                 {
926                     pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry];
927
928                     pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength;
929
930                     if( pDirEntry->NameInformation.ShortNameLength > 0)
931                     {
932                         RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
933                                        &pDirEntry->NameInformation.ShortName[ 0],
934                                        pBothDirInfo->ShortNameLength);
935                     }
936                 }
937                 case FileIdFullDirectoryInformation:
938                 case FileFullDirectoryInformation:
939                 {
940                     pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
941                     pFullDirInfo->EaSize = 0;
942                 }
943                 case FileDirectoryInformation:
944                 {
945                     pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
946
947                     if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
948                     {
949
950                         pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
951                         pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
952                         pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
953                         pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
954
955                         pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
956                         pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
957
958                         if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
959                         {
960                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
961                         }
962                         else
963                         {
964                             pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
965                         }
966                     }
967                     else
968                     {
969
970                         pDirInfo->CreationTime = pObjectInfo->CreationTime;
971                         pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
972                         pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
973                         pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
974
975                         pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
976                         pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
977
978                         if ( ulAdditionalAttributes && pObjectInfo->FileAttributes == FILE_ATTRIBUTE_NORMAL)
979                         {
980
981                             pDirInfo->FileAttributes = ulAdditionalAttributes;
982                         }
983                         else
984                         {
985
986                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
987                         }
988                     }
989
990                     pDirInfo->FileIndex = pDirEntry->FileIndex;
991                     pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
992
993                     break;
994                 }
995
996                 case FileNamesInformation:
997                 {
998                     pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
999                     pNamesInfo->FileIndex = pDirEntry->FileIndex;
1000                     pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
1001
1002                     break;
1003                 }
1004                 default:
1005                 {
1006                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1007                                   AFS_TRACE_LEVEL_ERROR,
1008                                   "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
1009                                   Irp,
1010                                   FileInformationClass);
1011
1012                     lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1013
1014                     AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1015                                   AFS_TRACE_LEVEL_VERBOSE,
1016                                   "AFSQueryDirectory Decrement6 count on %wZ DE %p Ccb %p Cnt %d\n",
1017                                   &pDirEntry->NameInformation.FileName,
1018                                   pDirEntry,
1019                                   pCcb,
1020                                   lCount);
1021
1022                     ASSERT( lCount >= 0);
1023
1024                     try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
1025
1026                     break;
1027                 }
1028             }
1029
1030             ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
1031                                             pDirEntry->NameInformation.FileName.Length :
1032                                             ulBytesRemainingInBuffer - ulBaseLength;
1033
1034             RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
1035                            pDirEntry->NameInformation.FileName.Buffer,
1036                            ulBytesConverted);
1037
1038             //  Set up the previous next entry offset
1039             *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
1040
1041             //  And indicate how much of the user buffer we have currently
1042             //  used up.
1043             Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
1044
1045             //  Check for the case that a single entry doesn't fit.
1046             //  This should only get this far on the first entry.
1047             if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
1048             {
1049
1050                 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1051
1052                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1053                               AFS_TRACE_LEVEL_VERBOSE,
1054                               "AFSQueryDirectory Decrement7 count on %wZ DE %p Ccb %p Cnt %d\n",
1055                               &pDirEntry->NameInformation.FileName,
1056                               pDirEntry,
1057                               pCcb,
1058                               lCount);
1059
1060                 ASSERT( lCount >= 0);
1061
1062                 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
1063             }
1064
1065             lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1066
1067             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1068                           AFS_TRACE_LEVEL_VERBOSE,
1069                           "AFSQueryDirectory Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n",
1070                           &pDirEntry->NameInformation.FileName,
1071                           pDirEntry,
1072                           pCcb,
1073                           lCount);
1074
1075             ASSERT( lCount >= 0);
1076
1077             dStatus = STATUS_SUCCESS;
1078
1079             //  Set ourselves up for the next iteration
1080             ulLastEntry = ulNextEntry;
1081             ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
1082         }
1083
1084 try_exit:
1085
1086         if( bReleaseMain)
1087         {
1088
1089             AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1090         }
1091
1092         if ( bReleaseFcb)
1093         {
1094
1095             AFSReleaseResource( &pFcb->NPFcb->Resource);
1096         }
1097
1098         if( pFcb != NULL)
1099         {
1100
1101             AFSClearEnumerationEvent( pFcb);
1102         }
1103     }
1104
1105     return ntStatus;
1106 }
1107
1108 NTSTATUS
1109 AFSNotifyChangeDirectory( IN PIRP Irp)
1110 {
1111
1112     NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1113     PIO_STACK_LOCATION pIrpSp;
1114     AFSFcb *pFcb = NULL;
1115     AFSCcb *pCcb = NULL;
1116     ULONG ulCompletionFilter;
1117     BOOLEAN bWatchTree;
1118     BOOLEAN bReleaseLock = FALSE;
1119
1120     __Enter
1121     {
1122
1123         //  Get the current Stack location
1124         pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1125
1126         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1127         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1128
1129         if( pFcb == NULL)
1130         {
1131
1132             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1133                           AFS_TRACE_LEVEL_ERROR,
1134                           "AFSNotifyChangeDirectory Attempted access (%08lX) when pFcb == NULL\n",
1135                           Irp);
1136
1137             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1138         }
1139
1140         if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1141             pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1142             pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1143         {
1144
1145             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1146                           AFS_TRACE_LEVEL_ERROR,
1147                           "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1148                           &pCcb->DirectoryCB->NameInformation.FileName,
1149                           pFcb->Header.NodeTypeCode);
1150
1151             try_return( ntStatus = STATUS_INVALID_PARAMETER);
1152         }
1153
1154         //  Reference our input parameter to make things easier
1155         ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1156         bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1157
1158         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1159                       AFS_TRACE_LEVEL_VERBOSE,
1160                       "AFSNotifyChangeDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
1161                       &pFcb->NPFcb->Resource,
1162                       PsGetCurrentThread());
1163
1164         AFSAcquireExcl( &pFcb->NPFcb->Resource,
1165                           TRUE);
1166
1167         bReleaseLock = TRUE;
1168
1169         //
1170         // Check if the node has already been deleted
1171         //
1172
1173         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1174         {
1175
1176             try_return( ntStatus = STATUS_FILE_DELETED);
1177         }
1178         else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1179         {
1180
1181             try_return( ntStatus = STATUS_DELETE_PENDING);
1182         }
1183
1184         //  Call the Fsrtl package to process the request.
1185         ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1186                                                       pCcb,
1187                                                       bWatchTree,
1188                                                       ulCompletionFilter,
1189                                                       Irp);
1190
1191         if( !NT_SUCCESS( ntStatus))
1192         {
1193             try_return( ntStatus);
1194         }
1195
1196         ntStatus = STATUS_PENDING;
1197
1198 try_exit:
1199
1200         if( bReleaseLock)
1201         {
1202
1203             AFSReleaseResource( &pFcb->NPFcb->Resource);
1204         }
1205     }
1206
1207     return ntStatus;
1208 }
1209
1210 AFSDirectoryCB *
1211 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1212                        IN AFSCcb *Ccb)
1213 {
1214
1215     AFSDirectoryCB *pDirEntry = NULL;
1216     NTSTATUS ntStatus = STATUS_SUCCESS;
1217     AFSSnapshotHdr *pSnapshotHdr = NULL;
1218     AFSSnapshotEntry *pSnapshotEntry = NULL;
1219     ULONG ulCount = 0;
1220     LONG lCount;
1221
1222     __Enter
1223     {
1224
1225         AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1226                           TRUE);
1227
1228         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1229                         TRUE);
1230
1231         //
1232         // Is this a PIOCtl query
1233         //
1234
1235         if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1236         {
1237
1238             if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1239                 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1240             {
1241
1242                 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1243
1244                 if( pDirEntry != NULL)
1245                 {
1246
1247                     lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1248
1249                     AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1250                                   AFS_TRACE_LEVEL_VERBOSE,
1251                                   "AFSLocateNextDirEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n",
1252                                   &pDirEntry->NameInformation.FileName,
1253                                   pDirEntry,
1254                                   Ccb,
1255                                   lCount);
1256
1257                     ASSERT( lCount >= 0);
1258                 }
1259
1260                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1261                               AFS_TRACE_LEVEL_VERBOSE,
1262                               "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1263                               &pDirEntry->NameInformation.FileName,
1264                               ObjectInfo->FileId.Cell,
1265                               ObjectInfo->FileId.Volume,
1266                               ObjectInfo->FileId.Vnode,
1267                               ObjectInfo->FileId.Unique);
1268             }
1269
1270             Ccb->CurrentDirIndex++;
1271
1272             try_return( ntStatus);
1273         }
1274
1275         Ccb->CurrentDirIndex++;
1276
1277         if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1278         {
1279
1280             //
1281             // Return the .. entry
1282             //
1283
1284             pDirEntry = AFSGlobalDotDirEntry;
1285
1286             if( pDirEntry != NULL)
1287             {
1288
1289                 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1290
1291                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1292                               AFS_TRACE_LEVEL_VERBOSE,
1293                               "AFSLocateNextDirEntry Increment2 count on %wZ DE %p Ccb %p Cnt %d\n",
1294                               &pDirEntry->NameInformation.FileName,
1295                               pDirEntry,
1296                               Ccb,
1297                               lCount);
1298
1299                 ASSERT( lCount >= 0);
1300             }
1301
1302             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1303                           AFS_TRACE_LEVEL_VERBOSE,
1304                           "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1305                           &pDirEntry->NameInformation.FileName,
1306                           ObjectInfo->FileId.Cell,
1307                           ObjectInfo->FileId.Volume,
1308                           ObjectInfo->FileId.Vnode,
1309                           ObjectInfo->FileId.Unique);
1310         }
1311         else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1312         {
1313
1314             //
1315             // Return the .. entry
1316             //
1317
1318             pDirEntry = AFSGlobalDotDotDirEntry;
1319
1320             if( pDirEntry != NULL)
1321             {
1322
1323                 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1324
1325                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1326                               AFS_TRACE_LEVEL_VERBOSE,
1327                               "AFSLocateNextDirEntry Increment3 count on %wZ DE %p Ccb %p Cnt %d\n",
1328                               &pDirEntry->NameInformation.FileName,
1329                               pDirEntry,
1330                               Ccb,
1331                               lCount);
1332
1333                 ASSERT( lCount >= 0);
1334             }
1335
1336             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1337                           AFS_TRACE_LEVEL_VERBOSE,
1338                           "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1339                           &pDirEntry->NameInformation.FileName,
1340                           ObjectInfo->FileId.Cell,
1341                           ObjectInfo->FileId.Volume,
1342                           ObjectInfo->FileId.Vnode,
1343                           ObjectInfo->FileId.Unique);
1344         }
1345         else
1346         {
1347
1348             pSnapshotHdr = Ccb->DirectorySnapshot;
1349
1350             if( pSnapshotHdr == NULL ||
1351                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1352             {
1353
1354                 try_return( ntStatus);
1355             }
1356
1357             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1358
1359             ulCount = Ccb->CurrentDirIndex;
1360
1361             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1362                           AFS_TRACE_LEVEL_VERBOSE,
1363                           "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1364                           ulCount);
1365
1366             //
1367             // Get to a valid entry
1368             //
1369
1370             while( ulCount < pSnapshotHdr->EntryCount)
1371             {
1372
1373                 pDirEntry = NULL;
1374
1375                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1376                               AFS_TRACE_LEVEL_VERBOSE,
1377                               "AFSLocateNextDirEntry Searching for hash %08lX\n",
1378                               pSnapshotEntry->NameHash);
1379
1380                 if( pSnapshotEntry->NameHash == 0)
1381                 {
1382
1383                     break;
1384                 }
1385
1386                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1387                                                            pSnapshotEntry->NameHash,
1388                                                            &pDirEntry);
1389
1390                 if( !NT_SUCCESS( ntStatus) ||
1391                     pDirEntry != NULL)
1392                 {
1393
1394                     if( pDirEntry != NULL)
1395                     {
1396
1397                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1398                                       AFS_TRACE_LEVEL_VERBOSE,
1399                                       "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1400                                       &pDirEntry->NameInformation.FileName,
1401                                       (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1402                                       ObjectInfo->FileId.Cell,
1403                                       ObjectInfo->FileId.Volume,
1404                                       ObjectInfo->FileId.Vnode,
1405                                       ObjectInfo->FileId.Unique);
1406
1407                         lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1408
1409                         AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1410                                       AFS_TRACE_LEVEL_VERBOSE,
1411                                       "AFSLocateNextDirEntry Increment4 count on %wZ DE %p Ccb %p Cnt %d\n",
1412                                       &pDirEntry->NameInformation.FileName,
1413                                       pDirEntry,
1414                                       Ccb,
1415                                       lCount);
1416
1417                         ASSERT( lCount >= 0);
1418                     }
1419                     else
1420                     {
1421
1422
1423                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1424                                       AFS_TRACE_LEVEL_VERBOSE,
1425                                       "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1426                                       ObjectInfo->FileId.Cell,
1427                                       ObjectInfo->FileId.Volume,
1428                                       ObjectInfo->FileId.Vnode,
1429                                       ObjectInfo->FileId.Unique);
1430                     }
1431
1432                     break;
1433                 }
1434
1435                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1436                               AFS_TRACE_LEVEL_VERBOSE,
1437                               "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1438                               pSnapshotEntry->NameHash,
1439                               ObjectInfo->FileId.Cell,
1440                               ObjectInfo->FileId.Volume,
1441                               ObjectInfo->FileId.Vnode,
1442                               ObjectInfo->FileId.Unique);
1443
1444                 pSnapshotEntry++;
1445
1446                 ulCount++;
1447
1448                 Ccb->CurrentDirIndex++;
1449             }
1450         }
1451
1452 try_exit:
1453
1454         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1455
1456         AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1457     }
1458
1459     return pDirEntry;
1460 }
1461
1462 AFSDirectoryCB *
1463 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1464                           IN AFSCcb *Ccb,
1465                           IN ULONG DirIndex)
1466 {
1467
1468     AFSDirectoryCB *pDirEntry = NULL;
1469     NTSTATUS ntStatus = STATUS_SUCCESS;
1470     AFSSnapshotHdr *pSnapshotHdr = NULL;
1471     AFSSnapshotEntry *pSnapshotEntry = NULL;
1472     ULONG ulCount = 0;
1473
1474     __Enter
1475     {
1476
1477         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1478                         TRUE);
1479
1480         Ccb->CurrentDirIndex = DirIndex;
1481
1482         if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1483         {
1484
1485             //
1486             // Return the .. entry
1487             //
1488
1489             pDirEntry = AFSGlobalDotDirEntry;
1490         }
1491         else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1492         {
1493
1494             //
1495             // Return the .. entry
1496             //
1497
1498             pDirEntry = AFSGlobalDotDotDirEntry;
1499         }
1500         else
1501         {
1502
1503             pSnapshotHdr = Ccb->DirectorySnapshot;
1504
1505             if( pSnapshotHdr == NULL ||
1506                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1507             {
1508
1509                 try_return( ntStatus);
1510             }
1511
1512             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1513
1514             ulCount = Ccb->CurrentDirIndex;
1515
1516             //
1517             // Get to a valid entry
1518             //
1519
1520             while( ulCount < pSnapshotHdr->EntryCount)
1521             {
1522
1523                 pDirEntry = NULL;
1524
1525                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1526                                                            pSnapshotEntry->NameHash,
1527                                                            &pDirEntry);
1528
1529                 if( !NT_SUCCESS( ntStatus) ||
1530                     ( pDirEntry != NULL &&
1531                       pDirEntry->FileIndex == DirIndex))
1532                 {
1533
1534                     break;
1535                 }
1536
1537                 pSnapshotEntry++;
1538
1539                 ulCount++;
1540             }
1541
1542             if( pDirEntry != NULL)
1543             {
1544
1545                 Ccb->CurrentDirIndex = ulCount;
1546             }
1547         }
1548
1549 try_exit:
1550
1551         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1552     }
1553
1554     return pDirEntry;
1555 }
1556
1557 NTSTATUS
1558 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1559                       IN AFSCcb *Ccb,
1560                       IN BOOLEAN ResetIndex)
1561 {
1562
1563     NTSTATUS ntStatus = STATUS_SUCCESS;
1564     AFSSnapshotHdr *pSnapshotHdr = NULL;
1565     AFSSnapshotEntry *pSnapshotEntry = NULL;
1566     AFSDirectoryCB *pDirEntry = NULL;
1567
1568     __Enter
1569     {
1570
1571         if( ResetIndex)
1572         {
1573
1574             //
1575             // Set it up so we still get the . and .. entries for empty directories
1576             //
1577
1578             if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1579             {
1580
1581                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1582             }
1583             else
1584             {
1585
1586                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1587             }
1588         }
1589
1590         if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1591         {
1592
1593             //
1594             // If we have a snapshot then clear it out
1595             //
1596
1597             if( Ccb->DirectorySnapshot != NULL)
1598             {
1599
1600                 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1601
1602                 Ccb->DirectorySnapshot = NULL;
1603             }
1604
1605             try_return( ntStatus);
1606         }
1607
1608         //
1609         // Allocate our snapshot buffer for this enumeration
1610         //
1611
1612         pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1613                                                                    sizeof( AFSSnapshotHdr) +
1614                                                                         ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1615                                                                                 sizeof( AFSSnapshotEntry)),
1616                                                                    AFS_DIR_SNAPSHOT_TAG);
1617
1618         if( pSnapshotHdr == NULL)
1619         {
1620
1621             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1622         }
1623
1624         RtlZeroMemory( pSnapshotHdr,
1625                        sizeof( AFSSnapshotHdr) +
1626                             ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1627                                     sizeof( AFSSnapshotEntry)));
1628
1629         pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1630
1631         pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1632
1633         //
1634         // Populate our snapshot
1635         //
1636
1637         pSnapshotEntry = pSnapshotHdr->TopEntry;
1638
1639         pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1640
1641         while( pDirEntry != NULL)
1642         {
1643
1644             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1645                 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1646                 !AFSIsNameInSnapshot( pSnapshotHdr,
1647                                       (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1648             {
1649
1650                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1651                               AFS_TRACE_LEVEL_VERBOSE,
1652                               "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1653                               pSnapshotHdr->EntryCount,
1654                               &pDirEntry->NameInformation.FileName,
1655                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1656                               pDirEntry->Flags,
1657                               Fcb->ObjectInformation->FileId.Cell,
1658                               Fcb->ObjectInformation->FileId.Volume,
1659                               Fcb->ObjectInformation->FileId.Vnode,
1660                               Fcb->ObjectInformation->FileId.Unique);
1661
1662                 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1663
1664                 pSnapshotEntry++;
1665             }
1666             else
1667             {
1668
1669                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1670                               AFS_TRACE_LEVEL_VERBOSE,
1671                               "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1672                               pSnapshotHdr->EntryCount,
1673                               &pDirEntry->NameInformation.FileName,
1674                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1675                               pDirEntry->Flags,
1676                               Fcb->ObjectInformation->FileId.Cell,
1677                               Fcb->ObjectInformation->FileId.Volume,
1678                               Fcb->ObjectInformation->FileId.Vnode,
1679                               Fcb->ObjectInformation->FileId.Unique);
1680             }
1681
1682             pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1683         }
1684
1685         if( Ccb->DirectorySnapshot != NULL)
1686         {
1687
1688             AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1689
1690             Ccb->DirectorySnapshot = NULL;
1691         }
1692
1693         Ccb->DirectorySnapshot = pSnapshotHdr;
1694
1695 try_exit:
1696
1697         NOTHING;
1698     }
1699
1700     return ntStatus;
1701 }
1702
1703 NTSTATUS
1704 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1705                                    IN AFSCcb *Ccb,
1706                                    IN BOOLEAN WatchTree,
1707                                    IN ULONG CompletionFilter,
1708                                    IN PIRP NotifyIrp)
1709 {
1710
1711     NTSTATUS ntStatus = STATUS_SUCCESS;
1712     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1713     size_t sztLength;
1714
1715     __Enter
1716     {
1717
1718         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1719                         TRUE);
1720
1721         //
1722         // Build a dir name based on the FID of the file
1723         //
1724
1725         if( Ccb->NotifyMask.Buffer == NULL)
1726         {
1727
1728             Ccb->NotifyMask.Length = 0;
1729             Ccb->NotifyMask.MaximumLength = 1024;
1730
1731             Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1732                                                                         Ccb->NotifyMask.MaximumLength,
1733                                                                         AFS_GENERIC_MEMORY_7_TAG);
1734
1735             if( Ccb->NotifyMask.Buffer == NULL)
1736             {
1737
1738                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1739             }
1740
1741             ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1742                                            Ccb->NotifyMask.MaximumLength,
1743                                            L"\\%08lX.%08lX.%08lX.%08lX",
1744                                            ObjectInfo->FileId.Cell,
1745                                            ObjectInfo->FileId.Volume,
1746                                            ObjectInfo->FileId.Vnode,
1747                                            ObjectInfo->FileId.Unique);
1748
1749             if( !NT_SUCCESS( ntStatus))
1750             {
1751
1752                 try_return( ntStatus);
1753             }
1754
1755             ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1756                                            (size_t)Ccb->NotifyMask.MaximumLength,
1757                                            &sztLength);
1758
1759             if( !NT_SUCCESS( ntStatus))
1760             {
1761
1762                 try_return( ntStatus);
1763             }
1764
1765             Ccb->NotifyMask.Length = (USHORT)sztLength;
1766         }
1767
1768         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1769                       AFS_TRACE_LEVEL_VERBOSE,
1770                       "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1771                       &Ccb->NotifyMask,
1772                       NotifyIrp,
1773                       CompletionFilter,
1774                       WatchTree);
1775
1776         FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1777                                         &pDeviceExt->Specific.Control.DirNotifyList,
1778                                         (void *)Ccb,
1779                                         (PSTRING)&Ccb->NotifyMask,
1780                                         WatchTree,
1781                                         TRUE,
1782                                         CompletionFilter,
1783                                         NotifyIrp,
1784                                         NULL,
1785                                         NULL,
1786                                         NULL);
1787
1788 try_exit:
1789
1790         if( !NT_SUCCESS( ntStatus))
1791         {
1792
1793             if( Ccb->NotifyMask.Buffer != NULL)
1794             {
1795
1796                 AFSExFreePoolWithTag( Ccb->NotifyMask.Buffer, AFS_GENERIC_MEMORY_7_TAG);
1797
1798                 Ccb->NotifyMask.Buffer = NULL;
1799             }
1800         }
1801
1802         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1803     }
1804
1805     return ntStatus;
1806 }
1807
1808 void
1809 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1810                                 IN AFSCcb *Ccb,
1811                                 IN ULONG NotifyFilter,
1812                                 IN ULONG NotificationAction)
1813 {
1814
1815     NTSTATUS ntStatus = STATUS_SUCCESS;
1816     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1817     UNICODE_STRING uniName, uniComponentName;
1818     size_t sztLength;
1819     USHORT usNameOffset = 0;
1820
1821     __Enter
1822     {
1823
1824         uniName.Buffer = NULL;
1825
1826         if( ParentObjectInfo == NULL ||
1827             AFSGlobalRoot == NULL)
1828         {
1829
1830             try_return( ntStatus);
1831         }
1832
1833         if( Ccb == NULL)
1834         {
1835
1836             RtlInitUnicodeString( &uniComponentName,
1837                                   L"_AFSChange.dat");
1838         }
1839         else
1840         {
1841
1842             uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1843         }
1844
1845         //
1846         // Build a dir name based on the FID of the file
1847         //
1848
1849         uniName.Length = 0;
1850         uniName.MaximumLength = 1024 + uniComponentName.Length;
1851
1852         uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1853                                                             uniName.MaximumLength,
1854                                                             AFS_GENERIC_MEMORY_8_TAG);
1855
1856         if( uniName.Buffer == NULL)
1857         {
1858
1859             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1860         }
1861
1862         ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1863                                        uniName.MaximumLength,
1864                                        L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1865                                        ParentObjectInfo->FileId.Cell,
1866                                        ParentObjectInfo->FileId.Volume,
1867                                        ParentObjectInfo->FileId.Vnode,
1868                                        ParentObjectInfo->FileId.Unique,
1869                                        &uniComponentName);
1870
1871         if( !NT_SUCCESS( ntStatus))
1872         {
1873
1874             try_return( ntStatus);
1875         }
1876
1877         ntStatus = RtlStringCbLengthW( uniName.Buffer,
1878                                        (size_t)uniName.MaximumLength,
1879                                        &sztLength);
1880
1881         if( !NT_SUCCESS( ntStatus))
1882         {
1883
1884             try_return( ntStatus);
1885         }
1886
1887         uniName.Length = (USHORT)sztLength;
1888
1889         usNameOffset = uniName.Length - uniComponentName.Length;
1890
1891         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1892                       AFS_TRACE_LEVEL_VERBOSE,
1893                       "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1894                       &uniName,
1895                       NotifyFilter,
1896                       NotificationAction,
1897                       usNameOffset,
1898                       uniName.Length,
1899                       uniComponentName.Length);
1900
1901         FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1902                                        &pDeviceExt->Specific.Control.DirNotifyList,
1903                                        (PSTRING)&uniName,
1904                                        usNameOffset,
1905                                        NULL,
1906                                        NULL,
1907                                        NotifyFilter,
1908                                        NotificationAction,
1909                                        NULL,
1910                                        (void *)Ccb);
1911
1912 try_exit:
1913
1914         if( uniName.Buffer != NULL)
1915         {
1916
1917             AFSExFreePoolWithTag( uniName.Buffer, AFS_GENERIC_MEMORY_8_TAG);
1918         }
1919     }
1920
1921     return;
1922 }
1923
1924 // For use with FsRtlNotifyFilterChangeDirectory but must
1925 // be implemented in the Framework because the library can
1926 // be unloaded.
1927
1928 BOOLEAN
1929 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1930                                IN void *FilterContext)
1931 {
1932     UNREFERENCED_PARAMETER(NotifyContext);
1933     UNREFERENCED_PARAMETER(FilterContext);
1934     BOOLEAN bReturn = TRUE;
1935
1936     __Enter
1937     {
1938
1939     }
1940
1941     return bReturn;
1942 }
1943
1944 BOOLEAN
1945 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1946                      IN ULONG HashIndex)
1947 {
1948
1949     BOOLEAN bIsInSnapshot = FALSE;
1950     AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1951     ULONG ulCount = 0;
1952
1953     while( ulCount < SnapshotHdr->EntryCount)
1954     {
1955
1956         if( pSnapshotEntry->NameHash == HashIndex)
1957         {
1958
1959             bIsInSnapshot = TRUE;
1960
1961             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1962                           AFS_TRACE_LEVEL_VERBOSE,
1963                           "AFSIsNameInSnapshot  Hash index %08lX already in snapshot\n",
1964                           HashIndex);
1965
1966             break;
1967         }
1968         else if( pSnapshotEntry->NameHash == 0)
1969         {
1970
1971             break;
1972         }
1973
1974         pSnapshotEntry++;
1975
1976         ulCount++;
1977     }
1978
1979     return bIsInSnapshot;
1980 }