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