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