Windows: Add CCB NonPaged Resource for synchronization
[openafs.git] / src / WINNT / afsrdr / kernel / lib / AFSDirControl.cpp
1 /*
2  * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3  * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistributions of source code must retain the above copyright notice,
11  *   this list of conditions and the following disclaimer.
12  * - Redistributions in binary form must reproduce the above copyright
13  *   notice,
14  *   this list of conditions and the following disclaimer in the
15  *   documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
18  *   nor the names of their contributors may be used to endorse or promote
19  *   products derived from this software without specific prior written
20  *   permission from Kernel Drivers, LLC and Your File System, Inc.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
25  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 //
36 // File: AFSDirControl.cpp
37 //
38
39 #include "AFSCommon.h"
40
41 //
42 // Function: AFSDirControl
43 //
44 // Description:
45 //
46 //      This function is the IRP_MJ_DIRECTORY_CONTROL dispatch handler
47 //
48 // Return:
49 //
50 //       A status is returned for the handling of this request
51 //
52
53 NTSTATUS
54 AFSDirControl( IN PDEVICE_OBJECT LibDeviceObject,
55                IN PIRP Irp)
56 {
57
58     NTSTATUS ntStatus = STATUS_SUCCESS;
59     ULONG ulRequestType = 0;
60     IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
61     AFSFcb *pFcb = NULL;
62
63     __try
64     {
65
66         switch( pIrpSp->MinorFunction )
67         {
68
69             case IRP_MN_QUERY_DIRECTORY:
70             {
71
72                 ntStatus = AFSQueryDirectory( Irp);
73
74                 break;
75             }
76
77             case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
78             {
79
80                 ntStatus = AFSNotifyChangeDirectory( Irp);
81
82                 break;
83             }
84
85             default:
86
87                 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
88
89                 break;
90         }
91     }
92     __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
93     {
94
95         AFSDbgLogMsg( 0,
96                       0,
97                       "EXCEPTION - AFSDirControl\n");
98
99         AFSDumpTraceFilesFnc();
100     }
101
102     if( ntStatus != STATUS_PENDING)
103     {
104
105         AFSCompleteRequest( Irp,
106                             ntStatus);
107     }
108
109     return ntStatus;
110 }
111
112 NTSTATUS
113 AFSQueryDirectory( IN PIRP Irp)
114 {
115
116     NTSTATUS ntStatus = STATUS_SUCCESS;
117     NTSTATUS dStatus = STATUS_SUCCESS;
118     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
119     PIO_STACK_LOCATION pIrpSp;
120     AFSFcb *pFcb = NULL;
121     AFSCcb *pCcb = NULL;
122     BOOLEAN bInitialQuery = FALSE;
123     ULONG ulIndex;
124     PUCHAR pBuffer;
125     ULONG ulUserBufferLength;
126     PUNICODE_STRING puniArgFileName = NULL;
127     UNICODE_STRING uniTmpMaskName;
128     UNICODE_STRING uniDirUniBuf;
129     WCHAR wchMaskBuffer[ 4];
130     FILE_INFORMATION_CLASS FileInformationClass;
131     ULONG ulFileIndex, ulDOSFileIndex;
132     BOOLEAN bRestartScan;
133     BOOLEAN bReturnSingleEntry;
134     BOOLEAN bIndexSpecified;
135     ULONG ulNextEntry = 0;
136     ULONG ulLastEntry = 0;
137     BOOLEAN bDoCase;
138     PFILE_DIRECTORY_INFORMATION pDirInfo;
139     PFILE_FULL_DIR_INFORMATION pFullDirInfo;
140     PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
141     PFILE_NAMES_INFORMATION pNamesInfo;
142     ULONG ulBaseLength;
143     ULONG ulBytesConverted;
144     AFSDirectoryCB *pDirEntry = NULL;
145     BOOLEAN bReleaseMain = FALSE;
146     BOOLEAN bReleaseFcb = FALSE;
147     ULONG ulTargetFileType = AFS_FILE_TYPE_UNKNOWN;
148     AFSFileInfoCB       stFileInfo;
149     BOOLEAN         bUseFileInfo = TRUE;
150     AFSObjectInfoCB *pObjectInfo = NULL;
151     ULONG ulAdditionalAttributes = 0;
152     LONG lCount;
153
154     __Enter
155     {
156
157         //  Get the current Stack location
158         pIrpSp = IoGetCurrentIrpStackLocation( Irp);
159
160         pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
161         pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
162
163         if( pFcb == NULL)
164         {
165
166             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
167                           AFS_TRACE_LEVEL_ERROR,
168                           "AFSQueryDirectory Attempted access (%08lX) when pFcb == NULL\n",
169                           Irp);
170
171             try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
172         }
173
174         if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
175             pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
176             pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
177         {
178
179             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
180                           AFS_TRACE_LEVEL_ERROR,
181                           "AFSQueryDirectory Attempted access (%08lX) to non-directory Fcb %08lX NodeType %u\n",
182                           Irp,
183                           pFcb,
184                           pFcb->Header.NodeTypeCode);
185
186             pFcb = NULL;
187
188             try_return( ntStatus = STATUS_INVALID_PARAMETER);
189         }
190
191         //
192         // Set the enumeration event ...
193         //
194
195         AFSSetEnumerationEvent( pFcb);
196
197         //  Reference our input parameters to make things easier
198         ulUserBufferLength = pIrpSp->Parameters.QueryDirectory.Length;
199
200         FileInformationClass = pIrpSp->Parameters.QueryDirectory.FileInformationClass;
201         ulFileIndex = pIrpSp->Parameters.QueryDirectory.FileIndex;
202
203         puniArgFileName = (PUNICODE_STRING)pIrpSp->Parameters.QueryDirectory.FileName;
204
205         bRestartScan       = BooleanFlagOn( pIrpSp->Flags, SL_RESTART_SCAN);
206         bReturnSingleEntry = BooleanFlagOn( pIrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
207         bIndexSpecified    = BooleanFlagOn( pIrpSp->Flags, SL_INDEX_SPECIFIED);
208
209         bInitialQuery = (BOOLEAN)( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED));
210
211         if( bInitialQuery)
212         {
213
214             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
215                           AFS_TRACE_LEVEL_VERBOSE,
216                           "AFSQueryDirectory Enumerating content for parent %wZ Initial Query\n",
217                           &pCcb->DirectoryCB->NameInformation.FileName);
218
219             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
220                           AFS_TRACE_LEVEL_VERBOSE,
221                           "AFSQueryDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
222                           &pFcb->NPFcb->Resource,
223                           PsGetCurrentThread());
224
225             AFSAcquireExcl( &pFcb->NPFcb->Resource,
226                             TRUE);
227
228             bReleaseFcb = TRUE;
229         }
230         else
231         {
232
233             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
234                           AFS_TRACE_LEVEL_VERBOSE,
235                           "AFSQueryDirectory Enumerating content for parent %wZ Subsequent\n",
236                           &pCcb->DirectoryCB->NameInformation.FileName);
237
238             AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
239                           AFS_TRACE_LEVEL_VERBOSE,
240                           "AFSQueryDirectory Acquiring Dcb lock %08lX SHARED %08lX\n",
241                           &pFcb->NPFcb->Resource,
242                           PsGetCurrentThread());
243
244             AFSAcquireShared( &pFcb->NPFcb->Resource,
245                               TRUE);
246
247             bReleaseFcb = TRUE;
248         }
249
250         //
251         // Grab the directory node hdr tree lock while parsing the directory
252         // contents
253         //
254
255         AFSAcquireExcl( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
256                         TRUE);
257
258         bReleaseMain = TRUE;
259
260         //
261         // Before attempting to insert the new entry, check if we need to validate the parent
262         //
263
264         if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
265         {
266
267             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
268                           AFS_TRACE_LEVEL_VERBOSE,
269                           "AFSQueryDirectory Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n",
270                           &pCcb->DirectoryCB->NameInformation.FileName,
271                           pFcb->ObjectInformation->FileId.Cell,
272                           pFcb->ObjectInformation->FileId.Volume,
273                           pFcb->ObjectInformation->FileId.Vnode,
274                           pFcb->ObjectInformation->FileId.Unique);
275
276             ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
277                                        pCcb->DirectoryCB);
278
279             if( !NT_SUCCESS( ntStatus))
280             {
281
282                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
283                               AFS_TRACE_LEVEL_ERROR,
284                               "AFSQueryDirectory Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
285                               &pCcb->DirectoryCB->NameInformation.FileName,
286                               pFcb->ObjectInformation->FileId.Cell,
287                               pFcb->ObjectInformation->FileId.Volume,
288                               pFcb->ObjectInformation->FileId.Vnode,
289                               pFcb->ObjectInformation->FileId.Unique,
290                               ntStatus);
291
292                 try_return( ntStatus);
293             }
294
295             //
296             // Perform a new snapshot of the directory
297             //
298
299             AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
300                             TRUE);
301
302             ntStatus = AFSSnapshotDirectory( pFcb,
303                                              pCcb,
304                                              FALSE);
305
306             AFSReleaseResource( &pCcb->NPCcb->CcbLock);
307
308             if( !NT_SUCCESS( ntStatus))
309             {
310
311                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
312                               AFS_TRACE_LEVEL_ERROR,
313                               "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
314                               &pCcb->DirectoryCB->NameInformation.FileName,
315                               &pCcb->MaskName,
316                               ntStatus);
317
318                 try_return( ntStatus);
319             }
320         }
321
322         AFSConvertToShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
323
324         //
325         // We can now safely drop the lock on the node
326         //
327
328         AFSReleaseResource( &pFcb->NPFcb->Resource);
329
330         bReleaseFcb = FALSE;
331
332         //
333         // Start processing the data
334         //
335
336         pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
337                                                ulUserBufferLength);
338
339         if( pBuffer == NULL)
340         {
341
342             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
343         }
344
345         AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
346                         TRUE);
347
348         // Check if initial on this map
349         if( bInitialQuery)
350         {
351
352             ntStatus = AFSSnapshotDirectory( pFcb,
353                                              pCcb,
354                                              TRUE);
355
356             if( !NT_SUCCESS( ntStatus))
357             {
358
359                 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
360
361                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
362                               AFS_TRACE_LEVEL_ERROR,
363                               "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
364                               &pCcb->DirectoryCB->NameInformation.FileName,
365                               &pCcb->MaskName,
366                               ntStatus);
367
368                 try_return( ntStatus);
369             }
370
371             SetFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED);
372
373             ClearFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
374
375             // build mask if none
376             if( puniArgFileName == NULL)
377             {
378                 puniArgFileName = &uniTmpMaskName;
379                 puniArgFileName->Length = 0;
380                 puniArgFileName->Buffer = NULL;
381             }
382
383             if( puniArgFileName->Length == 0)
384             {
385
386                 puniArgFileName->Length = sizeof(WCHAR);
387                 puniArgFileName->MaximumLength = (USHORT)4;
388             }
389
390             if( puniArgFileName->Buffer == NULL)
391             {
392
393                 puniArgFileName->Buffer = wchMaskBuffer;
394
395                 RtlZeroMemory( wchMaskBuffer,
396                                4);
397
398                 RtlCopyMemory( &puniArgFileName->Buffer[ 0],
399                                L"*",
400                                sizeof(WCHAR));
401             }
402
403             if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
404                  ( puniArgFileName->Buffer[0] == L'*')))
405             {
406
407                 SetFlag( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY);
408             }
409             else
410             {
411
412                 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
413                      ( puniArgFileName->Buffer[0] == L'<')) ||
414                     (( puniArgFileName->Length == 2*sizeof(WCHAR)) &&
415                     ( RtlEqualMemory( puniArgFileName->Buffer, L"*.", 2*sizeof(WCHAR) ))))
416                 {
417
418                     SetFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
419                 }
420
421                 //
422                 // Build the name for procesisng
423                 //
424
425                 pCcb->MaskName.Length = puniArgFileName->Length;
426                 pCcb->MaskName.MaximumLength = pCcb->MaskName.Length;
427
428                 pCcb->MaskName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
429                                                                            pCcb->MaskName.Length,
430                                                                            AFS_GENERIC_MEMORY_6_TAG);
431
432                 if( pCcb->MaskName.Buffer == NULL)
433                 {
434
435                     try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
436                 }
437
438                 if( FsRtlDoesNameContainWildCards( puniArgFileName))
439                 {
440
441                     RtlUpcaseUnicodeString( &pCcb->MaskName,
442                                             puniArgFileName,
443                                             FALSE);
444
445                     SetFlag( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS);
446
447                     if( FsRtlIsNameInExpression( &pCcb->MaskName,
448                                                  &AFSPIOCtlName,
449                                                  TRUE,
450                                                  NULL))
451                     {
452                         SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
453                     }
454                 }
455                 else
456                 {
457
458                     RtlCopyMemory( pCcb->MaskName.Buffer,
459                                    puniArgFileName->Buffer,
460                                    pCcb->MaskName.Length);
461
462                     if( RtlCompareUnicodeString( &AFSPIOCtlName,
463                                                  &pCcb->MaskName,
464                                                  TRUE) == 0)
465                     {
466                         SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
467                     }
468                 }
469
470                 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
471                 {
472                     if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
473                     {
474
475                         AFSReleaseResource( &pCcb->NPCcb->CcbLock);
476
477                         AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
478
479                         bReleaseMain = FALSE;
480
481                         AFSAcquireExcl( &pFcb->NPFcb->Resource,
482                                         TRUE);
483
484                         if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
485                         {
486
487                             ntStatus = AFSInitPIOCtlDirectoryCB( pFcb->ObjectInformation);
488
489                             if( !NT_SUCCESS( ntStatus))
490                             {
491
492                                 AFSReleaseResource( &pFcb->NPFcb->Resource);
493
494                                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
495                                               AFS_TRACE_LEVEL_ERROR,
496                                               "AFSQueryDirectory Init PIOCtl directory failure for parent %wZ Mask %wZ Status %08lX\n",
497                                               &pCcb->DirectoryCB->NameInformation.FileName,
498                                               &pCcb->MaskName,
499                                               ntStatus);
500
501                                 try_return( ntStatus);
502                             }
503                         }
504
505                         AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
506                                           TRUE);
507
508                         bReleaseMain = TRUE;
509
510                         AFSReleaseResource( &pFcb->NPFcb->Resource);
511
512                         AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
513                                         TRUE);
514                     }
515                 }
516
517                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
518                               AFS_TRACE_LEVEL_VERBOSE,
519                               "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ\n",
520                               &pCcb->DirectoryCB->NameInformation.FileName,
521                               &pCcb->MaskName);
522             }
523         }
524
525         // Check if we need to start from index
526         if( bIndexSpecified)
527         {
528
529             //
530             // Need to set up the initial point for the query
531             //
532
533             pCcb->CurrentDirIndex = ulFileIndex - 1;
534         }
535
536         // Check if we need to restart the scan
537         else if( bRestartScan)
538         {
539
540             //
541             // Reset the current scan processing
542             //
543
544             if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
545             {
546
547                 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
548             }
549             else
550             {
551
552                 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
553             }
554         }
555
556         AFSReleaseResource( &pCcb->NPCcb->CcbLock);
557
558         AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
559
560         bReleaseMain = FALSE;
561
562         switch( FileInformationClass)
563         {
564
565             case FileDirectoryInformation:
566
567                 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
568                                              FileName[0] );
569                 break;
570
571             case FileFullDirectoryInformation:
572
573                 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
574                                              FileName[0] );
575                 break;
576
577             case FileNamesInformation:
578
579                 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
580                                              FileName[0] );
581                 break;
582
583             case FileBothDirectoryInformation:
584
585                 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
586                                              FileName[0] );
587                 break;
588
589             case FileIdBothDirectoryInformation:
590
591                 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
592                                              FileName[0] );
593
594                 break;
595
596             case FileIdFullDirectoryInformation:
597
598                 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
599                                              FileName[0] );
600
601                 break;
602
603             default:
604
605                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
606                               AFS_TRACE_LEVEL_ERROR,
607                               "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
608                               Irp,
609                               FileInformationClass);
610
611                 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
612         }
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                 lCount = 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                         lCount = 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                             lCount = 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                                 lCount = InterlockedDecrement( &pDirEntry->OpenReferenceCount);
731
732                                 continue;
733                             }
734                         }
735                     }
736                 }
737             }
738
739             //
740             // Be sure the information is valid
741             // We don't worry about entries while enumerating the directory
742             //
743
744             AFSValidateEntry( pDirEntry,
745                               &pCcb->AuthGroup,
746                               FALSE);
747
748             pObjectInfo = pDirEntry->ObjectInformation;
749
750             bUseFileInfo = FALSE;
751
752             ulAdditionalAttributes = 0;
753
754             if( pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK)
755             {
756
757                 //
758                 // Go grab the file information for this entry
759                 // No worries on failures since we will just display
760                 // pseudo information
761                 //
762
763                 RtlZeroMemory( &stFileInfo,
764                                sizeof( AFSFileInfoCB));
765
766                 if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
767                                                            pDirEntry,
768                                                            &pCcb->FullFileName,
769                                                            pCcb->NameArray,
770                                                            &pCcb->AuthGroup,
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                 lCount = 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                     lCount = 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                 lCount = InterlockedDecrement( &pDirEntry->OpenReferenceCount);
960
961                 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
962             }
963
964             lCount = 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     LONG lCount;
1110
1111     __Enter
1112     {
1113
1114         AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1115                           TRUE);
1116
1117         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1118                         TRUE);
1119
1120         //
1121         // Is this a PIOCtl query
1122         //
1123
1124         if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1125         {
1126
1127             if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1128                 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1129             {
1130
1131                 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1132
1133                 if( pDirEntry != NULL)
1134                 {
1135
1136                     lCount = InterlockedIncrement( &pDirEntry->OpenReferenceCount);
1137                 }
1138
1139                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1140                               AFS_TRACE_LEVEL_VERBOSE,
1141                               "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1142                               &pDirEntry->NameInformation.FileName,
1143                               ObjectInfo->FileId.Cell,
1144                               ObjectInfo->FileId.Volume,
1145                               ObjectInfo->FileId.Vnode,
1146                               ObjectInfo->FileId.Unique);
1147             }
1148
1149             Ccb->CurrentDirIndex++;
1150
1151             try_return( ntStatus);
1152         }
1153
1154         Ccb->CurrentDirIndex++;
1155
1156         if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1157         {
1158
1159             //
1160             // Return the .. entry
1161             //
1162
1163             pDirEntry = AFSGlobalDotDirEntry;
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 Returning1 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 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1181         {
1182
1183             //
1184             // Return the .. entry
1185             //
1186
1187             pDirEntry = AFSGlobalDotDotDirEntry;
1188
1189             if( pDirEntry != NULL)
1190             {
1191
1192                 lCount = InterlockedIncrement( &pDirEntry->OpenReferenceCount);
1193             }
1194
1195             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1196                           AFS_TRACE_LEVEL_VERBOSE,
1197                           "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1198                           &pDirEntry->NameInformation.FileName,
1199                           ObjectInfo->FileId.Cell,
1200                           ObjectInfo->FileId.Volume,
1201                           ObjectInfo->FileId.Vnode,
1202                           ObjectInfo->FileId.Unique);
1203         }
1204         else
1205         {
1206
1207             pSnapshotHdr = Ccb->DirectorySnapshot;
1208
1209             if( pSnapshotHdr == NULL ||
1210                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1211             {
1212
1213                 try_return( ntStatus);
1214             }
1215
1216             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1217
1218             ulCount = Ccb->CurrentDirIndex;
1219
1220             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1221                           AFS_TRACE_LEVEL_VERBOSE,
1222                           "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1223                           ulCount);
1224
1225             //
1226             // Get to a valid entry
1227             //
1228
1229             while( ulCount < pSnapshotHdr->EntryCount)
1230             {
1231
1232                 pDirEntry = NULL;
1233
1234                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1235                               AFS_TRACE_LEVEL_VERBOSE,
1236                               "AFSLocateNextDirEntry Searching for hash %08lX\n",
1237                               pSnapshotEntry->NameHash);
1238
1239                 if( pSnapshotEntry->NameHash == 0)
1240                 {
1241
1242                     break;
1243                 }
1244
1245                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1246                                                            pSnapshotEntry->NameHash,
1247                                                            &pDirEntry);
1248
1249                 if( !NT_SUCCESS( ntStatus) ||
1250                     pDirEntry != NULL)
1251                 {
1252
1253                     if( pDirEntry != NULL)
1254                     {
1255
1256                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1257                                       AFS_TRACE_LEVEL_VERBOSE,
1258                                       "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1259                                       &pDirEntry->NameInformation.FileName,
1260                                       (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1261                                       ObjectInfo->FileId.Cell,
1262                                       ObjectInfo->FileId.Volume,
1263                                       ObjectInfo->FileId.Vnode,
1264                                       ObjectInfo->FileId.Unique);
1265
1266                         lCount = InterlockedIncrement( &pDirEntry->OpenReferenceCount);
1267                     }
1268                     else
1269                     {
1270
1271
1272                         AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1273                                       AFS_TRACE_LEVEL_VERBOSE,
1274                                       "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1275                                       ObjectInfo->FileId.Cell,
1276                                       ObjectInfo->FileId.Volume,
1277                                       ObjectInfo->FileId.Vnode,
1278                                       ObjectInfo->FileId.Unique);
1279                     }
1280
1281                     break;
1282                 }
1283
1284                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1285                               AFS_TRACE_LEVEL_VERBOSE,
1286                               "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1287                               pSnapshotEntry->NameHash,
1288                               ObjectInfo->FileId.Cell,
1289                               ObjectInfo->FileId.Volume,
1290                               ObjectInfo->FileId.Vnode,
1291                               ObjectInfo->FileId.Unique);
1292
1293                 pSnapshotEntry++;
1294
1295                 ulCount++;
1296
1297                 Ccb->CurrentDirIndex++;
1298             }
1299         }
1300
1301 try_exit:
1302
1303         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1304
1305         AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1306     }
1307
1308     return pDirEntry;
1309 }
1310
1311 AFSDirectoryCB *
1312 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1313                           IN AFSCcb *Ccb,
1314                           IN ULONG DirIndex)
1315 {
1316
1317     AFSDirectoryCB *pDirEntry = NULL;
1318     NTSTATUS ntStatus = STATUS_SUCCESS;
1319     AFSSnapshotHdr *pSnapshotHdr = NULL;
1320     AFSSnapshotEntry *pSnapshotEntry = NULL;
1321     ULONG ulCount = 0;
1322
1323     __Enter
1324     {
1325
1326         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1327                         TRUE);
1328
1329         Ccb->CurrentDirIndex = DirIndex;
1330
1331         if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1332         {
1333
1334             //
1335             // Return the .. entry
1336             //
1337
1338             pDirEntry = AFSGlobalDotDirEntry;
1339         }
1340         else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1341         {
1342
1343             //
1344             // Return the .. entry
1345             //
1346
1347             pDirEntry = AFSGlobalDotDotDirEntry;
1348         }
1349         else
1350         {
1351
1352             pSnapshotHdr = Ccb->DirectorySnapshot;
1353
1354             if( pSnapshotHdr == NULL ||
1355                 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1356             {
1357
1358                 try_return( ntStatus);
1359             }
1360
1361             pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1362
1363             ulCount = Ccb->CurrentDirIndex;
1364
1365             //
1366             // Get to a valid entry
1367             //
1368
1369             while( ulCount < pSnapshotHdr->EntryCount)
1370             {
1371
1372                 pDirEntry = NULL;
1373
1374                 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1375                                                            pSnapshotEntry->NameHash,
1376                                                            &pDirEntry);
1377
1378                 if( !NT_SUCCESS( ntStatus) ||
1379                     ( pDirEntry != NULL &&
1380                       pDirEntry->FileIndex == DirIndex))
1381                 {
1382
1383                     break;
1384                 }
1385
1386                 pSnapshotEntry++;
1387
1388                 ulCount++;
1389             }
1390
1391             if( pDirEntry != NULL)
1392             {
1393
1394                 Ccb->CurrentDirIndex = ulCount;
1395             }
1396         }
1397
1398 try_exit:
1399
1400         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1401     }
1402
1403     return pDirEntry;
1404 }
1405
1406 NTSTATUS
1407 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1408                       IN AFSCcb *Ccb,
1409                       IN BOOLEAN ResetIndex)
1410 {
1411
1412     NTSTATUS ntStatus = STATUS_SUCCESS;
1413     AFSSnapshotHdr *pSnapshotHdr = NULL;
1414     AFSSnapshotEntry *pSnapshotEntry = NULL;
1415     AFSDirectoryCB *pDirEntry = NULL;
1416
1417     __Enter
1418     {
1419
1420         if( ResetIndex)
1421         {
1422
1423             //
1424             // Set it up so we still get the . and .. entries for empty directories
1425             //
1426
1427             if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1428             {
1429
1430                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1431             }
1432             else
1433             {
1434
1435                 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1436             }
1437         }
1438
1439         if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1440         {
1441
1442             //
1443             // If we have a snapshot then clear it out
1444             //
1445
1446             if( Ccb->DirectorySnapshot != NULL)
1447             {
1448
1449                 AFSExFreePool( Ccb->DirectorySnapshot);
1450
1451                 Ccb->DirectorySnapshot = NULL;
1452             }
1453
1454             try_return( ntStatus);
1455         }
1456
1457         //
1458         // Allocate our snapshot buffer for this enumeration
1459         //
1460
1461         pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1462                                                                    sizeof( AFSSnapshotHdr) +
1463                                                                         ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1464                                                                                 sizeof( AFSSnapshotEntry)),
1465                                                                    AFS_DIR_SNAPSHOT_TAG);
1466
1467         if( pSnapshotHdr == NULL)
1468         {
1469
1470             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1471         }
1472
1473         RtlZeroMemory( pSnapshotHdr,
1474                        sizeof( AFSSnapshotHdr) +
1475                             ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1476                                     sizeof( AFSSnapshotEntry)));
1477
1478         pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1479
1480         pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1481
1482         //
1483         // Populate our snapshot
1484         //
1485
1486         pSnapshotEntry = pSnapshotHdr->TopEntry;
1487
1488         pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1489
1490         while( pDirEntry != NULL)
1491         {
1492
1493             if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1494                 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1495                 !AFSIsNameInSnapshot( pSnapshotHdr,
1496                                       (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1497             {
1498
1499                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1500                               AFS_TRACE_LEVEL_VERBOSE,
1501                               "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1502                               pSnapshotHdr->EntryCount,
1503                               &pDirEntry->NameInformation.FileName,
1504                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1505                               pDirEntry->Flags,
1506                               Fcb->ObjectInformation->FileId.Cell,
1507                               Fcb->ObjectInformation->FileId.Volume,
1508                               Fcb->ObjectInformation->FileId.Vnode,
1509                               Fcb->ObjectInformation->FileId.Unique);
1510
1511                 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1512
1513                 pSnapshotEntry++;
1514             }
1515             else
1516             {
1517
1518                 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1519                               AFS_TRACE_LEVEL_VERBOSE,
1520                               "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1521                               pSnapshotHdr->EntryCount,
1522                               &pDirEntry->NameInformation.FileName,
1523                               (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1524                               pDirEntry->Flags,
1525                               Fcb->ObjectInformation->FileId.Cell,
1526                               Fcb->ObjectInformation->FileId.Volume,
1527                               Fcb->ObjectInformation->FileId.Vnode,
1528                               Fcb->ObjectInformation->FileId.Unique);
1529             }
1530
1531             pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1532         }
1533
1534         if( Ccb->DirectorySnapshot != NULL)
1535         {
1536
1537             AFSExFreePool( Ccb->DirectorySnapshot);
1538
1539             Ccb->DirectorySnapshot = NULL;
1540         }
1541
1542         Ccb->DirectorySnapshot = pSnapshotHdr;
1543
1544 try_exit:
1545
1546         NOTHING;
1547     }
1548
1549     return ntStatus;
1550 }
1551
1552 NTSTATUS
1553 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1554                                    IN AFSCcb *Ccb,
1555                                    IN BOOLEAN WatchTree,
1556                                    IN ULONG CompletionFilter,
1557                                    IN PIRP NotifyIrp)
1558 {
1559
1560     NTSTATUS ntStatus = STATUS_SUCCESS;
1561     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1562     size_t sztLength;
1563
1564     __Enter
1565     {
1566
1567         AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1568                         TRUE);
1569
1570         //
1571         // Build a dir name based on the FID of the file
1572         //
1573
1574         if( Ccb->NotifyMask.Buffer == NULL)
1575         {
1576
1577             Ccb->NotifyMask.Length = 0;
1578             Ccb->NotifyMask.MaximumLength = 1024;
1579
1580             Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1581                                                                         Ccb->NotifyMask.MaximumLength,
1582                                                                         AFS_GENERIC_MEMORY_7_TAG);
1583
1584             if( Ccb->NotifyMask.Buffer == NULL)
1585             {
1586
1587                 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1588             }
1589
1590             ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1591                                            Ccb->NotifyMask.MaximumLength,
1592                                            L"\\%08lX.%08lX.%08lX.%08lX",
1593                                            ObjectInfo->FileId.Cell,
1594                                            ObjectInfo->FileId.Volume,
1595                                            ObjectInfo->FileId.Vnode,
1596                                            ObjectInfo->FileId.Unique);
1597
1598             if( !NT_SUCCESS( ntStatus))
1599             {
1600
1601                 try_return( ntStatus);
1602             }
1603
1604             ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1605                                            (size_t)Ccb->NotifyMask.MaximumLength,
1606                                            &sztLength);
1607
1608             if( !NT_SUCCESS( ntStatus))
1609             {
1610
1611                 try_return( ntStatus);
1612             }
1613
1614             Ccb->NotifyMask.Length = (USHORT)sztLength;
1615         }
1616
1617         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1618                       AFS_TRACE_LEVEL_VERBOSE,
1619                       "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1620                       &Ccb->NotifyMask,
1621                       NotifyIrp,
1622                       CompletionFilter,
1623                       WatchTree);
1624
1625         FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1626                                         &pDeviceExt->Specific.Control.DirNotifyList,
1627                                         (void *)Ccb,
1628                                         (PSTRING)&Ccb->NotifyMask,
1629                                         WatchTree,
1630                                         TRUE,
1631                                         CompletionFilter,
1632                                         NotifyIrp,
1633                                         NULL,
1634                                         NULL,
1635                                         NULL);
1636
1637 try_exit:
1638
1639         if( !NT_SUCCESS( ntStatus))
1640         {
1641
1642             if( Ccb->NotifyMask.Buffer != NULL)
1643             {
1644
1645                 AFSExFreePool( Ccb->NotifyMask.Buffer);
1646
1647                 Ccb->NotifyMask.Buffer = NULL;
1648             }
1649         }
1650
1651         AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1652     }
1653
1654     return ntStatus;
1655 }
1656
1657 void
1658 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1659                                 IN AFSCcb *Ccb,
1660                                 IN ULONG NotifyFilter,
1661                                 IN ULONG NotificationAction)
1662 {
1663
1664     NTSTATUS ntStatus = STATUS_SUCCESS;
1665     AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1666     UNICODE_STRING uniName, uniComponentName;
1667     size_t sztLength;
1668     USHORT usNameOffset = 0;
1669
1670     __Enter
1671     {
1672
1673         uniName.Buffer = NULL;
1674
1675         if( ParentObjectInfo == NULL ||
1676             AFSGlobalRoot == NULL)
1677         {
1678
1679             try_return( ntStatus);
1680         }
1681
1682         if( Ccb == NULL)
1683         {
1684
1685             RtlInitUnicodeString( &uniComponentName,
1686                                   L"_AFSChange.dat");
1687         }
1688         else
1689         {
1690
1691             uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1692         }
1693
1694         //
1695         // Build a dir name based on the FID of the file
1696         //
1697
1698         uniName.Length = 0;
1699         uniName.MaximumLength = 1024 + uniComponentName.Length;
1700
1701         uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1702                                                             uniName.MaximumLength,
1703                                                             AFS_GENERIC_MEMORY_8_TAG);
1704
1705         if( uniName.Buffer == NULL)
1706         {
1707
1708             try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1709         }
1710
1711         ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1712                                        uniName.MaximumLength,
1713                                        L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1714                                        ParentObjectInfo->FileId.Cell,
1715                                        ParentObjectInfo->FileId.Volume,
1716                                        ParentObjectInfo->FileId.Vnode,
1717                                        ParentObjectInfo->FileId.Unique,
1718                                        &uniComponentName);
1719
1720         if( !NT_SUCCESS( ntStatus))
1721         {
1722
1723             try_return( ntStatus);
1724         }
1725
1726         ntStatus = RtlStringCbLengthW( uniName.Buffer,
1727                                        (size_t)uniName.MaximumLength,
1728                                        &sztLength);
1729
1730         if( !NT_SUCCESS( ntStatus))
1731         {
1732
1733             try_return( ntStatus);
1734         }
1735
1736         uniName.Length = (USHORT)sztLength;
1737
1738         usNameOffset = uniName.Length - uniComponentName.Length;
1739
1740         AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1741                       AFS_TRACE_LEVEL_VERBOSE,
1742                       "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1743                       &uniName,
1744                       NotifyFilter,
1745                       NotificationAction,
1746                       usNameOffset,
1747                       uniName.Length,
1748                       uniComponentName.Length);
1749
1750         FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1751                                        &pDeviceExt->Specific.Control.DirNotifyList,
1752                                        (PSTRING)&uniName,
1753                                        usNameOffset,
1754                                        NULL,
1755                                        NULL,
1756                                        NotifyFilter,
1757                                        NotificationAction,
1758                                        NULL,
1759                                        (void *)Ccb);
1760
1761 try_exit:
1762
1763         if( uniName.Buffer != NULL)
1764         {
1765
1766             AFSExFreePool( uniName.Buffer);
1767         }
1768     }
1769
1770     return;
1771 }
1772
1773 // For use with FsRtlNotifyFilterChangeDirectory but must
1774 // be implemented in the Framework because the library can
1775 // be unloaded.
1776
1777 BOOLEAN
1778 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1779                                IN void *FilterContext)
1780 {
1781
1782     BOOLEAN bReturn = TRUE;
1783     AFSCcb *pDirCcb = (AFSCcb *)NotifyContext;
1784     AFSCcb *pNotifyCcb = (AFSCcb *)FilterContext;
1785
1786     __Enter
1787     {
1788
1789     }
1790
1791     return bReturn;
1792 }
1793
1794 BOOLEAN
1795 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1796                      IN ULONG HashIndex)
1797 {
1798
1799     BOOLEAN bIsInSnapshot = FALSE;
1800     AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1801     ULONG ulCount = 0;
1802
1803     while( ulCount < SnapshotHdr->EntryCount)
1804     {
1805
1806         if( pSnapshotEntry->NameHash == HashIndex)
1807         {
1808
1809             bIsInSnapshot = TRUE;
1810
1811             AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1812                           AFS_TRACE_LEVEL_VERBOSE,
1813                           "AFSIsNameInSnapshot  Hash index %08lX already in snapshot\n",
1814                           HashIndex);
1815
1816             break;
1817         }
1818         else if( pSnapshotEntry->NameHash == 0)
1819         {
1820
1821             break;
1822         }
1823
1824         pSnapshotEntry++;
1825
1826         ulCount++;
1827     }
1828
1829     return bIsInSnapshot;
1830 }