2 * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
3 * Copyright (c) 2009, 2010, 2011 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
14 * this list of conditions and the following disclaimer in the
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.
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.
36 // File: AFSDirControl.cpp
39 #include "AFSCommon.h"
42 // Function: AFSDirControl
46 // This function is the IRP_MJ_DIRECTORY_CONTROL dispatch handler
50 // A status is returned for the handling of this request
54 AFSDirControl( IN PDEVICE_OBJECT LibDeviceObject,
58 NTSTATUS ntStatus = STATUS_SUCCESS;
59 ULONG ulRequestType = 0;
60 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
66 switch( pIrpSp->MinorFunction )
69 case IRP_MN_QUERY_DIRECTORY:
72 ntStatus = AFSQueryDirectory( Irp);
77 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
80 ntStatus = AFSNotifyChangeDirectory( Irp);
87 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
92 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
97 "EXCEPTION - AFSDirControl\n");
99 AFSDumpTraceFilesFnc();
102 if( ntStatus != STATUS_PENDING)
105 AFSCompleteRequest( Irp,
113 AFSQueryDirectory( IN PIRP Irp)
116 NTSTATUS ntStatus = STATUS_SUCCESS;
117 NTSTATUS dStatus = STATUS_SUCCESS;
118 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
119 PIO_STACK_LOCATION pIrpSp;
122 BOOLEAN bInitialQuery = FALSE;
125 ULONG ulUserBufferLength;
126 PUNICODE_STRING puniArgFileName = NULL;
127 UNICODE_STRING uniTmpMaskName;
128 UNICODE_STRING uniDirUniBuf;
129 WCHAR wchMaskBuffer[ 4];
130 FILE_INFORMATION_CLASS FileInformationClass;
131 ULONG ulFileIndex, ulDOSFileIndex;
132 BOOLEAN bRestartScan;
133 BOOLEAN bReturnSingleEntry;
134 BOOLEAN bIndexSpecified;
135 ULONG ulNextEntry = 0;
136 ULONG ulLastEntry = 0;
138 PFILE_DIRECTORY_INFORMATION pDirInfo;
139 PFILE_FULL_DIR_INFORMATION pFullDirInfo;
140 PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
141 PFILE_NAMES_INFORMATION pNamesInfo;
143 ULONG ulBytesConverted;
144 AFSDirectoryCB *pDirEntry = NULL;
145 BOOLEAN bReleaseMain = FALSE;
146 BOOLEAN bReleaseFcb = FALSE;
147 ULONG ulTargetFileType = AFS_FILE_TYPE_UNKNOWN;
148 AFSFileInfoCB stFileInfo;
149 AFSObjectInfoCB *pObjectInfo = NULL;
150 ULONG ulAdditionalAttributes = 0;
156 // Get the current Stack location
157 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
159 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
160 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
165 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
166 AFS_TRACE_LEVEL_ERROR,
167 "AFSQueryDirectory Attempted access (%08lX) when pFcb == NULL\n",
170 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
173 if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
174 pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
175 pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
178 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
179 AFS_TRACE_LEVEL_ERROR,
180 "AFSQueryDirectory Attempted access (%08lX) to non-directory Fcb %08lX NodeType %u\n",
183 pFcb->Header.NodeTypeCode);
187 try_return( ntStatus = STATUS_INVALID_PARAMETER);
191 // Set the enumeration event ...
194 AFSSetEnumerationEvent( pFcb);
196 // Reference our input parameters to make things easier
197 ulUserBufferLength = pIrpSp->Parameters.QueryDirectory.Length;
199 FileInformationClass = pIrpSp->Parameters.QueryDirectory.FileInformationClass;
200 ulFileIndex = pIrpSp->Parameters.QueryDirectory.FileIndex;
202 puniArgFileName = (PUNICODE_STRING)pIrpSp->Parameters.QueryDirectory.FileName;
204 bRestartScan = BooleanFlagOn( pIrpSp->Flags, SL_RESTART_SCAN);
205 bReturnSingleEntry = BooleanFlagOn( pIrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
206 bIndexSpecified = BooleanFlagOn( pIrpSp->Flags, SL_INDEX_SPECIFIED);
208 bInitialQuery = (BOOLEAN)( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED));
213 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
214 AFS_TRACE_LEVEL_VERBOSE,
215 "AFSQueryDirectory Enumerating content for parent %wZ Initial Query\n",
216 &pCcb->DirectoryCB->NameInformation.FileName);
218 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
219 AFS_TRACE_LEVEL_VERBOSE,
220 "AFSQueryDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
221 &pFcb->NPFcb->Resource,
222 PsGetCurrentThread());
224 AFSAcquireExcl( &pFcb->NPFcb->Resource,
232 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
233 AFS_TRACE_LEVEL_VERBOSE,
234 "AFSQueryDirectory Enumerating content for parent %wZ Subsequent\n",
235 &pCcb->DirectoryCB->NameInformation.FileName);
237 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
238 AFS_TRACE_LEVEL_VERBOSE,
239 "AFSQueryDirectory Acquiring Dcb lock %08lX SHARED %08lX\n",
240 &pFcb->NPFcb->Resource,
241 PsGetCurrentThread());
243 AFSAcquireShared( &pFcb->NPFcb->Resource,
250 // Grab the directory node hdr tree lock while parsing the directory
254 AFSAcquireExcl( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
260 // Before attempting to insert the new entry, check if we need to validate the parent
263 if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
266 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
267 AFS_TRACE_LEVEL_VERBOSE,
268 "AFSQueryDirectory Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n",
269 &pCcb->DirectoryCB->NameInformation.FileName,
270 pFcb->ObjectInformation->FileId.Cell,
271 pFcb->ObjectInformation->FileId.Volume,
272 pFcb->ObjectInformation->FileId.Vnode,
273 pFcb->ObjectInformation->FileId.Unique);
275 ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
278 if( !NT_SUCCESS( ntStatus))
281 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
282 AFS_TRACE_LEVEL_ERROR,
283 "AFSQueryDirectory Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
284 &pCcb->DirectoryCB->NameInformation.FileName,
285 pFcb->ObjectInformation->FileId.Cell,
286 pFcb->ObjectInformation->FileId.Volume,
287 pFcb->ObjectInformation->FileId.Vnode,
288 pFcb->ObjectInformation->FileId.Unique,
291 try_return( ntStatus);
295 // Perform a new snapshot of the directory
298 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
301 ntStatus = AFSSnapshotDirectory( pFcb,
305 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
307 if( !NT_SUCCESS( ntStatus))
310 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
311 AFS_TRACE_LEVEL_ERROR,
312 "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
313 &pCcb->DirectoryCB->NameInformation.FileName,
317 try_return( ntStatus);
321 AFSConvertToShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
324 // We can now safely drop the lock on the node
327 AFSReleaseResource( &pFcb->NPFcb->Resource);
332 // Start processing the data
335 pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
341 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
344 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
347 // Check if initial on this map
351 ntStatus = AFSSnapshotDirectory( pFcb,
355 if( !NT_SUCCESS( ntStatus))
358 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
360 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
361 AFS_TRACE_LEVEL_ERROR,
362 "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
363 &pCcb->DirectoryCB->NameInformation.FileName,
367 try_return( ntStatus);
370 SetFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED);
372 ClearFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
374 // build mask if none
375 if( puniArgFileName == NULL)
377 puniArgFileName = &uniTmpMaskName;
378 puniArgFileName->Length = 0;
379 puniArgFileName->Buffer = NULL;
382 if( puniArgFileName->Length == 0)
385 puniArgFileName->Length = sizeof(WCHAR);
386 puniArgFileName->MaximumLength = (USHORT)4;
389 if( puniArgFileName->Buffer == NULL)
392 puniArgFileName->Buffer = wchMaskBuffer;
394 RtlZeroMemory( wchMaskBuffer,
397 RtlCopyMemory( &puniArgFileName->Buffer[ 0],
402 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
403 ( puniArgFileName->Buffer[0] == L'*')))
406 SetFlag( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY);
411 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
412 ( puniArgFileName->Buffer[0] == L'<')) ||
413 (( puniArgFileName->Length == 2*sizeof(WCHAR)) &&
414 ( RtlEqualMemory( puniArgFileName->Buffer, L"*.", 2*sizeof(WCHAR) ))))
417 SetFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
421 // Build the name for procesisng
424 pCcb->MaskName.Length = puniArgFileName->Length;
425 pCcb->MaskName.MaximumLength = pCcb->MaskName.Length;
427 pCcb->MaskName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
428 pCcb->MaskName.Length,
429 AFS_GENERIC_MEMORY_6_TAG);
431 if( pCcb->MaskName.Buffer == NULL)
434 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
437 if( FsRtlDoesNameContainWildCards( puniArgFileName))
440 RtlUpcaseUnicodeString( &pCcb->MaskName,
444 SetFlag( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS);
446 if( FsRtlIsNameInExpression( &pCcb->MaskName,
451 SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
457 RtlCopyMemory( pCcb->MaskName.Buffer,
458 puniArgFileName->Buffer,
459 pCcb->MaskName.Length);
461 if( RtlCompareUnicodeString( &AFSPIOCtlName,
465 SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
469 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
471 if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
474 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
476 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
478 bReleaseMain = FALSE;
480 AFSAcquireExcl( &pFcb->NPFcb->Resource,
483 if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
486 ntStatus = AFSInitPIOCtlDirectoryCB( pFcb->ObjectInformation);
488 if( !NT_SUCCESS( ntStatus))
491 AFSReleaseResource( &pFcb->NPFcb->Resource);
493 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
494 AFS_TRACE_LEVEL_ERROR,
495 "AFSQueryDirectory Init PIOCtl directory failure for parent %wZ Mask %wZ Status %08lX\n",
496 &pCcb->DirectoryCB->NameInformation.FileName,
500 try_return( ntStatus);
504 AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
509 AFSReleaseResource( &pFcb->NPFcb->Resource);
511 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
516 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
517 AFS_TRACE_LEVEL_VERBOSE,
518 "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ\n",
519 &pCcb->DirectoryCB->NameInformation.FileName,
524 // Check if we need to start from index
529 // Need to set up the initial point for the query
532 pCcb->CurrentDirIndex = ulFileIndex - 1;
535 // Check if we need to restart the scan
536 else if( bRestartScan)
540 // Reset the current scan processing
543 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
546 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
551 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
555 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
557 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
559 bReleaseMain = FALSE;
561 switch( FileInformationClass)
564 case FileDirectoryInformation:
566 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
570 case FileFullDirectoryInformation:
572 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
576 case FileNamesInformation:
578 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
582 case FileBothDirectoryInformation:
584 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
588 case FileIdBothDirectoryInformation:
590 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
595 case FileIdFullDirectoryInformation:
597 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
604 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
605 AFS_TRACE_LEVEL_ERROR,
606 "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
608 FileInformationClass);
610 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
616 ULONG ulBytesRemainingInBuffer;
619 ulAdditionalAttributes = 0;
622 // If the user had requested only a single match and we have
623 // returned that, then we stop at this point.
626 if( bReturnSingleEntry && ulNextEntry != 0)
629 try_return( ntStatus);
632 pDirEntry = AFSLocateNextDirEntry( pFcb->ObjectInformation,
635 if( pDirEntry == NULL)
638 if( ulNextEntry == 0)
641 if( ( bInitialQuery ||
643 pCcb->MaskName.Buffer != NULL)
645 ntStatus = STATUS_NO_SUCH_FILE;
649 ntStatus = STATUS_NO_MORE_FILES;
653 try_return( ntStatus);
657 // Skip the entry if it is pending delete or deleted
660 else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) ||
661 BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED))
664 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
666 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
667 AFS_TRACE_LEVEL_VERBOSE,
668 "AFSQueryDirectory Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
669 &pDirEntry->NameInformation.FileName,
674 ASSERT( lCount >= 0);
679 pObjectInfo = pDirEntry->ObjectInformation;
682 // Apply the name filter if there is one
685 if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY))
689 // Only returning directories?
692 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY))
695 if( !FlagOn( pObjectInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))
698 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
700 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
701 AFS_TRACE_LEVEL_VERBOSE,
702 "AFSQueryDirectory Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n",
703 &pDirEntry->NameInformation.FileName,
708 ASSERT( lCount >= 0);
713 else if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
717 // Are we doing a wild card search?
720 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS))
723 if( !FsRtlIsNameInExpression( &pCcb->MaskName,
724 &pDirEntry->NameInformation.FileName,
729 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
731 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
732 AFS_TRACE_LEVEL_VERBOSE,
733 "AFSQueryDirectory Decrement3 count on %wZ DE %p Ccb %p Cnt %d\n",
734 &pDirEntry->NameInformation.FileName,
739 ASSERT( lCount >= 0);
747 if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
753 // See if this is a match for a case insensitive search
756 if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
761 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
763 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
764 AFS_TRACE_LEVEL_VERBOSE,
765 "AFSQueryDirectory Decrement4 count on %wZ DE %p Ccb %p Cnt %d\n",
766 &pDirEntry->NameInformation.FileName,
771 ASSERT( lCount >= 0);
781 // Be sure the information is valid
782 // We don't worry about entries while enumerating the directory
785 AFSValidateEntry( pDirEntry,
790 pObjectInfo = pDirEntry->ObjectInformation;
792 // Here are the rules concerning filling up the buffer:
794 // 1. The Io system guarantees that there will always be
795 // enough room for at least one base record.
797 // 2. If the full first record (including file name) cannot
798 // fit, as much of the name as possible is copied and
799 // STATUS_BUFFER_OVERFLOW is returned.
801 // 3. If a subsequent record cannot completely fit into the
802 // buffer, none of it (as in 0 bytes) is copied, and
803 // STATUS_SUCCESS is returned. A subsequent query will
804 // pick up with this record.
806 ulBytesRemainingInBuffer = ulUserBufferLength - ulNextEntry;
808 if( ( ulNextEntry != 0) &&
809 ( ( ulBaseLength + pDirEntry->NameInformation.FileName.Length > ulBytesRemainingInBuffer) ||
810 ( ulUserBufferLength < ulNextEntry) ) )
814 // Back off our current index
817 pCcb->CurrentDirIndex--;
819 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
821 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
822 AFS_TRACE_LEVEL_VERBOSE,
823 "AFSQueryDirectory Decrement5 count on %wZ DE %p Ccb %p Cnt %d\n",
824 &pDirEntry->NameInformation.FileName,
829 ASSERT( lCount >= 0);
831 try_return( ntStatus = STATUS_SUCCESS);
836 // For Symlinks and Mount Points the reparse point attribute
837 // must be associated with the directory entry. In addition,
838 // for Symlinks it must be determined if the target object is
839 // a directory or not. If so, the directory attribute must be
840 // specified. Mount points always refer to directories and
841 // must have the directory attribute set.
844 switch( pObjectInfo->FileType)
847 case AFS_FILE_TYPE_MOUNTPOINT:
848 case AFS_FILE_TYPE_DFSLINK:
851 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
856 case AFS_FILE_TYPE_SYMLINK:
860 // Go grab the file information for this entry
861 // No worries on failures since we will just display
862 // pseudo information
865 RtlZeroMemory( &stFileInfo,
866 sizeof( AFSFileInfoCB));
868 if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
876 if ( stFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
879 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY;
883 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
890 // Check if the name begins with a . and we are hiding them
893 if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
894 pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
895 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
898 ulAdditionalAttributes |= FILE_ATTRIBUTE_HIDDEN;
902 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
903 AFS_TRACE_LEVEL_VERBOSE,
904 "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n",
905 &pCcb->DirectoryCB->NameInformation.FileName,
906 &pDirEntry->NameInformation.FileName);
908 // Zero the base part of the structure.
909 RtlZeroMemory( &pBuffer[ ulNextEntry],
912 switch( FileInformationClass)
915 // Now fill the base parts of the structure that are applicable.
916 case FileIdBothDirectoryInformation:
917 case FileBothDirectoryInformation:
919 pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry];
921 pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength;
923 if( pDirEntry->NameInformation.ShortNameLength > 0)
925 RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
926 &pDirEntry->NameInformation.ShortName[ 0],
927 pBothDirInfo->ShortNameLength);
930 case FileIdFullDirectoryInformation:
931 case FileFullDirectoryInformation:
933 pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
934 pFullDirInfo->EaSize = 0;
936 case FileDirectoryInformation:
938 pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
940 if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
943 pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
944 pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
945 pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
946 pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
948 pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
949 pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
951 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
953 pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
957 pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
963 pDirInfo->CreationTime = pObjectInfo->CreationTime;
964 pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
965 pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
966 pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
968 pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
969 pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
971 if ( ulAdditionalAttributes && pObjectInfo->FileAttributes == FILE_ATTRIBUTE_NORMAL)
974 pDirInfo->FileAttributes = ulAdditionalAttributes;
979 pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
983 pDirInfo->FileIndex = pDirEntry->FileIndex;
984 pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
989 case FileNamesInformation:
991 pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
992 pNamesInfo->FileIndex = pDirEntry->FileIndex;
993 pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
999 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1000 AFS_TRACE_LEVEL_ERROR,
1001 "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
1003 FileInformationClass);
1005 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1007 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1008 AFS_TRACE_LEVEL_VERBOSE,
1009 "AFSQueryDirectory Decrement6 count on %wZ DE %p Ccb %p Cnt %d\n",
1010 &pDirEntry->NameInformation.FileName,
1015 ASSERT( lCount >= 0);
1017 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
1023 ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
1024 pDirEntry->NameInformation.FileName.Length :
1025 ulBytesRemainingInBuffer - ulBaseLength;
1027 RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
1028 pDirEntry->NameInformation.FileName.Buffer,
1031 // Set up the previous next entry offset
1032 *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
1034 // And indicate how much of the user buffer we have currently
1036 Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
1038 // Check for the case that a single entry doesn't fit.
1039 // This should only get this far on the first entry.
1040 if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
1043 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1045 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1046 AFS_TRACE_LEVEL_VERBOSE,
1047 "AFSQueryDirectory Decrement7 count on %wZ DE %p Ccb %p Cnt %d\n",
1048 &pDirEntry->NameInformation.FileName,
1053 ASSERT( lCount >= 0);
1055 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
1058 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1060 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1061 AFS_TRACE_LEVEL_VERBOSE,
1062 "AFSQueryDirectory Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n",
1063 &pDirEntry->NameInformation.FileName,
1068 ASSERT( lCount >= 0);
1070 dStatus = STATUS_SUCCESS;
1072 // Set ourselves up for the next iteration
1073 ulLastEntry = ulNextEntry;
1074 ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
1082 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1088 AFSReleaseResource( &pFcb->NPFcb->Resource);
1094 AFSClearEnumerationEvent( pFcb);
1102 AFSNotifyChangeDirectory( IN PIRP Irp)
1105 NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1106 PIO_STACK_LOCATION pIrpSp;
1107 AFSFcb *pFcb = NULL;
1108 AFSCcb *pCcb = NULL;
1109 ULONG ulCompletionFilter;
1111 BOOLEAN bReleaseLock = FALSE;
1116 // Get the current Stack location
1117 pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1119 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1120 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1125 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1126 AFS_TRACE_LEVEL_ERROR,
1127 "AFSNotifyChangeDirectory Attempted access (%08lX) when pFcb == NULL\n",
1130 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1133 if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1134 pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1135 pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1138 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1139 AFS_TRACE_LEVEL_ERROR,
1140 "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1141 &pCcb->DirectoryCB->NameInformation.FileName,
1142 pFcb->Header.NodeTypeCode);
1144 try_return( ntStatus = STATUS_INVALID_PARAMETER);
1147 // Reference our input parameter to make things easier
1148 ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1149 bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1151 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1152 AFS_TRACE_LEVEL_VERBOSE,
1153 "AFSNotifyChangeDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
1154 &pFcb->NPFcb->Resource,
1155 PsGetCurrentThread());
1157 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1160 bReleaseLock = TRUE;
1163 // Check if the node has already been deleted
1166 if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1169 try_return( ntStatus = STATUS_FILE_DELETED);
1171 else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1174 try_return( ntStatus = STATUS_DELETE_PENDING);
1177 // Call the Fsrtl package to process the request.
1178 ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1184 if( !NT_SUCCESS( ntStatus))
1186 try_return( ntStatus);
1189 ntStatus = STATUS_PENDING;
1196 AFSReleaseResource( &pFcb->NPFcb->Resource);
1204 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1208 AFSDirectoryCB *pDirEntry = NULL;
1209 NTSTATUS ntStatus = STATUS_SUCCESS;
1210 AFSSnapshotHdr *pSnapshotHdr = NULL;
1211 AFSSnapshotEntry *pSnapshotEntry = NULL;
1218 AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1221 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1225 // Is this a PIOCtl query
1228 if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1231 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1232 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1235 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1237 if( pDirEntry != NULL)
1240 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1242 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1243 AFS_TRACE_LEVEL_VERBOSE,
1244 "AFSLocateNextDirEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n",
1245 &pDirEntry->NameInformation.FileName,
1250 ASSERT( lCount >= 0);
1253 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1254 AFS_TRACE_LEVEL_VERBOSE,
1255 "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1256 &pDirEntry->NameInformation.FileName,
1257 ObjectInfo->FileId.Cell,
1258 ObjectInfo->FileId.Volume,
1259 ObjectInfo->FileId.Vnode,
1260 ObjectInfo->FileId.Unique);
1263 Ccb->CurrentDirIndex++;
1265 try_return( ntStatus);
1268 Ccb->CurrentDirIndex++;
1270 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1274 // Return the .. entry
1277 pDirEntry = AFSGlobalDotDirEntry;
1279 if( pDirEntry != NULL)
1282 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1284 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1285 AFS_TRACE_LEVEL_VERBOSE,
1286 "AFSLocateNextDirEntry Increment2 count on %wZ DE %p Ccb %p Cnt %d\n",
1287 &pDirEntry->NameInformation.FileName,
1292 ASSERT( lCount >= 0);
1295 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1296 AFS_TRACE_LEVEL_VERBOSE,
1297 "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1298 &pDirEntry->NameInformation.FileName,
1299 ObjectInfo->FileId.Cell,
1300 ObjectInfo->FileId.Volume,
1301 ObjectInfo->FileId.Vnode,
1302 ObjectInfo->FileId.Unique);
1304 else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1308 // Return the .. entry
1311 pDirEntry = AFSGlobalDotDotDirEntry;
1313 if( pDirEntry != NULL)
1316 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1318 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1319 AFS_TRACE_LEVEL_VERBOSE,
1320 "AFSLocateNextDirEntry Increment3 count on %wZ DE %p Ccb %p Cnt %d\n",
1321 &pDirEntry->NameInformation.FileName,
1326 ASSERT( lCount >= 0);
1329 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1330 AFS_TRACE_LEVEL_VERBOSE,
1331 "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1332 &pDirEntry->NameInformation.FileName,
1333 ObjectInfo->FileId.Cell,
1334 ObjectInfo->FileId.Volume,
1335 ObjectInfo->FileId.Vnode,
1336 ObjectInfo->FileId.Unique);
1341 pSnapshotHdr = Ccb->DirectorySnapshot;
1343 if( pSnapshotHdr == NULL ||
1344 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1347 try_return( ntStatus);
1350 pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1352 ulCount = Ccb->CurrentDirIndex;
1354 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1355 AFS_TRACE_LEVEL_VERBOSE,
1356 "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1360 // Get to a valid entry
1363 while( ulCount < pSnapshotHdr->EntryCount)
1368 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1369 AFS_TRACE_LEVEL_VERBOSE,
1370 "AFSLocateNextDirEntry Searching for hash %08lX\n",
1371 pSnapshotEntry->NameHash);
1373 if( pSnapshotEntry->NameHash == 0)
1379 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1380 pSnapshotEntry->NameHash,
1383 if( !NT_SUCCESS( ntStatus) ||
1387 if( pDirEntry != NULL)
1390 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1391 AFS_TRACE_LEVEL_VERBOSE,
1392 "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1393 &pDirEntry->NameInformation.FileName,
1394 (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1395 ObjectInfo->FileId.Cell,
1396 ObjectInfo->FileId.Volume,
1397 ObjectInfo->FileId.Vnode,
1398 ObjectInfo->FileId.Unique);
1400 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1402 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1403 AFS_TRACE_LEVEL_VERBOSE,
1404 "AFSLocateNextDirEntry Increment4 count on %wZ DE %p Ccb %p Cnt %d\n",
1405 &pDirEntry->NameInformation.FileName,
1410 ASSERT( lCount >= 0);
1416 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1417 AFS_TRACE_LEVEL_VERBOSE,
1418 "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1419 ObjectInfo->FileId.Cell,
1420 ObjectInfo->FileId.Volume,
1421 ObjectInfo->FileId.Vnode,
1422 ObjectInfo->FileId.Unique);
1428 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1429 AFS_TRACE_LEVEL_VERBOSE,
1430 "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1431 pSnapshotEntry->NameHash,
1432 ObjectInfo->FileId.Cell,
1433 ObjectInfo->FileId.Volume,
1434 ObjectInfo->FileId.Vnode,
1435 ObjectInfo->FileId.Unique);
1441 Ccb->CurrentDirIndex++;
1447 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1449 AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1456 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1461 AFSDirectoryCB *pDirEntry = NULL;
1462 NTSTATUS ntStatus = STATUS_SUCCESS;
1463 AFSSnapshotHdr *pSnapshotHdr = NULL;
1464 AFSSnapshotEntry *pSnapshotEntry = NULL;
1470 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1473 Ccb->CurrentDirIndex = DirIndex;
1475 if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1479 // Return the .. entry
1482 pDirEntry = AFSGlobalDotDirEntry;
1484 else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1488 // Return the .. entry
1491 pDirEntry = AFSGlobalDotDotDirEntry;
1496 pSnapshotHdr = Ccb->DirectorySnapshot;
1498 if( pSnapshotHdr == NULL ||
1499 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1502 try_return( ntStatus);
1505 pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1507 ulCount = Ccb->CurrentDirIndex;
1510 // Get to a valid entry
1513 while( ulCount < pSnapshotHdr->EntryCount)
1518 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1519 pSnapshotEntry->NameHash,
1522 if( !NT_SUCCESS( ntStatus) ||
1523 ( pDirEntry != NULL &&
1524 pDirEntry->FileIndex == DirIndex))
1535 if( pDirEntry != NULL)
1538 Ccb->CurrentDirIndex = ulCount;
1544 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1551 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1553 IN BOOLEAN ResetIndex)
1556 NTSTATUS ntStatus = STATUS_SUCCESS;
1557 AFSSnapshotHdr *pSnapshotHdr = NULL;
1558 AFSSnapshotEntry *pSnapshotEntry = NULL;
1559 AFSDirectoryCB *pDirEntry = NULL;
1568 // Set it up so we still get the . and .. entries for empty directories
1571 if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1574 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1579 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1583 if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1587 // If we have a snapshot then clear it out
1590 if( Ccb->DirectorySnapshot != NULL)
1593 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1595 Ccb->DirectorySnapshot = NULL;
1598 try_return( ntStatus);
1602 // Allocate our snapshot buffer for this enumeration
1605 pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1606 sizeof( AFSSnapshotHdr) +
1607 ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1608 sizeof( AFSSnapshotEntry)),
1609 AFS_DIR_SNAPSHOT_TAG);
1611 if( pSnapshotHdr == NULL)
1614 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1617 RtlZeroMemory( pSnapshotHdr,
1618 sizeof( AFSSnapshotHdr) +
1619 ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1620 sizeof( AFSSnapshotEntry)));
1622 pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1624 pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1627 // Populate our snapshot
1630 pSnapshotEntry = pSnapshotHdr->TopEntry;
1632 pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1634 while( pDirEntry != NULL)
1637 if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1638 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1639 !AFSIsNameInSnapshot( pSnapshotHdr,
1640 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1643 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1644 AFS_TRACE_LEVEL_VERBOSE,
1645 "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1646 pSnapshotHdr->EntryCount,
1647 &pDirEntry->NameInformation.FileName,
1648 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1650 Fcb->ObjectInformation->FileId.Cell,
1651 Fcb->ObjectInformation->FileId.Volume,
1652 Fcb->ObjectInformation->FileId.Vnode,
1653 Fcb->ObjectInformation->FileId.Unique);
1655 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1662 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1663 AFS_TRACE_LEVEL_VERBOSE,
1664 "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1665 pSnapshotHdr->EntryCount,
1666 &pDirEntry->NameInformation.FileName,
1667 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1669 Fcb->ObjectInformation->FileId.Cell,
1670 Fcb->ObjectInformation->FileId.Volume,
1671 Fcb->ObjectInformation->FileId.Vnode,
1672 Fcb->ObjectInformation->FileId.Unique);
1675 pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1678 if( Ccb->DirectorySnapshot != NULL)
1681 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1683 Ccb->DirectorySnapshot = NULL;
1686 Ccb->DirectorySnapshot = pSnapshotHdr;
1697 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1699 IN BOOLEAN WatchTree,
1700 IN ULONG CompletionFilter,
1704 NTSTATUS ntStatus = STATUS_SUCCESS;
1705 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1711 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1715 // Build a dir name based on the FID of the file
1718 if( Ccb->NotifyMask.Buffer == NULL)
1721 Ccb->NotifyMask.Length = 0;
1722 Ccb->NotifyMask.MaximumLength = 1024;
1724 Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1725 Ccb->NotifyMask.MaximumLength,
1726 AFS_GENERIC_MEMORY_7_TAG);
1728 if( Ccb->NotifyMask.Buffer == NULL)
1731 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1734 ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1735 Ccb->NotifyMask.MaximumLength,
1736 L"\\%08lX.%08lX.%08lX.%08lX",
1737 ObjectInfo->FileId.Cell,
1738 ObjectInfo->FileId.Volume,
1739 ObjectInfo->FileId.Vnode,
1740 ObjectInfo->FileId.Unique);
1742 if( !NT_SUCCESS( ntStatus))
1745 try_return( ntStatus);
1748 ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1749 (size_t)Ccb->NotifyMask.MaximumLength,
1752 if( !NT_SUCCESS( ntStatus))
1755 try_return( ntStatus);
1758 Ccb->NotifyMask.Length = (USHORT)sztLength;
1761 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1762 AFS_TRACE_LEVEL_VERBOSE,
1763 "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1769 FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1770 &pDeviceExt->Specific.Control.DirNotifyList,
1772 (PSTRING)&Ccb->NotifyMask,
1783 if( !NT_SUCCESS( ntStatus))
1786 if( Ccb->NotifyMask.Buffer != NULL)
1789 AFSExFreePoolWithTag( Ccb->NotifyMask.Buffer, AFS_GENERIC_MEMORY_7_TAG);
1791 Ccb->NotifyMask.Buffer = NULL;
1795 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1802 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1804 IN ULONG NotifyFilter,
1805 IN ULONG NotificationAction)
1808 NTSTATUS ntStatus = STATUS_SUCCESS;
1809 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1810 UNICODE_STRING uniName, uniComponentName;
1812 USHORT usNameOffset = 0;
1817 uniName.Buffer = NULL;
1819 if( ParentObjectInfo == NULL ||
1820 AFSGlobalRoot == NULL)
1823 try_return( ntStatus);
1829 RtlInitUnicodeString( &uniComponentName,
1835 uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1839 // Build a dir name based on the FID of the file
1843 uniName.MaximumLength = 1024 + uniComponentName.Length;
1845 uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1846 uniName.MaximumLength,
1847 AFS_GENERIC_MEMORY_8_TAG);
1849 if( uniName.Buffer == NULL)
1852 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1855 ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1856 uniName.MaximumLength,
1857 L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1858 ParentObjectInfo->FileId.Cell,
1859 ParentObjectInfo->FileId.Volume,
1860 ParentObjectInfo->FileId.Vnode,
1861 ParentObjectInfo->FileId.Unique,
1864 if( !NT_SUCCESS( ntStatus))
1867 try_return( ntStatus);
1870 ntStatus = RtlStringCbLengthW( uniName.Buffer,
1871 (size_t)uniName.MaximumLength,
1874 if( !NT_SUCCESS( ntStatus))
1877 try_return( ntStatus);
1880 uniName.Length = (USHORT)sztLength;
1882 usNameOffset = uniName.Length - uniComponentName.Length;
1884 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1885 AFS_TRACE_LEVEL_VERBOSE,
1886 "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1892 uniComponentName.Length);
1894 FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1895 &pDeviceExt->Specific.Control.DirNotifyList,
1907 if( uniName.Buffer != NULL)
1910 AFSExFreePoolWithTag( uniName.Buffer, AFS_GENERIC_MEMORY_8_TAG);
1917 // For use with FsRtlNotifyFilterChangeDirectory but must
1918 // be implemented in the Framework because the library can
1922 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1923 IN void *FilterContext)
1926 BOOLEAN bReturn = TRUE;
1927 AFSCcb *pDirCcb = (AFSCcb *)NotifyContext;
1928 AFSCcb *pNotifyCcb = (AFSCcb *)FilterContext;
1939 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1943 BOOLEAN bIsInSnapshot = FALSE;
1944 AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1947 while( ulCount < SnapshotHdr->EntryCount)
1950 if( pSnapshotEntry->NameHash == HashIndex)
1953 bIsInSnapshot = TRUE;
1955 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1956 AFS_TRACE_LEVEL_VERBOSE,
1957 "AFSIsNameInSnapshot Hash index %08lX already in snapshot\n",
1962 else if( pSnapshotEntry->NameHash == 0)
1973 return bIsInSnapshot;