2 * Copyright (c) 2008-2013 Kernel Drivers, LLC.
3 * Copyright (c) 2009-2013 Your File System, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
16 * nor the names of their contributors may be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission from Kernel Drivers, LLC and Your File System, Inc.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
24 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // File: AFSDirControl.cpp
37 #include "AFSCommon.h"
40 // Function: AFSDirControl
44 // This function is the IRP_MJ_DIRECTORY_CONTROL dispatch handler
48 // A status is returned for the handling of this request
52 AFSDirControl( IN PDEVICE_OBJECT LibDeviceObject,
55 UNREFERENCED_PARAMETER(LibDeviceObject);
56 NTSTATUS ntStatus = STATUS_SUCCESS;
57 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
62 switch( pIrpSp->MinorFunction )
65 case IRP_MN_QUERY_DIRECTORY:
68 ntStatus = AFSQueryDirectory( Irp);
73 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
76 ntStatus = AFSNotifyChangeDirectory( Irp);
83 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
88 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
93 "EXCEPTION - AFSDirControl\n");
95 AFSDumpTraceFilesFnc();
98 if( ntStatus != STATUS_PENDING)
101 AFSCompleteRequest( Irp,
109 AFSQueryDirectory( IN PIRP Irp)
112 NTSTATUS ntStatus = STATUS_SUCCESS;
113 NTSTATUS dStatus = STATUS_SUCCESS;
114 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
115 PIO_STACK_LOCATION pIrpSp;
118 BOOLEAN bInitialQuery = FALSE;
120 ULONG ulUserBufferLength;
121 PUNICODE_STRING puniArgFileName = NULL;
122 UNICODE_STRING uniTmpMaskName;
123 WCHAR wchMaskBuffer[ 4];
124 FILE_INFORMATION_CLASS FileInformationClass;
126 BOOLEAN bRestartScan;
127 BOOLEAN bReturnSingleEntry;
128 BOOLEAN bIndexSpecified;
129 ULONG ulNextEntry = 0;
130 ULONG ulLastEntry = 0;
131 PFILE_DIRECTORY_INFORMATION pDirInfo;
132 PFILE_FULL_DIR_INFORMATION pFullDirInfo;
133 PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
134 PFILE_NAMES_INFORMATION pNamesInfo;
136 ULONG ulBytesConverted;
137 AFSDirectoryCB *pDirEntry = NULL;
138 BOOLEAN bReleaseMain = FALSE;
139 BOOLEAN bReleaseFcb = FALSE;
140 AFSFileInfoCB stFileInfo;
141 AFSObjectInfoCB *pObjectInfo = NULL;
142 ULONG ulAdditionalAttributes = 0;
144 BOOLEAN bNonWildcardMatch = FALSE;
149 // Get the current Stack location
150 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
152 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
153 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
158 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
159 AFS_TRACE_LEVEL_ERROR,
160 "AFSQueryDirectory Attempted access (%p) when pFcb == NULL\n",
163 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
166 if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
167 pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
168 pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
171 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
172 AFS_TRACE_LEVEL_ERROR,
173 "AFSQueryDirectory Attempted access (%p) to non-directory Fcb %p NodeType %u\n",
176 pFcb->Header.NodeTypeCode);
180 try_return( ntStatus = STATUS_INVALID_PARAMETER);
184 // Set the enumeration event ...
187 AFSSetEnumerationEvent( pFcb);
189 // Reference our input parameters to make things easier
190 ulUserBufferLength = pIrpSp->Parameters.QueryDirectory.Length;
192 FileInformationClass = pIrpSp->Parameters.QueryDirectory.FileInformationClass;
193 ulFileIndex = pIrpSp->Parameters.QueryDirectory.FileIndex;
195 puniArgFileName = (PUNICODE_STRING)pIrpSp->Parameters.QueryDirectory.FileName;
197 bRestartScan = BooleanFlagOn( pIrpSp->Flags, SL_RESTART_SCAN);
198 bReturnSingleEntry = BooleanFlagOn( pIrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
199 bIndexSpecified = BooleanFlagOn( pIrpSp->Flags, SL_INDEX_SPECIFIED);
201 bInitialQuery = (BOOLEAN)( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED));
204 // Check if we previously processed a direct query
208 BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_DIRECT_QUERY))
211 bInitialQuery = FALSE;
213 else if( bRestartScan)
216 // Clear our direct to service flag so we reprocess things correctly.
219 ClearFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_DIRECT_QUERY);
221 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
222 AFS_TRACE_LEVEL_VERBOSE,
223 "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ Restart Query\n",
224 &pCcb->DirectoryCB->NameInformation.FileName,
227 if( pCcb->MaskName.Length > 0 &&
228 !FsRtlDoesNameContainWildCards( &pCcb->MaskName))
231 if( RtlCompareUnicodeString( &AFSPIOCtlName,
235 bNonWildcardMatch = TRUE;
241 // Setup the query mask
247 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
248 AFS_TRACE_LEVEL_VERBOSE,
249 "AFSQueryDirectory Enumerating content for parent %wZ Initial Query\n",
250 &pCcb->DirectoryCB->NameInformation.FileName);
252 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
253 AFS_TRACE_LEVEL_VERBOSE,
254 "AFSQueryDirectory Acquiring Dcb lock %p EXCL %08lX\n",
255 &pFcb->NPFcb->Resource,
256 PsGetCurrentThread());
258 AFSAcquireExcl( &pFcb->NPFcb->Resource,
264 // Determine the type of mask passed in for later processing
267 ClearFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
269 // build mask if none
270 if( puniArgFileName == NULL)
272 puniArgFileName = &uniTmpMaskName;
273 puniArgFileName->Length = 0;
274 puniArgFileName->Buffer = NULL;
277 if( puniArgFileName->Length == 0)
280 puniArgFileName->Length = sizeof(WCHAR);
281 puniArgFileName->MaximumLength = (USHORT)4;
284 if( puniArgFileName->Buffer == NULL)
287 puniArgFileName->Buffer = wchMaskBuffer;
289 RtlZeroMemory( wchMaskBuffer,
292 RtlCopyMemory( &puniArgFileName->Buffer[ 0],
297 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
298 ( puniArgFileName->Buffer[0] == L'*')))
301 SetFlag( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY);
306 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
307 ( puniArgFileName->Buffer[0] == L'<')) ||
308 (( puniArgFileName->Length == 2*sizeof(WCHAR)) &&
309 ( RtlEqualMemory( puniArgFileName->Buffer, L"*.", 2*sizeof(WCHAR) ))))
312 SetFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
316 // Build the name for procesisng
319 pCcb->MaskName.Length = puniArgFileName->Length;
320 pCcb->MaskName.MaximumLength = pCcb->MaskName.Length;
322 pCcb->MaskName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
323 pCcb->MaskName.Length,
324 AFS_GENERIC_MEMORY_6_TAG);
326 if( pCcb->MaskName.Buffer == NULL)
329 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
332 if( FsRtlDoesNameContainWildCards( puniArgFileName))
335 RtlUpcaseUnicodeString( &pCcb->MaskName,
339 SetFlag( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS);
341 if( FsRtlIsNameInExpression( &pCcb->MaskName,
346 SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
352 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
353 AFS_TRACE_LEVEL_VERBOSE,
354 "AFSQueryDirectory FsRtlDoesNameContainWildCards == FALSE parent %wZ Mask %wZ\n",
355 &pCcb->DirectoryCB->NameInformation.FileName,
358 RtlCopyMemory( pCcb->MaskName.Buffer,
359 puniArgFileName->Buffer,
360 pCcb->MaskName.Length);
362 if( RtlCompareUnicodeString( &AFSPIOCtlName,
366 SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
370 bNonWildcardMatch = TRUE;
378 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
379 AFS_TRACE_LEVEL_VERBOSE,
380 "AFSQueryDirectory Enumerating content for parent %wZ Subsequent\n",
381 &pCcb->DirectoryCB->NameInformation.FileName);
383 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
384 AFS_TRACE_LEVEL_VERBOSE,
385 "AFSQueryDirectory Acquiring Dcb lock %p SHARED %08lX\n",
386 &pFcb->NPFcb->Resource,
387 PsGetCurrentThread());
389 AFSAcquireShared( &pFcb->NPFcb->Resource,
395 // Have we already processed this entry directly from the service?
398 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_DIRECT_QUERY))
400 try_return( ntStatus = STATUS_NO_MORE_FILES);
405 // Grab the directory node hdr tree lock while parsing the directory
409 AFSAcquireExcl( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
415 // Before attempting to insert the new entry, check if we need to enumerate or validate the parent
418 if( !BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED))
422 // If this is a non wildcard match then just process it directly from the service since the directory
423 // is not yet enumerated
426 if( bNonWildcardMatch)
429 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
430 AFS_TRACE_LEVEL_VERBOSE,
431 "AFSQueryDirectory Processing non-wildcard match directly parent %wZ Mask %wZ FID %08lX-%08lX-%08lX-%08lX\n",
432 &pCcb->DirectoryCB->NameInformation.FileName,
434 pFcb->ObjectInformation->FileId.Cell,
435 pFcb->ObjectInformation->FileId.Volume,
436 pFcb->ObjectInformation->FileId.Vnode,
437 pFcb->ObjectInformation->FileId.Unique);
439 ntStatus = AFSProcessDirectoryQueryDirect( pFcb,
443 SetFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_DIRECT_QUERY);
445 try_return( ntStatus);
448 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
449 AFS_TRACE_LEVEL_VERBOSE,
450 "AFSQueryDirectory Enumerating parent %wZ FID %08lX-%08lX-%08lX-%08lX\n",
451 &pCcb->DirectoryCB->NameInformation.FileName,
452 pFcb->ObjectInformation->FileId.Cell,
453 pFcb->ObjectInformation->FileId.Volume,
454 pFcb->ObjectInformation->FileId.Vnode,
455 pFcb->ObjectInformation->FileId.Unique);
457 ntStatus = AFSEnumerateDirectory( &pCcb->AuthGroup,
458 pFcb->ObjectInformation,
461 if( !NT_SUCCESS( ntStatus))
464 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
465 AFS_TRACE_LEVEL_ERROR,
466 "AFSQueryDirectory Failed to enumerate parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
467 &pCcb->DirectoryCB->NameInformation.FileName,
468 pFcb->ObjectInformation->FileId.Cell,
469 pFcb->ObjectInformation->FileId.Volume,
470 pFcb->ObjectInformation->FileId.Vnode,
471 pFcb->ObjectInformation->FileId.Unique,
474 try_return( ntStatus);
477 else if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
480 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
481 AFS_TRACE_LEVEL_VERBOSE,
482 "AFSQueryDirectory Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n",
483 &pCcb->DirectoryCB->NameInformation.FileName,
484 pFcb->ObjectInformation->FileId.Cell,
485 pFcb->ObjectInformation->FileId.Volume,
486 pFcb->ObjectInformation->FileId.Vnode,
487 pFcb->ObjectInformation->FileId.Unique);
489 ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
492 if( !NT_SUCCESS( ntStatus))
495 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
496 AFS_TRACE_LEVEL_ERROR,
497 "AFSQueryDirectory Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
498 &pCcb->DirectoryCB->NameInformation.FileName,
499 pFcb->ObjectInformation->FileId.Cell,
500 pFcb->ObjectInformation->FileId.Volume,
501 pFcb->ObjectInformation->FileId.Vnode,
502 pFcb->ObjectInformation->FileId.Unique,
505 try_return( ntStatus);
509 // Perform a new snapshot of the directory
512 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
515 ntStatus = AFSSnapshotDirectory( pFcb,
519 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
521 if( !NT_SUCCESS( ntStatus))
524 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
525 AFS_TRACE_LEVEL_ERROR,
526 "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
527 &pCcb->DirectoryCB->NameInformation.FileName,
531 try_return( ntStatus);
535 AFSConvertToShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
538 // We can now safely drop the lock on the node
541 AFSReleaseResource( &pFcb->NPFcb->Resource);
546 // Start processing the data
549 pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
555 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
558 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
561 // Check if initial on this map
565 ntStatus = AFSSnapshotDirectory( pFcb,
569 if( !NT_SUCCESS( ntStatus))
572 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
574 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
575 AFS_TRACE_LEVEL_ERROR,
576 "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
577 &pCcb->DirectoryCB->NameInformation.FileName,
581 try_return( ntStatus);
584 SetFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED);
586 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
588 if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
591 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
593 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
595 bReleaseMain = FALSE;
597 AFSAcquireExcl( &pFcb->NPFcb->Resource,
600 if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
603 ntStatus = AFSInitPIOCtlDirectoryCB( pFcb->ObjectInformation);
605 if( !NT_SUCCESS( ntStatus))
608 AFSReleaseResource( &pFcb->NPFcb->Resource);
610 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
611 AFS_TRACE_LEVEL_ERROR,
612 "AFSQueryDirectory Init PIOCtl directory failure for parent %wZ Mask %wZ Status %08lX\n",
613 &pCcb->DirectoryCB->NameInformation.FileName,
617 try_return( ntStatus);
621 AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
626 AFSReleaseResource( &pFcb->NPFcb->Resource);
628 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
633 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
634 AFS_TRACE_LEVEL_VERBOSE,
635 "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ\n",
636 &pCcb->DirectoryCB->NameInformation.FileName,
640 // Check if we need to start from index
645 // Need to set up the initial point for the query
648 pCcb->CurrentDirIndex = ulFileIndex - 1;
651 // Check if we need to restart the scan
652 else if( bRestartScan)
656 // Reset the current scan processing
659 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
662 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
667 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
671 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
673 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
675 bReleaseMain = FALSE;
677 switch( FileInformationClass)
680 case FileDirectoryInformation:
682 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
686 case FileFullDirectoryInformation:
688 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
692 case FileNamesInformation:
694 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
698 case FileBothDirectoryInformation:
700 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
704 case FileIdBothDirectoryInformation:
706 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
711 case FileIdFullDirectoryInformation:
713 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
720 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
721 AFS_TRACE_LEVEL_ERROR,
722 "AFSQueryDirectory (%p) Unknown FileInformationClass %u\n",
724 FileInformationClass);
726 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
732 ULONG ulBytesRemainingInBuffer;
735 // Drop the DirOpenReferenceCount held during a prior
736 // execution of the loop
739 if ( pDirEntry != NULL)
742 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
744 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
745 AFS_TRACE_LEVEL_VERBOSE,
746 "AFSQueryDirectory Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
747 &pDirEntry->NameInformation.FileName,
752 ASSERT( lCount >= 0);
757 ulAdditionalAttributes = 0;
760 // If the user had requested only a single match and we have
761 // returned that, then we stop at this point.
764 if( bReturnSingleEntry && ulNextEntry != 0)
767 try_return( ntStatus);
771 // On Success, pDirEntry has a held DirOpenReferenceCount
774 pDirEntry = AFSLocateNextDirEntry( pFcb->ObjectInformation,
777 if( pDirEntry == NULL)
780 if( ulNextEntry == 0)
783 if( ( bInitialQuery ||
785 pCcb->MaskName.Buffer != NULL)
787 ntStatus = STATUS_NO_SUCH_FILE;
791 ntStatus = STATUS_NO_MORE_FILES;
795 try_return( ntStatus);
799 // Skip the entry if it is pending delete or deleted
802 else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) ||
803 BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED))
809 pObjectInfo = pDirEntry->ObjectInformation;
812 // Apply the name filter if there is one
815 if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY))
819 // Only returning directories?
822 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY))
825 if( !FlagOn( pObjectInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))
831 else if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
835 // Are we doing a wild card search?
838 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS))
841 if( !FsRtlIsNameInExpression( &pCcb->MaskName,
842 &pDirEntry->NameInformation.FileName,
853 if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
859 // See if this is a match for a case insensitive search
862 if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
875 // Be sure the information is valid
876 // We don't worry about entries while enumerating the directory
879 if ( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
882 ntStatus = AFSValidateEntry( pDirEntry,
886 if ( NT_SUCCESS( ntStatus))
889 ClearFlag( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
894 ntStatus = STATUS_SUCCESS;
898 pObjectInfo = pDirEntry->ObjectInformation;
900 // Here are the rules concerning filling up the buffer:
902 // 1. The Io system guarantees that there will always be
903 // enough room for at least one base record.
905 // 2. If the full first record (including file name) cannot
906 // fit, as much of the name as possible is copied and
907 // STATUS_BUFFER_OVERFLOW is returned.
909 // 3. If a subsequent record cannot completely fit into the
910 // buffer, none of it (as in 0 bytes) is copied, and
911 // STATUS_SUCCESS is returned. A subsequent query will
912 // pick up with this record.
914 ulBytesRemainingInBuffer = ulUserBufferLength - ulNextEntry;
916 if( ( ulNextEntry != 0) &&
917 ( ( ulBaseLength + pDirEntry->NameInformation.FileName.Length > ulBytesRemainingInBuffer) ||
918 ( ulUserBufferLength < ulNextEntry) ) )
922 // Back off our current index
925 pCcb->CurrentDirIndex--;
927 try_return( ntStatus = STATUS_SUCCESS);
932 // For Symlinks and Mount Points the reparse point attribute
933 // must be associated with the directory entry. In addition,
934 // for Symlinks it must be determined if the target object is
935 // a directory or not. If so, the directory attribute must be
936 // specified. Mount points always refer to directories and
937 // must have the directory attribute set.
940 switch( pObjectInfo->FileType)
943 case AFS_FILE_TYPE_MOUNTPOINT:
944 case AFS_FILE_TYPE_DFSLINK:
947 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
952 case AFS_FILE_TYPE_SYMLINK:
956 // Go grab the file information for this entry
957 // No worries on failures since we will just display
958 // pseudo information
961 RtlZeroMemory( &stFileInfo,
962 sizeof( AFSFileInfoCB));
964 if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
972 if ( stFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
975 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY;
979 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
986 // Check if the name begins with a . and we are hiding them
989 if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
990 pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
991 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
994 ulAdditionalAttributes |= FILE_ATTRIBUTE_HIDDEN;
998 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
999 AFS_TRACE_LEVEL_VERBOSE,
1000 "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n",
1001 &pCcb->DirectoryCB->NameInformation.FileName,
1002 &pDirEntry->NameInformation.FileName);
1004 // Zero the base part of the structure.
1005 RtlZeroMemory( &pBuffer[ ulNextEntry],
1008 switch( FileInformationClass)
1011 // Now fill the base parts of the structure that are applicable.
1012 case FileIdBothDirectoryInformation:
1013 case FileBothDirectoryInformation:
1015 pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry];
1017 pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength;
1019 if( pDirEntry->NameInformation.ShortNameLength > 0)
1021 RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
1022 &pDirEntry->NameInformation.ShortName[ 0],
1023 pBothDirInfo->ShortNameLength);
1026 case FileIdFullDirectoryInformation:
1027 case FileFullDirectoryInformation:
1029 pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
1030 pFullDirInfo->EaSize = 0;
1032 case FileDirectoryInformation:
1034 pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
1036 if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
1039 pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
1040 pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
1041 pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
1042 pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
1044 pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
1045 pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
1047 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1049 pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
1053 pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
1059 pDirInfo->CreationTime = pObjectInfo->CreationTime;
1060 pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
1061 pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
1062 pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
1064 pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
1065 pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
1067 if ( ulAdditionalAttributes && pObjectInfo->FileAttributes == FILE_ATTRIBUTE_NORMAL)
1070 pDirInfo->FileAttributes = ulAdditionalAttributes;
1075 pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
1079 pDirInfo->FileIndex = pDirEntry->FileIndex;
1080 pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
1085 case FileNamesInformation:
1087 pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
1088 pNamesInfo->FileIndex = pDirEntry->FileIndex;
1089 pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
1096 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1097 AFS_TRACE_LEVEL_ERROR,
1098 "AFSQueryDirectory (%p) Unknown FileInformationClass %u\n",
1100 FileInformationClass);
1102 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
1106 ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
1107 pDirEntry->NameInformation.FileName.Length :
1108 ulBytesRemainingInBuffer - ulBaseLength;
1110 RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
1111 pDirEntry->NameInformation.FileName.Buffer,
1114 // Set up the previous next entry offset
1115 *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
1117 // And indicate how much of the user buffer we have currently
1119 Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
1121 // Check for the case that a single entry doesn't fit.
1122 // This should only get this far on the first entry.
1123 if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
1126 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
1129 dStatus = STATUS_SUCCESS;
1131 // Set ourselves up for the next iteration
1132 ulLastEntry = ulNextEntry;
1133 ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
1138 if ( pDirEntry != NULL)
1141 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1143 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1144 AFS_TRACE_LEVEL_VERBOSE,
1145 "AFSQueryDirectory Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n",
1146 &pDirEntry->NameInformation.FileName,
1151 ASSERT( lCount >= 0);
1157 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1163 AFSReleaseResource( &pFcb->NPFcb->Resource);
1169 AFSClearEnumerationEvent( pFcb);
1177 AFSNotifyChangeDirectory( IN PIRP Irp)
1180 NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1181 PIO_STACK_LOCATION pIrpSp;
1182 AFSFcb *pFcb = NULL;
1183 AFSCcb *pCcb = NULL;
1184 ULONG ulCompletionFilter;
1186 BOOLEAN bReleaseLock = FALSE;
1191 // Get the current Stack location
1192 pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1194 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1195 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1200 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1201 AFS_TRACE_LEVEL_ERROR,
1202 "AFSNotifyChangeDirectory Attempted access (%p) when pFcb == NULL\n",
1205 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1208 if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1209 pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1210 pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1213 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1214 AFS_TRACE_LEVEL_ERROR,
1215 "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1216 &pCcb->DirectoryCB->NameInformation.FileName,
1217 pFcb->Header.NodeTypeCode);
1219 try_return( ntStatus = STATUS_INVALID_PARAMETER);
1222 // Reference our input parameter to make things easier
1223 ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1224 bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1226 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1227 AFS_TRACE_LEVEL_VERBOSE,
1228 "AFSNotifyChangeDirectory Acquiring Dcb lock %p EXCL %08lX\n",
1229 &pFcb->NPFcb->Resource,
1230 PsGetCurrentThread());
1232 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1235 bReleaseLock = TRUE;
1238 // Check if the node has already been deleted
1241 if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1244 try_return( ntStatus = STATUS_FILE_DELETED);
1246 else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1249 try_return( ntStatus = STATUS_DELETE_PENDING);
1252 // Call the Fsrtl package to process the request.
1253 ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1259 if( !NT_SUCCESS( ntStatus))
1261 try_return( ntStatus);
1264 ntStatus = STATUS_PENDING;
1271 AFSReleaseResource( &pFcb->NPFcb->Resource);
1279 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1283 AFSDirectoryCB *pDirEntry = NULL;
1284 NTSTATUS ntStatus = STATUS_SUCCESS;
1285 AFSSnapshotHdr *pSnapshotHdr = NULL;
1286 AFSSnapshotEntry *pSnapshotEntry = NULL;
1293 AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1296 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1300 // Is this a PIOCtl query
1303 if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1306 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1307 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1310 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1312 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1313 AFS_TRACE_LEVEL_VERBOSE,
1314 "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1315 &pDirEntry->NameInformation.FileName,
1316 ObjectInfo->FileId.Cell,
1317 ObjectInfo->FileId.Volume,
1318 ObjectInfo->FileId.Vnode,
1319 ObjectInfo->FileId.Unique);
1322 Ccb->CurrentDirIndex++;
1324 try_return( ntStatus);
1327 Ccb->CurrentDirIndex++;
1329 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1333 // Return the .. entry
1336 pDirEntry = AFSGlobalDotDirEntry;
1338 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1339 AFS_TRACE_LEVEL_VERBOSE,
1340 "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1341 &pDirEntry->NameInformation.FileName,
1342 ObjectInfo->FileId.Cell,
1343 ObjectInfo->FileId.Volume,
1344 ObjectInfo->FileId.Vnode,
1345 ObjectInfo->FileId.Unique);
1347 else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1351 // Return the .. entry
1354 pDirEntry = AFSGlobalDotDotDirEntry;
1356 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1357 AFS_TRACE_LEVEL_VERBOSE,
1358 "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1359 &pDirEntry->NameInformation.FileName,
1360 ObjectInfo->FileId.Cell,
1361 ObjectInfo->FileId.Volume,
1362 ObjectInfo->FileId.Vnode,
1363 ObjectInfo->FileId.Unique);
1368 pSnapshotHdr = Ccb->DirectorySnapshot;
1370 if( pSnapshotHdr == NULL ||
1371 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1374 try_return( ntStatus);
1377 pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1379 ulCount = Ccb->CurrentDirIndex;
1381 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1382 AFS_TRACE_LEVEL_VERBOSE,
1383 "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1387 // Get to a valid entry
1390 while( ulCount < pSnapshotHdr->EntryCount)
1395 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1396 AFS_TRACE_LEVEL_VERBOSE,
1397 "AFSLocateNextDirEntry Searching for hash %08lX\n",
1398 pSnapshotEntry->NameHash);
1400 if( pSnapshotEntry->NameHash == 0)
1406 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1407 pSnapshotEntry->NameHash,
1410 if( !NT_SUCCESS( ntStatus) ||
1414 if( pDirEntry != NULL)
1417 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1418 AFS_TRACE_LEVEL_VERBOSE,
1419 "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1420 &pDirEntry->NameInformation.FileName,
1421 (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1422 ObjectInfo->FileId.Cell,
1423 ObjectInfo->FileId.Volume,
1424 ObjectInfo->FileId.Vnode,
1425 ObjectInfo->FileId.Unique);
1431 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1432 AFS_TRACE_LEVEL_VERBOSE,
1433 "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1434 ObjectInfo->FileId.Cell,
1435 ObjectInfo->FileId.Volume,
1436 ObjectInfo->FileId.Vnode,
1437 ObjectInfo->FileId.Unique);
1443 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1444 AFS_TRACE_LEVEL_VERBOSE,
1445 "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1446 pSnapshotEntry->NameHash,
1447 ObjectInfo->FileId.Cell,
1448 ObjectInfo->FileId.Volume,
1449 ObjectInfo->FileId.Vnode,
1450 ObjectInfo->FileId.Unique);
1456 Ccb->CurrentDirIndex++;
1462 if( pDirEntry != NULL)
1465 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1467 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1468 AFS_TRACE_LEVEL_VERBOSE,
1469 "AFSLocateNextDirEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n",
1470 &pDirEntry->NameInformation.FileName,
1475 ASSERT( lCount >= 0);
1478 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1480 AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1487 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1492 AFSDirectoryCB *pDirEntry = NULL;
1493 NTSTATUS ntStatus = STATUS_SUCCESS;
1494 AFSSnapshotHdr *pSnapshotHdr = NULL;
1495 AFSSnapshotEntry *pSnapshotEntry = NULL;
1501 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1504 Ccb->CurrentDirIndex = DirIndex;
1506 if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1510 // Return the .. entry
1513 pDirEntry = AFSGlobalDotDirEntry;
1515 else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1519 // Return the .. entry
1522 pDirEntry = AFSGlobalDotDotDirEntry;
1527 pSnapshotHdr = Ccb->DirectorySnapshot;
1529 if( pSnapshotHdr == NULL ||
1530 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1533 try_return( ntStatus);
1536 pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1538 ulCount = Ccb->CurrentDirIndex;
1541 // Get to a valid entry
1544 while( ulCount < pSnapshotHdr->EntryCount)
1549 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1550 pSnapshotEntry->NameHash,
1553 if( !NT_SUCCESS( ntStatus) ||
1554 ( pDirEntry != NULL &&
1555 pDirEntry->FileIndex == DirIndex))
1566 if( pDirEntry != NULL)
1569 Ccb->CurrentDirIndex = ulCount;
1575 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1582 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1584 IN BOOLEAN ResetIndex)
1587 NTSTATUS ntStatus = STATUS_SUCCESS;
1588 AFSSnapshotHdr *pSnapshotHdr = NULL;
1589 AFSSnapshotEntry *pSnapshotEntry = NULL;
1590 AFSDirectoryCB *pDirEntry = NULL;
1599 // Set it up so we still get the . and .. entries for empty directories
1602 if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1605 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1610 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1614 if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1618 // If we have a snapshot then clear it out
1621 if( Ccb->DirectorySnapshot != NULL)
1624 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1626 Ccb->DirectorySnapshot = NULL;
1629 try_return( ntStatus);
1633 // Allocate our snapshot buffer for this enumeration
1636 pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1637 sizeof( AFSSnapshotHdr) +
1638 ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1639 sizeof( AFSSnapshotEntry)),
1640 AFS_DIR_SNAPSHOT_TAG);
1642 if( pSnapshotHdr == NULL)
1645 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1648 RtlZeroMemory( pSnapshotHdr,
1649 sizeof( AFSSnapshotHdr) +
1650 ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1651 sizeof( AFSSnapshotEntry)));
1653 pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1655 pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1658 // Populate our snapshot
1661 pSnapshotEntry = pSnapshotHdr->TopEntry;
1663 pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1665 while( pDirEntry != NULL)
1668 if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1669 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1670 !AFSIsNameInSnapshot( pSnapshotHdr,
1671 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1674 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1675 AFS_TRACE_LEVEL_VERBOSE,
1676 "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1677 pSnapshotHdr->EntryCount,
1678 &pDirEntry->NameInformation.FileName,
1679 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1681 Fcb->ObjectInformation->FileId.Cell,
1682 Fcb->ObjectInformation->FileId.Volume,
1683 Fcb->ObjectInformation->FileId.Vnode,
1684 Fcb->ObjectInformation->FileId.Unique);
1686 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1693 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1694 AFS_TRACE_LEVEL_VERBOSE,
1695 "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1696 pSnapshotHdr->EntryCount,
1697 &pDirEntry->NameInformation.FileName,
1698 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1700 Fcb->ObjectInformation->FileId.Cell,
1701 Fcb->ObjectInformation->FileId.Volume,
1702 Fcb->ObjectInformation->FileId.Vnode,
1703 Fcb->ObjectInformation->FileId.Unique);
1706 pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1709 if( Ccb->DirectorySnapshot != NULL)
1712 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1714 Ccb->DirectorySnapshot = NULL;
1717 Ccb->DirectorySnapshot = pSnapshotHdr;
1728 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1730 IN BOOLEAN WatchTree,
1731 IN ULONG CompletionFilter,
1735 NTSTATUS ntStatus = STATUS_SUCCESS;
1736 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1742 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1746 // Build a dir name based on the FID of the file
1749 if( Ccb->NotifyMask.Buffer == NULL)
1752 Ccb->NotifyMask.Length = 0;
1753 Ccb->NotifyMask.MaximumLength = 1024;
1755 Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1756 Ccb->NotifyMask.MaximumLength,
1757 AFS_GENERIC_MEMORY_7_TAG);
1759 if( Ccb->NotifyMask.Buffer == NULL)
1762 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1765 ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1766 Ccb->NotifyMask.MaximumLength,
1767 L"\\%08lX.%08lX.%08lX.%08lX",
1768 ObjectInfo->FileId.Cell,
1769 ObjectInfo->FileId.Volume,
1770 ObjectInfo->FileId.Vnode,
1771 ObjectInfo->FileId.Unique);
1773 if( !NT_SUCCESS( ntStatus))
1776 try_return( ntStatus);
1779 ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1780 (size_t)Ccb->NotifyMask.MaximumLength,
1783 if( !NT_SUCCESS( ntStatus))
1786 try_return( ntStatus);
1789 Ccb->NotifyMask.Length = (USHORT)sztLength;
1792 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1793 AFS_TRACE_LEVEL_VERBOSE,
1794 "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %p Filter %08lX Tree %02lX\n",
1800 FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1801 &pDeviceExt->Specific.Control.DirNotifyList,
1803 (PSTRING)&Ccb->NotifyMask,
1814 if( !NT_SUCCESS( ntStatus))
1817 if( Ccb->NotifyMask.Buffer != NULL)
1820 AFSExFreePoolWithTag( Ccb->NotifyMask.Buffer, AFS_GENERIC_MEMORY_7_TAG);
1822 Ccb->NotifyMask.Buffer = NULL;
1826 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1833 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1835 IN ULONG NotifyFilter,
1836 IN ULONG NotificationAction)
1839 NTSTATUS ntStatus = STATUS_SUCCESS;
1840 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1841 UNICODE_STRING uniName, uniComponentName;
1843 USHORT usNameOffset = 0;
1848 uniName.Buffer = NULL;
1850 if( ParentObjectInfo == NULL ||
1851 AFSGlobalRoot == NULL)
1854 try_return( ntStatus);
1860 RtlInitUnicodeString( &uniComponentName,
1866 uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1870 // Build a dir name based on the FID of the file
1874 uniName.MaximumLength = 1024 + uniComponentName.Length;
1876 uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1877 uniName.MaximumLength,
1878 AFS_GENERIC_MEMORY_8_TAG);
1880 if( uniName.Buffer == NULL)
1883 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1886 ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1887 uniName.MaximumLength,
1888 L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1889 ParentObjectInfo->FileId.Cell,
1890 ParentObjectInfo->FileId.Volume,
1891 ParentObjectInfo->FileId.Vnode,
1892 ParentObjectInfo->FileId.Unique,
1895 if( !NT_SUCCESS( ntStatus))
1898 try_return( ntStatus);
1901 ntStatus = RtlStringCbLengthW( uniName.Buffer,
1902 (size_t)uniName.MaximumLength,
1905 if( !NT_SUCCESS( ntStatus))
1908 try_return( ntStatus);
1911 uniName.Length = (USHORT)sztLength;
1913 usNameOffset = uniName.Length - uniComponentName.Length;
1915 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1916 AFS_TRACE_LEVEL_VERBOSE,
1917 "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1923 uniComponentName.Length);
1925 FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1926 &pDeviceExt->Specific.Control.DirNotifyList,
1938 if( uniName.Buffer != NULL)
1941 AFSExFreePoolWithTag( uniName.Buffer, AFS_GENERIC_MEMORY_8_TAG);
1948 // For use with FsRtlNotifyFilterChangeDirectory but must
1949 // be implemented in the Framework because the library can
1953 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1954 IN void *FilterContext)
1956 UNREFERENCED_PARAMETER(NotifyContext);
1957 UNREFERENCED_PARAMETER(FilterContext);
1958 BOOLEAN bReturn = TRUE;
1969 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1973 BOOLEAN bIsInSnapshot = FALSE;
1974 AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1977 while( ulCount < SnapshotHdr->EntryCount)
1980 if( pSnapshotEntry->NameHash == HashIndex)
1983 bIsInSnapshot = TRUE;
1985 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1986 AFS_TRACE_LEVEL_VERBOSE,
1987 "AFSIsNameInSnapshot Hash index %08lX already in snapshot\n",
1992 else if( pSnapshotEntry->NameHash == 0)
2003 return bIsInSnapshot;
2007 AFSProcessDirectoryQueryDirect( IN AFSFcb *Fcb,
2012 NTSTATUS ntStatus = STATUS_SUCCESS;
2013 AFSDirEnumEntry *pDirEnum = NULL;
2014 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
2015 PUCHAR pBuffer = NULL;
2016 ULONG ulBaseLength = 0;
2017 ULONG ulAdditionalAttributes = 0;
2018 AFSFileInfoCB stFileInfo;
2019 ULONG ulBytesConverted = 0;
2020 PFILE_DIRECTORY_INFORMATION pDirInfo;
2021 PFILE_FULL_DIR_INFORMATION pFullDirInfo;
2022 PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
2023 PFILE_NAMES_INFORMATION pNamesInfo;
2029 // query the service for the entry
2032 ntStatus = AFSEvaluateTargetByName( &Ccb->AuthGroup,
2033 Fcb->ObjectInformation,
2035 AFS_REQUEST_FLAG_LAST_COMPONENT,
2038 if( !NT_SUCCESS( ntStatus))
2041 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2042 AFS_TRACE_LEVEL_ERROR,
2043 "AFSProcessDirectoryQueryDirect Failed to locate non-wildcard match directly parent %wZ Mask %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
2044 &Ccb->DirectoryCB->NameInformation.FileName,
2046 Fcb->ObjectInformation->FileId.Cell,
2047 Fcb->ObjectInformation->FileId.Volume,
2048 Fcb->ObjectInformation->FileId.Vnode,
2049 Fcb->ObjectInformation->FileId.Unique,
2052 try_return( ntStatus = STATUS_NO_SUCH_FILE);
2055 pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
2056 pIrpSp->Parameters.QueryDirectory.Length);
2058 if( pBuffer == NULL)
2061 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
2065 // Process the enum request
2068 switch( pIrpSp->Parameters.QueryDirectory.FileInformationClass)
2071 case FileDirectoryInformation:
2073 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
2077 case FileFullDirectoryInformation:
2079 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
2083 case FileNamesInformation:
2085 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
2089 case FileBothDirectoryInformation:
2091 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
2095 case FileIdBothDirectoryInformation:
2097 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
2102 case FileIdFullDirectoryInformation:
2104 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
2111 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2112 AFS_TRACE_LEVEL_ERROR,
2113 "AFSProcessDirectoryQueryDirect (%p) Unknown FileInformationClass %u\n",
2115 pIrpSp->Parameters.QueryDirectory.FileInformationClass);
2117 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
2120 switch( pDirEnum->FileType)
2123 case AFS_FILE_TYPE_MOUNTPOINT:
2124 case AFS_FILE_TYPE_DFSLINK:
2127 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
2132 case AFS_FILE_TYPE_SYMLINK:
2136 // Note: we need to evaluate this entry to determine if the target is a directory or not
2139 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
2145 // Zero the base part of the structure.
2146 RtlZeroMemory( pBuffer,
2149 switch( pIrpSp->Parameters.QueryDirectory.FileInformationClass)
2152 // Now fill the base parts of the structure that are applicable.
2153 case FileIdBothDirectoryInformation:
2154 case FileBothDirectoryInformation:
2156 pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)pBuffer;
2158 pBothDirInfo->ShortNameLength = (CHAR)pDirEnum->ShortNameLength;
2160 if( pDirEnum->ShortNameLength > 0)
2162 RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
2163 &pDirEnum->ShortName[ 0],
2164 pBothDirInfo->ShortNameLength);
2167 case FileIdFullDirectoryInformation:
2168 case FileFullDirectoryInformation:
2170 pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)pBuffer;
2171 pFullDirInfo->EaSize = 0;
2173 case FileDirectoryInformation:
2175 pDirInfo = (PFILE_DIRECTORY_INFORMATION)pBuffer;
2177 pDirInfo->CreationTime = pDirEnum->CreationTime;
2178 pDirInfo->LastWriteTime = pDirEnum->LastWriteTime;
2179 pDirInfo->LastAccessTime = pDirEnum->LastAccessTime;
2180 pDirInfo->ChangeTime = pDirEnum->ChangeTime;
2182 pDirInfo->EndOfFile = pDirEnum->EndOfFile;
2183 pDirInfo->AllocationSize = pDirEnum->AllocationSize;
2185 if ( ulAdditionalAttributes && pDirEnum->FileAttributes == FILE_ATTRIBUTE_NORMAL)
2187 pDirInfo->FileAttributes = ulAdditionalAttributes;
2191 pDirInfo->FileAttributes = pDirEnum->FileAttributes | ulAdditionalAttributes;
2194 pDirInfo->FileIndex = pDirEnum->FileIndex;
2195 pDirInfo->FileNameLength = pDirEnum->FileNameLength;
2200 case FileNamesInformation:
2202 pNamesInfo = (PFILE_NAMES_INFORMATION)pBuffer;
2203 pNamesInfo->FileIndex = pDirEnum->FileIndex;
2204 pNamesInfo->FileNameLength = pDirEnum->FileNameLength;
2211 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
2212 AFS_TRACE_LEVEL_ERROR,
2213 "AFSProcessDirectoryQueryDirect (%p) Unknown FileInformationClass %u\n",
2215 pIrpSp->Parameters.QueryDirectory.FileInformationClass);
2217 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
2221 ulBytesConverted = pIrpSp->Parameters.QueryDirectory.Length - ulBaseLength >= pDirEnum->FileNameLength ?
2222 pDirEnum->FileNameLength :
2223 pIrpSp->Parameters.QueryDirectory.Length - ulBaseLength;
2225 RtlCopyMemory( &pBuffer[ ulBaseLength],
2226 (void *)((char *)pDirEnum + pDirEnum->FileNameOffset),
2229 Irp->IoStatus.Information = ulBaseLength + ulBytesConverted;
2233 if( pDirEnum != NULL)
2235 ExFreePool( pDirEnum);