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