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