/* * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC. * Copyright (c) 2009, 2010, 2011 Your File System, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, * this list of conditions and the following disclaimer in the * documentation * and/or other materials provided with the distribution. * - Neither the names of Kernel Drivers, LLC and Your File System, Inc. * nor the names of their contributors may be used to endorse or promote * products derived from this software without specific prior written * permission from Kernel Drivers, LLC and Your File System, Inc. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // // File: AFSDirControl.cpp // #include "AFSCommon.h" // // Function: AFSDirControl // // Description: // // This function is the IRP_MJ_DIRECTORY_CONTROL dispatch handler // // Return: // // A status is returned for the handling of this request // NTSTATUS AFSDirControl( IN PDEVICE_OBJECT LibDeviceObject, IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; ULONG ulRequestType = 0; IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); AFSFcb *pFcb = NULL; __try { switch( pIrpSp->MinorFunction ) { case IRP_MN_QUERY_DIRECTORY: { ntStatus = AFSQueryDirectory( Irp); break; } case IRP_MN_NOTIFY_CHANGE_DIRECTORY: { ntStatus = AFSNotifyChangeDirectory( Irp); break; } default: ntStatus = STATUS_INVALID_DEVICE_REQUEST; break; } } __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) { AFSDbgLogMsg( 0, 0, "EXCEPTION - AFSDirControl\n"); } if( ntStatus != STATUS_PENDING) { AFSCompleteRequest( Irp, ntStatus); } return ntStatus; } NTSTATUS AFSQueryDirectory( IN PIRP Irp) { NTSTATUS ntStatus = STATUS_SUCCESS; NTSTATUS dStatus = STATUS_SUCCESS; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; PIO_STACK_LOCATION pIrpSp; AFSFcb *pFcb = NULL; AFSCcb *pCcb = NULL; BOOLEAN bInitialQuery = FALSE; ULONG ulIndex; PUCHAR pBuffer; ULONG ulUserBufferLength; PUNICODE_STRING puniArgFileName = NULL; UNICODE_STRING uniTmpMaskName; UNICODE_STRING uniDirUniBuf; WCHAR wchMaskBuffer[ 4]; FILE_INFORMATION_CLASS FileInformationClass; ULONG ulFileIndex, ulDOSFileIndex; BOOLEAN bRestartScan; BOOLEAN bReturnSingleEntry; BOOLEAN bIndexSpecified; ULONG ulNextEntry = 0; ULONG ulLastEntry = 0; BOOLEAN bDoCase; PFILE_DIRECTORY_INFORMATION pDirInfo; PFILE_FULL_DIR_INFORMATION pFullDirInfo; PFILE_BOTH_DIR_INFORMATION pBothDirInfo; PFILE_NAMES_INFORMATION pNamesInfo; ULONG ulBaseLength; ULONG ulBytesConverted; AFSDirectoryCB *pDirEntry = NULL; BOOLEAN bReleaseMain = FALSE; BOOLEAN bReleaseFcb = FALSE; ULONG ulTargetFileType = AFS_FILE_TYPE_UNKNOWN; AFSFileInfoCB stFileInfo; BOOLEAN bUseFileInfo = TRUE; AFSObjectInfoCB *pObjectInfo = NULL; ULONG ulAdditionalAttributes = 0; __Enter { // Get the current Stack location pIrpSp = IoGetCurrentIrpStackLocation( Irp); pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; if( pFcb == NULL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory Attempted access (%08lX) when pFcb == NULL\n", Irp); try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); } if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB && pFcb->Header.NodeTypeCode != AFS_ROOT_FCB && pFcb->Header.NodeTypeCode != AFS_ROOT_ALL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory Attempted access (%08lX) to non-directory Fcb %08lX NodeType %u\n", Irp, pFcb, pFcb->Header.NodeTypeCode); pFcb = NULL; try_return( ntStatus = STATUS_INVALID_PARAMETER); } // // Set the enumeration event ... // AFSSetEnumerationEvent( pFcb); // Reference our input parameters to make things easier ulUserBufferLength = pIrpSp->Parameters.QueryDirectory.Length; FileInformationClass = pIrpSp->Parameters.QueryDirectory.FileInformationClass; ulFileIndex = pIrpSp->Parameters.QueryDirectory.FileIndex; puniArgFileName = (PUNICODE_STRING)pIrpSp->Parameters.QueryDirectory.FileName; bRestartScan = BooleanFlagOn( pIrpSp->Flags, SL_RESTART_SCAN); bReturnSingleEntry = BooleanFlagOn( pIrpSp->Flags, SL_RETURN_SINGLE_ENTRY); bIndexSpecified = BooleanFlagOn( pIrpSp->Flags, SL_INDEX_SPECIFIED); bInitialQuery = (BOOLEAN)( !BooleanFlagOn( pCcb->Flags, CCB_FLAGS_DIRECTORY_QUERY_MAPPED)); if( bInitialQuery) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Enumerating content for parent %wZ Initial Query\n", &pCcb->DirectoryCB->NameInformation.FileName); AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Acquiring Dcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); bReleaseFcb = TRUE; } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Enumerating content for parent %wZ Subsequent\n", &pCcb->DirectoryCB->NameInformation.FileName); AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Acquiring Dcb lock %08lX SHARED %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireShared( &pFcb->NPFcb->Resource, TRUE); bReleaseFcb = TRUE; } // // Grab the directory node hdr tree lock while parsing the directory // contents // AFSAcquireExcl( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); bReleaseMain = TRUE; // // Before attempting to insert the new entry, check if we need to validate the parent // if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY)) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileId.Cell, pFcb->ObjectInformation->FileId.Volume, pFcb->ObjectInformation->FileId.Vnode, pFcb->ObjectInformation->FileId.Unique); ntStatus = AFSVerifyEntry( &pCcb->AuthGroup, pCcb->DirectoryCB); if( !NT_SUCCESS( ntStatus)) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->ObjectInformation->FileId.Cell, pFcb->ObjectInformation->FileId.Volume, pFcb->ObjectInformation->FileId.Vnode, pFcb->ObjectInformation->FileId.Unique, ntStatus); try_return( ntStatus); } // // Perform a new snapshot of the directory // ntStatus = AFSSnapshotDirectory( pFcb, pCcb, FALSE); if( !NT_SUCCESS( ntStatus)) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, &pCcb->MaskName, ntStatus); try_return( ntStatus); } } AFSConvertToShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); // // We can now safely drop the lock on the node // AFSReleaseResource( &pFcb->NPFcb->Resource); bReleaseFcb = FALSE; // // Start processing the data // pBuffer = (PUCHAR)AFSLockSystemBuffer( Irp, ulUserBufferLength); if( pBuffer == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } // Check if initial on this map if( bInitialQuery) { ntStatus = AFSSnapshotDirectory( pFcb, pCcb, TRUE); if( !NT_SUCCESS( ntStatus)) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory Snapshot directory failure for parent %wZ Mask %wZ Status %08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, &pCcb->MaskName, ntStatus); try_return( ntStatus); } SetFlag( pCcb->Flags, CCB_FLAGS_DIRECTORY_QUERY_MAPPED); ClearFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY); // build mask if none if( puniArgFileName == NULL) { puniArgFileName = &uniTmpMaskName; puniArgFileName->Length = 0; puniArgFileName->Buffer = NULL; } if( puniArgFileName->Length == 0) { puniArgFileName->Length = sizeof(WCHAR); puniArgFileName->MaximumLength = (USHORT)4; } if( puniArgFileName->Buffer == NULL) { puniArgFileName->Buffer = wchMaskBuffer; RtlZeroMemory( wchMaskBuffer, 4); RtlCopyMemory( &puniArgFileName->Buffer[ 0], L"*", sizeof(WCHAR)); } if( (( puniArgFileName->Length == sizeof(WCHAR)) && ( puniArgFileName->Buffer[0] == L'*'))) { SetFlag( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY); } else { if( (( puniArgFileName->Length == sizeof(WCHAR)) && ( puniArgFileName->Buffer[0] == L'<')) || (( puniArgFileName->Length == 2*sizeof(WCHAR)) && ( RtlEqualMemory( puniArgFileName->Buffer, L"*.", 2*sizeof(WCHAR) )))) { SetFlag( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY); } // // Build the name for procesisng // pCcb->MaskName.Length = puniArgFileName->Length; pCcb->MaskName.MaximumLength = pCcb->MaskName.Length; pCcb->MaskName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, pCcb->MaskName.Length, AFS_GENERIC_MEMORY_6_TAG); if( pCcb->MaskName.Buffer == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } if( FsRtlDoesNameContainWildCards( puniArgFileName)) { RtlUpcaseUnicodeString( &pCcb->MaskName, puniArgFileName, FALSE); SetFlag( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS); if( FsRtlIsNameInExpression( &pCcb->MaskName, &AFSPIOCtlName, TRUE, NULL)) { SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY); } } else { RtlCopyMemory( pCcb->MaskName.Buffer, puniArgFileName->Buffer, pCcb->MaskName.Length); if( RtlCompareUnicodeString( &AFSPIOCtlName, &pCcb->MaskName, TRUE) == 0) { SetFlag( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY); } } if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY)) { if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL) { AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); bReleaseMain = FALSE; AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); if( pFcb->ObjectInformation->Specific.Directory.PIOCtlDirectoryCB == NULL) { ntStatus = AFSInitPIOCtlDirectoryCB( pFcb->ObjectInformation); if( !NT_SUCCESS( ntStatus)) { AFSReleaseResource( &pFcb->NPFcb->Resource); AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory Init PIOCtl directory failure for parent %wZ Mask %wZ Status %08lX\n", &pCcb->DirectoryCB->NameInformation.FileName, &pCcb->MaskName, ntStatus); try_return( ntStatus); } } AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); bReleaseMain = TRUE; AFSReleaseResource( &pFcb->NPFcb->Resource); } } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Enumerating content for parent %wZ Mask %wZ\n", &pCcb->DirectoryCB->NameInformation.FileName, &pCcb->MaskName); } } // Check if we need to start from index if( bIndexSpecified) { // // Need to set up the initial point for the query // pCcb->CurrentDirIndex = ulFileIndex - 1; } // Check if we need to restart the scan else if( bRestartScan) { // // Reset the current scan processing // if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES)) { pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX; } else { pCcb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX; } } switch( FileInformationClass) { case FileDirectoryInformation: ulBaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION, FileName[0] ); break; case FileFullDirectoryInformation: ulBaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ); break; case FileNamesInformation: ulBaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION, FileName[0] ); break; case FileBothDirectoryInformation: ulBaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION, FileName[0] ); break; case FileIdBothDirectoryInformation: ulBaseLength = FIELD_OFFSET( FILE_ID_BOTH_DIR_INFORMATION, FileName[0] ); break; case FileIdFullDirectoryInformation: ulBaseLength = FIELD_OFFSET( FILE_ID_FULL_DIR_INFORMATION, FileName[0] ); break; default: AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n", Irp, FileInformationClass); try_return( ntStatus = STATUS_INVALID_INFO_CLASS); } AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); bReleaseMain = FALSE; while( TRUE) { ULONG ulBytesRemainingInBuffer; int rc; // // If the user had requested only a single match and we have // returned that, then we stop at this point. // if( bReturnSingleEntry && ulNextEntry != 0) { try_return( ntStatus); } pDirEntry = AFSLocateNextDirEntry( pFcb->ObjectInformation, pCcb); if( pDirEntry == NULL) { if( ulNextEntry == 0) { if( ( bInitialQuery || bRestartScan) && pCcb->MaskName.Buffer != NULL) { ntStatus = STATUS_NO_SUCH_FILE; } else { ntStatus = STATUS_NO_MORE_FILES; } } try_return( ntStatus); } // // Skip the entry if it is pending delete or deleted // else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) || BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED)) { InterlockedDecrement( &pDirEntry->OpenReferenceCount); continue; } pObjectInfo = pDirEntry->ObjectInformation; // // Apply the name filter if there is one // if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_FULL_DIRECTORY_QUERY)) { // // Only returning directories? // if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_DIR_OF_DIRS_ONLY)) { if( !FlagOn( pObjectInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) { InterlockedDecrement( &pDirEntry->OpenReferenceCount); continue; } } else if( !BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY)) { // // Are we doing a wild card search? // if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_CONTAINS_WILD_CARDS)) { if( !FsRtlIsNameInExpression( &pCcb->MaskName, &pDirEntry->NameInformation.FileName, TRUE, NULL)) { InterlockedDecrement( &pDirEntry->OpenReferenceCount); continue; } } else { if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName, &pCcb->MaskName, FALSE)) { // // See if this is a match for a case insensitive search // if( RtlCompareUnicodeString( &pDirEntry->NameInformation.FileName, &pCcb->MaskName, TRUE)) { InterlockedDecrement( &pDirEntry->OpenReferenceCount); continue; } } } } } // // Be sure the information is valid // We don't worry about entries while enumerating the directory // AFSValidateEntry( pDirEntry, &pCcb->AuthGroup, FALSE, FALSE); pObjectInfo = pDirEntry->ObjectInformation; bUseFileInfo = FALSE; ulAdditionalAttributes = 0; if( pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK) { // // Go grab the file information for this entry // No worries on failures since we will just display // pseudo information // RtlZeroMemory( &stFileInfo, sizeof( AFSFileInfoCB)); if( NT_SUCCESS( AFSRetrieveFileAttributes( pCcb->DirectoryCB, pDirEntry, &pCcb->FullFileName, pCcb->NameArray, &pCcb->AuthGroup, &stFileInfo))) { ulAdditionalAttributes = FILE_ATTRIBUTE_REPARSE_POINT; bUseFileInfo = TRUE; } } // Here are the rules concerning filling up the buffer: // // 1. The Io system guarantees that there will always be // enough room for at least one base record. // // 2. If the full first record (including file name) cannot // fit, as much of the name as possible is copied and // STATUS_BUFFER_OVERFLOW is returned. // // 3. If a subsequent record cannot completely fit into the // buffer, none of it (as in 0 bytes) is copied, and // STATUS_SUCCESS is returned. A subsequent query will // pick up with this record. ulBytesRemainingInBuffer = ulUserBufferLength - ulNextEntry; if( ( ulNextEntry != 0) && ( ( ulBaseLength + pDirEntry->NameInformation.FileName.Length > ulBytesRemainingInBuffer) || ( ulUserBufferLength < ulNextEntry) ) ) { // // Back off our current index // pCcb->CurrentDirIndex--; InterlockedDecrement( &pDirEntry->OpenReferenceCount); try_return( ntStatus = STATUS_SUCCESS); } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSQueryDirectory Insert into parent %wZ Entry %wZ\n", &pCcb->DirectoryCB->NameInformation.FileName, &pDirEntry->NameInformation.FileName); // Zero the base part of the structure. RtlZeroMemory( &pBuffer[ ulNextEntry], ulBaseLength); switch( FileInformationClass) { // Now fill the base parts of the structure that are applicable. case FileIdBothDirectoryInformation: case FileBothDirectoryInformation: { pBothDirInfo = (PFILE_BOTH_DIR_INFORMATION)&pBuffer[ ulNextEntry]; pBothDirInfo->ShortNameLength = (CHAR)pDirEntry->NameInformation.ShortNameLength; if( pDirEntry->NameInformation.ShortNameLength > 0) { RtlCopyMemory( &pBothDirInfo->ShortName[ 0], &pDirEntry->NameInformation.ShortName[ 0], pBothDirInfo->ShortNameLength); } } case FileIdFullDirectoryInformation: case FileFullDirectoryInformation: { pFullDirInfo = (PFILE_FULL_DIR_INFORMATION)&pBuffer[ ulNextEntry]; pFullDirInfo->EaSize = 0; } case FileDirectoryInformation: { pDirInfo = (PFILE_DIRECTORY_INFORMATION)&pBuffer[ ulNextEntry]; if( bUseFileInfo) { pDirInfo->CreationTime = stFileInfo.CreationTime; pDirInfo->LastWriteTime = stFileInfo.LastWriteTime; pDirInfo->LastAccessTime = stFileInfo.LastAccessTime; pDirInfo->ChangeTime = stFileInfo.ChangeTime; pDirInfo->EndOfFile = stFileInfo.EndOfFile; pDirInfo->AllocationSize = stFileInfo.AllocationSize; pDirInfo->FileAttributes = stFileInfo.FileAttributes | ulAdditionalAttributes; } else if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE)) { pDirInfo->CreationTime = pFcb->ObjectInformation->CreationTime; pDirInfo->LastWriteTime = pFcb->ObjectInformation->LastWriteTime; pDirInfo->LastAccessTime = pFcb->ObjectInformation->LastAccessTime; pDirInfo->ChangeTime = pFcb->ObjectInformation->ChangeTime; pDirInfo->EndOfFile = pFcb->ObjectInformation->EndOfFile; pDirInfo->AllocationSize = pFcb->ObjectInformation->AllocationSize; if( BooleanFlagOn( pCcb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY)) { pDirInfo->FileAttributes = pObjectInfo->FileAttributes; } else { pDirInfo->FileAttributes = pFcb->ObjectInformation->FileAttributes; } } else { pDirInfo->CreationTime = pObjectInfo->CreationTime; pDirInfo->LastWriteTime = pObjectInfo->LastWriteTime; pDirInfo->LastAccessTime = pObjectInfo->LastAccessTime; pDirInfo->ChangeTime = pObjectInfo->ChangeTime; pDirInfo->EndOfFile = pObjectInfo->EndOfFile; pDirInfo->AllocationSize = pObjectInfo->AllocationSize; pDirInfo->FileAttributes = pObjectInfo->FileAttributes | ulAdditionalAttributes; } // // Check if the name begins with a . and we are hiding them // if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) && pDirEntry->NameInformation.FileName.Buffer[ 0] == L'.' && BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES)) { pDirInfo->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; } pDirInfo->FileIndex = pDirEntry->FileIndex; pDirInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length; break; } case FileNamesInformation: { pNamesInfo = (PFILE_NAMES_INFORMATION)&pBuffer[ ulNextEntry]; pNamesInfo->FileIndex = pDirEntry->FileIndex; pNamesInfo->FileNameLength = pDirEntry->NameInformation.FileName.Length; break; } default: { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSQueryDirectory (%08lX) Unknown FileInformationClass %u\n", Irp, FileInformationClass); InterlockedDecrement( &pDirEntry->OpenReferenceCount); try_return( ntStatus = STATUS_INVALID_INFO_CLASS); break; } } ulBytesConverted = ulBytesRemainingInBuffer - ulBaseLength >= pDirEntry->NameInformation.FileName.Length ? pDirEntry->NameInformation.FileName.Length : ulBytesRemainingInBuffer - ulBaseLength; RtlCopyMemory( &pBuffer[ ulNextEntry + ulBaseLength], pDirEntry->NameInformation.FileName.Buffer, ulBytesConverted); // Set up the previous next entry offset *((PULONG)(&pBuffer[ ulLastEntry])) = ulNextEntry - ulLastEntry; // And indicate how much of the user buffer we have currently // used up. Irp->IoStatus.Information = QuadAlign( Irp->IoStatus.Information) + ulBaseLength + ulBytesConverted; // Check for the case that a single entry doesn't fit. // This should only get this far on the first entry. if( ulBytesConverted < pDirEntry->NameInformation.FileName.Length) { InterlockedDecrement( &pDirEntry->OpenReferenceCount); try_return( ntStatus = STATUS_BUFFER_OVERFLOW); } InterlockedDecrement( &pDirEntry->OpenReferenceCount); dStatus = STATUS_SUCCESS; // Set ourselves up for the next iteration ulLastEntry = ulNextEntry; ulNextEntry += (ULONG)QuadAlign( ulBaseLength + ulBytesConverted); } try_exit: if( bReleaseMain) { AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } if ( bReleaseFcb) { AFSReleaseResource( &pFcb->NPFcb->Resource); } if( pFcb != NULL) { AFSClearEnumerationEvent( pFcb); } } return ntStatus; } NTSTATUS AFSNotifyChangeDirectory( IN PIRP Irp) { NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; PIO_STACK_LOCATION pIrpSp; AFSFcb *pFcb = NULL; AFSCcb *pCcb = NULL; ULONG ulCompletionFilter; BOOLEAN bWatchTree; BOOLEAN bReleaseLock = FALSE; __Enter { // Get the current Stack location pIrpSp = IoGetCurrentIrpStackLocation( Irp ); pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; if( pFcb == NULL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSNotifyChangeDirectory Attempted access (%08lX) when pFcb == NULL\n", Irp); try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); } if( pFcb->Header.NodeTypeCode != AFS_DIRECTORY_FCB && pFcb->Header.NodeTypeCode != AFS_ROOT_FCB && pFcb->Header.NodeTypeCode != AFS_ROOT_ALL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSNotifyChangeDirectory NodeTypeCode !AFS_DIRECTORY_FCB && !AFS_ROOT_FCB %wZ NodeTypeCode 0x%x\n", &pCcb->DirectoryCB->NameInformation.FileName, pFcb->Header.NodeTypeCode); try_return( ntStatus = STATUS_INVALID_PARAMETER); } // Reference our input parameter to make things easier ulCompletionFilter = pIrpSp->Parameters.NotifyDirectory.CompletionFilter; bWatchTree = BooleanFlagOn( pIrpSp->Flags, SL_WATCH_TREE); AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSNotifyChangeDirectory Acquiring Dcb lock %08lX EXCL %08lX\n", &pFcb->NPFcb->Resource, PsGetCurrentThread()); AFSAcquireExcl( &pFcb->NPFcb->Resource, TRUE); bReleaseLock = TRUE; // // Check if the node has already been deleted // if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) { try_return( ntStatus = STATUS_FILE_DELETED); } else if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) { try_return( ntStatus = STATUS_DELETE_PENDING); } // Call the Fsrtl package to process the request. ntStatus = AFSFsRtlNotifyFullChangeDirectory( pFcb->ObjectInformation, pCcb, bWatchTree, ulCompletionFilter, Irp); if( !NT_SUCCESS( ntStatus)) { try_return( ntStatus); } ntStatus = STATUS_PENDING; try_exit: if( bReleaseLock) { AFSReleaseResource( &pFcb->NPFcb->Resource); } } return ntStatus; } AFSDirectoryCB * AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo, IN AFSCcb *Ccb) { AFSDirectoryCB *pDirEntry = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; AFSSnapshotHdr *pSnapshotHdr = NULL; AFSSnapshotEntry *pSnapshotEntry = NULL; ULONG ulCount = 0; __Enter { // // Is this a PIOCtl query // if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_MASK_PIOCTL_QUERY)) { if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_DIR_INDEX || Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_INITIAL_ROOT_INDEX) { pDirEntry = ObjectInfo->Specific.Directory.PIOCtlDirectoryCB; if( pDirEntry != NULL) { InterlockedIncrement( &pDirEntry->OpenReferenceCount); } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Returning PIOctl entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n", &pDirEntry->NameInformation.FileName, ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); } Ccb->CurrentDirIndex++; try_return( ntStatus); } Ccb->CurrentDirIndex++; if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX) { // // Return the .. entry // pDirEntry = AFSGlobalDotDirEntry; if( pDirEntry != NULL) { InterlockedIncrement( &pDirEntry->OpenReferenceCount); } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Returning1 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n", &pDirEntry->NameInformation.FileName, ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); } else if( Ccb->CurrentDirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX) { // // Return the .. entry // pDirEntry = AFSGlobalDotDotDirEntry; if( pDirEntry != NULL) { InterlockedIncrement( &pDirEntry->OpenReferenceCount); } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Returning2 snapshot entry %wZ in parent FID %08lX-%08lX-%08lX-%08lX\n", &pDirEntry->NameInformation.FileName, ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); } else { pSnapshotHdr = Ccb->DirectorySnapshot; if( pSnapshotHdr == NULL || Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount) { try_return( ntStatus); } pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex]; ulCount = Ccb->CurrentDirIndex; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry CurrentDirIndex %08lX\n", ulCount); // // Get to a valid entry // AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); while( ulCount < pSnapshotHdr->EntryCount) { pDirEntry = NULL; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Searching for hash %08lX\n", pSnapshotEntry->NameHash); if( pSnapshotEntry->NameHash == 0) { break; } ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, pSnapshotEntry->NameHash, &pDirEntry); if( !NT_SUCCESS( ntStatus) || pDirEntry != NULL) { if( pDirEntry != NULL) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Returning3 snapshot entry %wZ (%08lX) in parent FID %08lX-%08lX-%08lX-%08lX\n", &pDirEntry->NameInformation.FileName, (ULONG)pDirEntry->CaseInsensitiveTreeEntry.HashIndex, ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); InterlockedIncrement( &pDirEntry->OpenReferenceCount); } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Returning3 NO snapshot entry in parent FID %08lX-%08lX-%08lX-%08lX\n", ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); } break; } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSLocateNextDirEntry Entry %08lX not found in parent FID %08lX-%08lX-%08lX-%08lX\n", pSnapshotEntry->NameHash, ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); pSnapshotEntry++; ulCount++; Ccb->CurrentDirIndex++; } AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); } try_exit: NOTHING; } return pDirEntry; } AFSDirectoryCB * AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo, IN AFSCcb *Ccb, IN ULONG DirIndex) { AFSDirectoryCB *pDirEntry = NULL; NTSTATUS ntStatus = STATUS_SUCCESS; AFSSnapshotHdr *pSnapshotHdr = NULL; AFSSnapshotEntry *pSnapshotEntry = NULL; ULONG ulCount = 0; __Enter { Ccb->CurrentDirIndex = DirIndex; if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_INDEX) { // // Return the .. entry // pDirEntry = AFSGlobalDotDirEntry; } else if( DirIndex == (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX) { // // Return the .. entry // pDirEntry = AFSGlobalDotDotDirEntry; } else { pSnapshotHdr = Ccb->DirectorySnapshot; if( pSnapshotHdr == NULL || Ccb->CurrentDirIndex >= pSnapshotHdr->EntryCount) { try_return( ntStatus); } pSnapshotEntry = &pSnapshotHdr->TopEntry[ Ccb->CurrentDirIndex]; ulCount = Ccb->CurrentDirIndex; // // Get to a valid entry // while( ulCount < pSnapshotHdr->EntryCount) { pDirEntry = NULL; ntStatus = AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, pSnapshotEntry->NameHash, &pDirEntry); if( !NT_SUCCESS( ntStatus) || ( pDirEntry != NULL && pDirEntry->FileIndex == DirIndex)) { break; } pSnapshotEntry++; ulCount++; } if( pDirEntry != NULL) { Ccb->CurrentDirIndex = ulCount; } } try_exit: NOTHING; } return pDirEntry; } NTSTATUS AFSSnapshotDirectory( IN AFSFcb *Fcb, IN AFSCcb *Ccb, IN BOOLEAN ResetIndex) { NTSTATUS ntStatus = STATUS_SUCCESS; AFSSnapshotHdr *pSnapshotHdr = NULL; AFSSnapshotEntry *pSnapshotEntry = NULL; AFSDirectoryCB *pDirEntry = NULL; __Enter { if( ResetIndex) { // // Set it up so we still get the . and .. entries for empty directories // if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES)) { Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX; } else { Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX; } } if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0) { // // If we have a snapshot then clear it out // if( Ccb->DirectorySnapshot != NULL) { AFSExFreePool( Ccb->DirectorySnapshot); Ccb->DirectorySnapshot = NULL; } try_return( ntStatus); } // // Allocate our snapshot buffer for this enumeration // pSnapshotHdr = (AFSSnapshotHdr *)AFSExAllocatePoolWithTag( PagedPool, sizeof( AFSSnapshotHdr) + ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount * sizeof( AFSSnapshotEntry)), AFS_DIR_SNAPSHOT_TAG); if( pSnapshotHdr == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } RtlZeroMemory( pSnapshotHdr, sizeof( AFSSnapshotHdr) + ( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount * sizeof( AFSSnapshotEntry))); pSnapshotHdr->EntryCount = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount; pSnapshotHdr->TopEntry = (AFSSnapshotEntry *)((char *)pSnapshotHdr + sizeof( AFSSnapshotHdr)); // // Populate our snapshot // pSnapshotEntry = pSnapshotHdr->TopEntry; pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead; while( pDirEntry != NULL) { if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED) && !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE) && !AFSIsNameInSnapshot( pSnapshotHdr, (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex)) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSSnapshotDirectory Snapshot (%08lX) Inserting entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n", pSnapshotHdr->EntryCount, &pDirEntry->NameInformation.FileName, (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex, pDirEntry->Flags, Fcb->ObjectInformation->FileId.Cell, Fcb->ObjectInformation->FileId.Volume, Fcb->ObjectInformation->FileId.Vnode, Fcb->ObjectInformation->FileId.Unique); pSnapshotEntry->NameHash = (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex; pSnapshotEntry++; } else { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSSnapshotDirectory Snapshot (%08lX) Skipping entry %wZ (%08lX) Flags %08lX in parent FID %08lX-%08lX-%08lX-%08lX\n", pSnapshotHdr->EntryCount, &pDirEntry->NameInformation.FileName, (ULONG)pDirEntry->CaseSensitiveTreeEntry.HashIndex, pDirEntry->Flags, Fcb->ObjectInformation->FileId.Cell, Fcb->ObjectInformation->FileId.Volume, Fcb->ObjectInformation->FileId.Vnode, Fcb->ObjectInformation->FileId.Unique); } pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink; } if( Ccb->DirectorySnapshot != NULL) { AFSExFreePool( Ccb->DirectorySnapshot); Ccb->DirectorySnapshot = NULL; } Ccb->DirectorySnapshot = pSnapshotHdr; try_exit: NOTHING; } return ntStatus; } NTSTATUS AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo, IN AFSCcb *Ccb, IN BOOLEAN WatchTree, IN ULONG CompletionFilter, IN PIRP NotifyIrp) { NTSTATUS ntStatus = STATUS_SUCCESS; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; size_t sztLength; __Enter { // // Build a dir name based on the FID of the file // if( Ccb->NotifyMask.Buffer == NULL) { Ccb->NotifyMask.Length = 0; Ccb->NotifyMask.MaximumLength = 1024; Ccb->NotifyMask.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, Ccb->NotifyMask.MaximumLength, AFS_GENERIC_MEMORY_7_TAG); if( Ccb->NotifyMask.Buffer == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } ntStatus = RtlStringCbPrintfW( Ccb->NotifyMask.Buffer, Ccb->NotifyMask.MaximumLength, L"\\%08lX.%08lX.%08lX.%08lX", ObjectInfo->FileId.Cell, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); if( !NT_SUCCESS( ntStatus)) { try_return( ntStatus); } ntStatus = RtlStringCbLengthW( Ccb->NotifyMask.Buffer, (size_t)Ccb->NotifyMask.MaximumLength, &sztLength); if( !NT_SUCCESS( ntStatus)) { try_return( ntStatus); } Ccb->NotifyMask.Length = (USHORT)sztLength; } AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSFsRtlNotifyFullChangeDirectory Registering notification on %wZ Irp %08lX Filter %08lX Tree %02lX\n", &Ccb->NotifyMask, NotifyIrp, CompletionFilter, WatchTree); FsRtlNotifyFilterChangeDirectory( pDeviceExt->Specific.Control.NotifySync, &pDeviceExt->Specific.Control.DirNotifyList, (void *)Ccb, (PSTRING)&Ccb->NotifyMask, WatchTree, TRUE, CompletionFilter, NotifyIrp, NULL, NULL, NULL); try_exit: if( !NT_SUCCESS( ntStatus)) { if( Ccb->NotifyMask.Buffer != NULL) { AFSExFreePool( Ccb->NotifyMask.Buffer); Ccb->NotifyMask.Buffer = NULL; } } } return ntStatus; } void AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ParentObjectInfo, IN AFSCcb *Ccb, IN ULONG NotifyFilter, IN ULONG NotificationAction) { NTSTATUS ntStatus = STATUS_SUCCESS; AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; UNICODE_STRING uniName, uniComponentName; size_t sztLength; USHORT usNameOffset = 0; __Enter { uniName.Buffer = NULL; if( ParentObjectInfo == NULL || AFSGlobalRoot == NULL) { try_return( ntStatus); } if( Ccb == NULL) { RtlInitUnicodeString( &uniComponentName, L"_AFSChange.dat"); } else { uniComponentName = Ccb->DirectoryCB->NameInformation.FileName; } // // Build a dir name based on the FID of the file // uniName.Length = 0; uniName.MaximumLength = 1024 + uniComponentName.Length; uniName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, uniName.MaximumLength, AFS_GENERIC_MEMORY_8_TAG); if( uniName.Buffer == NULL) { try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); } ntStatus = RtlStringCbPrintfW( uniName.Buffer, uniName.MaximumLength, L"\\%08lX.%08lX.%08lX.%08lX\\%wZ", ParentObjectInfo->FileId.Cell, ParentObjectInfo->FileId.Volume, ParentObjectInfo->FileId.Vnode, ParentObjectInfo->FileId.Unique, &uniComponentName); if( !NT_SUCCESS( ntStatus)) { try_return( ntStatus); } ntStatus = RtlStringCbLengthW( uniName.Buffer, (size_t)uniName.MaximumLength, &sztLength); if( !NT_SUCCESS( ntStatus)) { try_return( ntStatus); } uniName.Length = (USHORT)sztLength; usNameOffset = uniName.Length - uniComponentName.Length; AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NOTIF_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSFsRtlNotifyFullReportChange Notification call for %wZ Filter %08lX Action %08lX Offset %08lX Len %08lX CompLen %08lX\n", &uniName, NotifyFilter, NotificationAction, usNameOffset, uniName.Length, uniComponentName.Length); FsRtlNotifyFilterReportChange( pDeviceExt->Specific.Control.NotifySync, &pDeviceExt->Specific.Control.DirNotifyList, (PSTRING)&uniName, usNameOffset, NULL, NULL, NotifyFilter, NotificationAction, NULL, (void *)Ccb); try_exit: if( uniName.Buffer != NULL) { AFSExFreePool( uniName.Buffer); } } return; } // For use with FsRtlNotifyFilterChangeDirectory but must // be implemented in the Framework because the library can // be unloaded. BOOLEAN AFSNotifyReportChangeCallback( IN void *NotifyContext, IN void *FilterContext) { BOOLEAN bReturn = TRUE; AFSCcb *pDirCcb = (AFSCcb *)NotifyContext; AFSCcb *pNotifyCcb = (AFSCcb *)FilterContext; __Enter { } return bReturn; } BOOLEAN AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr, IN ULONG HashIndex) { BOOLEAN bIsInSnapshot = FALSE; AFSSnapshotEntry *pSnapshotEntry = SnapshotHdr->TopEntry; ULONG ulCount = 0; while( ulCount < SnapshotHdr->EntryCount) { if( pSnapshotEntry->NameHash == HashIndex) { bIsInSnapshot = TRUE; AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSIsNameInSnapshot Hash index %08lX already in snapshot\n", HashIndex); break; } else if( pSnapshotEntry->NameHash == 0) { break; } pSnapshotEntry++; ulCount++; } return bIsInSnapshot; }