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