2ac140e8507ce428c2d09926882f30df1c79f75a
[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             AFSValidateEntry( pDirEntry,
786                               &pCcb->AuthGroup,
787                               FALSE,
788                               FALSE);
789
790             pObjectInfo = pDirEntry->ObjectInformation;
791
792             //  Here are the rules concerning filling up the buffer:
793             //
794             //  1.  The Io system guarantees that there will always be
795             //      enough room for at least one base record.
796             //
797             //  2.  If the full first record (including file name) cannot
798             //      fit, as much of the name as possible is copied and
799             //      STATUS_BUFFER_OVERFLOW is returned.
800             //
801             //  3.  If a subsequent record cannot completely fit into the
802             //      buffer, none of it (as in 0 bytes) is copied, and
803             //      STATUS_SUCCESS is returned.  A subsequent query will
804             //      pick up with this record.
805
806             ulBytesRemainingInBuffer = ulUserBufferLength - ulNextEntry;
807
808             if( ( ulNextEntry != 0) &&
809                 ( ( ulBaseLength + pDirEntry->NameInformation.FileName.Length > ulBytesRemainingInBuffer) ||
810                   ( ulUserBufferLength < ulNextEntry) ) )
811             {
812
813                 //
814                 // Back off our current index
815                 //
816
817                 pCcb->CurrentDirIndex--;
818
819                 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
820
821                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
822                               AFS_TRACE_LEVEL_VERBOSE,
823                               "AFSQueryDirectory Decrement5 count on %wZ DE %p Ccb %p Cnt %d\n",
824                               &pDirEntry->NameInformation.FileName,
825                               pDirEntry,
826                               pCcb,
827                               lCount);
828
829                 ASSERT( lCount >= 0);
830
831                 try_return( ntStatus = STATUS_SUCCESS);
832             }
833
834
835             //
836             // For Symlinks and Mount Points the reparse point attribute
837             // must be associated with the directory entry.  In addition,
838             // for Symlinks it must be determined if the target object is
839             // a directory or not.  If so, the directory attribute must be
840             // specified.  Mount points always refer to directories and
841             // must have the directory attribute set.
842             //
843
844             switch( pObjectInfo->FileType)
845             {
846
847             case AFS_FILE_TYPE_MOUNTPOINT:
848             case AFS_FILE_TYPE_DFSLINK:
849             {
850
851                 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
852
853                 break;
854             }
855
856             case AFS_FILE_TYPE_SYMLINK:
857             {
858
859                 //
860                 // Go grab the file information for this entry
861                 // No worries on failures since we will just display
862                 // pseudo information
863                 //
864
865                 RtlZeroMemory( &stFileInfo,
866                                sizeof( AFSFileInfoCB));
867
868                 if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
869                                                            pDirEntry,
870                                                            &pCcb->FullFileName,
871                                                            pCcb->NameArray,
872                                                            &pCcb->AuthGroup,
873                                                            &stFileInfo)))
874                 {
875
876                     if ( stFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
877                     {
878
879                         ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY;
880                     }
881                 }
882
883                 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
884
885                 break;
886             }
887             }
888
889             //
890             // Check if the name begins with a . and we are hiding them
891             //
892
893             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
894                 pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
895                 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
896             {
897
898                 ulAdditionalAttributes |= FILE_ATTRIBUTE_HIDDEN;
899             }
900
901
902             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
903                           AFS_TRACE_LEVEL_VERBOSE,
904                           "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n",
905                           &pCcb->DirectoryCB->NameInformation.FileName,
906                           &pDirEntry->NameInformation.FileName);
907
908             //  Zero the base part of the structure.
909             RtlZeroMemory( &pBuffer[ ulNextEntry],
910                            ulBaseLength);
911
912             switch( FileInformationClass)
913             {
914
915                 //  Now fill the base parts of the structure that are applicable.
916                 case FileIdBothDirectoryInformation:
917                 case FileBothDirectoryInformation:
918                 {
919                     pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry];
920
921                     pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength;
922
923                     if( pDirEntry->NameInformation.ShortNameLength > 0)
924                     {
925                         RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
926                                        &pDirEntry->NameInformation.ShortName[ 0],
927                                        pBothDirInfo->ShortNameLength);
928                     }
929                 }
930                 case FileIdFullDirectoryInformation:
931                 case FileFullDirectoryInformation:
932                 {
933                     pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
934                     pFullDirInfo->EaSize = 0;
935                 }
936                 case FileDirectoryInformation:
937                 {
938                     pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
939
940                     if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
941                     {
942
943                         pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
944                         pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
945                         pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
946                         pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
947
948                         pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
949                         pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
950
951                         if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
952                         {
953                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
954                         }
955                         else
956                         {
957                             pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
958                         }
959                     }
960                     else
961                     {
962
963                         pDirInfo->CreationTime = pObjectInfo->CreationTime;
964                         pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
965                         pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
966                         pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
967
968                         pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
969                         pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
970
971                         if ( ulAdditionalAttributes && pObjectInfo->FileAttributes == FILE_ATTRIBUTE_NORMAL)
972                         {
973
974                             pDirInfo->FileAttributes = ulAdditionalAttributes;
975                         }
976                         else
977                         {
978
979                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
980                         }
981                     }
982
983                     pDirInfo->FileIndex = pDirEntry->FileIndex;
984                     pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
985
986                     break;
987                 }
988
989                 case FileNamesInformation:
990                 {
991                     pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
992                     pNamesInfo->FileIndex = pDirEntry->FileIndex;
993                     pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
994
995                     break;
996                 }
997                 default:
998                 {
999                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1000                                   AFS_TRACE_LEVEL_ERROR,
1001                                   "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
1002                                   Irp,
1003                                   FileInformationClass);
1004
1005                     lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1006
1007                     AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1008                                   AFS_TRACE_LEVEL_VERBOSE,
1009                                   "AFSQueryDirectory Decrement6 count on %wZ DE %p Ccb %p Cnt %d\n",
1010                                   &pDirEntry->NameInformation.FileName,
1011                                   pDirEntry,
1012                                   pCcb,
1013                                   lCount);
1014
1015                     ASSERT( lCount >= 0);
1016
1017                     try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
1018
1019                     break;
1020                 }
1021             }
1022
1023             ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
1024                                             pDirEntry->NameInformation.FileName.Length :
1025                                             ulBytesRemainingInBuffer - ulBaseLength;
1026
1027             RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
1028                            pDirEntry->NameInformation.FileName.Buffer,
1029                            ulBytesConverted);
1030
1031             //  Set up the previous next entry offset
1032             *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
1033
1034             //  And indicate how much of the user buffer we have currently
1035             //  used up.
1036             Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
1037
1038             //  Check for the case that a single entry doesn't fit.
1039             //  This should only get this far on the first entry.
1040             if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
1041             {
1042
1043                 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1044
1045                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1046                               AFS_TRACE_LEVEL_VERBOSE,
1047                               "AFSQueryDirectory Decrement7 count on %wZ DE %p Ccb %p Cnt %d\n",
1048                               &pDirEntry->NameInformation.FileName,
1049                               pDirEntry,
1050                               pCcb,
1051                               lCount);
1052
1053                 ASSERT( lCount >= 0);
1054
1055                 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
1056             }
1057
1058             lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1059
1060             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1061                           AFS_TRACE_LEVEL_VERBOSE,
1062                           "AFSQueryDirectory Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n",
1063                           &pDirEntry->NameInformation.FileName,
1064                           pDirEntry,
1065                           pCcb,
1066                           lCount);
1067
1068             ASSERT( lCount >= 0);
1069
1070             dStatus = STATUS_SUCCESS;
1071
1072             //  Set ourselves up for the next iteration
1073             ulLastEntry = ulNextEntry;
1074             ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
1075         }
1076
1077 try_exit:
1078
1079         if( bReleaseMain)
1080         {
1081
1082             AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1083         }
1084
1085         if ( bReleaseFcb)
1086         {
1087
1088             AFSReleaseResource( &pFcb->NPFcb->Resource);
1089         }
1090
1091         if( pFcb != NULL)
1092         {
1093
1094             AFSClearEnumerationEvent( pFcb);
1095         }
1096     }
1097
1098     return ntStatus;
1099 }
1100
1101 NTSTATUS
1102 AFSNotifyChangeDirectory( IN PIRP Irp)
1103 {
1104
1105     NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1106     PIO_STACK_LOCATION pIrpSp;
1107     AFSFcb *pFcb = NULL;
1108     AFSCcb *pCcb = NULL;
1109     ULONG ulCompletionFilter;
1110     BOOLEAN bWatchTree;
1111     BOOLEAN bReleaseLock = FALSE;
1112
1113     __Enter
1114     {
1115
1116         //  Get the current Stack location
1117         pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1118
1119         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1120         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1121
1122         if( pFcb == NULL)
1123         {
1124
1125             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1126                           AFS_TRACE_LEVEL_ERROR,
1127                           "AFSNotifyChangeDirectory Attempted access (%08lX) when pFcb == NULL\n",
1128                           Irp);
1129
1130             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1131         }
1132
1133         if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1134             pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1135             pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1136         {
1137
1138             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1139                           AFS_TRACE_LEVEL_ERROR,
1140                           "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1141                           &pCcb->DirectoryCB->NameInformation.FileName,
1142                           pFcb->Header.NodeTypeCode);
1143
1144             try_return( ntStatus = STATUS_INVALID_PARAMETER);
1145         }
1146
1147         //  Reference our input parameter to make things easier
1148         ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1149         bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1150
1151         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1152                       AFS_TRACE_LEVEL_VERBOSE,
1153                       "AFSNotifyChangeDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
1154                       &pFcb->NPFcb->Resource,
1155                       PsGetCurrentThread());
1156
1157         AFSAcquireExcl( &pFcb->NPFcb->Resource,
1158                           TRUE);
1159
1160         bReleaseLock = TRUE;
1161
1162         //
1163         // Check if the node has already been deleted
1164         //
1165
1166         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1167         {
1168
1169             try_return( ntStatus = STATUS_FILE_DELETED);
1170         }
1171         else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1172         {
1173
1174             try_return( ntStatus = STATUS_DELETE_PENDING);
1175         }
1176
1177         //  Call the Fsrtl package to process the request.
1178         ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1179                                                       pCcb,
1180                                                       bWatchTree,
1181                                                       ulCompletionFilter,
1182                                                       Irp);
1183
1184         if( !NT_SUCCESS( ntStatus))
1185         {
1186             try_return( ntStatus);
1187         }
1188
1189         ntStatus = STATUS_PENDING;
1190
1191 try_exit:
1192
1193         if( bReleaseLock)
1194         {
1195
1196             AFSReleaseResource( &pFcb->NPFcb->Resource);
1197         }
1198     }
1199
1200     return ntStatus;
1201 }
1202
1203 AFSDirectoryCB *
1204 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1205                        IN AFSCcb *Ccb)
1206 {
1207
1208     AFSDirectoryCB *pDirEntry = NULL;
1209     NTSTATUS ntStatus = STATUS_SUCCESS;
1210     AFSSnapshotHdr *pSnapshotHdr = NULL;
1211     AFSSnapshotEntry *pSnapshotEntry = NULL;
1212     ULONG ulCount = 0;
1213     LONG lCount;
1214
1215     __Enter
1216     {
1217
1218         AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1219                           TRUE);
1220
1221         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1222                         TRUE);
1223
1224         //
1225         // Is this a PIOCtl query
1226         //
1227
1228         if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1229         {
1230
1231             if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1232                 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1233             {
1234
1235                 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1236
1237                 if( pDirEntry != NULL)
1238                 {
1239
1240                     lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1241
1242                     AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1243                                   AFS_TRACE_LEVEL_VERBOSE,
1244                                   "AFSLocateNextDirEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n",
1245                                   &pDirEntry->NameInformation.FileName,
1246                                   pDirEntry,
1247                                   Ccb,
1248                                   lCount);
1249
1250                     ASSERT( lCount >= 0);
1251                 }
1252
1253                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1254                               AFS_TRACE_LEVEL_VERBOSE,
1255                               "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1256                               &pDirEntry->NameInformation.FileName,
1257                               ObjectInfo->FileId.Cell,
1258                               ObjectInfo->FileId.Volume,
1259                               ObjectInfo->FileId.Vnode,
1260                               ObjectInfo->FileId.Unique);
1261             }
1262
1263             Ccb->CurrentDirIndex++;
1264
1265             try_return( ntStatus);
1266         }
1267
1268         Ccb->CurrentDirIndex++;
1269
1270         if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1271         {
1272
1273             //
1274             // Return the .. entry
1275             //
1276
1277             pDirEntry = AFSGlobalDotDirEntry;
1278
1279             if( pDirEntry != NULL)
1280             {
1281
1282                 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1283
1284                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1285                               AFS_TRACE_LEVEL_VERBOSE,
1286                               "AFSLocateNextDirEntry Increment2 count on %wZ DE %p Ccb %p Cnt %d\n",
1287                               &pDirEntry->NameInformation.FileName,
1288                               pDirEntry,
1289                               Ccb,
1290                               lCount);
1291
1292                 ASSERT( lCount >= 0);
1293             }
1294
1295             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1296                           AFS_TRACE_LEVEL_VERBOSE,
1297                           "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1298                           &pDirEntry->NameInformation.FileName,
1299                           ObjectInfo->FileId.Cell,
1300                           ObjectInfo->FileId.Volume,
1301                           ObjectInfo->FileId.Vnode,
1302                           ObjectInfo->FileId.Unique);
1303         }
1304         else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1305         {
1306
1307             //
1308             // Return the .. entry
1309             //
1310
1311             pDirEntry = AFSGlobalDotDotDirEntry;
1312
1313             if( pDirEntry != NULL)
1314             {
1315
1316                 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1317
1318                 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1319                               AFS_TRACE_LEVEL_VERBOSE,
1320                               "AFSLocateNextDirEntry Increment3 count on %wZ DE %p Ccb %p Cnt %d\n",
1321                               &pDirEntry->NameInformation.FileName,
1322                               pDirEntry,
1323                               Ccb,
1324                               lCount);
1325
1326                 ASSERT( lCount >= 0);
1327             }
1328
1329             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1330                           AFS_TRACE_LEVEL_VERBOSE,
1331                           "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1332                           &pDirEntry->NameInformation.FileName,
1333                           ObjectInfo->FileId.Cell,
1334                           ObjectInfo->FileId.Volume,
1335                           ObjectInfo->FileId.Vnode,
1336                           ObjectInfo->FileId.Unique);
1337         }
1338         else
1339         {
1340
1341             pSnapshotHdr = Ccb->DirectorySnapshot;
1342
1343             if( pSnapshotHdr == NULL ||
1344                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1345             {
1346
1347                 try_return( ntStatus);
1348             }
1349
1350             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1351
1352             ulCount = Ccb->CurrentDirIndex;
1353
1354             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1355                           AFS_TRACE_LEVEL_VERBOSE,
1356                           "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1357                           ulCount);
1358
1359             //
1360             // Get to a valid entry
1361             //
1362
1363             while( ulCount < pSnapshotHdr->EntryCount)
1364             {
1365
1366                 pDirEntry = NULL;
1367
1368                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1369                               AFS_TRACE_LEVEL_VERBOSE,
1370                               "AFSLocateNextDirEntry Searching for hash %08lX\n",
1371                               pSnapshotEntry->NameHash);
1372
1373                 if( pSnapshotEntry->NameHash == 0)
1374                 {
1375
1376                     break;
1377                 }
1378
1379                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1380                                                            pSnapshotEntry->NameHash,
1381                                                            &pDirEntry);
1382
1383                 if( !NT_SUCCESS( ntStatus) ||
1384                     pDirEntry != NULL)
1385                 {
1386
1387                     if( pDirEntry != NULL)
1388                     {
1389
1390                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1391                                       AFS_TRACE_LEVEL_VERBOSE,
1392                                       "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1393                                       &pDirEntry->NameInformation.FileName,
1394                                       (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1395                                       ObjectInfo->FileId.Cell,
1396                                       ObjectInfo->FileId.Volume,
1397                                       ObjectInfo->FileId.Vnode,
1398                                       ObjectInfo->FileId.Unique);
1399
1400                         lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1401
1402                         AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1403                                       AFS_TRACE_LEVEL_VERBOSE,
1404                                       "AFSLocateNextDirEntry Increment4 count on %wZ DE %p Ccb %p Cnt %d\n",
1405                                       &pDirEntry->NameInformation.FileName,
1406                                       pDirEntry,
1407                                       Ccb,
1408                                       lCount);
1409
1410                         ASSERT( lCount >= 0);
1411                     }
1412                     else
1413                     {
1414
1415
1416                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1417                                       AFS_TRACE_LEVEL_VERBOSE,
1418                                       "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1419                                       ObjectInfo->FileId.Cell,
1420                                       ObjectInfo->FileId.Volume,
1421                                       ObjectInfo->FileId.Vnode,
1422                                       ObjectInfo->FileId.Unique);
1423                     }
1424
1425                     break;
1426                 }
1427
1428                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1429                               AFS_TRACE_LEVEL_VERBOSE,
1430                               "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1431                               pSnapshotEntry->NameHash,
1432                               ObjectInfo->FileId.Cell,
1433                               ObjectInfo->FileId.Volume,
1434                               ObjectInfo->FileId.Vnode,
1435                               ObjectInfo->FileId.Unique);
1436
1437                 pSnapshotEntry++;
1438
1439                 ulCount++;
1440
1441                 Ccb->CurrentDirIndex++;
1442             }
1443         }
1444
1445 try_exit:
1446
1447         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1448
1449         AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1450     }
1451
1452     return pDirEntry;
1453 }
1454
1455 AFSDirectoryCB *
1456 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1457                           IN AFSCcb *Ccb,
1458                           IN ULONG DirIndex)
1459 {
1460
1461     AFSDirectoryCB *pDirEntry = NULL;
1462     NTSTATUS ntStatus = STATUS_SUCCESS;
1463     AFSSnapshotHdr *pSnapshotHdr = NULL;
1464     AFSSnapshotEntry *pSnapshotEntry = NULL;
1465     ULONG ulCount = 0;
1466
1467     __Enter
1468     {
1469
1470         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1471                         TRUE);
1472
1473         Ccb->CurrentDirIndex = DirIndex;
1474
1475         if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1476         {
1477
1478             //
1479             // Return the .. entry
1480             //
1481
1482             pDirEntry = AFSGlobalDotDirEntry;
1483         }
1484         else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1485         {
1486
1487             //
1488             // Return the .. entry
1489             //
1490
1491             pDirEntry = AFSGlobalDotDotDirEntry;
1492         }
1493         else
1494         {
1495
1496             pSnapshotHdr = Ccb->DirectorySnapshot;
1497
1498             if( pSnapshotHdr == NULL ||
1499                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1500             {
1501
1502                 try_return( ntStatus);
1503             }
1504
1505             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1506
1507             ulCount = Ccb->CurrentDirIndex;
1508
1509             //
1510             // Get to a valid entry
1511             //
1512
1513             while( ulCount < pSnapshotHdr->EntryCount)
1514             {
1515
1516                 pDirEntry = NULL;
1517
1518                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1519                                                            pSnapshotEntry->NameHash,
1520                                                            &pDirEntry);
1521
1522                 if( !NT_SUCCESS( ntStatus) ||
1523                     ( pDirEntry != NULL &&
1524                       pDirEntry->FileIndex == DirIndex))
1525                 {
1526
1527                     break;
1528                 }
1529
1530                 pSnapshotEntry++;
1531
1532                 ulCount++;
1533             }
1534
1535             if( pDirEntry != NULL)
1536             {
1537
1538                 Ccb->CurrentDirIndex = ulCount;
1539             }
1540         }
1541
1542 try_exit:
1543
1544         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1545     }
1546
1547     return pDirEntry;
1548 }
1549
1550 NTSTATUS
1551 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1552                       IN AFSCcb *Ccb,
1553                       IN BOOLEAN ResetIndex)
1554 {
1555
1556     NTSTATUS ntStatus = STATUS_SUCCESS;
1557     AFSSnapshotHdr *pSnapshotHdr = NULL;
1558     AFSSnapshotEntry *pSnapshotEntry = NULL;
1559     AFSDirectoryCB *pDirEntry = NULL;
1560
1561     __Enter
1562     {
1563
1564         if( ResetIndex)
1565         {
1566
1567             //
1568             // Set it up so we still get the . and .. entries for empty directories
1569             //
1570
1571             if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1572             {
1573
1574                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1575             }
1576             else
1577             {
1578
1579                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1580             }
1581         }
1582
1583         if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1584         {
1585
1586             //
1587             // If we have a snapshot then clear it out
1588             //
1589
1590             if( Ccb->DirectorySnapshot != NULL)
1591             {
1592
1593                 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1594
1595                 Ccb->DirectorySnapshot = NULL;
1596             }
1597
1598             try_return( ntStatus);
1599         }
1600
1601         //
1602         // Allocate our snapshot buffer for this enumeration
1603         //
1604
1605         pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1606                                                                    sizeof( AFSSnapshotHdr) +
1607                                                                         ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1608                                                                                 sizeof( AFSSnapshotEntry)),
1609                                                                    AFS_DIR_SNAPSHOT_TAG);
1610
1611         if( pSnapshotHdr == NULL)
1612         {
1613
1614             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1615         }
1616
1617         RtlZeroMemory( pSnapshotHdr,
1618                        sizeof( AFSSnapshotHdr) +
1619                             ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1620                                     sizeof( AFSSnapshotEntry)));
1621
1622         pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1623
1624         pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1625
1626         //
1627         // Populate our snapshot
1628         //
1629
1630         pSnapshotEntry = pSnapshotHdr->TopEntry;
1631
1632         pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1633
1634         while( pDirEntry != NULL)
1635         {
1636
1637             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1638                 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1639                 !AFSIsNameInSnapshot( pSnapshotHdr,
1640                                       (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1641             {
1642
1643                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1644                               AFS_TRACE_LEVEL_VERBOSE,
1645                               "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1646                               pSnapshotHdr->EntryCount,
1647                               &pDirEntry->NameInformation.FileName,
1648                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1649                               pDirEntry->Flags,
1650                               Fcb->ObjectInformation->FileId.Cell,
1651                               Fcb->ObjectInformation->FileId.Volume,
1652                               Fcb->ObjectInformation->FileId.Vnode,
1653                               Fcb->ObjectInformation->FileId.Unique);
1654
1655                 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1656
1657                 pSnapshotEntry++;
1658             }
1659             else
1660             {
1661
1662                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1663                               AFS_TRACE_LEVEL_VERBOSE,
1664                               "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1665                               pSnapshotHdr->EntryCount,
1666                               &pDirEntry->NameInformation.FileName,
1667                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1668                               pDirEntry->Flags,
1669                               Fcb->ObjectInformation->FileId.Cell,
1670                               Fcb->ObjectInformation->FileId.Volume,
1671                               Fcb->ObjectInformation->FileId.Vnode,
1672                               Fcb->ObjectInformation->FileId.Unique);
1673             }
1674
1675             pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1676         }
1677
1678         if( Ccb->DirectorySnapshot != NULL)
1679         {
1680
1681             AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1682
1683             Ccb->DirectorySnapshot = NULL;
1684         }
1685
1686         Ccb->DirectorySnapshot = pSnapshotHdr;
1687
1688 try_exit:
1689
1690         NOTHING;
1691     }
1692
1693     return ntStatus;
1694 }
1695
1696 NTSTATUS
1697 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1698                                    IN AFSCcb *Ccb,
1699                                    IN BOOLEAN WatchTree,
1700                                    IN ULONG CompletionFilter,
1701                                    IN PIRP NotifyIrp)
1702 {
1703
1704     NTSTATUS ntStatus = STATUS_SUCCESS;
1705     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1706     size_t sztLength;
1707
1708     __Enter
1709     {
1710
1711         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1712                         TRUE);
1713
1714         //
1715         // Build a dir name based on the FID of the file
1716         //
1717
1718         if( Ccb->NotifyMask.Buffer == NULL)
1719         {
1720
1721             Ccb->NotifyMask.Length = 0;
1722             Ccb->NotifyMask.MaximumLength = 1024;
1723
1724             Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1725                                                                         Ccb->NotifyMask.MaximumLength,
1726                                                                         AFS_GENERIC_MEMORY_7_TAG);
1727
1728             if( Ccb->NotifyMask.Buffer == NULL)
1729             {
1730
1731                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1732             }
1733
1734             ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1735                                            Ccb->NotifyMask.MaximumLength,
1736                                            L"\\%08lX.%08lX.%08lX.%08lX",
1737                                            ObjectInfo->FileId.Cell,
1738                                            ObjectInfo->FileId.Volume,
1739                                            ObjectInfo->FileId.Vnode,
1740                                            ObjectInfo->FileId.Unique);
1741
1742             if( !NT_SUCCESS( ntStatus))
1743             {
1744
1745                 try_return( ntStatus);
1746             }
1747
1748             ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1749                                            (size_t)Ccb->NotifyMask.MaximumLength,
1750                                            &sztLength);
1751
1752             if( !NT_SUCCESS( ntStatus))
1753             {
1754
1755                 try_return( ntStatus);
1756             }
1757
1758             Ccb->NotifyMask.Length = (USHORT)sztLength;
1759         }
1760
1761         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1762                       AFS_TRACE_LEVEL_VERBOSE,
1763                       "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1764                       &Ccb->NotifyMask,
1765                       NotifyIrp,
1766                       CompletionFilter,
1767                       WatchTree);
1768
1769         FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1770                                         &pDeviceExt->Specific.Control.DirNotifyList,
1771                                         (void *)Ccb,
1772                                         (PSTRING)&Ccb->NotifyMask,
1773                                         WatchTree,
1774                                         TRUE,
1775                                         CompletionFilter,
1776                                         NotifyIrp,
1777                                         NULL,
1778                                         NULL,
1779                                         NULL);
1780
1781 try_exit:
1782
1783         if( !NT_SUCCESS( ntStatus))
1784         {
1785
1786             if( Ccb->NotifyMask.Buffer != NULL)
1787             {
1788
1789                 AFSExFreePoolWithTag( Ccb->NotifyMask.Buffer, AFS_GENERIC_MEMORY_7_TAG);
1790
1791                 Ccb->NotifyMask.Buffer = NULL;
1792             }
1793         }
1794
1795         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1796     }
1797
1798     return ntStatus;
1799 }
1800
1801 void
1802 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1803                                 IN AFSCcb *Ccb,
1804                                 IN ULONG NotifyFilter,
1805                                 IN ULONG NotificationAction)
1806 {
1807
1808     NTSTATUS ntStatus = STATUS_SUCCESS;
1809     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1810     UNICODE_STRING uniName, uniComponentName;
1811     size_t sztLength;
1812     USHORT usNameOffset = 0;
1813
1814     __Enter
1815     {
1816
1817         uniName.Buffer = NULL;
1818
1819         if( ParentObjectInfo == NULL ||
1820             AFSGlobalRoot == NULL)
1821         {
1822
1823             try_return( ntStatus);
1824         }
1825
1826         if( Ccb == NULL)
1827         {
1828
1829             RtlInitUnicodeString( &uniComponentName,
1830                                   L"_AFSChange.dat");
1831         }
1832         else
1833         {
1834
1835             uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1836         }
1837
1838         //
1839         // Build a dir name based on the FID of the file
1840         //
1841
1842         uniName.Length = 0;
1843         uniName.MaximumLength = 1024 + uniComponentName.Length;
1844
1845         uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1846                                                             uniName.MaximumLength,
1847                                                             AFS_GENERIC_MEMORY_8_TAG);
1848
1849         if( uniName.Buffer == NULL)
1850         {
1851
1852             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1853         }
1854
1855         ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1856                                        uniName.MaximumLength,
1857                                        L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1858                                        ParentObjectInfo->FileId.Cell,
1859                                        ParentObjectInfo->FileId.Volume,
1860                                        ParentObjectInfo->FileId.Vnode,
1861                                        ParentObjectInfo->FileId.Unique,
1862                                        &uniComponentName);
1863
1864         if( !NT_SUCCESS( ntStatus))
1865         {
1866
1867             try_return( ntStatus);
1868         }
1869
1870         ntStatus = RtlStringCbLengthW( uniName.Buffer,
1871                                        (size_t)uniName.MaximumLength,
1872                                        &sztLength);
1873
1874         if( !NT_SUCCESS( ntStatus))
1875         {
1876
1877             try_return( ntStatus);
1878         }
1879
1880         uniName.Length = (USHORT)sztLength;
1881
1882         usNameOffset = uniName.Length - uniComponentName.Length;
1883
1884         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1885                       AFS_TRACE_LEVEL_VERBOSE,
1886                       "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1887                       &uniName,
1888                       NotifyFilter,
1889                       NotificationAction,
1890                       usNameOffset,
1891                       uniName.Length,
1892                       uniComponentName.Length);
1893
1894         FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1895                                        &pDeviceExt->Specific.Control.DirNotifyList,
1896                                        (PSTRING)&uniName,
1897                                        usNameOffset,
1898                                        NULL,
1899                                        NULL,
1900                                        NotifyFilter,
1901                                        NotificationAction,
1902                                        NULL,
1903                                        (void *)Ccb);
1904
1905 try_exit:
1906
1907         if( uniName.Buffer != NULL)
1908         {
1909
1910             AFSExFreePoolWithTag( uniName.Buffer, AFS_GENERIC_MEMORY_8_TAG);
1911         }
1912     }
1913
1914     return;
1915 }
1916
1917 // For use with FsRtlNotifyFilterChangeDirectory but must
1918 // be implemented in the Framework because the library can
1919 // be unloaded.
1920
1921 BOOLEAN
1922 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1923                                IN void *FilterContext)
1924 {
1925
1926     BOOLEAN bReturn = TRUE;
1927     AFSCcb *pDirCcb = (AFSCcb *)NotifyContext;
1928     AFSCcb *pNotifyCcb = (AFSCcb *)FilterContext;
1929
1930     __Enter
1931     {
1932
1933     }
1934
1935     return bReturn;
1936 }
1937
1938 BOOLEAN
1939 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1940                      IN ULONG HashIndex)
1941 {
1942
1943     BOOLEAN bIsInSnapshot = FALSE;
1944     AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1945     ULONG ulCount = 0;
1946
1947     while( ulCount < SnapshotHdr->EntryCount)
1948     {
1949
1950         if( pSnapshotEntry->NameHash == HashIndex)
1951         {
1952
1953             bIsInSnapshot = TRUE;
1954
1955             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1956                           AFS_TRACE_LEVEL_VERBOSE,
1957                           "AFSIsNameInSnapshot  Hash index %08lX already in snapshot\n",
1958                           HashIndex);
1959
1960             break;
1961         }
1962         else if( pSnapshotEntry->NameHash == 0)
1963         {
1964
1965             break;
1966         }
1967
1968         pSnapshotEntry++;
1969
1970         ulCount++;
1971     }
1972
1973     return bIsInSnapshot;
1974 }