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