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