1c5a8cc6677cb9591c295403667d9b6e4688a20d
[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                 }
833                 case FileIdFullDirectoryInformation:
834                 case FileFullDirectoryInformation:
835                 {
836                     pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
837                     pFullDirInfo->EaSize = 0;
838                 }
839                 case FileDirectoryInformation:
840                 {
841                     pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
842
843                     if( bUseFileInfo)
844                     {
845
846                         pDirInfo->CreationTime = stFileInfo.CreationTime;
847                         pDirInfo->LastWriteTime = stFileInfo.LastWriteTime;
848                         pDirInfo->LastAccessTime = stFileInfo.LastAccessTime;
849                         pDirInfo->ChangeTime = stFileInfo.ChangeTime;
850
851                         pDirInfo->EndOfFile = stFileInfo.EndOfFile;
852                         pDirInfo->AllocationSize = stFileInfo.AllocationSize;
853
854                         pDirInfo->FileAttributes = stFileInfo.FileAttributes;
855                     }
856                     else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
857                     {
858
859                         pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
860                         pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
861                         pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
862                         pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
863
864                         pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
865                         pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
866
867                         if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
868                         {
869                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
870                         }
871                         else
872                         {
873                             pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
874                         }
875                     }
876                     else
877                     {
878
879                         pDirInfo->CreationTime = pObjectInfo->CreationTime;
880                         pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
881                         pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
882                         pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
883
884                         pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
885                         pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
886
887                         pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
888                     }
889
890                     //
891                     // Check if the name begins with a . and we are hiding them
892                     //
893
894                     if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
895                         pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
896                         BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
897                     {
898
899                         pDirInfo->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
900                     }
901
902                     pDirInfo->FileIndex = pDirEntry->FileIndex;
903                     pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
904
905                     break;
906                 }
907
908                 case FileNamesInformation:
909                 {
910                     pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
911                     pNamesInfo->FileIndex = pDirEntry->FileIndex;
912                     pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
913
914                     break;
915                 }
916                 default:
917                 {
918                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
919                                   AFS_TRACE_LEVEL_ERROR,
920                                   "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
921                                   Irp,
922                                   FileInformationClass);
923
924                     InterlockedDecrement( &pDirEntry->OpenReferenceCount);
925
926                     try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
927
928                     break;
929                 }
930             }
931
932             ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
933                                             pDirEntry->NameInformation.FileName.Length :
934                                             ulBytesRemainingInBuffer - ulBaseLength;
935
936             RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
937                            pDirEntry->NameInformation.FileName.Buffer,
938                            ulBytesConverted);
939
940             //  Set up the previous next entry offset
941             *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
942
943             //  And indicate how much of the user buffer we have currently
944             //  used up.
945             Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
946
947             //  Check for the case that a single entry doesn't fit.
948             //  This should only get this far on the first entry.
949             if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
950             {
951
952                 InterlockedDecrement( &pDirEntry->OpenReferenceCount);
953
954                 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
955             }
956
957             InterlockedDecrement( &pDirEntry->OpenReferenceCount);
958
959             dStatus = STATUS_SUCCESS;
960
961             //  Set ourselves up for the next iteration
962             ulLastEntry = ulNextEntry;
963             ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
964         }
965
966 try_exit:
967
968         if( bReleaseMain)
969         {
970
971             AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
972         }
973
974         if( pFcb != NULL)
975         {
976
977             AFSClearEnumerationEvent( pFcb);
978         }
979     }
980
981     return ntStatus;
982 }
983
984 NTSTATUS
985 AFSNotifyChangeDirectory( IN PIRP Irp)
986 {
987
988     NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
989     PIO_STACK_LOCATION pIrpSp;
990     AFSFcb *pFcb = NULL;
991     AFSCcb *pCcb = NULL;
992     ULONG ulCompletionFilter;
993     BOOLEAN bWatchTree;
994     BOOLEAN bReleaseLock = FALSE;
995
996     __Enter
997     {
998
999         //  Get the current Stack location
1000         pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1001
1002         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1003         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1004
1005         if( pFcb == NULL)
1006         {
1007
1008             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1009                           AFS_TRACE_LEVEL_ERROR,
1010                           "AFSNotifyChangeDirectory Attempted access (%08lX) when pFcb == NULL\n",
1011                           Irp);
1012
1013             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1014         }
1015
1016         if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1017             pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1018             pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1019         {
1020
1021             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1022                           AFS_TRACE_LEVEL_ERROR,
1023                           "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1024                           &pCcb->DirectoryCB->NameInformation.FileName,
1025                           pFcb->Header.NodeTypeCode);
1026
1027             try_return( ntStatus = STATUS_INVALID_PARAMETER);
1028         }
1029
1030         //  Reference our input parameter to make things easier
1031         ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1032         bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1033
1034         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1035                       AFS_TRACE_LEVEL_VERBOSE,
1036                       "AFSNotifyChangeDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
1037                       &pFcb->NPFcb->Resource,
1038                       PsGetCurrentThread());
1039
1040         AFSAcquireExcl( &pFcb->NPFcb->Resource,
1041                           TRUE);
1042
1043         bReleaseLock = TRUE;
1044
1045         //
1046         // Check if the node has already been deleted
1047         //
1048
1049         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1050         {
1051
1052             try_return( ntStatus = STATUS_FILE_DELETED);
1053         }
1054         else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1055         {
1056
1057             try_return( ntStatus = STATUS_DELETE_PENDING);
1058         }
1059
1060         //  Call the Fsrtl package to process the request.
1061         ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1062                                                       pCcb,
1063                                                       bWatchTree,
1064                                                       ulCompletionFilter,
1065                                                       Irp);
1066
1067         if( !NT_SUCCESS( ntStatus))
1068         {
1069             try_return( ntStatus);
1070         }
1071
1072         ntStatus = STATUS_PENDING;
1073
1074 try_exit:
1075
1076         if( bReleaseLock)
1077         {
1078
1079             AFSReleaseResource( &pFcb->NPFcb->Resource);
1080         }
1081     }
1082
1083     return ntStatus;
1084 }
1085
1086 AFSDirectoryCB *
1087 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1088                        IN AFSCcb *Ccb)
1089 {
1090
1091     AFSDirectoryCB *pDirEntry = NULL;
1092     NTSTATUS ntStatus = STATUS_SUCCESS;
1093     AFSSnapshotHdr *pSnapshotHdr = NULL;
1094     AFSSnapshotEntry *pSnapshotEntry = NULL;
1095     ULONG ulCount = 0;
1096
1097     __Enter
1098     {
1099
1100         //
1101         // Is this a PIOCtl query
1102         //
1103
1104         if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1105         {
1106
1107             if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1108                 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1109             {
1110
1111                 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1112
1113                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1114                               AFS_TRACE_LEVEL_VERBOSE,
1115                               "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1116                               &pDirEntry->NameInformation.FileName,
1117                               ObjectInfo->FileId.Cell,
1118                               ObjectInfo->FileId.Volume,
1119                               ObjectInfo->FileId.Vnode,
1120                               ObjectInfo->FileId.Unique);
1121             }
1122
1123             Ccb->CurrentDirIndex++;
1124
1125             try_return( ntStatus);
1126         }
1127
1128         Ccb->CurrentDirIndex++;
1129
1130         if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1131         {
1132
1133             //
1134             // Return the .. entry
1135             //
1136
1137             pDirEntry = AFSGlobalDotDirEntry;
1138
1139             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1140                           AFS_TRACE_LEVEL_VERBOSE,
1141                           "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1142                           &pDirEntry->NameInformation.FileName,
1143                           ObjectInfo->FileId.Cell,
1144                           ObjectInfo->FileId.Volume,
1145                           ObjectInfo->FileId.Vnode,
1146                           ObjectInfo->FileId.Unique);
1147         }
1148         else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1149         {
1150
1151             //
1152             // Return the .. entry
1153             //
1154
1155             pDirEntry = AFSGlobalDotDotDirEntry;
1156
1157             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1158                           AFS_TRACE_LEVEL_VERBOSE,
1159                           "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1160                           &pDirEntry->NameInformation.FileName,
1161                           ObjectInfo->FileId.Cell,
1162                           ObjectInfo->FileId.Volume,
1163                           ObjectInfo->FileId.Vnode,
1164                           ObjectInfo->FileId.Unique);
1165         }
1166         else
1167         {
1168
1169             pSnapshotHdr = Ccb->DirectorySnapshot;
1170
1171             if( pSnapshotHdr == NULL ||
1172                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1173             {
1174
1175                 try_return( ntStatus);
1176             }
1177
1178             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1179
1180             ulCount = Ccb->CurrentDirIndex;
1181
1182             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1183                           AFS_TRACE_LEVEL_VERBOSE,
1184                           "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1185                           ulCount);
1186
1187             //
1188             // Get to a valid entry
1189             //
1190
1191             AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1192                               TRUE);
1193
1194             while( ulCount < pSnapshotHdr->EntryCount)
1195             {
1196
1197                 pDirEntry = NULL;
1198
1199                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1200                               AFS_TRACE_LEVEL_VERBOSE,
1201                               "AFSLocateNextDirEntry Searching for hash %08lX\n",
1202                               pSnapshotEntry->NameHash);
1203
1204                 if( pSnapshotEntry->NameHash == 0)
1205                 {
1206
1207                     break;
1208                 }
1209
1210                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1211                                                            pSnapshotEntry->NameHash,
1212                                                            &pDirEntry);
1213
1214                 if( !NT_SUCCESS( ntStatus) ||
1215                     pDirEntry != NULL)
1216                 {
1217
1218                     if( pDirEntry != NULL)
1219                     {
1220
1221                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1222                                       AFS_TRACE_LEVEL_VERBOSE,
1223                                       "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1224                                       &pDirEntry->NameInformation.FileName,
1225                                       (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1226                                       ObjectInfo->FileId.Cell,
1227                                       ObjectInfo->FileId.Volume,
1228                                       ObjectInfo->FileId.Vnode,
1229                                       ObjectInfo->FileId.Unique);
1230
1231                         InterlockedIncrement( &pDirEntry->OpenReferenceCount);
1232                     }
1233                     else
1234                     {
1235
1236
1237                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1238                                       AFS_TRACE_LEVEL_VERBOSE,
1239                                       "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1240                                       ObjectInfo->FileId.Cell,
1241                                       ObjectInfo->FileId.Volume,
1242                                       ObjectInfo->FileId.Vnode,
1243                                       ObjectInfo->FileId.Unique);
1244                     }
1245
1246                     break;
1247                 }
1248
1249                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1250                               AFS_TRACE_LEVEL_VERBOSE,
1251                               "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1252                               pSnapshotEntry->NameHash,
1253                               ObjectInfo->FileId.Cell,
1254                               ObjectInfo->FileId.Volume,
1255                               ObjectInfo->FileId.Vnode,
1256                               ObjectInfo->FileId.Unique);
1257
1258                 pSnapshotEntry++;
1259
1260                 ulCount++;
1261
1262                 Ccb->CurrentDirIndex++;
1263             }
1264
1265             AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1266         }
1267
1268 try_exit:
1269
1270         NOTHING;
1271     }
1272
1273     return pDirEntry;
1274 }
1275
1276 AFSDirectoryCB *
1277 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1278                           IN AFSCcb *Ccb,
1279                           IN ULONG DirIndex)
1280 {
1281
1282     AFSDirectoryCB *pDirEntry = NULL;
1283     NTSTATUS ntStatus = STATUS_SUCCESS;
1284     AFSSnapshotHdr *pSnapshotHdr = NULL;
1285     AFSSnapshotEntry *pSnapshotEntry = NULL;
1286     ULONG ulCount = 0;
1287
1288     __Enter
1289     {
1290
1291         Ccb->CurrentDirIndex = DirIndex;
1292
1293         if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1294         {
1295
1296             //
1297             // Return the .. entry
1298             //
1299
1300             pDirEntry = AFSGlobalDotDirEntry;
1301         }
1302         else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1303         {
1304
1305             //
1306             // Return the .. entry
1307             //
1308
1309             pDirEntry = AFSGlobalDotDotDirEntry;
1310         }
1311         else
1312         {
1313
1314             pSnapshotHdr = Ccb->DirectorySnapshot;
1315
1316             if( pSnapshotHdr == NULL ||
1317                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1318             {
1319
1320                 try_return( ntStatus);
1321             }
1322
1323             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1324
1325             ulCount = Ccb->CurrentDirIndex;
1326
1327             //
1328             // Get to a valid entry
1329             //
1330
1331             while( ulCount < pSnapshotHdr->EntryCount)
1332             {
1333
1334                 pDirEntry = NULL;
1335
1336                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1337                                                            pSnapshotEntry->NameHash,
1338                                                            &pDirEntry);
1339
1340                 if( !NT_SUCCESS( ntStatus) ||
1341                     ( pDirEntry != NULL &&
1342                       pDirEntry->FileIndex == DirIndex))
1343                 {
1344
1345                     break;
1346                 }
1347
1348                 pSnapshotEntry++;
1349
1350                 ulCount++;
1351             }
1352
1353             if( pDirEntry != NULL)
1354             {
1355
1356                 Ccb->CurrentDirIndex = ulCount;
1357             }
1358         }
1359
1360 try_exit:
1361
1362         NOTHING;
1363     }
1364
1365     return pDirEntry;
1366 }
1367
1368 NTSTATUS
1369 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1370                       IN AFSCcb *Ccb,
1371                       IN BOOLEAN ResetIndex)
1372 {
1373
1374     NTSTATUS ntStatus = STATUS_SUCCESS;
1375     AFSSnapshotHdr *pSnapshotHdr = NULL;
1376     AFSSnapshotEntry *pSnapshotEntry = NULL;
1377     AFSDirectoryCB *pDirEntry = NULL;
1378
1379     __Enter
1380     {
1381
1382         if( ResetIndex)
1383         {
1384
1385             //
1386             // Set it up so we still get the . and .. entries for empty directories
1387             //
1388
1389             if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1390             {
1391
1392                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1393             }
1394             else
1395             {
1396
1397                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1398             }
1399         }
1400
1401         if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1402         {
1403
1404             //
1405             // If we have a snapshot then clear it out
1406             //
1407
1408             if( Ccb->DirectorySnapshot != NULL)
1409             {
1410
1411                 AFSExFreePool( Ccb->DirectorySnapshot);
1412
1413                 Ccb->DirectorySnapshot = NULL;
1414             }
1415
1416             try_return( ntStatus);
1417         }
1418
1419         //
1420         // Allocate our snapshot buffer for this enumeration
1421         //
1422
1423         pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1424                                                                    sizeof( AFSSnapshotHdr) +
1425                                                                         ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1426                                                                                 sizeof( AFSSnapshotEntry)),
1427                                                                    AFS_DIR_SNAPSHOT_TAG);
1428
1429         if( pSnapshotHdr == NULL)
1430         {
1431
1432             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1433         }
1434
1435         RtlZeroMemory( pSnapshotHdr,
1436                        sizeof( AFSSnapshotHdr) +
1437                             ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1438                                     sizeof( AFSSnapshotEntry)));
1439
1440         pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1441
1442         pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1443
1444         //
1445         // Populate our snapshot
1446         //
1447
1448         pSnapshotEntry = pSnapshotHdr->TopEntry;
1449
1450         pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1451
1452         while( pDirEntry != NULL)
1453         {
1454
1455             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1456                 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1457                 !AFSIsNameInSnapshot( pSnapshotHdr,
1458                                       (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1459             {
1460
1461                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1462                               AFS_TRACE_LEVEL_VERBOSE,
1463                               "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1464                               pSnapshotHdr->EntryCount,
1465                               &pDirEntry->NameInformation.FileName,
1466                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1467                               pDirEntry->Flags,
1468                               Fcb->ObjectInformation->FileId.Cell,
1469                               Fcb->ObjectInformation->FileId.Volume,
1470                               Fcb->ObjectInformation->FileId.Vnode,
1471                               Fcb->ObjectInformation->FileId.Unique);
1472
1473                 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1474
1475                 pSnapshotEntry++;
1476             }
1477             else
1478             {
1479
1480                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1481                               AFS_TRACE_LEVEL_VERBOSE,
1482                               "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1483                               pSnapshotHdr->EntryCount,
1484                               &pDirEntry->NameInformation.FileName,
1485                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1486                               pDirEntry->Flags,
1487                               Fcb->ObjectInformation->FileId.Cell,
1488                               Fcb->ObjectInformation->FileId.Volume,
1489                               Fcb->ObjectInformation->FileId.Vnode,
1490                               Fcb->ObjectInformation->FileId.Unique);
1491             }
1492
1493             pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1494         }
1495
1496         if( Ccb->DirectorySnapshot != NULL)
1497         {
1498
1499             AFSExFreePool( Ccb->DirectorySnapshot);
1500
1501             Ccb->DirectorySnapshot = NULL;
1502         }
1503
1504         Ccb->DirectorySnapshot = pSnapshotHdr;
1505
1506 try_exit:
1507
1508         NOTHING;
1509     }
1510
1511     return ntStatus;
1512 }
1513
1514 NTSTATUS
1515 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1516                                    IN AFSCcb *Ccb,
1517                                    IN BOOLEAN WatchTree,
1518                                    IN ULONG CompletionFilter,
1519                                    IN PIRP NotifyIrp)
1520 {
1521
1522     NTSTATUS ntStatus = STATUS_SUCCESS;
1523     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1524     size_t sztLength;
1525
1526     __Enter
1527     {
1528
1529         //
1530         // Build a dir name based on the FID of the file
1531         //
1532
1533         if( Ccb->NotifyMask.Buffer == NULL)
1534         {
1535
1536             Ccb->NotifyMask.Length = 0;
1537             Ccb->NotifyMask.MaximumLength = 1024;
1538
1539             Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1540                                                                         Ccb->NotifyMask.MaximumLength,
1541                                                                         AFS_GENERIC_MEMORY_7_TAG);
1542
1543             if( Ccb->NotifyMask.Buffer == NULL)
1544             {
1545
1546                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1547             }
1548
1549             ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1550                                            Ccb->NotifyMask.MaximumLength,
1551                                            L"\\%08lX.%08lX.%08lX.%08lX",
1552                                            ObjectInfo->FileId.Cell,
1553                                            ObjectInfo->FileId.Volume,
1554                                            ObjectInfo->FileId.Vnode,
1555                                            ObjectInfo->FileId.Unique);
1556
1557             if( !NT_SUCCESS( ntStatus))
1558             {
1559
1560                 try_return( ntStatus);
1561             }
1562
1563             ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1564                                            (size_t)Ccb->NotifyMask.MaximumLength,
1565                                            &sztLength);
1566
1567             if( !NT_SUCCESS( ntStatus))
1568             {
1569
1570                 try_return( ntStatus);
1571             }
1572
1573             Ccb->NotifyMask.Length = (USHORT)sztLength;
1574         }
1575
1576         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1577                       AFS_TRACE_LEVEL_VERBOSE,
1578                       "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1579                       &Ccb->NotifyMask,
1580                       NotifyIrp,
1581                       CompletionFilter,
1582                       WatchTree);
1583
1584         FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1585                                         &pDeviceExt->Specific.Control.DirNotifyList,
1586                                         (void *)Ccb,
1587                                         (PSTRING)&Ccb->NotifyMask,
1588                                         WatchTree,
1589                                         TRUE,
1590                                         CompletionFilter,
1591                                         NotifyIrp,
1592                                         NULL,
1593                                         NULL,
1594                                         NULL);
1595
1596 try_exit:
1597
1598         if( !NT_SUCCESS( ntStatus))
1599         {
1600
1601             if( Ccb->NotifyMask.Buffer != NULL)
1602             {
1603
1604                 AFSExFreePool( Ccb->NotifyMask.Buffer);
1605
1606                 Ccb->NotifyMask.Buffer = NULL;
1607             }
1608         }
1609     }
1610
1611     return ntStatus;
1612 }
1613
1614 void
1615 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1616                                 IN AFSCcb *Ccb,
1617                                 IN ULONG NotifyFilter,
1618                                 IN ULONG NotificationAction)
1619 {
1620
1621     NTSTATUS ntStatus = STATUS_SUCCESS;
1622     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1623     UNICODE_STRING uniName, uniComponentName;
1624     size_t sztLength;
1625     USHORT usNameOffset = 0;
1626
1627     __Enter
1628     {
1629
1630         uniName.Buffer = NULL;
1631
1632         if( ParentObjectInfo == NULL ||
1633             AFSGlobalRoot == NULL)
1634         {
1635
1636             try_return( ntStatus);
1637         }
1638
1639         if( Ccb == NULL)
1640         {
1641
1642             RtlInitUnicodeString( &uniComponentName,
1643                                   L"_AFSChange.dat");
1644         }
1645         else
1646         {
1647
1648             uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1649         }
1650
1651         //
1652         // Build a dir name based on the FID of the file
1653         //
1654
1655         uniName.Length = 0;
1656         uniName.MaximumLength = 1024 + uniComponentName.Length;
1657
1658         uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1659                                                             uniName.MaximumLength,
1660                                                             AFS_GENERIC_MEMORY_8_TAG);
1661
1662         if( uniName.Buffer == NULL)
1663         {
1664
1665             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1666         }
1667
1668         ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1669                                        uniName.MaximumLength,
1670                                        L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1671                                        ParentObjectInfo->FileId.Cell,
1672                                        ParentObjectInfo->FileId.Volume,
1673                                        ParentObjectInfo->FileId.Vnode,
1674                                        ParentObjectInfo->FileId.Unique,
1675                                        &uniComponentName);
1676
1677         if( !NT_SUCCESS( ntStatus))
1678         {
1679
1680             try_return( ntStatus);
1681         }
1682
1683         ntStatus = RtlStringCbLengthW( uniName.Buffer,
1684                                        (size_t)uniName.MaximumLength,
1685                                        &sztLength);
1686
1687         if( !NT_SUCCESS( ntStatus))
1688         {
1689
1690             try_return( ntStatus);
1691         }
1692
1693         uniName.Length = (USHORT)sztLength;
1694
1695         usNameOffset = uniName.Length - uniComponentName.Length;
1696
1697         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1698                       AFS_TRACE_LEVEL_VERBOSE,
1699                       "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1700                       &uniName,
1701                       NotifyFilter,
1702                       NotificationAction,
1703                       usNameOffset,
1704                       uniName.Length,
1705                       uniComponentName.Length);
1706
1707         FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1708                                        &pDeviceExt->Specific.Control.DirNotifyList,
1709                                        (PSTRING)&uniName,
1710                                        usNameOffset,
1711                                        NULL,
1712                                        NULL,
1713                                        NotifyFilter,
1714                                        NotificationAction,
1715                                        NULL,
1716                                        (void *)Ccb);
1717
1718 try_exit:
1719
1720         if( uniName.Buffer != NULL)
1721         {
1722
1723             AFSExFreePool( uniName.Buffer);
1724         }
1725     }
1726
1727     return;
1728 }
1729
1730 // For use with FsRtlNotifyFilterChangeDirectory but must
1731 // be implemented in the Framework because the library can
1732 // be unloaded.
1733
1734 BOOLEAN
1735 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1736                                IN void *FilterContext)
1737 {
1738
1739     BOOLEAN bReturn = TRUE;
1740     AFSCcb *pDirCcb = (AFSCcb *)NotifyContext;
1741     AFSCcb *pNotifyCcb = (AFSCcb *)FilterContext;
1742
1743     __Enter
1744     {
1745
1746     }
1747
1748     return bReturn;
1749 }
1750
1751 BOOLEAN
1752 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1753                      IN ULONG HashIndex)
1754 {
1755
1756     BOOLEAN bIsInSnapshot = FALSE;
1757     AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1758     ULONG ulCount = 0;
1759
1760     while( ulCount < SnapshotHdr->EntryCount)
1761     {
1762
1763         if( pSnapshotEntry->NameHash == HashIndex)
1764         {
1765
1766             bIsInSnapshot = TRUE;
1767
1768             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1769                           AFS_TRACE_LEVEL_VERBOSE,
1770                           "AFSIsNameInSnapshot  Hash index %08lX already in snapshot\n",
1771                           HashIndex);
1772
1773             break;
1774         }
1775         else if( pSnapshotEntry->NameHash == 0)
1776         {
1777
1778             break;
1779         }
1780
1781         pSnapshotEntry++;
1782
1783         ulCount++;
1784     }
1785
1786     return bIsInSnapshot;
1787 }