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