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,
57 UNREFERENCED_PARAMETER(LibDeviceObject);
58 NTSTATUS ntStatus = STATUS_SUCCESS;
59 IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp);
64 switch( pIrpSp->MinorFunction )
67 case IRP_MN_QUERY_DIRECTORY:
70 ntStatus = AFSQueryDirectory( Irp);
75 case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
78 ntStatus = AFSNotifyChangeDirectory( Irp);
85 ntStatus = STATUS_INVALID_DEVICE_REQUEST;
90 __except( AFSExceptionFilter( __FUNCTION__, GetExceptionCode(), GetExceptionInformation()) )
95 "EXCEPTION - AFSDirControl\n");
97 AFSDumpTraceFilesFnc();
100 if( ntStatus != STATUS_PENDING)
103 AFSCompleteRequest( Irp,
111 AFSQueryDirectory( IN PIRP Irp)
114 NTSTATUS ntStatus = STATUS_SUCCESS;
115 NTSTATUS dStatus = STATUS_SUCCESS;
116 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension;
117 PIO_STACK_LOCATION pIrpSp;
120 BOOLEAN bInitialQuery = FALSE;
122 ULONG ulUserBufferLength;
123 PUNICODE_STRING puniArgFileName = NULL;
124 UNICODE_STRING uniTmpMaskName;
125 WCHAR wchMaskBuffer[ 4];
126 FILE_INFORMATION_CLASS FileInformationClass;
128 BOOLEAN bRestartScan;
129 BOOLEAN bReturnSingleEntry;
130 BOOLEAN bIndexSpecified;
131 ULONG ulNextEntry = 0;
132 ULONG ulLastEntry = 0;
133 PFILE_DIRECTORY_INFORMATION pDirInfo;
134 PFILE_FULL_DIR_INFORMATION pFullDirInfo;
135 PFILE_BOTH_DIR_INFORMATION pBothDirInfo;
136 PFILE_NAMES_INFORMATION pNamesInfo;
138 ULONG ulBytesConverted;
139 AFSDirectoryCB *pDirEntry = NULL;
140 BOOLEAN bReleaseMain = FALSE;
141 BOOLEAN bReleaseFcb = FALSE;
142 AFSFileInfoCB stFileInfo;
143 AFSObjectInfoCB *pObjectInfo = NULL;
144 ULONG ulAdditionalAttributes = 0;
150 // Get the current Stack location
151 pIrpSp = IoGetCurrentIrpStackLocation( Irp);
153 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
154 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
159 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
160 AFS_TRACE_LEVEL_ERROR,
161 "AFSQueryDirectory Attempted access (%08lX) when pFcb == NULL\n",
164 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
167 if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
168 pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
169 pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
172 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
173 AFS_TRACE_LEVEL_ERROR,
174 "AFSQueryDirectory Attempted access (%08lX) to non-directory Fcb %08lX NodeType %u\n",
177 pFcb->Header.NodeTypeCode);
181 try_return( ntStatus = STATUS_INVALID_PARAMETER);
185 // Set the enumeration event ...
188 AFSSetEnumerationEvent( pFcb);
190 // Reference our input parameters to make things easier
191 ulUserBufferLength = pIrpSp->Parameters.QueryDirectory.Length;
193 FileInformationClass = pIrpSp->Parameters.QueryDirectory.FileInformationClass;
194 ulFileIndex = pIrpSp->Parameters.QueryDirectory.FileIndex;
196 puniArgFileName = (PUNICODE_STRING)pIrpSp->Parameters.QueryDirectory.FileName;
198 bRestartScan = BooleanFlagOn( pIrpSp->Flags, SL_RESTART_SCAN);
199 bReturnSingleEntry = BooleanFlagOn( pIrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
200 bIndexSpecified = BooleanFlagOn( pIrpSp->Flags, SL_INDEX_SPECIFIED);
202 bInitialQuery = (BOOLEAN)( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED));
207 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
208 AFS_TRACE_LEVEL_VERBOSE,
209 "AFSQueryDirectory Enumerating content for parent %wZ Initial Query\n",
210 &pCcb->DirectoryCB->NameInformation.FileName);
212 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
213 AFS_TRACE_LEVEL_VERBOSE,
214 "AFSQueryDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
215 &pFcb->NPFcb->Resource,
216 PsGetCurrentThread());
218 AFSAcquireExcl( &pFcb->NPFcb->Resource,
226 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
227 AFS_TRACE_LEVEL_VERBOSE,
228 "AFSQueryDirectory Enumerating content for parent %wZ Subsequent\n",
229 &pCcb->DirectoryCB->NameInformation.FileName);
231 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
232 AFS_TRACE_LEVEL_VERBOSE,
233 "AFSQueryDirectory Acquiring Dcb lock %08lX SHARED %08lX\n",
234 &pFcb->NPFcb->Resource,
235 PsGetCurrentThread());
237 AFSAcquireShared( &pFcb->NPFcb->Resource,
244 // Grab the directory node hdr tree lock while parsing the directory
248 AFSAcquireExcl( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
254 // Before attempting to insert the new entry, check if we need to validate the parent
257 if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
260 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
261 AFS_TRACE_LEVEL_VERBOSE,
262 "AFSQueryDirectory Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n",
263 &pCcb->DirectoryCB->NameInformation.FileName,
264 pFcb->ObjectInformation->FileId.Cell,
265 pFcb->ObjectInformation->FileId.Volume,
266 pFcb->ObjectInformation->FileId.Vnode,
267 pFcb->ObjectInformation->FileId.Unique);
269 ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
272 if( !NT_SUCCESS( ntStatus))
275 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
276 AFS_TRACE_LEVEL_ERROR,
277 "AFSQueryDirectory Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
278 &pCcb->DirectoryCB->NameInformation.FileName,
279 pFcb->ObjectInformation->FileId.Cell,
280 pFcb->ObjectInformation->FileId.Volume,
281 pFcb->ObjectInformation->FileId.Vnode,
282 pFcb->ObjectInformation->FileId.Unique,
285 try_return( ntStatus);
289 // Perform a new snapshot of the directory
292 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
295 ntStatus = AFSSnapshotDirectory( pFcb,
299 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
301 if( !NT_SUCCESS( ntStatus))
304 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
305 AFS_TRACE_LEVEL_ERROR,
306 "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
307 &pCcb->DirectoryCB->NameInformation.FileName,
311 try_return( ntStatus);
315 AFSConvertToShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
318 // We can now safely drop the lock on the node
321 AFSReleaseResource( &pFcb->NPFcb->Resource);
326 // Start processing the data
329 pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp,
335 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
338 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
341 // Check if initial on this map
345 ntStatus = AFSSnapshotDirectory( pFcb,
349 if( !NT_SUCCESS( ntStatus))
352 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
354 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
355 AFS_TRACE_LEVEL_ERROR,
356 "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n",
357 &pCcb->DirectoryCB->NameInformation.FileName,
361 try_return( ntStatus);
364 SetFlag( pCcb->Flags, CCB_FLAG_DIRECTORY_QUERY_MAPPED);
366 ClearFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
368 // build mask if none
369 if( puniArgFileName == NULL)
371 puniArgFileName = &uniTmpMaskName;
372 puniArgFileName->Length = 0;
373 puniArgFileName->Buffer = NULL;
376 if( puniArgFileName->Length == 0)
379 puniArgFileName->Length = sizeof(WCHAR);
380 puniArgFileName->MaximumLength = (USHORT)4;
383 if( puniArgFileName->Buffer == NULL)
386 puniArgFileName->Buffer = wchMaskBuffer;
388 RtlZeroMemory( wchMaskBuffer,
391 RtlCopyMemory( &puniArgFileName->Buffer[ 0],
396 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
397 ( puniArgFileName->Buffer[0] == L'*')))
400 SetFlag( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY);
405 if( (( puniArgFileName->Length == sizeof(WCHAR)) &&
406 ( puniArgFileName->Buffer[0] == L'<')) ||
407 (( puniArgFileName->Length == 2*sizeof(WCHAR)) &&
408 ( RtlEqualMemory( puniArgFileName->Buffer, L"*.", 2*sizeof(WCHAR) ))))
411 SetFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY);
415 // Build the name for procesisng
418 pCcb->MaskName.Length = puniArgFileName->Length;
419 pCcb->MaskName.MaximumLength = pCcb->MaskName.Length;
421 pCcb->MaskName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
422 pCcb->MaskName.Length,
423 AFS_GENERIC_MEMORY_6_TAG);
425 if( pCcb->MaskName.Buffer == NULL)
428 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
431 if( FsRtlDoesNameContainWildCards( puniArgFileName))
434 RtlUpcaseUnicodeString( &pCcb->MaskName,
438 SetFlag( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS);
440 if( FsRtlIsNameInExpression( &pCcb->MaskName,
445 SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
451 RtlCopyMemory( pCcb->MaskName.Buffer,
452 puniArgFileName->Buffer,
453 pCcb->MaskName.Length);
455 if( RtlCompareUnicodeString( &AFSPIOCtlName,
459 SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY);
463 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
465 if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
468 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
470 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
472 bReleaseMain = FALSE;
474 AFSAcquireExcl( &pFcb->NPFcb->Resource,
477 if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL)
480 ntStatus = AFSInitPIOCtlDirectoryCB( pFcb->ObjectInformation);
482 if( !NT_SUCCESS( ntStatus))
485 AFSReleaseResource( &pFcb->NPFcb->Resource);
487 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
488 AFS_TRACE_LEVEL_ERROR,
489 "AFSQueryDirectory Init PIOCtl directory failure for parent %wZ Mask %wZ Status %08lX\n",
490 &pCcb->DirectoryCB->NameInformation.FileName,
494 try_return( ntStatus);
498 AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock,
503 AFSReleaseResource( &pFcb->NPFcb->Resource);
505 AFSAcquireExcl( &pCcb->NPCcb->CcbLock,
510 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
511 AFS_TRACE_LEVEL_VERBOSE,
512 "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ\n",
513 &pCcb->DirectoryCB->NameInformation.FileName,
518 // Check if we need to start from index
523 // Need to set up the initial point for the query
526 pCcb->CurrentDirIndex = ulFileIndex - 1;
529 // Check if we need to restart the scan
530 else if( bRestartScan)
534 // Reset the current scan processing
537 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
540 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
545 pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
549 AFSReleaseResource( &pCcb->NPCcb->CcbLock);
551 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
553 bReleaseMain = FALSE;
555 switch( FileInformationClass)
558 case FileDirectoryInformation:
560 ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
564 case FileFullDirectoryInformation:
566 ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
570 case FileNamesInformation:
572 ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
576 case FileBothDirectoryInformation:
578 ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
582 case FileIdBothDirectoryInformation:
584 ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION,
589 case FileIdFullDirectoryInformation:
591 ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION,
598 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
599 AFS_TRACE_LEVEL_ERROR,
600 "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
602 FileInformationClass);
604 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
610 ULONG ulBytesRemainingInBuffer;
612 ulAdditionalAttributes = 0;
615 // If the user had requested only a single match and we have
616 // returned that, then we stop at this point.
619 if( bReturnSingleEntry && ulNextEntry != 0)
622 try_return( ntStatus);
625 pDirEntry = AFSLocateNextDirEntry( pFcb->ObjectInformation,
628 if( pDirEntry == NULL)
631 if( ulNextEntry == 0)
634 if( ( bInitialQuery ||
636 pCcb->MaskName.Buffer != NULL)
638 ntStatus = STATUS_NO_SUCH_FILE;
642 ntStatus = STATUS_NO_MORE_FILES;
646 try_return( ntStatus);
650 // Skip the entry if it is pending delete or deleted
653 else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) ||
654 BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED))
657 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
659 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
660 AFS_TRACE_LEVEL_VERBOSE,
661 "AFSQueryDirectory Decrement count on %wZ DE %p Ccb %p Cnt %d\n",
662 &pDirEntry->NameInformation.FileName,
667 ASSERT( lCount >= 0);
672 pObjectInfo = pDirEntry->ObjectInformation;
675 // Apply the name filter if there is one
678 if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY))
682 // Only returning directories?
685 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY))
688 if( !FlagOn( pObjectInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))
691 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
693 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
694 AFS_TRACE_LEVEL_VERBOSE,
695 "AFSQueryDirectory Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n",
696 &pDirEntry->NameInformation.FileName,
701 ASSERT( lCount >= 0);
706 else if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
710 // Are we doing a wild card search?
713 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS))
716 if( !FsRtlIsNameInExpression( &pCcb->MaskName,
717 &pDirEntry->NameInformation.FileName,
722 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
724 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
725 AFS_TRACE_LEVEL_VERBOSE,
726 "AFSQueryDirectory Decrement3 count on %wZ DE %p Ccb %p Cnt %d\n",
727 &pDirEntry->NameInformation.FileName,
732 ASSERT( lCount >= 0);
740 if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
746 // See if this is a match for a case insensitive search
749 if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName,
754 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
756 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
757 AFS_TRACE_LEVEL_VERBOSE,
758 "AFSQueryDirectory Decrement4 count on %wZ DE %p Ccb %p Cnt %d\n",
759 &pDirEntry->NameInformation.FileName,
764 ASSERT( lCount >= 0);
774 // Be sure the information is valid
775 // We don't worry about entries while enumerating the directory
778 if ( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY))
781 ntStatus = AFSValidateEntry( pDirEntry,
785 if ( NT_SUCCESS( ntStatus))
788 ClearFlag( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);
793 ntStatus = STATUS_SUCCESS;
797 pObjectInfo = pDirEntry->ObjectInformation;
799 // Here are the rules concerning filling up the buffer:
801 // 1. The Io system guarantees that there will always be
802 // enough room for at least one base record.
804 // 2. If the full first record (including file name) cannot
805 // fit, as much of the name as possible is copied and
806 // STATUS_BUFFER_OVERFLOW is returned.
808 // 3. If a subsequent record cannot completely fit into the
809 // buffer, none of it (as in 0 bytes) is copied, and
810 // STATUS_SUCCESS is returned. A subsequent query will
811 // pick up with this record.
813 ulBytesRemainingInBuffer = ulUserBufferLength - ulNextEntry;
815 if( ( ulNextEntry != 0) &&
816 ( ( ulBaseLength + pDirEntry->NameInformation.FileName.Length > ulBytesRemainingInBuffer) ||
817 ( ulUserBufferLength < ulNextEntry) ) )
821 // Back off our current index
824 pCcb->CurrentDirIndex--;
826 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
828 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
829 AFS_TRACE_LEVEL_VERBOSE,
830 "AFSQueryDirectory Decrement5 count on %wZ DE %p Ccb %p Cnt %d\n",
831 &pDirEntry->NameInformation.FileName,
836 ASSERT( lCount >= 0);
838 try_return( ntStatus = STATUS_SUCCESS);
843 // For Symlinks and Mount Points the reparse point attribute
844 // must be associated with the directory entry. In addition,
845 // for Symlinks it must be determined if the target object is
846 // a directory or not. If so, the directory attribute must be
847 // specified. Mount points always refer to directories and
848 // must have the directory attribute set.
851 switch( pObjectInfo->FileType)
854 case AFS_FILE_TYPE_MOUNTPOINT:
855 case AFS_FILE_TYPE_DFSLINK:
858 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT;
863 case AFS_FILE_TYPE_SYMLINK:
867 // Go grab the file information for this entry
868 // No worries on failures since we will just display
869 // pseudo information
872 RtlZeroMemory( &stFileInfo,
873 sizeof( AFSFileInfoCB));
875 if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB,
883 if ( stFileInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
886 ulAdditionalAttributes = FILE_ATTRIBUTE_DIRECTORY;
890 ulAdditionalAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
897 // Check if the name begins with a . and we are hiding them
900 if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) &&
901 pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' &&
902 BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES))
905 ulAdditionalAttributes |= FILE_ATTRIBUTE_HIDDEN;
909 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
910 AFS_TRACE_LEVEL_VERBOSE,
911 "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n",
912 &pCcb->DirectoryCB->NameInformation.FileName,
913 &pDirEntry->NameInformation.FileName);
915 // Zero the base part of the structure.
916 RtlZeroMemory( &pBuffer[ ulNextEntry],
919 switch( FileInformationClass)
922 // Now fill the base parts of the structure that are applicable.
923 case FileIdBothDirectoryInformation:
924 case FileBothDirectoryInformation:
926 pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry];
928 pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength;
930 if( pDirEntry->NameInformation.ShortNameLength > 0)
932 RtlCopyMemory( &pBothDirInfo->ShortName[ 0],
933 &pDirEntry->NameInformation.ShortName[ 0],
934 pBothDirInfo->ShortNameLength);
937 case FileIdFullDirectoryInformation:
938 case FileFullDirectoryInformation:
940 pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry];
941 pFullDirInfo->EaSize = 0;
943 case FileDirectoryInformation:
945 pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry];
947 if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE))
950 pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime;
951 pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime;
952 pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime;
953 pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime;
955 pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile;
956 pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize;
958 if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
960 pDirInfo->FileAttributes = pObjectInfo->FileAttributes;
964 pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes;
970 pDirInfo->CreationTime = pObjectInfo->CreationTime;
971 pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime;
972 pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime;
973 pDirInfo->ChangeTime = pObjectInfo->ChangeTime;
975 pDirInfo->EndOfFile = pObjectInfo->EndOfFile;
976 pDirInfo->AllocationSize = pObjectInfo->AllocationSize;
978 if ( ulAdditionalAttributes && pObjectInfo->FileAttributes == FILE_ATTRIBUTE_NORMAL)
981 pDirInfo->FileAttributes = ulAdditionalAttributes;
986 pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes;
990 pDirInfo->FileIndex = pDirEntry->FileIndex;
991 pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
996 case FileNamesInformation:
998 pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry];
999 pNamesInfo->FileIndex = pDirEntry->FileIndex;
1000 pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length;
1006 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1007 AFS_TRACE_LEVEL_ERROR,
1008 "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n",
1010 FileInformationClass);
1012 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1014 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1015 AFS_TRACE_LEVEL_VERBOSE,
1016 "AFSQueryDirectory Decrement6 count on %wZ DE %p Ccb %p Cnt %d\n",
1017 &pDirEntry->NameInformation.FileName,
1022 ASSERT( lCount >= 0);
1024 try_return( ntStatus = STATUS_INVALID_INFO_CLASS);
1030 ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ?
1031 pDirEntry->NameInformation.FileName.Length :
1032 ulBytesRemainingInBuffer - ulBaseLength;
1034 RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength],
1035 pDirEntry->NameInformation.FileName.Buffer,
1038 // Set up the previous next entry offset
1039 *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry;
1041 // And indicate how much of the user buffer we have currently
1043 Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted;
1045 // Check for the case that a single entry doesn't fit.
1046 // This should only get this far on the first entry.
1047 if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length)
1050 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1052 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1053 AFS_TRACE_LEVEL_VERBOSE,
1054 "AFSQueryDirectory Decrement7 count on %wZ DE %p Ccb %p Cnt %d\n",
1055 &pDirEntry->NameInformation.FileName,
1060 ASSERT( lCount >= 0);
1062 try_return( ntStatus = STATUS_BUFFER_OVERFLOW);
1065 lCount = InterlockedDecrement( &pDirEntry->DirOpenReferenceCount);
1067 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1068 AFS_TRACE_LEVEL_VERBOSE,
1069 "AFSQueryDirectory Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n",
1070 &pDirEntry->NameInformation.FileName,
1075 ASSERT( lCount >= 0);
1077 dStatus = STATUS_SUCCESS;
1079 // Set ourselves up for the next iteration
1080 ulLastEntry = ulNextEntry;
1081 ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted);
1089 AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock);
1095 AFSReleaseResource( &pFcb->NPFcb->Resource);
1101 AFSClearEnumerationEvent( pFcb);
1109 AFSNotifyChangeDirectory( IN PIRP Irp)
1112 NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
1113 PIO_STACK_LOCATION pIrpSp;
1114 AFSFcb *pFcb = NULL;
1115 AFSCcb *pCcb = NULL;
1116 ULONG ulCompletionFilter;
1118 BOOLEAN bReleaseLock = FALSE;
1123 // Get the current Stack location
1124 pIrpSp = IoGetCurrentIrpStackLocation( Irp );
1126 pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext;
1127 pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2;
1132 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1133 AFS_TRACE_LEVEL_ERROR,
1134 "AFSNotifyChangeDirectory Attempted access (%08lX) when pFcb == NULL\n",
1137 try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST);
1140 if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB &&
1141 pFcb->Header.NodeTypeCode != AFS_ROOT_FCB &&
1142 pFcb->Header.NodeTypeCode != AFS_ROOT_ALL)
1145 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1146 AFS_TRACE_LEVEL_ERROR,
1147 "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n",
1148 &pCcb->DirectoryCB->NameInformation.FileName,
1149 pFcb->Header.NodeTypeCode);
1151 try_return( ntStatus = STATUS_INVALID_PARAMETER);
1154 // Reference our input parameter to make things easier
1155 ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter;
1156 bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE);
1158 AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING,
1159 AFS_TRACE_LEVEL_VERBOSE,
1160 "AFSNotifyChangeDirectory Acquiring Dcb lock %08lX EXCL %08lX\n",
1161 &pFcb->NPFcb->Resource,
1162 PsGetCurrentThread());
1164 AFSAcquireExcl( &pFcb->NPFcb->Resource,
1167 bReleaseLock = TRUE;
1170 // Check if the node has already been deleted
1173 if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED))
1176 try_return( ntStatus = STATUS_FILE_DELETED);
1178 else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE))
1181 try_return( ntStatus = STATUS_DELETE_PENDING);
1184 // Call the Fsrtl package to process the request.
1185 ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation,
1191 if( !NT_SUCCESS( ntStatus))
1193 try_return( ntStatus);
1196 ntStatus = STATUS_PENDING;
1203 AFSReleaseResource( &pFcb->NPFcb->Resource);
1211 AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo,
1215 AFSDirectoryCB *pDirEntry = NULL;
1216 NTSTATUS ntStatus = STATUS_SUCCESS;
1217 AFSSnapshotHdr *pSnapshotHdr = NULL;
1218 AFSSnapshotEntry *pSnapshotEntry = NULL;
1225 AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock,
1228 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1232 // Is this a PIOCtl query
1235 if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY))
1238 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX ||
1239 Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX)
1242 pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB;
1244 if( pDirEntry != NULL)
1247 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1249 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1250 AFS_TRACE_LEVEL_VERBOSE,
1251 "AFSLocateNextDirEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n",
1252 &pDirEntry->NameInformation.FileName,
1257 ASSERT( lCount >= 0);
1260 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1261 AFS_TRACE_LEVEL_VERBOSE,
1262 "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1263 &pDirEntry->NameInformation.FileName,
1264 ObjectInfo->FileId.Cell,
1265 ObjectInfo->FileId.Volume,
1266 ObjectInfo->FileId.Vnode,
1267 ObjectInfo->FileId.Unique);
1270 Ccb->CurrentDirIndex++;
1272 try_return( ntStatus);
1275 Ccb->CurrentDirIndex++;
1277 if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1281 // Return the .. entry
1284 pDirEntry = AFSGlobalDotDirEntry;
1286 if( pDirEntry != NULL)
1289 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1291 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1292 AFS_TRACE_LEVEL_VERBOSE,
1293 "AFSLocateNextDirEntry Increment2 count on %wZ DE %p Ccb %p Cnt %d\n",
1294 &pDirEntry->NameInformation.FileName,
1299 ASSERT( lCount >= 0);
1302 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1303 AFS_TRACE_LEVEL_VERBOSE,
1304 "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1305 &pDirEntry->NameInformation.FileName,
1306 ObjectInfo->FileId.Cell,
1307 ObjectInfo->FileId.Volume,
1308 ObjectInfo->FileId.Vnode,
1309 ObjectInfo->FileId.Unique);
1311 else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1315 // Return the .. entry
1318 pDirEntry = AFSGlobalDotDotDirEntry;
1320 if( pDirEntry != NULL)
1323 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1325 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1326 AFS_TRACE_LEVEL_VERBOSE,
1327 "AFSLocateNextDirEntry Increment3 count on %wZ DE %p Ccb %p Cnt %d\n",
1328 &pDirEntry->NameInformation.FileName,
1333 ASSERT( lCount >= 0);
1336 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1337 AFS_TRACE_LEVEL_VERBOSE,
1338 "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n",
1339 &pDirEntry->NameInformation.FileName,
1340 ObjectInfo->FileId.Cell,
1341 ObjectInfo->FileId.Volume,
1342 ObjectInfo->FileId.Vnode,
1343 ObjectInfo->FileId.Unique);
1348 pSnapshotHdr = Ccb->DirectorySnapshot;
1350 if( pSnapshotHdr == NULL ||
1351 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1354 try_return( ntStatus);
1357 pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1359 ulCount = Ccb->CurrentDirIndex;
1361 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1362 AFS_TRACE_LEVEL_VERBOSE,
1363 "AFSLocateNextDirEntry CurrentDirIndex %08lX\n",
1367 // Get to a valid entry
1370 while( ulCount < pSnapshotHdr->EntryCount)
1375 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1376 AFS_TRACE_LEVEL_VERBOSE,
1377 "AFSLocateNextDirEntry Searching for hash %08lX\n",
1378 pSnapshotEntry->NameHash);
1380 if( pSnapshotEntry->NameHash == 0)
1386 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1387 pSnapshotEntry->NameHash,
1390 if( !NT_SUCCESS( ntStatus) ||
1394 if( pDirEntry != NULL)
1397 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1398 AFS_TRACE_LEVEL_VERBOSE,
1399 "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n",
1400 &pDirEntry->NameInformation.FileName,
1401 (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex,
1402 ObjectInfo->FileId.Cell,
1403 ObjectInfo->FileId.Volume,
1404 ObjectInfo->FileId.Vnode,
1405 ObjectInfo->FileId.Unique);
1407 lCount = InterlockedIncrement( &pDirEntry->DirOpenReferenceCount);
1409 AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
1410 AFS_TRACE_LEVEL_VERBOSE,
1411 "AFSLocateNextDirEntry Increment4 count on %wZ DE %p Ccb %p Cnt %d\n",
1412 &pDirEntry->NameInformation.FileName,
1417 ASSERT( lCount >= 0);
1423 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1424 AFS_TRACE_LEVEL_VERBOSE,
1425 "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n",
1426 ObjectInfo->FileId.Cell,
1427 ObjectInfo->FileId.Volume,
1428 ObjectInfo->FileId.Vnode,
1429 ObjectInfo->FileId.Unique);
1435 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1436 AFS_TRACE_LEVEL_VERBOSE,
1437 "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n",
1438 pSnapshotEntry->NameHash,
1439 ObjectInfo->FileId.Cell,
1440 ObjectInfo->FileId.Volume,
1441 ObjectInfo->FileId.Vnode,
1442 ObjectInfo->FileId.Unique);
1448 Ccb->CurrentDirIndex++;
1454 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1456 AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock);
1463 AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo,
1468 AFSDirectoryCB *pDirEntry = NULL;
1469 NTSTATUS ntStatus = STATUS_SUCCESS;
1470 AFSSnapshotHdr *pSnapshotHdr = NULL;
1471 AFSSnapshotEntry *pSnapshotEntry = NULL;
1477 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1480 Ccb->CurrentDirIndex = DirIndex;
1482 if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX)
1486 // Return the .. entry
1489 pDirEntry = AFSGlobalDotDirEntry;
1491 else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX)
1495 // Return the .. entry
1498 pDirEntry = AFSGlobalDotDotDirEntry;
1503 pSnapshotHdr = Ccb->DirectorySnapshot;
1505 if( pSnapshotHdr == NULL ||
1506 Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount)
1509 try_return( ntStatus);
1512 pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex];
1514 ulCount = Ccb->CurrentDirIndex;
1517 // Get to a valid entry
1520 while( ulCount < pSnapshotHdr->EntryCount)
1525 ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead,
1526 pSnapshotEntry->NameHash,
1529 if( !NT_SUCCESS( ntStatus) ||
1530 ( pDirEntry != NULL &&
1531 pDirEntry->FileIndex == DirIndex))
1542 if( pDirEntry != NULL)
1545 Ccb->CurrentDirIndex = ulCount;
1551 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1558 AFSSnapshotDirectory( IN AFSFcb *Fcb,
1560 IN BOOLEAN ResetIndex)
1563 NTSTATUS ntStatus = STATUS_SUCCESS;
1564 AFSSnapshotHdr *pSnapshotHdr = NULL;
1565 AFSSnapshotEntry *pSnapshotEntry = NULL;
1566 AFSDirectoryCB *pDirEntry = NULL;
1575 // Set it up so we still get the . and .. entries for empty directories
1578 if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES))
1581 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX;
1586 Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX;
1590 if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0)
1594 // If we have a snapshot then clear it out
1597 if( Ccb->DirectorySnapshot != NULL)
1600 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1602 Ccb->DirectorySnapshot = NULL;
1605 try_return( ntStatus);
1609 // Allocate our snapshot buffer for this enumeration
1612 pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool,
1613 sizeof( AFSSnapshotHdr) +
1614 ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1615 sizeof( AFSSnapshotEntry)),
1616 AFS_DIR_SNAPSHOT_TAG);
1618 if( pSnapshotHdr == NULL)
1621 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1624 RtlZeroMemory( pSnapshotHdr,
1625 sizeof( AFSSnapshotHdr) +
1626 ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount *
1627 sizeof( AFSSnapshotEntry)));
1629 pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount;
1631 pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr));
1634 // Populate our snapshot
1637 pSnapshotEntry = pSnapshotHdr->TopEntry;
1639 pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead;
1641 while( pDirEntry != NULL)
1644 if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) &&
1645 !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) &&
1646 !AFSIsNameInSnapshot( pSnapshotHdr,
1647 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex))
1650 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1651 AFS_TRACE_LEVEL_VERBOSE,
1652 "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1653 pSnapshotHdr->EntryCount,
1654 &pDirEntry->NameInformation.FileName,
1655 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1657 Fcb->ObjectInformation->FileId.Cell,
1658 Fcb->ObjectInformation->FileId.Volume,
1659 Fcb->ObjectInformation->FileId.Vnode,
1660 Fcb->ObjectInformation->FileId.Unique);
1662 pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex;
1669 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1670 AFS_TRACE_LEVEL_VERBOSE,
1671 "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n",
1672 pSnapshotHdr->EntryCount,
1673 &pDirEntry->NameInformation.FileName,
1674 (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex,
1676 Fcb->ObjectInformation->FileId.Cell,
1677 Fcb->ObjectInformation->FileId.Volume,
1678 Fcb->ObjectInformation->FileId.Vnode,
1679 Fcb->ObjectInformation->FileId.Unique);
1682 pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink;
1685 if( Ccb->DirectorySnapshot != NULL)
1688 AFSExFreePoolWithTag( Ccb->DirectorySnapshot, AFS_DIR_SNAPSHOT_TAG);
1690 Ccb->DirectorySnapshot = NULL;
1693 Ccb->DirectorySnapshot = pSnapshotHdr;
1704 AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo,
1706 IN BOOLEAN WatchTree,
1707 IN ULONG CompletionFilter,
1711 NTSTATUS ntStatus = STATUS_SUCCESS;
1712 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1718 AFSAcquireExcl( &Ccb->NPCcb->CcbLock,
1722 // Build a dir name based on the FID of the file
1725 if( Ccb->NotifyMask.Buffer == NULL)
1728 Ccb->NotifyMask.Length = 0;
1729 Ccb->NotifyMask.MaximumLength = 1024;
1731 Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1732 Ccb->NotifyMask.MaximumLength,
1733 AFS_GENERIC_MEMORY_7_TAG);
1735 if( Ccb->NotifyMask.Buffer == NULL)
1738 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1741 ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer,
1742 Ccb->NotifyMask.MaximumLength,
1743 L"\\%08lX.%08lX.%08lX.%08lX",
1744 ObjectInfo->FileId.Cell,
1745 ObjectInfo->FileId.Volume,
1746 ObjectInfo->FileId.Vnode,
1747 ObjectInfo->FileId.Unique);
1749 if( !NT_SUCCESS( ntStatus))
1752 try_return( ntStatus);
1755 ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer,
1756 (size_t)Ccb->NotifyMask.MaximumLength,
1759 if( !NT_SUCCESS( ntStatus))
1762 try_return( ntStatus);
1765 Ccb->NotifyMask.Length = (USHORT)sztLength;
1768 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1769 AFS_TRACE_LEVEL_VERBOSE,
1770 "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n",
1776 FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync,
1777 &pDeviceExt->Specific.Control.DirNotifyList,
1779 (PSTRING)&Ccb->NotifyMask,
1790 if( !NT_SUCCESS( ntStatus))
1793 if( Ccb->NotifyMask.Buffer != NULL)
1796 AFSExFreePoolWithTag( Ccb->NotifyMask.Buffer, AFS_GENERIC_MEMORY_7_TAG);
1798 Ccb->NotifyMask.Buffer = NULL;
1802 AFSReleaseResource( &Ccb->NPCcb->CcbLock);
1809 AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo,
1811 IN ULONG NotifyFilter,
1812 IN ULONG NotificationAction)
1815 NTSTATUS ntStatus = STATUS_SUCCESS;
1816 AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension;
1817 UNICODE_STRING uniName, uniComponentName;
1819 USHORT usNameOffset = 0;
1824 uniName.Buffer = NULL;
1826 if( ParentObjectInfo == NULL ||
1827 AFSGlobalRoot == NULL)
1830 try_return( ntStatus);
1836 RtlInitUnicodeString( &uniComponentName,
1842 uniComponentName = Ccb->DirectoryCB->NameInformation.FileName;
1846 // Build a dir name based on the FID of the file
1850 uniName.MaximumLength = 1024 + uniComponentName.Length;
1852 uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
1853 uniName.MaximumLength,
1854 AFS_GENERIC_MEMORY_8_TAG);
1856 if( uniName.Buffer == NULL)
1859 try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
1862 ntStatus = RtlStringCbPrintfW( uniName.Buffer,
1863 uniName.MaximumLength,
1864 L"\\%08lX.%08lX.%08lX.%08lX\\%wZ",
1865 ParentObjectInfo->FileId.Cell,
1866 ParentObjectInfo->FileId.Volume,
1867 ParentObjectInfo->FileId.Vnode,
1868 ParentObjectInfo->FileId.Unique,
1871 if( !NT_SUCCESS( ntStatus))
1874 try_return( ntStatus);
1877 ntStatus = RtlStringCbLengthW( uniName.Buffer,
1878 (size_t)uniName.MaximumLength,
1881 if( !NT_SUCCESS( ntStatus))
1884 try_return( ntStatus);
1887 uniName.Length = (USHORT)sztLength;
1889 usNameOffset = uniName.Length - uniComponentName.Length;
1891 AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING,
1892 AFS_TRACE_LEVEL_VERBOSE,
1893 "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n",
1899 uniComponentName.Length);
1901 FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync,
1902 &pDeviceExt->Specific.Control.DirNotifyList,
1914 if( uniName.Buffer != NULL)
1917 AFSExFreePoolWithTag( uniName.Buffer, AFS_GENERIC_MEMORY_8_TAG);
1924 // For use with FsRtlNotifyFilterChangeDirectory but must
1925 // be implemented in the Framework because the library can
1929 AFSNotifyReportChangeCallback( IN void *NotifyContext,
1930 IN void *FilterContext)
1932 UNREFERENCED_PARAMETER(NotifyContext);
1933 UNREFERENCED_PARAMETER(FilterContext);
1934 BOOLEAN bReturn = TRUE;
1945 AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr,
1949 BOOLEAN bIsInSnapshot = FALSE;
1950 AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry;
1953 while( ulCount < SnapshotHdr->EntryCount)
1956 if( pSnapshotEntry->NameHash == HashIndex)
1959 bIsInSnapshot = TRUE;
1961 AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
1962 AFS_TRACE_LEVEL_VERBOSE,
1963 "AFSIsNameInSnapshot Hash index %08lX already in snapshot\n",
1968 else if( pSnapshotEntry->NameHash == 0)
1979 return bIsInSnapshot;