From: Peter Scott Date: Sat, 29 Oct 2011 17:55:46 +0000 (-0400) Subject: Windows: Directory Entry Processing X-Git-Tag: openafs-stable-1_8_0pre1~3109 X-Git-Url: https://git.openafs.org/?p=openafs.git;a=commitdiff_plain;h=af3dbb34a1ff226ac693c143f8e9d94ced4114c9 Windows: Directory Entry Processing Memory corruption was detected due to improper handling of directory entries and the short name b-tree during directory revalidation and tear down. The problem resulted in a BSOD most frequently when roaming profiles were written back to the file server or when multiple clients were actively modifying the contents of a directory simultaneously. This patchset makes a number of changes: . rename processing no longer handles collisions locally. the file server replaces a target atomicly when there is a collision. . directory validation is no longer delayed until a handle is closed . data version numbers are checked for implied invalidation Change-Id: Ib4b281bfb5da4b5a5ce735e85d85c50e15fbcde1 Reviewed-on: http://gerrit.openafs.org/5736 Tested-by: BuildBot Reviewed-by: Rod Widdowson Reviewed-by: Jeffrey Altman Tested-by: Jeffrey Altman --- diff --git a/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp index 5320e7e..0e4331d 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp @@ -1083,6 +1083,8 @@ AFSInsertShortNameDirEntry( IN AFSDirectoryCB *RootNode, else { + ntStatus = STATUS_UNSUCCESSFUL; + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSInsertShortNameDirEntry Collision with DE %p for shortname %S and %wZ\n", diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp index c5d380c..df5ce4b 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp @@ -263,17 +263,35 @@ AFSEnumerateDirectory( IN GUID *AuthGroup, // uniShortName.Length = pDirNode->NameInformation.ShortNameLength; + uniShortName.MaximumLength = uniShortName.Length; uniShortName.Buffer = pDirNode->NameInformation.ShortName; - pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, - TRUE); + if( !RtlIsNameLegalDOS8Dot3( &pDirNode->NameInformation.FileName, + NULL, + NULL)) + { - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSEnumerateDirectory Initialized short name %wZ for DE %p for %wZ\n", - &uniShortName, - pDirNode, - &pDirNode->NameInformation.FileName); + pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, + TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateDirectory Initialized short name %wZ for DE %p for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &uniShortName, + pDirNode, + &pDirNode->NameInformation.FileName, + pCurrentDirEntry->FileId.Cell, + pCurrentDirEntry->FileId.Volume, + pCurrentDirEntry->FileId.Vnode, + pCurrentDirEntry->FileId.Unique); + } + else + { + pDirNode->NameInformation.ShortNameLength = 0; + + RtlZeroMemory( pDirNode->NameInformation.ShortName, + (12 * sizeof( WCHAR))); + } } // @@ -302,10 +320,34 @@ AFSEnumerateDirectory( IN GUID *AuthGroup, pDirNode, &pDirNode->NameInformation.FileName); - AFSInsertCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, - pDirNode); + if( !NT_SUCCESS( AFSInsertCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + pDirNode))) + { + + // + // Delete this dir entry and continue on + // + + AFSDeleteDirEntry( ObjectInfoCB, + pDirNode); + + pCurrentDirEntry = (AFSDirEnumEntry *)((char *)pCurrentDirEntry + ulEntryLength); + + if( ulResultLen >= ulEntryLength) + { + ulResultLen -= ulEntryLength; + } + else + { + ulResultLen = 0; + } + + continue; + } } + ClearFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); + if( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead == NULL) { @@ -378,18 +420,23 @@ AFSEnumerateDirectory( IN GUID *AuthGroup, &pDirNode->NameInformation.FileName); ObjectInfoCB->Specific.Directory.ShortNameTree = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); } else { - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSEnumerateDirectory Insert DE %p to shortname tree for %wZ\n", - pDirNode, - &pDirNode->NameInformation.FileName); + if( NT_SUCCESS( AFSInsertShortNameDirEntry( ObjectInfoCB->Specific.Directory.ShortNameTree, + pDirNode))) + { + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); - AFSInsertShortNameDirEntry( ObjectInfoCB->Specific.Directory.ShortNameTree, - pDirNode); + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateDirectory Insert DE %p to shortname tree for %wZ\n", + pDirNode, + &pDirNode->NameInformation.FileName); + } } } @@ -907,10 +954,38 @@ AFSVerifyDirectoryContent( IN AFSObjectInfoCB *ObjectInfoCB, // uniShortName.Length = pDirNode->NameInformation.ShortNameLength; + uniShortName.MaximumLength = uniShortName.Length; uniShortName.Buffer = pDirNode->NameInformation.ShortName; - pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, - TRUE); + if( !RtlIsNameLegalDOS8Dot3( &pDirNode->NameInformation.FileName, + NULL, + NULL)) + { + + pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, + TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Initialized short name %wZ for DE %p for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &uniShortName, + pDirNode, + &pDirNode->NameInformation.FileName, + pCurrentDirEntry->FileId.Cell, + pCurrentDirEntry->FileId.Volume, + pCurrentDirEntry->FileId.Vnode, + pCurrentDirEntry->FileId.Unique); + } + else + { + pDirNode->NameInformation.ShortNameLength = 0; + + RtlZeroMemory( pDirNode->NameInformation.ShortName, + (12 * sizeof( WCHAR))); + } + } + else + { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, @@ -943,16 +1018,47 @@ AFSVerifyDirectoryContent( IN AFSObjectInfoCB *ObjectInfoCB, else { - AFSInsertCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, - pDirNode); + if( !NT_SUCCESS( AFSInsertCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + pDirNode))) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Failed to nsert DE %p to case sensitive tree for %wZ\n", + pDirNode, + &pDirNode->NameInformation.FileName); + + // + // Delete this dir entry and continue on + // - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSVerifyDirectoryContent Insert DE %p to case sensitive tree for %wZ\n", - pDirNode, - &pDirNode->NameInformation.FileName); + AFSDeleteDirEntry( ObjectInfoCB, + pDirNode); + + pCurrentDirEntry = (AFSDirEnumEntry *)((char *)pCurrentDirEntry + ulEntryLength); + + if( ulResultLen >= ulEntryLength) + { + ulResultLen -= ulEntryLength; + } + else + { + ulResultLen = 0; + } + + continue; + } + else + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Insert DE %p to case sensitive tree for %wZ\n", + pDirNode, + &pDirNode->NameInformation.FileName); + } } + ClearFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); + if( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead == NULL) { @@ -1025,18 +1131,32 @@ AFSVerifyDirectoryContent( IN AFSObjectInfoCB *ObjectInfoCB, "AFSVerifyDirectoryContent Insert DE %p to head of shortname tree for %wZ\n", pDirNode, &pDirNode->NameInformation.FileName); + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); } else { - AFSInsertShortNameDirEntry( ObjectInfoCB->Specific.Directory.ShortNameTree, - pDirNode); + if( !NT_SUCCESS( AFSInsertShortNameDirEntry( ObjectInfoCB->Specific.Directory.ShortNameTree, + pDirNode))) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Failed to insert DE %p (%08lX) to shortname tree for %wZ\n", + pDirNode, + pDirNode->Type.Data.ShortNameTreeEntry.HashIndex, + &pDirNode->NameInformation.FileName); + } + else + { + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSVerifyDirectoryContent Insert DE %p to shortname tree for %wZ\n", - pDirNode, - &pDirNode->NameInformation.FileName); + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Insert DE %p to shortname tree for %wZ\n", + pDirNode, + &pDirNode->NameInformation.FileName); + } } } @@ -1589,14 +1709,59 @@ AFSNotifyRename( IN AFSObjectInfoCB *ObjectInfo, if( DirectoryCB->NameInformation.ShortNameLength > 0) { + UNICODE_STRING uniShortName; + + uniShortName.Length = DirectoryCB->NameInformation.ShortNameLength; + uniShortName.MaximumLength = uniShortName.Length; + uniShortName.Buffer = DirectoryCB->NameInformation.ShortName; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNotifyRename Update old short name %wZ for DE %p for %wZ\n", + &uniShortName, + DirectoryCB, + &DirectoryCB->NameInformation.FileName); + + DirectoryCB->NameInformation.ShortNameLength = pRenameResultCB->DirEnum.ShortNameLength; + RtlCopyMemory( DirectoryCB->NameInformation.ShortName, pRenameResultCB->DirEnum.ShortName, DirectoryCB->NameInformation.ShortNameLength); + + uniShortName.Length = DirectoryCB->NameInformation.ShortNameLength; + uniShortName.MaximumLength = uniShortName.Length; + uniShortName.Buffer = DirectoryCB->NameInformation.ShortName; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNotifyRename Initialized short name %wZ for DE %p for %wZ\n", + &uniShortName, + DirectoryCB, + &DirectoryCB->NameInformation.FileName); + } + else + { + + UNICODE_STRING uniShortName; + + uniShortName.Length = DirectoryCB->NameInformation.ShortNameLength; + uniShortName.MaximumLength = uniShortName.Length; + uniShortName.Buffer = DirectoryCB->NameInformation.ShortName; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNotifyRename Removing old short name %wZ for DE %p for %wZ\n", + &uniShortName, + DirectoryCB, + &DirectoryCB->NameInformation.FileName); + + DirectoryCB->NameInformation.ShortNameLength = 0; + + DirectoryCB->Type.Data.ShortNameTreeEntry.HashIndex = 0; } if( UpdatedFID != NULL) { - *UpdatedFID = pRenameResultCB->DirEnum.FileId; } diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp index e9412e4..0143aed 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp @@ -1776,6 +1776,43 @@ AFSProcessCreate( IN PIRP Irp, pObjectInfo = pDirEntry->ObjectInformation; + if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED) || + pObjectInfo->FileType == AFS_FILE_TYPE_UNKNOWN) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate (%08lX) Evaluating object %wZ FID %08lX-%08lX-%08lX-%08lX\n", + Irp, + &pDirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + ntStatus = AFSEvaluateNode( AuthGroup, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessCreate (%08lX) Failed to evaluate object %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + Irp, + &pDirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED); + } + // // We may have raced and the Fcb is already created // @@ -2030,8 +2067,24 @@ try_exit: AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, TRUE); - AFSDeleteDirEntry( pParentObjectInfo, - pDirEntry); + SetFlag( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED); + + // + // Pull the directory entry from the parent + // + + AFSRemoveDirNodeFromParent( pParentObjectInfo, + pDirEntry, + FALSE); // Leave it in the enum list so the worker cleans it up + + AFSNotifyDelete( pDirEntry, + FALSE); + + // + // Tag the parent as needing verification + // + + SetFlag( pParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); } diff --git a/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp index ca759ff..7cf9da4 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp @@ -262,16 +262,75 @@ AFSQueryDirectory( IN PIRP Irp) } // - // Grab the directory node hdr tree lock shared while parsing the directory + // Grab the directory node hdr tree lock while parsing the directory // contents // - AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, - TRUE); + 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( &pFcb->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 // @@ -295,7 +354,8 @@ AFSQueryDirectory( IN PIRP Irp) { ntStatus = AFSSnapshotDirectory( pFcb, - pCcb); + pCcb, + TRUE); if( !NT_SUCCESS( ntStatus)) { @@ -540,7 +600,7 @@ AFSQueryDirectory( IN PIRP Irp) FileInformationClass); try_return( ntStatus = STATUS_INVALID_INFO_CLASS); - } + } AFSReleaseResource( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); @@ -595,6 +655,8 @@ AFSQueryDirectory( IN PIRP Irp) BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED)) { + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + continue; } @@ -617,6 +679,8 @@ AFSQueryDirectory( IN PIRP Irp) if( !FlagOn( pObjectInfo->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) { + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + continue; } } @@ -636,6 +700,8 @@ AFSQueryDirectory( IN PIRP Irp) NULL)) { + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + continue; } } @@ -656,6 +722,8 @@ AFSQueryDirectory( IN PIRP Irp) TRUE)) { + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + continue; } } @@ -729,6 +797,8 @@ AFSQueryDirectory( IN PIRP Irp) pCcb->CurrentDirIndex--; + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + try_return( ntStatus = STATUS_SUCCESS); } @@ -849,6 +919,8 @@ AFSQueryDirectory( IN PIRP Irp) Irp, FileInformationClass); + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + try_return( ntStatus = STATUS_INVALID_INFO_CLASS); break; @@ -874,9 +946,13 @@ AFSQueryDirectory( IN PIRP Irp) 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 @@ -1109,6 +1185,9 @@ AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo, // Get to a valid entry // + AFSAcquireShared( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + while( ulCount < pSnapshotHdr->EntryCount) { @@ -1145,6 +1224,8 @@ AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo, ObjectInfo->FileId.Volume, ObjectInfo->FileId.Vnode, ObjectInfo->FileId.Unique); + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); } else { @@ -1177,6 +1258,8 @@ AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo, Ccb->CurrentDirIndex++; } + + AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); } try_exit: @@ -1281,7 +1364,8 @@ try_exit: NTSTATUS AFSSnapshotDirectory( IN AFSFcb *Fcb, - IN AFSCcb *Ccb) + IN AFSCcb *Ccb, + IN BOOLEAN ResetIndex) { NTSTATUS ntStatus = STATUS_SUCCESS; @@ -1292,19 +1376,23 @@ AFSSnapshotDirectory( IN AFSFcb *Fcb, __Enter { - // - // Set it up so we still get the . and .. entries for empty directories - // - - if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES)) + if( ResetIndex) { - Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_DIR_INDEX; - } - else - { + // + // 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; + Ccb->CurrentDirIndex = AFS_DIR_ENTRY_INITIAL_ROOT_INDEX; + } } if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeCount == 0) diff --git a/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp b/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp index bc7967c..c08a020 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp @@ -1746,12 +1746,13 @@ AFSSetRenameInfo( IN PIRP Irp) AFSObjectInfoCB *pSrcObject = NULL, *pTargetObject = NULL; AFSObjectInfoCB *pSrcParentObject = NULL, *pTargetParentObject = NULL; AFSFileID stNewFid, stTmpTargetFid; - UNICODE_STRING uniTmpTargetName; - BOOLEAN bReplaceTmpTargetEntry = FALSE; ULONG ulNotificationAction = 0, ulNotifyFilter = 0; UNICODE_STRING uniFullTargetPath; BOOLEAN bCommonParent = FALSE; ULONG oldFileIndex; + BOOLEAN bReleaseVolumeLock = FALSE; + BOOLEAN bReleaseTargetDirLock = FALSE; + BOOLEAN bReleaseSourceDirLock = FALSE; __Enter { @@ -1763,10 +1764,6 @@ AFSSetRenameInfo( IN PIRP Irp) pSrcObject = pSrcFcb->ObjectInformation; - uniTmpTargetName.Length = 0; - uniTmpTargetName.MaximumLength = 0; - uniTmpTargetName.Buffer = NULL; - // // Perform some basic checks to ensure FS integrity // @@ -1879,14 +1876,26 @@ AFSSetRenameInfo( IN PIRP Irp) // If the target exists be sure the ReplaceIfExists flag is set // - AFSAcquireShared( pTargetParentObject->VolumeCB->VolumeLock, - TRUE); + AFSAcquireExcl( pTargetParentObject->VolumeCB->VolumeLock, + TRUE); + + bReleaseVolumeLock = TRUE; ulTargetCRC = AFSGenerateCRC( &uniTargetName, FALSE); - AFSAcquireShared( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.TreeLock, - TRUE); + AFSAcquireExcl( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + bReleaseTargetDirLock = TRUE; + + if( pTargetParentObject != pSrcFcb->ObjectInformation->ParentObjectInformation) + { + AFSAcquireExcl( pSrcFcb->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + bReleaseSourceDirLock = TRUE; + } AFSLocateCaseSensitiveDirEntry( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, ulTargetCRC, @@ -1918,25 +1927,21 @@ AFSSetRenameInfo( IN PIRP Irp) ulTargetCRC, &pTargetDirEntry); } + // // Increment our ref count on the dir entry // if( pTargetDirEntry != NULL) { - InterlockedIncrement( &pTargetDirEntry->OpenReferenceCount); - } - AFSReleaseResource( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + ASSERT( pTargetParentObject == pTargetDirEntry->ObjectInformation->ParentObjectInformation); - if( pTargetDirEntry != NULL) - { + InterlockedIncrement( &pTargetDirEntry->OpenReferenceCount); if( !bReplaceIfExists) { - AFSReleaseResource( pTargetParentObject->VolumeCB->VolumeLock); - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_ERROR, "AFSSetRenameInfo Attempt to rename directory with target collision %wZ Target %wZ\n", @@ -1953,10 +1958,22 @@ AFSSetRenameInfo( IN PIRP Irp) pTargetDirEntry, pTargetDirEntry->OpenReferenceCount); + // + // Pull the directory entry from the parent + // + + AFSRemoveDirNodeFromParent( pTargetParentObject, + pTargetDirEntry, + FALSE); + bTargetEntryExists = TRUE; } - - AFSReleaseResource( pTargetParentObject->VolumeCB->VolumeLock); + else + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Target Target does NOT exist, normal rename\n"); + } // // Extract off the final component name from the Fcb @@ -1980,29 +1997,9 @@ AFSSetRenameInfo( IN PIRP Irp) if( FsRtlAreNamesEqual( &uniTargetName, &uniSourceName, - TRUE, + FALSE, NULL)) { - - // - // Check for case only rename - // - - if( !FsRtlAreNamesEqual( &uniTargetName, - &uniSourceName, - FALSE, - NULL)) - { - - // - // Just move in the new case form of the name - // - - RtlCopyMemory( pSrcCcb->DirectoryCB->NameInformation.FileName.Buffer, - uniTargetName.Buffer, - uniTargetName.Length); - } - try_return( ntStatus = STATUS_SUCCESS); } } @@ -2013,123 +2010,17 @@ AFSSetRenameInfo( IN PIRP Irp) } // - // If the target name exists then we need to 'move' the target before - // sending the rename to the service - // - - if( bReplaceIfExists && - pTargetDirEntry != NULL) - { - - // - // What we will do is temporarily rename the file to a tmp file - // so we can back out if anything fails below - // First thing is to remove the original target from the parent - // - - AFSAcquireExcl( pTargetDirEntry->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, - TRUE); - - AFSRemoveDirNodeFromParent( pTargetDirEntry->ObjectInformation->ParentObjectInformation, - pTargetDirEntry, - TRUE); - - AFSReleaseResource( pTargetDirEntry->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); - - pTargetDirEntry->FileIndex = (ULONG)InterlockedIncrement( &pTargetDirEntry->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.ContentIndex); - - uniTmpTargetName.Length = 0; - uniTmpTargetName.MaximumLength = uniTargetName.Length + (4 * sizeof( WCHAR)); - - uniTmpTargetName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, - uniTmpTargetName.MaximumLength, - AFS_GENERIC_MEMORY_11_TAG); - - if( uniTmpTargetName.Buffer == NULL) - { - - // - // Re-insert the entry - // - - AFSInsertDirectoryNode( pTargetDirEntry->ObjectInformation->ParentObjectInformation, - pTargetDirEntry, - TRUE); - - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_ERROR, - "AFSSetRenameInfo Failed tmp buffer allocation during rename of %wZ\n", - &pSrcCcb->DirectoryCB->NameInformation.FileName); - - try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); - } - - RtlZeroMemory( uniTmpTargetName.Buffer, - uniTmpTargetName.MaximumLength); - - uniTmpTargetName.Length = uniTargetName.Length; - - RtlCopyMemory( uniTmpTargetName.Buffer, - uniTargetName.Buffer, - uniTmpTargetName.Length); - - RtlCopyMemory( &uniTmpTargetName.Buffer[ uniTmpTargetName.Length/sizeof( WCHAR)], - L".tmp", - 4 * sizeof( WCHAR)); - - uniTmpTargetName.Length += (4 * sizeof( WCHAR)); - - ntStatus = AFSNotifyRename( pTargetDirEntry->ObjectInformation, - pTargetDirEntry->ObjectInformation->ParentObjectInformation, - pTargetDcb->ObjectInformation, - pTargetDirEntry, - &uniTmpTargetName, - &stTmpTargetFid); - - if( !NT_SUCCESS( ntStatus)) - { - - // - // Re-insert the entry - // - - AFSInsertDirectoryNode( pTargetDirEntry->ObjectInformation->ParentObjectInformation, - pTargetDirEntry, - TRUE); - - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_ERROR, - "AFSSetRenameInfo Failed rename of %wZ to tmp %wZ Status %08lX\n", - &pSrcCcb->DirectoryCB->NameInformation.FileName, - &uniTmpTargetName, - ntStatus); - - try_return( ntStatus); - } - - // - // Indicate we need to replace this entry if any failure occurs below - // - - bReplaceTmpTargetEntry = TRUE; - } - - // // We need to remove the DirEntry from the parent node, update the index // and reinsert it into the parent tree. Note that for entries with the // same parent we do not pull the node from the enumeration list // - AFSAcquireExcl( pSrcFcb->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, - TRUE); - AFSRemoveDirNodeFromParent( pSrcFcb->ObjectInformation->ParentObjectInformation, pSrcCcb->DirectoryCB, !bCommonParent); - AFSReleaseResource( pSrcFcb->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); - oldFileIndex = pSrcCcb->DirectoryCB->FileIndex; + if( !bCommonParent) { @@ -2182,7 +2073,7 @@ AFSSetRenameInfo( IN PIRP Irp) // if( pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation == pTargetParentObject && - !bReplaceTmpTargetEntry) + !bTargetEntryExists) { ulNotificationAction = FILE_ACTION_RENAMED_OLD_NAME; @@ -2250,9 +2141,6 @@ AFSSetRenameInfo( IN PIRP Irp) // Remove the old information entry // - AFSAcquireExcl( pSrcObject->VolumeCB->ObjectInfoTree.TreeLock, - TRUE); - AFSRemoveHashEntry( &pSrcObject->VolumeCB->ObjectInfoTree.TreeHead, &pSrcObject->TreeEntry); @@ -2277,8 +2165,6 @@ AFSSetRenameInfo( IN PIRP Irp) AFSInsertHashEntry( pSrcObject->VolumeCB->ObjectInfoTree.TreeHead, &pSrcObject->TreeEntry); } - - AFSReleaseResource( pSrcObject->VolumeCB->ObjectInfoTree.TreeLock); } // @@ -2291,10 +2177,14 @@ AFSSetRenameInfo( IN PIRP Irp) pSrcCcb->DirectoryCB->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pSrcCcb->DirectoryCB->NameInformation.FileName, TRUE); - if( pSrcCcb->DirectoryCB->NameInformation.ShortNameLength > 0) + if( pSrcCcb->DirectoryCB->NameInformation.ShortNameLength > 0 && + !RtlIsNameLegalDOS8Dot3( &pSrcCcb->DirectoryCB->NameInformation.FileName, + NULL, + NULL)) { uniShortName.Length = pSrcCcb->DirectoryCB->NameInformation.ShortNameLength; + uniShortName.MaximumLength = uniShortName.Length; uniShortName.Buffer = pSrcCcb->DirectoryCB->NameInformation.ShortName; pSrcCcb->DirectoryCB->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, @@ -2369,49 +2259,9 @@ AFSSetRenameInfo( IN PIRP Irp) // delete the tmp target we created above // - if( bReplaceTmpTargetEntry) + if( bTargetEntryExists) { - RtlCopyMemory( &pTargetDirEntry->ObjectInformation->FileId, - &stTmpTargetFid, - sizeof( AFSFileID)); - - // - // Update the name in the dir entry - // - - ntStatus = AFSUpdateDirEntryName( pTargetDirEntry, - &uniTmpTargetName); - - if( !NT_SUCCESS( ntStatus)) - { - - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_ERROR, - "AFSSetRenameInfo Failed update of target dir entry %wZ to tmp %wZ Status %08lX\n", - &pTargetDirEntry->NameInformation.FileName, - &uniTmpTargetName, - ntStatus); - - try_return( ntStatus); - } - - ntStatus = AFSNotifyDelete( pTargetDirEntry, - FALSE); - - if( !NT_SUCCESS( ntStatus)) - { - - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSSetRenameInfo object deletion failure dir entry %p name %wZ to tmp %wZ\n", - pTargetDirEntry, - &pTargetDirEntry->NameInformation.FileName, - &uniTmpTargetName); - - try_return( ntStatus); - } - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, "AFSSetRenameInfo Setting DELETE flag in dir entry %p name %wZ\n", @@ -2435,11 +2285,11 @@ AFSSetRenameInfo( IN PIRP Irp) TRUE); // - // Try and flush the cache map + // Close the section in the event it was mapped // - if( !MmFlushImageSection( &pTargetFcb->NPFcb->SectionObjectPointers, - MmFlushForDelete)) + if( !MmForceSectionClosed( &pTargetFcb->NPFcb->SectionObjectPointers, + TRUE)) { AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, @@ -2453,54 +2303,19 @@ AFSSetRenameInfo( IN PIRP Irp) ASSERT( pTargetDirEntry->OpenReferenceCount > 0); - InterlockedDecrement( &pTargetDirEntry->OpenReferenceCount); + InterlockedDecrement( &pTargetDirEntry->OpenReferenceCount); // The count we added above if( pTargetDirEntry->OpenReferenceCount == 0) { - SetFlag( pTargetDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED); - - ASSERT( BooleanFlagOn( pTargetDirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)); - - // - // Free up the name buffer if it was reallocated - // - - if( BooleanFlagOn( pTargetDirEntry->Flags, AFS_DIR_RELEASE_NAME_BUFFER)) - { - - AFSExFreePool( pTargetDirEntry->NameInformation.FileName.Buffer); - } - - if( BooleanFlagOn( pTargetDirEntry->Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER)) - { - - AFSExFreePool( pTargetDirEntry->NameInformation.TargetName.Buffer); - } - - // - // Dereference the object for this dir entry - // - - ASSERT( pTargetDirEntry->ObjectInformation->ObjectReferenceCount > 0); - - InterlockedDecrement( &pTargetDirEntry->ObjectInformation->ObjectReferenceCount); - - AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE, - "AFSSetRenameInfo Decrement3 count on object %08lX Cnt %d\n", - pTargetDirEntry->ObjectInformation, - pTargetDirEntry->ObjectInformation->ObjectReferenceCount); - - // - // Free up the dir entry - // - - ExDeleteResourceLite( &pTargetDirEntry->NonPaged->Lock); - - AFSExFreePool( pTargetDirEntry->NonPaged); + "AFSSetRenameInfo Deleting dir entry %p name %wZ\n", + pTargetDirEntry, + &pTargetDirEntry->NameInformation.FileName); - AFSExFreePool( pTargetDirEntry); + AFSDeleteDirEntry( pTargetParentObject, + pTargetDirEntry); } pTargetDirEntry = NULL; @@ -2512,46 +2327,11 @@ try_exit: if( !NT_SUCCESS( ntStatus)) { - if( bReplaceTmpTargetEntry) + if( bTargetEntryExists) { - - AFSNotifyRename( pTargetDirEntry->ObjectInformation, - pTargetDirEntry->ObjectInformation->ParentObjectInformation, - pTargetDcb->ObjectInformation, - pTargetDirEntry, - &uniTargetName, - &stTmpTargetFid); - - // - // Replace the target entry - // - - AFSAcquireExcl( pTargetDirEntry->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock, - TRUE); - - if( pTargetDirEntry->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead == NULL) - { - - pTargetDirEntry->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead = &pTargetDirEntry->ObjectInformation->TreeEntry; - } - else - { - AFSInsertHashEntry( pTargetDirEntry->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead, - &pTargetDirEntry->ObjectInformation->TreeEntry); - } - - AFSReleaseResource( pTargetDirEntry->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock); - - // - // We always need to update the FileIndex since this entry will be put at the 'end' - // of the enumeraiton list. If we don't it will cause recursion ... - // - - pTargetDirEntry->FileIndex = (ULONG)InterlockedIncrement( &pTargetDirEntry->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.ContentIndex); - AFSInsertDirectoryNode( pTargetDirEntry->ObjectInformation->ParentObjectInformation, pTargetDirEntry, - TRUE); + FALSE); } } @@ -2561,10 +2341,19 @@ try_exit: InterlockedDecrement( &pTargetDirEntry->OpenReferenceCount); } - if( uniTmpTargetName.Buffer != NULL) + if( bReleaseVolumeLock) { + AFSReleaseResource( pTargetParentObject->VolumeCB->VolumeLock); + } - AFSExFreePool( uniTmpTargetName.Buffer); + if( bReleaseTargetDirLock) + { + AFSReleaseResource( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + if( bReleaseSourceDirLock) + { + AFSReleaseResource( pSrcFcb->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); } } diff --git a/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp b/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp index 4251e74..3fa2e59 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp @@ -1022,10 +1022,10 @@ AFSInitDirEntry( IN AFSObjectInfoCB *ParentObjectInfo, pDirNode->ObjectInformation = pObjectInfoCB; // - // Set valid entry + // Set valid entry and NOT_IN_PARENT flag // - SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID); + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID | AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); pDirNode->FileIndex = FileIndex; @@ -3246,20 +3246,62 @@ AFSValidateDirectoryCache( IN AFSObjectInfoCB *ObjectInfo, while( pCurrentDirEntry != NULL) { + pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_FAKE)) { - ClearFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID); + // + // If this entry has been deleted then process it here + // - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSValidateDirectoryCache Clear VALID flag on DE %p Reference count %08lX\n", - pCurrentDirEntry, - pCurrentDirEntry->OpenReferenceCount); + if( BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_DELETED) && + pCurrentDirEntry->OpenReferenceCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Deleting dir entry %p name %wZ\n", + pCurrentDirEntry, + &pCurrentDirEntry->NameInformation.FileName); + + AFSDeleteDirEntry( ObjectInfo, + pCurrentDirEntry); + } + else + { + + ClearFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID); + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Clear VALID flag on DE %p Reference count %08lX\n", + pCurrentDirEntry, + pCurrentDirEntry->OpenReferenceCount); + + // + // We pull the short name from the parent tree since it could change below + // + + if( BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Removing DE %p (%08lX) from shortname tree for %wZ\n", + pCurrentDirEntry, + pCurrentDirEntry->Type.Data.ShortNameTreeEntry.HashIndex, + &pCurrentDirEntry->NameInformation.FileName); + + AFSRemoveShortNameDirEntry( &ObjectInfo->Specific.Directory.ShortNameTree, + pCurrentDirEntry); + + ClearFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); + } + } } - pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + pCurrentDirEntry = pNextDirEntry; } // @@ -3283,6 +3325,49 @@ AFSValidateDirectoryCache( IN AFSObjectInfoCB *ObjectInfo, if( BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID)) { + if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME) && + pCurrentDirEntry->Type.Data.ShortNameTreeEntry.HashIndex > 0) + { + + if( ObjectInfo->Specific.Directory.ShortNameTree == NULL) + { + + ObjectInfo->Specific.Directory.ShortNameTree = pCurrentDirEntry; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Insert DE %p to head of shortname tree for %wZ\n", + pCurrentDirEntry, + &pCurrentDirEntry->NameInformation.FileName); + + SetFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); + } + else + { + + if( !NT_SUCCESS( AFSInsertShortNameDirEntry( ObjectInfo->Specific.Directory.ShortNameTree, + pCurrentDirEntry))) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Failed to insert DE %p (%08lX) to shortname tree for %wZ\n", + pCurrentDirEntry, + pCurrentDirEntry->Type.Data.ShortNameTreeEntry.HashIndex, + &pCurrentDirEntry->NameInformation.FileName); + } + else + { + SetFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Insert DE %p to shortname tree for %wZ\n", + pCurrentDirEntry, + &pCurrentDirEntry->NameInformation.FileName); + } + } + } + pCurrentDirEntry = pNextDirEntry; continue; @@ -6958,8 +7043,7 @@ AFSRemoveNameEntry( IN AFSObjectInfoCB *ParentObjectInfo, AFSRemoveCaseInsensitiveDirEntry( &ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, DirEntry); - if( ParentObjectInfo->Specific.Directory.ShortNameTree && - DirEntry->Type.Data.ShortNameTreeEntry.HashIndex != 0) + if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME)) { // @@ -6974,6 +7058,8 @@ AFSRemoveNameEntry( IN AFSObjectInfoCB *ParentObjectInfo, AFSRemoveShortNameDirEntry( &ParentObjectInfo->Specific.Directory.ShortNameTree, DirEntry); + + ClearFlag( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); } AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, @@ -6984,6 +7070,8 @@ AFSRemoveNameEntry( IN AFSObjectInfoCB *ParentObjectInfo, SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); + ClearFlag( DirEntry->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + try_exit: NOTHING; @@ -7119,7 +7207,7 @@ AFSValidateDirList( IN AFSObjectInfoCB *ObjectInfo) BOOLEAN bIsValid = TRUE; ULONG ulCount = 0; - AFSDirectoryCB *pCurrentDirEntry = NULL; + AFSDirectoryCB *pCurrentDirEntry = NULL, *pDirEntry = NULL; pCurrentDirEntry = ObjectInfo->Specific.Directory.DirectoryNodeListHead; @@ -7129,6 +7217,21 @@ AFSValidateDirList( IN AFSObjectInfoCB *ObjectInfo) if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_FAKE)) { ulCount++; + + if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) + { + + pDirEntry = NULL; + + AFSLocateCaseSensitiveDirEntry( ObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + (ULONG)pCurrentDirEntry->CaseSensitiveTreeEntry.HashIndex, + &pDirEntry); + + if( pDirEntry == NULL) + { + DbgBreakPoint(); + } + } } pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; diff --git a/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp index f4fad07..26b6e51 100644 --- a/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp +++ b/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp @@ -1943,7 +1943,7 @@ AFSCreateDirEntry( IN GUID *AuthGroup, { NTSTATUS ntStatus = STATUS_SUCCESS; - AFSDirectoryCB *pDirNode = NULL; + AFSDirectoryCB *pDirNode = NULL, *pExistingDirNode = NULL; UNICODE_STRING uniShortName; LARGE_INTEGER liFileSize = {0,0}; @@ -2005,6 +2005,68 @@ AFSCreateDirEntry( IN GUID *AuthGroup, try_return( ntStatus); } + AFSAcquireExcl( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + // + // Before attempting to insert the new entry, check if we need to validate the parent + // + + if( BooleanFlagOn( ParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreateDirEntry Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &ParentDirCB->NameInformation.FileName, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique); + + ntStatus = AFSVerifyEntry( AuthGroup, + ParentDirCB); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCreateDirEntry Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &ParentDirCB->NameInformation.FileName, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique, + ntStatus); + + AFSReleaseResource( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + + try_return( ntStatus); + } + } + + // + // Check for the entry in the event we raced with some other thread + // + + AFSLocateCaseSensitiveDirEntry( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + (ULONG)pDirNode->CaseSensitiveTreeEntry.HashIndex, + &pExistingDirNode); + + if( pExistingDirNode != NULL) + { + + AFSDeleteDirEntry( ParentObjectInfo, + pDirNode); + + *DirEntry = pExistingDirNode; + + AFSReleaseResource( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + + try_return( ntStatus = STATUS_SUCCESS); + } + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, AFS_TRACE_LEVEL_VERBOSE_2, "AFSCreateDirEntry Inserting dir entry in parent %wZ FID %08lX-%08lX-%08lX-%08lX Component %wZ\n", @@ -2029,6 +2091,8 @@ AFSCreateDirEntry( IN GUID *AuthGroup, *DirEntry = pDirNode; + AFSReleaseResource( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + try_exit: NOTHING; @@ -2046,8 +2110,7 @@ AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo, __Enter { - AFSAcquireExcl( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, - TRUE); + ASSERT( ExIsResourceAcquiredExclusiveLite( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock)); // // Insert the node into the directory node tree @@ -2128,18 +2191,31 @@ AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo, "AFSInsertDirectoryNode Insert DE %p to head of shortname tree for %wZ\n", DirEntry, &DirEntry->NameInformation.FileName); + + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); } else { - AFSInsertShortNameDirEntry( ParentObjectInfo->Specific.Directory.ShortNameTree, - DirEntry); + if( !NT_SUCCESS( AFSInsertShortNameDirEntry( ParentObjectInfo->Specific.Directory.ShortNameTree, + DirEntry))) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertDirectoryNode Failed to insert DE %p to shortname tree for %wZ\n", + DirEntry, + &DirEntry->NameInformation.FileName); + } + else + { + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_SHORT_NAME); - AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, - AFS_TRACE_LEVEL_VERBOSE, - "AFSInsertDirectoryNode Insert DE %p to shortname tree for %wZ\n", - DirEntry, - &DirEntry->NameInformation.FileName); + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertDirectoryNode Insert DE %p to shortname tree for %wZ\n", + DirEntry, + &DirEntry->NameInformation.FileName); + } } } @@ -2189,8 +2265,6 @@ AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo, ParentObjectInfo->FileId.Vnode, ParentObjectInfo->FileId.Unique); } - - AFSReleaseResource( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); } return; @@ -2243,7 +2317,10 @@ AFSDeleteDirEntry( IN AFSObjectInfoCB *ParentObjectInfo, ASSERT( DirEntry->ObjectInformation->ObjectReferenceCount > 0); - InterlockedDecrement( &DirEntry->ObjectInformation->ObjectReferenceCount); + if( InterlockedDecrement( &DirEntry->ObjectInformation->ObjectReferenceCount) == 0) + { + SetFlag( DirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED); + } AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, AFS_TRACE_LEVEL_VERBOSE, @@ -3707,10 +3784,21 @@ AFSCheckCellName( IN GUID *AuthGroup, else { - AFSInsertCaseSensitiveDirEntry( pDirHdr->CaseSensitiveTreeHead, - pDirNode); + if( !NT_SUCCESS( AFSInsertCaseSensitiveDirEntry( pDirHdr->CaseSensitiveTreeHead, + pDirNode))) + { + + AFSDeleteDirEntry( &AFSGlobalRoot->ObjectInformation, + pDirNode); + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } } + ClearFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); + if( pDirHdr->CaseInsensitiveTreeHead == NULL) { diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h index cdaa8e1..24125fa 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h @@ -885,7 +885,8 @@ AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo, NTSTATUS AFSSnapshotDirectory( IN AFSFcb *Fcb, - IN AFSCcb *Ccb); + IN AFSCcb *Ccb, + IN BOOLEAN ResetIndex); NTSTATUS AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo, diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h index 0b88e0b..8107ea7 100644 --- a/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h @@ -244,6 +244,7 @@ NTSTATUS #define AFS_DIR_ENTRY_SERVER_SERVICE 0x00000400 #define AFS_DIR_ENTRY_WORKSTATION_SERVICE 0x00000800 #define AFS_DIR_ENTRY_IPC 0x00001000 +#define AFS_DIR_ENTRY_INSERTED_SHORT_NAME 0x00002000 // // Network provider errors