Windows: File Attribute Reporting Consistency
[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             switch ( FileInformationClass)
932             {
933             case FileIdBothDirectoryInformation:
934             case FileBothDirectoryInformation:
935             case FileIdFullDirectoryInformation:
936             case FileFullDirectoryInformation:
937             case FileDirectoryInformation:
938
939                 //
940                 // For Symlinks and Mount Points the reparse point attribute
941                 // must be associated with the directory entry.  In addition,
942                 // for Symlinks it must be determined if the target object is
943                 // a directory or not.  If so, the directory attribute must be
944                 // specified.  Mount points always refer to directories and
945                 // must have the directory attribute set.
946                 //
947
948                 switch( pObjectInfo->FileType)
949                 {
950
951                 case AFS_FILE_TYPE_MOUNTPOINT:
952                 case AFS_FILE_TYPE_DFSLINK:
953                     {
954
955                         ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
956
957                         break;
958                     }
959
960                 case AFS_FILE_TYPE_SYMLINK:
961                     {
962
963                         //
964                         // Go grab the file information for this entry
965                         // No worries on failures since we will just display
966                         // pseudo information
967                         //
968
969                         RtlZeroMemory( &stFileInfo,
970                                        sizeof( AFSFileInfoCB));
971
972                         if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
973                                                                    pDirEntry,
974                                                                    &pCcb->FullFileName,
975                                                                    pCcb->NameArray,
976                                                                    &pCcb->AuthGroup,
977                                                                    &stFileInfo)))
978                         {
979
980                             if ( stFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
981                             {
982
983                                 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY;
984                             }
985                         }
986
987                         ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
988
989                         break;
990                     }
991                 }
992             }
993
994             //
995             // Check if the name begins with a . and we are hiding them
996             //
997
998             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
999                 pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
1000                 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
1001             {
1002
1003                 ulAdditionalAttributes |= FILE_ATTRIBUTE_HIDDEN;
1004             }
1005
1006
1007             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1008                           AFS_TRACE_LEVEL_VERBOSE,
1009                           "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n",
1010                           &pCcb->DirectoryCB->NameInformation.FileName,
1011                           &pDirEntry->NameInformation.FileName);
1012
1013             //  Zero the base part of the structure.
1014             RtlZeroMemory( &pBuffer[ ulNextEntry],
1015                            ulBaseLength);
1016
1017             switch( FileInformationClass)
1018             {
1019
1020                 //  Now fill the base parts of the structure that are applicable.
1021                 case FileIdBothDirectoryInformation:
1022                 case FileBothDirectoryInformation:
1023                 {
1024                     pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry];
1025
1026                     pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength;
1027
1028                     if( pDirEntry->NameInformation.ShortNameLength > 0)
1029                     {
1030                         RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
1031                                        &pDirEntry->NameInformation.ShortName[ 0],
1032                                        pBothDirInfo->ShortNameLength);
1033                     }
1034                 }
1035                 case FileIdFullDirectoryInformation:
1036                 case FileFullDirectoryInformation:
1037                 {
1038                     pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
1039                     pFullDirInfo->EaSize = 0;
1040                 }
1041                 case FileDirectoryInformation:
1042                 {
1043                     pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
1044
1045                     if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
1046                     {
1047
1048                         pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
1049                         pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
1050                         pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
1051                         pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
1052
1053                         pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
1054                         pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
1055
1056                         if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1057                         {
1058                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
1059                         }
1060                         else
1061                         {
1062                             pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
1063                         }
1064                     }
1065                     else
1066                     {
1067
1068                         pDirInfo->CreationTime = pObjectInfo->CreationTime;
1069                         pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
1070                         pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
1071                         pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
1072
1073                         pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
1074                         pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
1075
1076                         if ( ulAdditionalAttributes && pObjectInfo->FileAttributes == FILE_ATTRIBUTE_NORMAL)
1077                         {
1078
1079                             pDirInfo->FileAttributes = ulAdditionalAttributes;
1080                         }
1081                         else
1082                         {
1083
1084                             pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
1085                         }
1086                     }
1087
1088                     pDirInfo->FileIndex = pDirEntry->FileIndex;
1089                     pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
1090
1091                     break;
1092                 }
1093
1094                 case FileNamesInformation:
1095                 {
1096                     pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
1097                     pNamesInfo->FileIndex = pDirEntry->FileIndex;
1098                     pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
1099
1100                     break;
1101                 }
1102
1103                 default:
1104                 {
1105                     AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1106                                   AFS_TRACE_LEVEL_ERROR,
1107                                   "AFSQueryDirectory (%p) Unknown FileInformationClass %u\n",
1108                                   Irp,
1109                                   FileInformationClass);
1110
1111                     try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
1112                 }
1113             }
1114
1115             ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
1116                                             pDirEntry->NameInformation.FileName.Length :
1117                                             ulBytesRemainingInBuffer - ulBaseLength;
1118
1119             RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
1120                            pDirEntry->NameInformation.FileName.Buffer,
1121                            ulBytesConverted);
1122
1123             //  Set up the previous next entry offset
1124             *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
1125
1126             //  And indicate how much of the user buffer we have currently
1127             //  used up.
1128             Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
1129
1130             //  Check for the case that a single entry doesn't fit.
1131             //  This should only get this far on the first entry.
1132             if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
1133             {
1134
1135                 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
1136             }
1137
1138             dStatus = STATUS_SUCCESS;
1139
1140             //  Set ourselves up for the next iteration
1141             ulLastEntry = ulNextEntry;
1142             ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
1143         }
1144
1145 try_exit:
1146
1147         if ( pDirEntry != NULL)
1148         {
1149
1150             lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1151
1152             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1153                           AFS_TRACE_LEVEL_VERBOSE,
1154                           "AFSQueryDirectory Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n",
1155                           &pDirEntry->NameInformation.FileName,
1156                           pDirEntry,
1157                           pCcb,
1158                           lCount);
1159
1160             ASSERT( lCount >= 0);
1161         }
1162
1163         if( bReleaseMain)
1164         {
1165
1166             AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1167         }
1168
1169         if ( bReleaseFcb)
1170         {
1171
1172             AFSReleaseResource( &pFcb->NPFcb->Resource);
1173         }
1174
1175         if( pFcb != NULL)
1176         {
1177
1178             AFSClearEnumerationEvent( pFcb);
1179         }
1180     }
1181
1182     return ntStatus;
1183 }
1184
1185 NTSTATUS
1186 AFSNotifyChangeDirectory( IN PIRP Irp)
1187 {
1188
1189     NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1190     PIO_STACK_LOCATION pIrpSp;
1191     AFSFcb *pFcb = NULL;
1192     AFSCcb *pCcb = NULL;
1193     ULONG ulCompletionFilter;
1194     BOOLEAN bWatchTree;
1195     BOOLEAN bReleaseLock = FALSE;
1196
1197     __Enter
1198     {
1199
1200         //  Get the current Stack location
1201         pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1202
1203         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1204         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1205
1206         if( pFcb == NULL)
1207         {
1208
1209             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1210                           AFS_TRACE_LEVEL_ERROR,
1211                           "AFSNotifyChangeDirectory Attempted access (%p) when pFcb == NULL\n",
1212                           Irp);
1213
1214             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1215         }
1216
1217         if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1218             pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1219             pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1220         {
1221
1222             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1223                           AFS_TRACE_LEVEL_ERROR,
1224                           "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1225                           &pCcb->DirectoryCB->NameInformation.FileName,
1226                           pFcb->Header.NodeTypeCode);
1227
1228             try_return( ntStatus = STATUS_INVALID_PARAMETER);
1229         }
1230
1231         //  Reference our input parameter to make things easier
1232         ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1233         bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1234
1235         AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1236                       AFS_TRACE_LEVEL_VERBOSE,
1237                       "AFSNotifyChangeDirectory Acquiring Dcb lock %p EXCL %08lX\n",
1238                       &pFcb->NPFcb->Resource,
1239                       PsGetCurrentThread());
1240
1241         AFSAcquireExcl( &pFcb->NPFcb->Resource,
1242                           TRUE);
1243
1244         bReleaseLock = TRUE;
1245
1246         //
1247         // Check if the node has already been deleted
1248         //
1249
1250         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1251         {
1252
1253             try_return( ntStatus = STATUS_FILE_DELETED);
1254         }
1255         else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1256         {
1257
1258             try_return( ntStatus = STATUS_DELETE_PENDING);
1259         }
1260
1261         //  Call the Fsrtl package to process the request.
1262         ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1263                                                       pCcb,
1264                                                       bWatchTree,
1265                                                       ulCompletionFilter,
1266                                                       Irp);
1267
1268         if( !NT_SUCCESS( ntStatus))
1269         {
1270             try_return( ntStatus);
1271         }
1272
1273         ntStatus = STATUS_PENDING;
1274
1275 try_exit:
1276
1277         if( bReleaseLock)
1278         {
1279
1280             AFSReleaseResource( &pFcb->NPFcb->Resource);
1281         }
1282     }
1283
1284     return ntStatus;
1285 }
1286
1287 AFSDirectoryCB *
1288 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1289                        IN AFSCcb *Ccb)
1290 {
1291
1292     AFSDirectoryCB *pDirEntry = NULL;
1293     NTSTATUS ntStatus = STATUS_SUCCESS;
1294     AFSSnapshotHdr *pSnapshotHdr = NULL;
1295     AFSSnapshotEntry *pSnapshotEntry = NULL;
1296     ULONG ulCount = 0;
1297     LONG lCount;
1298
1299     __Enter
1300     {
1301
1302         AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1303                           TRUE);
1304
1305         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1306                         TRUE);
1307
1308         //
1309         // Is this a PIOCtl query
1310         //
1311
1312         if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1313         {
1314
1315             if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1316                 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1317             {
1318
1319                 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1320
1321                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1322                               AFS_TRACE_LEVEL_VERBOSE,
1323                               "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1324                               &pDirEntry->NameInformation.FileName,
1325                               ObjectInfo->FileId.Cell,
1326                               ObjectInfo->FileId.Volume,
1327                               ObjectInfo->FileId.Vnode,
1328                               ObjectInfo->FileId.Unique);
1329             }
1330
1331             Ccb->CurrentDirIndex++;
1332
1333             try_return( ntStatus);
1334         }
1335
1336         Ccb->CurrentDirIndex++;
1337
1338         if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1339         {
1340
1341             //
1342             // Return the .. entry
1343             //
1344
1345             pDirEntry = AFSGlobalDotDirEntry;
1346
1347             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1348                           AFS_TRACE_LEVEL_VERBOSE,
1349                           "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1350                           &pDirEntry->NameInformation.FileName,
1351                           ObjectInfo->FileId.Cell,
1352                           ObjectInfo->FileId.Volume,
1353                           ObjectInfo->FileId.Vnode,
1354                           ObjectInfo->FileId.Unique);
1355         }
1356         else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1357         {
1358
1359             //
1360             // Return the .. entry
1361             //
1362
1363             pDirEntry = AFSGlobalDotDotDirEntry;
1364
1365             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1366                           AFS_TRACE_LEVEL_VERBOSE,
1367                           "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1368                           &pDirEntry->NameInformation.FileName,
1369                           ObjectInfo->FileId.Cell,
1370                           ObjectInfo->FileId.Volume,
1371                           ObjectInfo->FileId.Vnode,
1372                           ObjectInfo->FileId.Unique);
1373         }
1374         else
1375         {
1376
1377             pSnapshotHdr = Ccb->DirectorySnapshot;
1378
1379             if( pSnapshotHdr == NULL ||
1380                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1381             {
1382
1383                 try_return( ntStatus);
1384             }
1385
1386             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1387
1388             ulCount = Ccb->CurrentDirIndex;
1389
1390             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1391                           AFS_TRACE_LEVEL_VERBOSE,
1392                           "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1393                           ulCount);
1394
1395             //
1396             // Get to a valid entry
1397             //
1398
1399             while( ulCount < pSnapshotHdr->EntryCount)
1400             {
1401
1402                 pDirEntry = NULL;
1403
1404                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1405                               AFS_TRACE_LEVEL_VERBOSE,
1406                               "AFSLocateNextDirEntry Searching for hash %08lX\n",
1407                               pSnapshotEntry->NameHash);
1408
1409                 if( pSnapshotEntry->NameHash == 0)
1410                 {
1411
1412                     break;
1413                 }
1414
1415                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1416                                                            pSnapshotEntry->NameHash,
1417                                                            &pDirEntry);
1418
1419                 if( !NT_SUCCESS( ntStatus) ||
1420                     pDirEntry != NULL)
1421                 {
1422
1423                     if( pDirEntry != NULL)
1424                     {
1425
1426                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1427                                       AFS_TRACE_LEVEL_VERBOSE,
1428                                       "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1429                                       &pDirEntry->NameInformation.FileName,
1430                                       (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1431                                       ObjectInfo->FileId.Cell,
1432                                       ObjectInfo->FileId.Volume,
1433                                       ObjectInfo->FileId.Vnode,
1434                                       ObjectInfo->FileId.Unique);
1435                     }
1436                     else
1437                     {
1438
1439
1440                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1441                                       AFS_TRACE_LEVEL_VERBOSE,
1442                                       "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1443                                       ObjectInfo->FileId.Cell,
1444                                       ObjectInfo->FileId.Volume,
1445                                       ObjectInfo->FileId.Vnode,
1446                                       ObjectInfo->FileId.Unique);
1447                     }
1448
1449                     break;
1450                 }
1451
1452                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1453                               AFS_TRACE_LEVEL_VERBOSE,
1454                               "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1455                               pSnapshotEntry->NameHash,
1456                               ObjectInfo->FileId.Cell,
1457                               ObjectInfo->FileId.Volume,
1458                               ObjectInfo->FileId.Vnode,
1459                               ObjectInfo->FileId.Unique);
1460
1461                 pSnapshotEntry++;
1462
1463                 ulCount++;
1464
1465                 Ccb->CurrentDirIndex++;
1466             }
1467         }
1468
1469 try_exit:
1470
1471         if( pDirEntry != NULL)
1472         {
1473
1474             lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1475
1476             AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1477                           AFS_TRACE_LEVEL_VERBOSE,
1478                           "AFSLocateNextDirEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n",
1479                           &pDirEntry->NameInformation.FileName,
1480                           pDirEntry,
1481                           Ccb,
1482                           lCount);
1483
1484             ASSERT( lCount >= 0);
1485         }
1486
1487         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1488
1489         AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1490     }
1491
1492     return pDirEntry;
1493 }
1494
1495 AFSDirectoryCB *
1496 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1497                           IN AFSCcb *Ccb,
1498                           IN ULONG DirIndex)
1499 {
1500
1501     AFSDirectoryCB *pDirEntry = NULL;
1502     NTSTATUS ntStatus = STATUS_SUCCESS;
1503     AFSSnapshotHdr *pSnapshotHdr = NULL;
1504     AFSSnapshotEntry *pSnapshotEntry = NULL;
1505     ULONG ulCount = 0;
1506
1507     __Enter
1508     {
1509
1510         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1511                         TRUE);
1512
1513         Ccb->CurrentDirIndex = DirIndex;
1514
1515         if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1516         {
1517
1518             //
1519             // Return the .. entry
1520             //
1521
1522             pDirEntry = AFSGlobalDotDirEntry;
1523         }
1524         else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1525         {
1526
1527             //
1528             // Return the .. entry
1529             //
1530
1531             pDirEntry = AFSGlobalDotDotDirEntry;
1532         }
1533         else
1534         {
1535
1536             pSnapshotHdr = Ccb->DirectorySnapshot;
1537
1538             if( pSnapshotHdr == NULL ||
1539                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1540             {
1541
1542                 try_return( ntStatus);
1543             }
1544
1545             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1546
1547             ulCount = Ccb->CurrentDirIndex;
1548
1549             //
1550             // Get to a valid entry
1551             //
1552
1553             while( ulCount < pSnapshotHdr->EntryCount)
1554             {
1555
1556                 pDirEntry = NULL;
1557
1558                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1559                                                            pSnapshotEntry->NameHash,
1560                                                            &pDirEntry);
1561
1562                 if( !NT_SUCCESS( ntStatus) ||
1563                     ( pDirEntry != NULL &&
1564                       pDirEntry->FileIndex == DirIndex))
1565                 {
1566
1567                     break;
1568                 }
1569
1570                 pSnapshotEntry++;
1571
1572                 ulCount++;
1573             }
1574
1575             if( pDirEntry != NULL)
1576             {
1577
1578                 Ccb->CurrentDirIndex = ulCount;
1579             }
1580         }
1581
1582 try_exit:
1583
1584         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1585     }
1586
1587     return pDirEntry;
1588 }
1589
1590 NTSTATUS
1591 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1592                       IN AFSCcb *Ccb,
1593                       IN BOOLEAN ResetIndex)
1594 {
1595
1596     NTSTATUS ntStatus = STATUS_SUCCESS;
1597     AFSSnapshotHdr *pSnapshotHdr = NULL;
1598     AFSSnapshotEntry *pSnapshotEntry = NULL;
1599     AFSDirectoryCB *pDirEntry = NULL;
1600
1601     __Enter
1602     {
1603
1604         if( ResetIndex)
1605         {
1606
1607             //
1608             // Set it up so we still get the . and .. entries for empty directories
1609             //
1610
1611             if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1612             {
1613
1614                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1615             }
1616             else
1617             {
1618
1619                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1620             }
1621         }
1622
1623         if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1624         {
1625
1626             //
1627             // If we have a snapshot then clear it out
1628             //
1629
1630             if( Ccb->DirectorySnapshot != NULL)
1631             {
1632
1633                 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1634
1635                 Ccb->DirectorySnapshot = NULL;
1636             }
1637
1638             try_return( ntStatus);
1639         }
1640
1641         //
1642         // Allocate our snapshot buffer for this enumeration
1643         //
1644
1645         pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1646                                                                    sizeof( AFSSnapshotHdr) +
1647                                                                         ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1648                                                                                 sizeof( AFSSnapshotEntry)),
1649                                                                    AFS_DIR_SNAPSHOT_TAG);
1650
1651         if( pSnapshotHdr == NULL)
1652         {
1653
1654             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1655         }
1656
1657         RtlZeroMemory( pSnapshotHdr,
1658                        sizeof( AFSSnapshotHdr) +
1659                             ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1660                                     sizeof( AFSSnapshotEntry)));
1661
1662         pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1663
1664         pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1665
1666         //
1667         // Populate our snapshot
1668         //
1669
1670         pSnapshotEntry = pSnapshotHdr->TopEntry;
1671
1672         pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1673
1674         while( pDirEntry != NULL)
1675         {
1676
1677             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1678                 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1679                 !AFSIsNameInSnapshot( pSnapshotHdr,
1680                                       (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1681             {
1682
1683                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1684                               AFS_TRACE_LEVEL_VERBOSE,
1685                               "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1686                               pSnapshotHdr->EntryCount,
1687                               &pDirEntry->NameInformation.FileName,
1688                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1689                               pDirEntry->Flags,
1690                               Fcb->ObjectInformation->FileId.Cell,
1691                               Fcb->ObjectInformation->FileId.Volume,
1692                               Fcb->ObjectInformation->FileId.Vnode,
1693                               Fcb->ObjectInformation->FileId.Unique);
1694
1695                 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1696
1697                 pSnapshotEntry++;
1698             }
1699             else
1700             {
1701
1702                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1703                               AFS_TRACE_LEVEL_VERBOSE,
1704                               "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1705                               pSnapshotHdr->EntryCount,
1706                               &pDirEntry->NameInformation.FileName,
1707                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1708                               pDirEntry->Flags,
1709                               Fcb->ObjectInformation->FileId.Cell,
1710                               Fcb->ObjectInformation->FileId.Volume,
1711                               Fcb->ObjectInformation->FileId.Vnode,
1712                               Fcb->ObjectInformation->FileId.Unique);
1713             }
1714
1715             pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1716         }
1717
1718         if( Ccb->DirectorySnapshot != NULL)
1719         {
1720
1721             AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1722
1723             Ccb->DirectorySnapshot = NULL;
1724         }
1725
1726         Ccb->DirectorySnapshot = pSnapshotHdr;
1727
1728 try_exit:
1729
1730         NOTHING;
1731     }
1732
1733     return ntStatus;
1734 }
1735
1736 NTSTATUS
1737 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1738                                    IN AFSCcb *Ccb,
1739                                    IN BOOLEAN WatchTree,
1740                                    IN ULONG CompletionFilter,
1741                                    IN PIRP NotifyIrp)
1742 {
1743
1744     NTSTATUS ntStatus = STATUS_SUCCESS;
1745     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1746     size_t sztLength;
1747
1748     __Enter
1749     {
1750
1751         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1752                         TRUE);
1753
1754         //
1755         // Build a dir name based on the FID of the file
1756         //
1757
1758         if( Ccb->NotifyMask.Buffer == NULL)
1759         {
1760
1761             Ccb->NotifyMask.Length = 0;
1762             Ccb->NotifyMask.MaximumLength = 1024;
1763
1764             Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1765                                                                         Ccb->NotifyMask.MaximumLength,
1766                                                                         AFS_GENERIC_MEMORY_7_TAG);
1767
1768             if( Ccb->NotifyMask.Buffer == NULL)
1769             {
1770
1771                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1772             }
1773
1774             ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1775                                            Ccb->NotifyMask.MaximumLength,
1776                                            L"\\%08lX.%08lX.%08lX.%08lX",
1777                                            ObjectInfo->FileId.Cell,
1778                                            ObjectInfo->FileId.Volume,
1779                                            ObjectInfo->FileId.Vnode,
1780                                            ObjectInfo->FileId.Unique);
1781
1782             if( !NT_SUCCESS( ntStatus))
1783             {
1784
1785                 try_return( ntStatus);
1786             }
1787
1788             ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1789                                            (size_t)Ccb->NotifyMask.MaximumLength,
1790                                            &sztLength);
1791
1792             if( !NT_SUCCESS( ntStatus))
1793             {
1794
1795                 try_return( ntStatus);
1796             }
1797
1798             Ccb->NotifyMask.Length = (USHORT)sztLength;
1799         }
1800
1801         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1802                       AFS_TRACE_LEVEL_VERBOSE,
1803                       "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %p Filter %08lX Tree %02lX\n",
1804                       &Ccb->NotifyMask,
1805                       NotifyIrp,
1806                       CompletionFilter,
1807                       WatchTree);
1808
1809         FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1810                                         &pDeviceExt->Specific.Control.DirNotifyList,
1811                                         (void *)Ccb,
1812                                         (PSTRING)&Ccb->NotifyMask,
1813                                         WatchTree,
1814                                         TRUE,
1815                                         CompletionFilter,
1816                                         NotifyIrp,
1817                                         NULL,
1818                                         NULL,
1819                                         NULL);
1820
1821 try_exit:
1822
1823         if( !NT_SUCCESS( ntStatus))
1824         {
1825
1826             if( Ccb->NotifyMask.Buffer != NULL)
1827             {
1828
1829                 AFSExFreePoolWithTag( Ccb->NotifyMask.Buffer, AFS_GENERIC_MEMORY_7_TAG);
1830
1831                 Ccb->NotifyMask.Buffer = NULL;
1832             }
1833         }
1834
1835         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1836     }
1837
1838     return ntStatus;
1839 }
1840
1841 void
1842 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1843                                 IN AFSCcb *Ccb,
1844                                 IN ULONG NotifyFilter,
1845                                 IN ULONG NotificationAction)
1846 {
1847
1848     NTSTATUS ntStatus = STATUS_SUCCESS;
1849     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1850     UNICODE_STRING uniName, uniComponentName;
1851     size_t sztLength;
1852     USHORT usNameOffset = 0;
1853
1854     __Enter
1855     {
1856
1857         uniName.Buffer = NULL;
1858
1859         if( ParentObjectInfo == NULL ||
1860             AFSGlobalRoot == NULL)
1861         {
1862
1863             try_return( ntStatus);
1864         }
1865
1866         if( Ccb == NULL)
1867         {
1868
1869             RtlInitUnicodeString( &uniComponentName,
1870                                   L"_AFSChange.dat");
1871         }
1872         else
1873         {
1874
1875             uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1876         }
1877
1878         //
1879         // Build a dir name based on the FID of the file
1880         //
1881
1882         uniName.Length = 0;
1883         uniName.MaximumLength = 1024 + uniComponentName.Length;
1884
1885         uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1886                                                             uniName.MaximumLength,
1887                                                             AFS_GENERIC_MEMORY_8_TAG);
1888
1889         if( uniName.Buffer == NULL)
1890         {
1891
1892             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1893         }
1894
1895         ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1896                                        uniName.MaximumLength,
1897                                        L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1898                                        ParentObjectInfo->FileId.Cell,
1899                                        ParentObjectInfo->FileId.Volume,
1900                                        ParentObjectInfo->FileId.Vnode,
1901                                        ParentObjectInfo->FileId.Unique,
1902                                        &uniComponentName);
1903
1904         if( !NT_SUCCESS( ntStatus))
1905         {
1906
1907             try_return( ntStatus);
1908         }
1909
1910         ntStatus = RtlStringCbLengthW( uniName.Buffer,
1911                                        (size_t)uniName.MaximumLength,
1912                                        &sztLength);
1913
1914         if( !NT_SUCCESS( ntStatus))
1915         {
1916
1917             try_return( ntStatus);
1918         }
1919
1920         uniName.Length = (USHORT)sztLength;
1921
1922         usNameOffset = uniName.Length - uniComponentName.Length;
1923
1924         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1925                       AFS_TRACE_LEVEL_VERBOSE,
1926                       "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1927                       &uniName,
1928                       NotifyFilter,
1929                       NotificationAction,
1930                       usNameOffset,
1931                       uniName.Length,
1932                       uniComponentName.Length);
1933
1934         FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1935                                        &pDeviceExt->Specific.Control.DirNotifyList,
1936                                        (PSTRING)&uniName,
1937                                        usNameOffset,
1938                                        NULL,
1939                                        NULL,
1940                                        NotifyFilter,
1941                                        NotificationAction,
1942                                        NULL,
1943                                        (void *)Ccb);
1944
1945 try_exit:
1946
1947         if( uniName.Buffer != NULL)
1948         {
1949
1950             AFSExFreePoolWithTag( uniName.Buffer, AFS_GENERIC_MEMORY_8_TAG);
1951         }
1952     }
1953
1954     return;
1955 }
1956
1957 // For use with FsRtlNotifyFilterChangeDirectory but must
1958 // be implemented in the Framework because the library can
1959 // be unloaded.
1960
1961 BOOLEAN
1962 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1963                                IN void *FilterContext)
1964 {
1965     UNREFERENCED_PARAMETER(NotifyContext);
1966     UNREFERENCED_PARAMETER(FilterContext);
1967     BOOLEAN bReturn = TRUE;
1968
1969     __Enter
1970     {
1971
1972     }
1973
1974     return bReturn;
1975 }
1976
1977 BOOLEAN
1978 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1979                      IN ULONG HashIndex)
1980 {
1981
1982     BOOLEAN bIsInSnapshot = FALSE;
1983     AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1984     ULONG ulCount = 0;
1985
1986     while( ulCount < SnapshotHdr->EntryCount)
1987     {
1988
1989         if( pSnapshotEntry->NameHash == HashIndex)
1990         {
1991
1992             bIsInSnapshot = TRUE;
1993
1994             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1995                           AFS_TRACE_LEVEL_VERBOSE,
1996                           "AFSIsNameInSnapshot  Hash index %08lX already in snapshot\n",
1997                           HashIndex);
1998
1999             break;
2000         }
2001         else if( pSnapshotEntry->NameHash == 0)
2002         {
2003
2004             break;
2005         }
2006
2007         pSnapshotEntry++;
2008
2009         ulCount++;
2010     }
2011
2012     return bIsInSnapshot;
2013 }
2014
2015 NTSTATUS
2016 AFSProcessDirectoryQueryDirect( IN AFSFcb *Fcb,
2017                                 IN AFSCcb *Ccb,
2018                                 IN IRP *Irp)
2019 {
2020
2021     NTSTATUS        ntStatus = STATUS_SUCCESS;
2022     AFSDirEnumEntry *pDirEnum = NULL;
2023     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2024     PUCHAR           pBuffer = NULL;
2025     ULONG            ulBaseLength = 0;
2026     ULONG            ulAdditionalAttributes = 0;
2027     ULONG            ulBytesConverted = 0;
2028     PFILE_DIRECTORY_INFORMATION pDirInfo;
2029     PFILE_FULL_DIR_INFORMATION pFullDirInfo;
2030     PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
2031     PFILE_NAMES_INFORMATION pNamesInfo;
2032
2033     __Enter
2034     {
2035
2036         //
2037         // query the service for the entry
2038         //
2039
2040         ntStatus = AFSEvaluateTargetByName( &Ccb->AuthGroup,
2041                                             Fcb->ObjectInformation,
2042                                             &Ccb->MaskName,
2043                                             AFS_REQUEST_FLAG_LAST_COMPONENT,
2044                                             &pDirEnum);
2045
2046         if( !NT_SUCCESS( ntStatus))
2047         {
2048
2049             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2050                           AFS_TRACE_LEVEL_ERROR,
2051                           "AFSProcessDirectoryQueryDirect Failed to locate non-wildcard match directly parent %wZ Mask %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2052                           &Ccb->DirectoryCB->NameInformation.FileName,
2053                           &Ccb->MaskName,
2054                           Fcb->ObjectInformation->FileId.Cell,
2055                           Fcb->ObjectInformation->FileId.Volume,
2056                           Fcb->ObjectInformation->FileId.Vnode,
2057                           Fcb->ObjectInformation->FileId.Unique,
2058                           ntStatus);
2059
2060             try_return( ntStatus = STATUS_NO_SUCH_FILE);
2061         }
2062
2063         pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
2064                                                pIrpSp->Parameters.QueryDirectory.Length);
2065
2066         if( pBuffer == NULL)
2067         {
2068
2069             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2070         }
2071
2072         //
2073         // Process the enum request
2074         //
2075
2076         switch( pIrpSp->Parameters.QueryDirectory.FileInformationClass)
2077         {
2078
2079             case FileDirectoryInformation:
2080
2081                 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
2082                                              FileName[0] );
2083                 break;
2084
2085             case FileFullDirectoryInformation:
2086
2087                 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
2088                                              FileName[0] );
2089                 break;
2090
2091             case FileNamesInformation:
2092
2093                 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
2094                                              FileName[0] );
2095                 break;
2096
2097             case FileBothDirectoryInformation:
2098
2099                 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
2100                                              FileName[0] );
2101                 break;
2102
2103             case FileIdBothDirectoryInformation:
2104
2105                 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
2106                                              FileName[0] );
2107
2108                 break;
2109
2110             case FileIdFullDirectoryInformation:
2111
2112                 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
2113                                              FileName[0] );
2114
2115                 break;
2116
2117             default:
2118
2119                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2120                               AFS_TRACE_LEVEL_ERROR,
2121                               "AFSProcessDirectoryQueryDirect (%p) Unknown FileInformationClass %u\n",
2122                               Irp,
2123                               pIrpSp->Parameters.QueryDirectory.FileInformationClass);
2124
2125                 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
2126         }
2127
2128         switch( pDirEnum->FileType)
2129         {
2130
2131             case AFS_FILE_TYPE_MOUNTPOINT:
2132             case AFS_FILE_TYPE_DFSLINK:
2133             {
2134
2135                 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
2136
2137                 break;
2138             }
2139
2140             case AFS_FILE_TYPE_SYMLINK:
2141             {
2142
2143                 //
2144                 // Note: we need to evaluate this entry to determine if the target is a directory or not
2145                 //
2146
2147                 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
2148
2149                 break;
2150             }
2151         }
2152
2153         //  Zero the base part of the structure.
2154         RtlZeroMemory( pBuffer,
2155                        ulBaseLength);
2156
2157         switch( pIrpSp->Parameters.QueryDirectory.FileInformationClass)
2158         {
2159
2160             //  Now fill the base parts of the structure that are applicable.
2161             case FileIdBothDirectoryInformation:
2162             case FileBothDirectoryInformation:
2163             {
2164                 pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)pBuffer;
2165
2166                 pBothDirInfo->ShortNameLength = (CHAR)pDirEnum->ShortNameLength;
2167
2168                 if( pDirEnum->ShortNameLength > 0)
2169                 {
2170                     RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
2171                                    &pDirEnum->ShortName[ 0],
2172                                    pBothDirInfo->ShortNameLength);
2173                 }
2174             }
2175             case FileIdFullDirectoryInformation:
2176             case FileFullDirectoryInformation:
2177             {
2178                 pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)pBuffer;
2179                 pFullDirInfo->EaSize = 0;
2180             }
2181             case FileDirectoryInformation:
2182             {
2183                 pDirInfo = (PFILE_DIRECTORY_INFORMATION)pBuffer;
2184
2185                 pDirInfo->CreationTime = pDirEnum->CreationTime;
2186                 pDirInfo->LastWriteTime = pDirEnum->LastWriteTime;
2187                 pDirInfo->LastAccessTime = pDirEnum->LastAccessTime;
2188                 pDirInfo->ChangeTime = pDirEnum->ChangeTime;
2189
2190                 pDirInfo->EndOfFile = pDirEnum->EndOfFile;
2191                 pDirInfo->AllocationSize = pDirEnum->AllocationSize;
2192
2193                 if ( ulAdditionalAttributes && pDirEnum->FileAttributes == FILE_ATTRIBUTE_NORMAL)
2194                 {
2195                     pDirInfo->FileAttributes = ulAdditionalAttributes;
2196                 }
2197                 else
2198                 {
2199                     pDirInfo->FileAttributes = pDirEnum->FileAttributes | ulAdditionalAttributes;
2200                 }
2201
2202                 pDirInfo->FileIndex = pDirEnum->FileIndex;
2203                 pDirInfo->FileNameLength = pDirEnum->FileNameLength;
2204
2205                 break;
2206             }
2207
2208             case FileNamesInformation:
2209             {
2210                 pNamesInfo = (PFILE_NAMES_INFORMATION)pBuffer;
2211                 pNamesInfo->FileIndex = pDirEnum->FileIndex;
2212                 pNamesInfo->FileNameLength = pDirEnum->FileNameLength;
2213
2214                 break;
2215             }
2216
2217             default:
2218             {
2219                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2220                               AFS_TRACE_LEVEL_ERROR,
2221                               "AFSProcessDirectoryQueryDirect (%p) Unknown FileInformationClass %u\n",
2222                               Irp,
2223                               pIrpSp->Parameters.QueryDirectory.FileInformationClass);
2224
2225                 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
2226             }
2227         }
2228
2229         ulBytesConverted = pIrpSp->Parameters.QueryDirectory.Length - ulBaseLength >= pDirEnum->FileNameLength ?
2230                                         pDirEnum->FileNameLength :
2231                                         pIrpSp->Parameters.QueryDirectory.Length - ulBaseLength;
2232
2233         RtlCopyMemory( &pBuffer[ ulBaseLength],
2234                        (void *)((char *)pDirEnum + pDirEnum->FileNameOffset),
2235                        ulBytesConverted);
2236
2237         Irp->IoStatus.Information = ulBaseLength + ulBytesConverted;
2238
2239 try_exit:
2240
2241         if( pDirEnum != NULL)
2242         {
2243             ExFreePool( pDirEnum);
2244         }
2245     }
2246
2247     return ntStatus;
2248 }