Windows: do not leak resource in AFSQueryDirectory
[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                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1127                               AFS_TRACE_LEVEL_VERBOSE,
1128                               "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1129                               &pDirEntry->NameInformation.FileName,
1130                               ObjectInfo->FileId.Cell,
1131                               ObjectInfo->FileId.Volume,
1132                               ObjectInfo->FileId.Vnode,
1133                               ObjectInfo->FileId.Unique);
1134             }
1135
1136             Ccb->CurrentDirIndex++;
1137
1138             try_return( ntStatus);
1139         }
1140
1141         Ccb->CurrentDirIndex++;
1142
1143         if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1144         {
1145
1146             //
1147             // Return the .. entry
1148             //
1149
1150             pDirEntry = AFSGlobalDotDirEntry;
1151
1152             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1153                           AFS_TRACE_LEVEL_VERBOSE,
1154                           "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1155                           &pDirEntry->NameInformation.FileName,
1156                           ObjectInfo->FileId.Cell,
1157                           ObjectInfo->FileId.Volume,
1158                           ObjectInfo->FileId.Vnode,
1159                           ObjectInfo->FileId.Unique);
1160         }
1161         else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1162         {
1163
1164             //
1165             // Return the .. entry
1166             //
1167
1168             pDirEntry = AFSGlobalDotDotDirEntry;
1169
1170             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1171                           AFS_TRACE_LEVEL_VERBOSE,
1172                           "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1173                           &pDirEntry->NameInformation.FileName,
1174                           ObjectInfo->FileId.Cell,
1175                           ObjectInfo->FileId.Volume,
1176                           ObjectInfo->FileId.Vnode,
1177                           ObjectInfo->FileId.Unique);
1178         }
1179         else
1180         {
1181
1182             pSnapshotHdr = Ccb->DirectorySnapshot;
1183
1184             if( pSnapshotHdr == NULL ||
1185                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1186             {
1187
1188                 try_return( ntStatus);
1189             }
1190
1191             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1192
1193             ulCount = Ccb->CurrentDirIndex;
1194
1195             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1196                           AFS_TRACE_LEVEL_VERBOSE,
1197                           "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1198                           ulCount);
1199
1200             //
1201             // Get to a valid entry
1202             //
1203
1204             AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1205                               TRUE);
1206
1207             while( ulCount < pSnapshotHdr->EntryCount)
1208             {
1209
1210                 pDirEntry = NULL;
1211
1212                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1213                               AFS_TRACE_LEVEL_VERBOSE,
1214                               "AFSLocateNextDirEntry Searching for hash %08lX\n",
1215                               pSnapshotEntry->NameHash);
1216
1217                 if( pSnapshotEntry->NameHash == 0)
1218                 {
1219
1220                     break;
1221                 }
1222
1223                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1224                                                            pSnapshotEntry->NameHash,
1225                                                            &pDirEntry);
1226
1227                 if( !NT_SUCCESS( ntStatus) ||
1228                     pDirEntry != NULL)
1229                 {
1230
1231                     if( pDirEntry != NULL)
1232                     {
1233
1234                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1235                                       AFS_TRACE_LEVEL_VERBOSE,
1236                                       "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1237                                       &pDirEntry->NameInformation.FileName,
1238                                       (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1239                                       ObjectInfo->FileId.Cell,
1240                                       ObjectInfo->FileId.Volume,
1241                                       ObjectInfo->FileId.Vnode,
1242                                       ObjectInfo->FileId.Unique);
1243
1244                         InterlockedIncrement( &pDirEntry->OpenReferenceCount);
1245                     }
1246                     else
1247                     {
1248
1249
1250                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1251                                       AFS_TRACE_LEVEL_VERBOSE,
1252                                       "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1253                                       ObjectInfo->FileId.Cell,
1254                                       ObjectInfo->FileId.Volume,
1255                                       ObjectInfo->FileId.Vnode,
1256                                       ObjectInfo->FileId.Unique);
1257                     }
1258
1259                     break;
1260                 }
1261
1262                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1263                               AFS_TRACE_LEVEL_VERBOSE,
1264                               "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1265                               pSnapshotEntry->NameHash,
1266                               ObjectInfo->FileId.Cell,
1267                               ObjectInfo->FileId.Volume,
1268                               ObjectInfo->FileId.Vnode,
1269                               ObjectInfo->FileId.Unique);
1270
1271                 pSnapshotEntry++;
1272
1273                 ulCount++;
1274
1275                 Ccb->CurrentDirIndex++;
1276             }
1277
1278             AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1279         }
1280
1281 try_exit:
1282
1283         NOTHING;
1284     }
1285
1286     return pDirEntry;
1287 }
1288
1289 AFSDirectoryCB *
1290 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1291                           IN AFSCcb *Ccb,
1292                           IN ULONG DirIndex)
1293 {
1294
1295     AFSDirectoryCB *pDirEntry = NULL;
1296     NTSTATUS ntStatus = STATUS_SUCCESS;
1297     AFSSnapshotHdr *pSnapshotHdr = NULL;
1298     AFSSnapshotEntry *pSnapshotEntry = NULL;
1299     ULONG ulCount = 0;
1300
1301     __Enter
1302     {
1303
1304         Ccb->CurrentDirIndex = DirIndex;
1305
1306         if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1307         {
1308
1309             //
1310             // Return the .. entry
1311             //
1312
1313             pDirEntry = AFSGlobalDotDirEntry;
1314         }
1315         else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1316         {
1317
1318             //
1319             // Return the .. entry
1320             //
1321
1322             pDirEntry = AFSGlobalDotDotDirEntry;
1323         }
1324         else
1325         {
1326
1327             pSnapshotHdr = Ccb->DirectorySnapshot;
1328
1329             if( pSnapshotHdr == NULL ||
1330                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1331             {
1332
1333                 try_return( ntStatus);
1334             }
1335
1336             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1337
1338             ulCount = Ccb->CurrentDirIndex;
1339
1340             //
1341             // Get to a valid entry
1342             //
1343
1344             while( ulCount < pSnapshotHdr->EntryCount)
1345             {
1346
1347                 pDirEntry = NULL;
1348
1349                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1350                                                            pSnapshotEntry->NameHash,
1351                                                            &pDirEntry);
1352
1353                 if( !NT_SUCCESS( ntStatus) ||
1354                     ( pDirEntry != NULL &&
1355                       pDirEntry->FileIndex == DirIndex))
1356                 {
1357
1358                     break;
1359                 }
1360
1361                 pSnapshotEntry++;
1362
1363                 ulCount++;
1364             }
1365
1366             if( pDirEntry != NULL)
1367             {
1368
1369                 Ccb->CurrentDirIndex = ulCount;
1370             }
1371         }
1372
1373 try_exit:
1374
1375         NOTHING;
1376     }
1377
1378     return pDirEntry;
1379 }
1380
1381 NTSTATUS
1382 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1383                       IN AFSCcb *Ccb,
1384                       IN BOOLEAN ResetIndex)
1385 {
1386
1387     NTSTATUS ntStatus = STATUS_SUCCESS;
1388     AFSSnapshotHdr *pSnapshotHdr = NULL;
1389     AFSSnapshotEntry *pSnapshotEntry = NULL;
1390     AFSDirectoryCB *pDirEntry = NULL;
1391
1392     __Enter
1393     {
1394
1395         if( ResetIndex)
1396         {
1397
1398             //
1399             // Set it up so we still get the . and .. entries for empty directories
1400             //
1401
1402             if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1403             {
1404
1405                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1406             }
1407             else
1408             {
1409
1410                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1411             }
1412         }
1413
1414         if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1415         {
1416
1417             //
1418             // If we have a snapshot then clear it out
1419             //
1420
1421             if( Ccb->DirectorySnapshot != NULL)
1422             {
1423
1424                 AFSExFreePool( Ccb->DirectorySnapshot);
1425
1426                 Ccb->DirectorySnapshot = NULL;
1427             }
1428
1429             try_return( ntStatus);
1430         }
1431
1432         //
1433         // Allocate our snapshot buffer for this enumeration
1434         //
1435
1436         pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1437                                                                    sizeof( AFSSnapshotHdr) +
1438                                                                         ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1439                                                                                 sizeof( AFSSnapshotEntry)),
1440                                                                    AFS_DIR_SNAPSHOT_TAG);
1441
1442         if( pSnapshotHdr == NULL)
1443         {
1444
1445             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1446         }
1447
1448         RtlZeroMemory( pSnapshotHdr,
1449                        sizeof( AFSSnapshotHdr) +
1450                             ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1451                                     sizeof( AFSSnapshotEntry)));
1452
1453         pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1454
1455         pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1456
1457         //
1458         // Populate our snapshot
1459         //
1460
1461         pSnapshotEntry = pSnapshotHdr->TopEntry;
1462
1463         pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1464
1465         while( pDirEntry != NULL)
1466         {
1467
1468             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1469                 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1470                 !AFSIsNameInSnapshot( pSnapshotHdr,
1471                                       (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1472             {
1473
1474                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1475                               AFS_TRACE_LEVEL_VERBOSE,
1476                               "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1477                               pSnapshotHdr->EntryCount,
1478                               &pDirEntry->NameInformation.FileName,
1479                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1480                               pDirEntry->Flags,
1481                               Fcb->ObjectInformation->FileId.Cell,
1482                               Fcb->ObjectInformation->FileId.Volume,
1483                               Fcb->ObjectInformation->FileId.Vnode,
1484                               Fcb->ObjectInformation->FileId.Unique);
1485
1486                 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1487
1488                 pSnapshotEntry++;
1489             }
1490             else
1491             {
1492
1493                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1494                               AFS_TRACE_LEVEL_VERBOSE,
1495                               "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1496                               pSnapshotHdr->EntryCount,
1497                               &pDirEntry->NameInformation.FileName,
1498                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1499                               pDirEntry->Flags,
1500                               Fcb->ObjectInformation->FileId.Cell,
1501                               Fcb->ObjectInformation->FileId.Volume,
1502                               Fcb->ObjectInformation->FileId.Vnode,
1503                               Fcb->ObjectInformation->FileId.Unique);
1504             }
1505
1506             pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1507         }
1508
1509         if( Ccb->DirectorySnapshot != NULL)
1510         {
1511
1512             AFSExFreePool( Ccb->DirectorySnapshot);
1513
1514             Ccb->DirectorySnapshot = NULL;
1515         }
1516
1517         Ccb->DirectorySnapshot = pSnapshotHdr;
1518
1519 try_exit:
1520
1521         NOTHING;
1522     }
1523
1524     return ntStatus;
1525 }
1526
1527 NTSTATUS
1528 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1529                                    IN AFSCcb *Ccb,
1530                                    IN BOOLEAN WatchTree,
1531                                    IN ULONG CompletionFilter,
1532                                    IN PIRP NotifyIrp)
1533 {
1534
1535     NTSTATUS ntStatus = STATUS_SUCCESS;
1536     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1537     size_t sztLength;
1538
1539     __Enter
1540     {
1541
1542         //
1543         // Build a dir name based on the FID of the file
1544         //
1545
1546         if( Ccb->NotifyMask.Buffer == NULL)
1547         {
1548
1549             Ccb->NotifyMask.Length = 0;
1550             Ccb->NotifyMask.MaximumLength = 1024;
1551
1552             Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1553                                                                         Ccb->NotifyMask.MaximumLength,
1554                                                                         AFS_GENERIC_MEMORY_7_TAG);
1555
1556             if( Ccb->NotifyMask.Buffer == NULL)
1557             {
1558
1559                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1560             }
1561
1562             ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1563                                            Ccb->NotifyMask.MaximumLength,
1564                                            L"\\%08lX.%08lX.%08lX.%08lX",
1565                                            ObjectInfo->FileId.Cell,
1566                                            ObjectInfo->FileId.Volume,
1567                                            ObjectInfo->FileId.Vnode,
1568                                            ObjectInfo->FileId.Unique);
1569
1570             if( !NT_SUCCESS( ntStatus))
1571             {
1572
1573                 try_return( ntStatus);
1574             }
1575
1576             ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1577                                            (size_t)Ccb->NotifyMask.MaximumLength,
1578                                            &sztLength);
1579
1580             if( !NT_SUCCESS( ntStatus))
1581             {
1582
1583                 try_return( ntStatus);
1584             }
1585
1586             Ccb->NotifyMask.Length = (USHORT)sztLength;
1587         }
1588
1589         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1590                       AFS_TRACE_LEVEL_VERBOSE,
1591                       "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1592                       &Ccb->NotifyMask,
1593                       NotifyIrp,
1594                       CompletionFilter,
1595                       WatchTree);
1596
1597         FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1598                                         &pDeviceExt->Specific.Control.DirNotifyList,
1599                                         (void *)Ccb,
1600                                         (PSTRING)&Ccb->NotifyMask,
1601                                         WatchTree,
1602                                         TRUE,
1603                                         CompletionFilter,
1604                                         NotifyIrp,
1605                                         NULL,
1606                                         NULL,
1607                                         NULL);
1608
1609 try_exit:
1610
1611         if( !NT_SUCCESS( ntStatus))
1612         {
1613
1614             if( Ccb->NotifyMask.Buffer != NULL)
1615             {
1616
1617                 AFSExFreePool( Ccb->NotifyMask.Buffer);
1618
1619                 Ccb->NotifyMask.Buffer = NULL;
1620             }
1621         }
1622     }
1623
1624     return ntStatus;
1625 }
1626
1627 void
1628 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1629                                 IN AFSCcb *Ccb,
1630                                 IN ULONG NotifyFilter,
1631                                 IN ULONG NotificationAction)
1632 {
1633
1634     NTSTATUS ntStatus = STATUS_SUCCESS;
1635     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1636     UNICODE_STRING uniName, uniComponentName;
1637     size_t sztLength;
1638     USHORT usNameOffset = 0;
1639
1640     __Enter
1641     {
1642
1643         uniName.Buffer = NULL;
1644
1645         if( ParentObjectInfo == NULL ||
1646             AFSGlobalRoot == NULL)
1647         {
1648
1649             try_return( ntStatus);
1650         }
1651
1652         if( Ccb == NULL)
1653         {
1654
1655             RtlInitUnicodeString( &uniComponentName,
1656                                   L"_AFSChange.dat");
1657         }
1658         else
1659         {
1660
1661             uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1662         }
1663
1664         //
1665         // Build a dir name based on the FID of the file
1666         //
1667
1668         uniName.Length = 0;
1669         uniName.MaximumLength = 1024 + uniComponentName.Length;
1670
1671         uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1672                                                             uniName.MaximumLength,
1673                                                             AFS_GENERIC_MEMORY_8_TAG);
1674
1675         if( uniName.Buffer == NULL)
1676         {
1677
1678             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1679         }
1680
1681         ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1682                                        uniName.MaximumLength,
1683                                        L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1684                                        ParentObjectInfo->FileId.Cell,
1685                                        ParentObjectInfo->FileId.Volume,
1686                                        ParentObjectInfo->FileId.Vnode,
1687                                        ParentObjectInfo->FileId.Unique,
1688                                        &uniComponentName);
1689
1690         if( !NT_SUCCESS( ntStatus))
1691         {
1692
1693             try_return( ntStatus);
1694         }
1695
1696         ntStatus = RtlStringCbLengthW( uniName.Buffer,
1697                                        (size_t)uniName.MaximumLength,
1698                                        &sztLength);
1699
1700         if( !NT_SUCCESS( ntStatus))
1701         {
1702
1703             try_return( ntStatus);
1704         }
1705
1706         uniName.Length = (USHORT)sztLength;
1707
1708         usNameOffset = uniName.Length - uniComponentName.Length;
1709
1710         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1711                       AFS_TRACE_LEVEL_VERBOSE,
1712                       "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1713                       &uniName,
1714                       NotifyFilter,
1715                       NotificationAction,
1716                       usNameOffset,
1717                       uniName.Length,
1718                       uniComponentName.Length);
1719
1720         FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1721                                        &pDeviceExt->Specific.Control.DirNotifyList,
1722                                        (PSTRING)&uniName,
1723                                        usNameOffset,
1724                                        NULL,
1725                                        NULL,
1726                                        NotifyFilter,
1727                                        NotificationAction,
1728                                        NULL,
1729                                        (void *)Ccb);
1730
1731 try_exit:
1732
1733         if( uniName.Buffer != NULL)
1734         {
1735
1736             AFSExFreePool( uniName.Buffer);
1737         }
1738     }
1739
1740     return;
1741 }
1742
1743 // For use with FsRtlNotifyFilterChangeDirectory but must
1744 // be implemented in the Framework because the library can
1745 // be unloaded.
1746
1747 BOOLEAN
1748 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1749                                IN void *FilterContext)
1750 {
1751
1752     BOOLEAN bReturn = TRUE;
1753     AFSCcb *pDirCcb = (AFSCcb *)NotifyContext;
1754     AFSCcb *pNotifyCcb = (AFSCcb *)FilterContext;
1755
1756     __Enter
1757     {
1758
1759     }
1760
1761     return bReturn;
1762 }
1763
1764 BOOLEAN
1765 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1766                      IN ULONG HashIndex)
1767 {
1768
1769     BOOLEAN bIsInSnapshot = FALSE;
1770     AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1771     ULONG ulCount = 0;
1772
1773     while( ulCount < SnapshotHdr->EntryCount)
1774     {
1775
1776         if( pSnapshotEntry->NameHash == HashIndex)
1777         {
1778
1779             bIsInSnapshot = TRUE;
1780
1781             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1782                           AFS_TRACE_LEVEL_VERBOSE,
1783                           "AFSIsNameInSnapshot  Hash index %08lX already in snapshot\n",
1784                           HashIndex);
1785
1786             break;
1787         }
1788         else if( pSnapshotEntry->NameHash == 0)
1789         {
1790
1791             break;
1792         }
1793
1794         pSnapshotEntry++;
1795
1796         ulCount++;
1797     }
1798
1799     return bIsInSnapshot;
1800 }