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