diff --git a/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp new file mode 100644 index 0000000000..107e53bca7 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp @@ -0,0 +1,1611 @@ +/* + * 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: AFSBTreeSupport.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSLocateCaseSensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN ULONG Index, + IN OUT AFSDirectoryCB **DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pEntry = NULL; + AFSDirectoryCB *pCurrentEntry = NULL; + + pCurrentEntry = RootNode; + + __Enter + { + + *DirEntry = NULL; + + // + // If the rootnode passed is null then the directory is empty + // + + if( RootNode == NULL) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // If the requestor is looking for the root node itself, then return it. + // + + if( RootNode->CaseSensitiveTreeEntry.HashIndex == Index) + { + + *DirEntry = RootNode; + + try_return( ntStatus); + } + + // + // Loop through the nodes in the tree + // + + while( pCurrentEntry != NULL) + { + + // + // Greater values are to the right link. + // + + if( Index > pCurrentEntry->CaseSensitiveTreeEntry.HashIndex) + { + + // + // Go to the next RIGHT entry, if there is one + // + + if( pCurrentEntry->CaseSensitiveTreeEntry.rightLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseSensitiveTreeEntry.rightLink; + } + else + { + + // + // Came to the end of the branch so bail + // + + pCurrentEntry = NULL; + + break; + } + } + else if( Index < pCurrentEntry->CaseSensitiveTreeEntry.HashIndex) + { + + // + // Go to the next LEFT entry, if one exists + // + + if( pCurrentEntry->CaseSensitiveTreeEntry.leftLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseSensitiveTreeEntry.leftLink; + } + else + { + + // + // End of the branch ... + // + + pCurrentEntry = NULL; + + break; + } + } + else + { + + // + // Found the entry. + // + + *DirEntry = pCurrentEntry; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSLocateCaseInsensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN ULONG Index, + IN OUT AFSDirectoryCB **DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pEntry = NULL; + AFSDirectoryCB *pCurrentEntry = NULL; + + pCurrentEntry = RootNode; + + __Enter + { + + *DirEntry = NULL; + + // + // If the rootnode passed is null then the directory is empty + // + + if( RootNode == NULL) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // If the requestor is looking for the root node itself, then return it. + // + + if( RootNode->CaseInsensitiveTreeEntry.HashIndex == Index) + { + + *DirEntry = RootNode; + + try_return( ntStatus); + } + + // + // Loop through the nodes in the tree + // + + while( pCurrentEntry != NULL) + { + + // + // Greater values are to the right link. + // + + if( Index > pCurrentEntry->CaseInsensitiveTreeEntry.HashIndex) + { + + // + // Go to the next RIGHT entry, if there is one + // + + if( pCurrentEntry->CaseInsensitiveTreeEntry.rightLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseInsensitiveTreeEntry.rightLink; + } + else + { + + // + // Came to the end of the branch so bail + // + + pCurrentEntry = NULL; + + break; + } + } + else if( Index < pCurrentEntry->CaseInsensitiveTreeEntry.HashIndex) + { + + // + // Go to the next LEFT entry, if one exists + // + + if( pCurrentEntry->CaseInsensitiveTreeEntry.leftLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseInsensitiveTreeEntry.leftLink; + } + else + { + + // + // End of the branch ... + // + + pCurrentEntry = NULL; + + break; + } + } + else + { + + // + // Found the entry. + // + + *DirEntry = pCurrentEntry; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSInsertCaseSensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pCurrentEntry = NULL; + + pCurrentEntry = RootNode; + + __Enter + { + + // + // If we have no root node then we can;t start the search. + // + + if( pCurrentEntry == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSInsertCaseSensitiveDirEntry Invalid root node\n"); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Locate the branch end to insert the node + // + + while( pCurrentEntry != NULL) + { + + // + // Greater vlued indices are to the right link + // + + if( DirEntry->CaseSensitiveTreeEntry.HashIndex > pCurrentEntry->CaseSensitiveTreeEntry.HashIndex) + { + + // + // Go to the next RIGHT entry, if it exists + // + + if( pCurrentEntry->CaseSensitiveTreeEntry.rightLink != NULL) + { + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseSensitiveTreeEntry.rightLink; + } + else + { + + // + // Located the end of the branch line so insert the node + // + + pCurrentEntry->CaseSensitiveTreeEntry.rightLink = (void *)DirEntry; + + DirEntry->CaseSensitiveTreeEntry.parentLink = (void *)pCurrentEntry; + + break; + } + } + else if( DirEntry->CaseSensitiveTreeEntry.HashIndex < pCurrentEntry->CaseSensitiveTreeEntry.HashIndex) + { + + // + // Go to the next LEFT entry, if it exists + // + + if( pCurrentEntry->CaseSensitiveTreeEntry.leftLink != NULL) + { + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseSensitiveTreeEntry.leftLink; + } + else + { + + // + // Located the branch line end so insert the node here + // + + pCurrentEntry->CaseSensitiveTreeEntry.leftLink = (void *)DirEntry; + + DirEntry->CaseSensitiveTreeEntry.parentLink = (void *)pCurrentEntry; + + break; + } + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSInsertCaseSensitiveDirEntry Attempt to re-insert a CRC %I64X\n", + DirEntry->CaseSensitiveTreeEntry.HashIndex); + + ASSERT( FALSE); + + ntStatus = STATUS_UNSUCCESSFUL; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSInsertCaseInsensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pCurrentEntry = NULL; + + pCurrentEntry = RootNode; + + __Enter + { + + // + // If we have no root node then we can;t start the search. + // + + if( pCurrentEntry == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSInsertCaseInsensitiveDirEntry Invalid root node\n"); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Locate the branch end to insert the node + // + + while( pCurrentEntry != NULL) + { + + // + // Greater vlued indices are to the right link + // + + if( DirEntry->CaseInsensitiveTreeEntry.HashIndex > pCurrentEntry->CaseInsensitiveTreeEntry.HashIndex) + { + + // + // Go to the next RIGHT entry, if it exists + // + + if( pCurrentEntry->CaseInsensitiveTreeEntry.rightLink != NULL) + { + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseInsensitiveTreeEntry.rightLink; + } + else + { + + // + // Located the end of the branch line so insert the node + // + + pCurrentEntry->CaseInsensitiveTreeEntry.rightLink = (void *)DirEntry; + + DirEntry->CaseInsensitiveTreeEntry.parentLink = (void *)pCurrentEntry; + + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + + break; + } + } + else if( DirEntry->CaseInsensitiveTreeEntry.HashIndex < pCurrentEntry->CaseInsensitiveTreeEntry.HashIndex) + { + + // + // Go to the next LEFT entry, if it exists + // + + if( pCurrentEntry->CaseInsensitiveTreeEntry.leftLink != NULL) + { + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseInsensitiveTreeEntry.leftLink; + } + else + { + + // + // Located the branch line end so insert the node here + // + + pCurrentEntry->CaseInsensitiveTreeEntry.leftLink = (void *)DirEntry; + + DirEntry->CaseInsensitiveTreeEntry.parentLink = (void *)pCurrentEntry; + + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + + break; + } + } + else + { + + // + // Inser the the entry at the end of the insensitive list + // + + while( pCurrentEntry->CaseInsensitiveList.fLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->CaseInsensitiveList.fLink; + } + + pCurrentEntry->CaseInsensitiveList.fLink = (void *)DirEntry; + + DirEntry->CaseInsensitiveList.bLink = (void *)pCurrentEntry; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveCaseSensitiveDirEntry( IN AFSDirectoryCB **RootNode, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + AFSDirectoryCB *pRightNode = NULL; + AFSDirectoryCB *pLeftNode = NULL; + AFSDirectoryCB *pCurrentNode = NULL; + AFSDirectoryCB *pParentNode = NULL; + + pRightNode = (AFSDirectoryCB *)DirEntry->CaseSensitiveTreeEntry.rightLink; + pLeftNode = (AFSDirectoryCB *)DirEntry->CaseSensitiveTreeEntry.leftLink; + pParentNode = (AFSDirectoryCB *)DirEntry->CaseSensitiveTreeEntry.parentLink; + + __Enter + { + + if( (pRightNode == NULL) && (pLeftNode == NULL)) + { + + if( pParentNode != NULL) + { + + if( pParentNode->CaseSensitiveTreeEntry.leftLink == DirEntry) + { + + pParentNode->CaseSensitiveTreeEntry.leftLink = NULL; + } + else + { + + pParentNode->CaseSensitiveTreeEntry.rightLink = NULL; + } + } + else + { + + // + // Removing the top node + // + + *RootNode = NULL; + } + } + else + { + + if( pRightNode != NULL) + { + + if( pParentNode != NULL) + { + + // Replace the parent node where this entry was. + if( pParentNode->CaseSensitiveTreeEntry.rightLink == DirEntry) + { + + pParentNode->CaseSensitiveTreeEntry.rightLink = pRightNode; + } + else + { + + pParentNode->CaseSensitiveTreeEntry.leftLink = pRightNode; + } + } + else + { + + *RootNode = pRightNode; + + pRightNode->CaseSensitiveTreeEntry.parentLink = NULL; + } + + pRightNode->CaseSensitiveTreeEntry.parentLink = pParentNode; + } + + if( pLeftNode != NULL) + { + + // To connect the left node, we must walk the chain of the + // right nodes left side until we reach the end. + // At the end attach the leftNode + if( pRightNode != NULL) + { + + pCurrentNode = pRightNode; + + while( pCurrentNode->CaseSensitiveTreeEntry.leftLink != NULL) + { + + pCurrentNode = (AFSDirectoryCB *)pCurrentNode->CaseSensitiveTreeEntry.leftLink; + } + + pCurrentNode->CaseSensitiveTreeEntry.leftLink = pLeftNode; + + pLeftNode->CaseSensitiveTreeEntry.parentLink = pCurrentNode; + } + else + { + + if( pParentNode != NULL) + { + + // This is where we have a left node with no right node. + // So, attach the left node to the parent of + // the removed nodes branch + if( pParentNode->CaseSensitiveTreeEntry.rightLink == DirEntry) + { + + pParentNode->CaseSensitiveTreeEntry.rightLink = pLeftNode; + } + else + { + + pParentNode->CaseSensitiveTreeEntry.leftLink = pLeftNode; + } + + pLeftNode->CaseSensitiveTreeEntry.parentLink = pParentNode; + } + else + { + + *RootNode = pLeftNode; + + pLeftNode->CaseSensitiveTreeEntry.parentLink = NULL; + } + } + } + } + + // + // Cleanup the just removed node + // + + DirEntry->CaseSensitiveTreeEntry.leftLink = NULL; + DirEntry->CaseSensitiveTreeEntry.parentLink = NULL; + DirEntry->CaseSensitiveTreeEntry.rightLink = NULL; + + ntStatus = STATUS_SUCCESS; + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveCaseInsensitiveDirEntry( IN AFSDirectoryCB **RootNode, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + AFSDirectoryCB *pRightNode = NULL; + AFSDirectoryCB *pLeftNode = NULL; + AFSDirectoryCB *pCurrentNode = NULL; + AFSDirectoryCB *pParentNode = NULL; + AFSDirectoryCB *pNewHeadEntry = NULL; + + pRightNode = (AFSDirectoryCB *)DirEntry->CaseInsensitiveTreeEntry.rightLink; + pLeftNode = (AFSDirectoryCB *)DirEntry->CaseInsensitiveTreeEntry.leftLink; + pParentNode = (AFSDirectoryCB *)DirEntry->CaseInsensitiveTreeEntry.parentLink; + + __Enter + { + + // + // If this is not a head of list entry then just update the pointers for it + // + + if( !BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD)) + { + + ((AFSDirectoryCB *)DirEntry->CaseInsensitiveList.bLink)->CaseInsensitiveList.fLink = DirEntry->CaseInsensitiveList.fLink; + + if( DirEntry->CaseInsensitiveList.fLink != NULL) + { + + ((AFSDirectoryCB *)DirEntry->CaseInsensitiveList.fLink)->CaseInsensitiveList.bLink = DirEntry->CaseInsensitiveList.bLink; + } + + try_return( ntStatus); + } + else if( DirEntry->CaseInsensitiveList.fLink != NULL) + { + + // + // Removing the head of a list of entries so just update pointers + // + + pNewHeadEntry = (AFSDirectoryCB *)DirEntry->CaseInsensitiveList.fLink; + + if( pParentNode != NULL) + { + + if( pParentNode->CaseInsensitiveTreeEntry.rightLink == DirEntry) + { + pParentNode->CaseInsensitiveTreeEntry.rightLink = (void *)pNewHeadEntry; + } + else + { + pParentNode->CaseInsensitiveTreeEntry.leftLink = (void *)pNewHeadEntry; + } + } + + if( pRightNode != NULL) + { + + pRightNode->CaseInsensitiveTreeEntry.parentLink = (void *)pNewHeadEntry; + } + + if( pLeftNode != NULL) + { + + pLeftNode->CaseInsensitiveTreeEntry.parentLink = (void *)pNewHeadEntry; + } + + pNewHeadEntry->CaseInsensitiveList.bLink = NULL; + + pNewHeadEntry->CaseInsensitiveTreeEntry.parentLink = pParentNode; + + pNewHeadEntry->CaseInsensitiveTreeEntry.leftLink = pLeftNode; + + pNewHeadEntry->CaseInsensitiveTreeEntry.rightLink = pRightNode; + + SetFlag( ((AFSDirectoryCB *)DirEntry->CaseInsensitiveList.fLink)->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + + try_return( ntStatus); + } + + if( (pRightNode == NULL) && (pLeftNode == NULL)) + { + + if( pParentNode != NULL) + { + + if( pParentNode->CaseInsensitiveTreeEntry.leftLink == DirEntry) + { + + pParentNode->CaseInsensitiveTreeEntry.leftLink = NULL; + } + else + { + + pParentNode->CaseInsensitiveTreeEntry.rightLink = NULL; + } + } + else + { + + // + // Removing the top node + // + + *RootNode = NULL; + } + } + else + { + + if( pRightNode != NULL) + { + + if( pParentNode != NULL) + { + + // Replace the parent node where this entry was. + if( pParentNode->CaseInsensitiveTreeEntry.rightLink == DirEntry) + { + + pParentNode->CaseInsensitiveTreeEntry.rightLink = pRightNode; + } + else + { + + pParentNode->CaseInsensitiveTreeEntry.leftLink = pRightNode; + } + } + else + { + + *RootNode = pRightNode; + + pRightNode->CaseInsensitiveTreeEntry.parentLink = NULL; + } + + pRightNode->CaseInsensitiveTreeEntry.parentLink = pParentNode; + } + + if( pLeftNode != NULL) + { + + // To connect the left node, we must walk the chain of the + // right nodes left side until we reach the end. + // At the end attach the leftNode + if( pRightNode != NULL) + { + + pCurrentNode = pRightNode; + + while( pCurrentNode->CaseInsensitiveTreeEntry.leftLink != NULL) + { + + pCurrentNode = (AFSDirectoryCB *)pCurrentNode->CaseInsensitiveTreeEntry.leftLink; + } + + pCurrentNode->CaseInsensitiveTreeEntry.leftLink = pLeftNode; + + pLeftNode->CaseInsensitiveTreeEntry.parentLink = pCurrentNode; + } + else + { + + if( pParentNode != NULL) + { + + // This is where we have a left node with no right node. + // So, attach the left node to the parent of + // the removed nodes branch + if( pParentNode->CaseInsensitiveTreeEntry.rightLink == DirEntry) + { + + pParentNode->CaseInsensitiveTreeEntry.rightLink = pLeftNode; + } + else + { + + pParentNode->CaseInsensitiveTreeEntry.leftLink = pLeftNode; + } + + pLeftNode->CaseInsensitiveTreeEntry.parentLink = pParentNode; + } + else + { + + *RootNode = pLeftNode; + + pLeftNode->CaseInsensitiveTreeEntry.parentLink = NULL; + } + } + } + } + +try_exit: + + // + // Cleanup the just removed node + // + + DirEntry->CaseInsensitiveTreeEntry.leftLink = NULL; + DirEntry->CaseInsensitiveTreeEntry.parentLink = NULL; + DirEntry->CaseInsensitiveTreeEntry.rightLink = NULL; + + DirEntry->CaseInsensitiveList.bLink = NULL; + DirEntry->CaseInsensitiveList.fLink = NULL; + + ntStatus = STATUS_SUCCESS; + } + + return ntStatus; +} + +NTSTATUS +AFSLocateShortNameDirEntry( IN AFSDirectoryCB *RootNode, + IN ULONG Index, + IN OUT AFSDirectoryCB **DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pEntry = NULL; + AFSDirectoryCB *pCurrentEntry = NULL; + + pCurrentEntry = RootNode; + + __Enter + { + + *DirEntry = NULL; + + // + // If the rootnode passed is null then the directory is empty + // + + if( RootNode == NULL) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // If the requestor is looking for the root node itself, then return it. + // + + if( RootNode->Type.Data.ShortNameTreeEntry.HashIndex == Index) + { + + *DirEntry = RootNode; + + try_return( ntStatus); + } + + // + // Loop through the nodes in the tree + // + + while( pCurrentEntry != NULL) + { + + // + // Greater values are to the right link. + // + + if( Index > pCurrentEntry->Type.Data.ShortNameTreeEntry.HashIndex) + { + + // + // Go to the next RIGHT entry, if there is one + // + + if( pCurrentEntry->Type.Data.ShortNameTreeEntry.rightLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->Type.Data.ShortNameTreeEntry.rightLink; + } + else + { + + // + // Came to the end of the branch so bail + // + + pCurrentEntry = NULL; + + break; + } + } + else if( Index < pCurrentEntry->Type.Data.ShortNameTreeEntry.HashIndex) + { + + // + // Go to the next LEFT entry, if one exists + // + + if( pCurrentEntry->Type.Data.ShortNameTreeEntry.leftLink != NULL) + { + + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->Type.Data.ShortNameTreeEntry.leftLink; + } + else + { + + // + // End of the branch ... + // + + pCurrentEntry = NULL; + + break; + } + } + else + { + + // + // Found the entry. + // + + *DirEntry = pCurrentEntry; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSInsertShortNameDirEntry( IN AFSDirectoryCB *RootNode, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pCurrentEntry = NULL; + + pCurrentEntry = RootNode; + + __Enter + { + + // + // If we have no root node then we can;t start the search. + // + + if( pCurrentEntry == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSInsertShortNameDirEntry Invalid root node\n"); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Locate the branch end to insert the node + // + + while( pCurrentEntry != NULL) + { + + // + // Greater valued indices are to the right link + // + + if( DirEntry->Type.Data.ShortNameTreeEntry.HashIndex > pCurrentEntry->Type.Data.ShortNameTreeEntry.HashIndex) + { + + // + // Go to the next RIGHT entry, if it exists + // + + if( pCurrentEntry->Type.Data.ShortNameTreeEntry.rightLink != NULL) + { + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->Type.Data.ShortNameTreeEntry.rightLink; + } + else + { + + // + // Located the end of the branch line so insert the node + // + + pCurrentEntry->Type.Data.ShortNameTreeEntry.rightLink = (void *)DirEntry; + + DirEntry->Type.Data.ShortNameTreeEntry.parentLink = (void *)pCurrentEntry; + + break; + } + } + else if( DirEntry->Type.Data.ShortNameTreeEntry.HashIndex < pCurrentEntry->Type.Data.ShortNameTreeEntry.HashIndex) + { + + // + // Go to the next LEFT entry, if it exists + // + + if( pCurrentEntry->Type.Data.ShortNameTreeEntry.leftLink != NULL) + { + pCurrentEntry = (AFSDirectoryCB *)pCurrentEntry->Type.Data.ShortNameTreeEntry.leftLink; + } + else + { + + // + // Located the branch line end so insert the node here + // + + pCurrentEntry->Type.Data.ShortNameTreeEntry.leftLink = (void *)DirEntry; + + DirEntry->Type.Data.ShortNameTreeEntry.parentLink = (void *)pCurrentEntry; + + break; + } + } + else + { + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveShortNameDirEntry( IN AFSDirectoryCB **RootNode, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + AFSDirectoryCB *pRightNode = NULL; + AFSDirectoryCB *pLeftNode = NULL; + AFSDirectoryCB *pCurrentNode = NULL; + AFSDirectoryCB *pParentNode = NULL; + + pRightNode = (AFSDirectoryCB *)DirEntry->Type.Data.ShortNameTreeEntry.rightLink; + pLeftNode = (AFSDirectoryCB *)DirEntry->Type.Data.ShortNameTreeEntry.leftLink; + pParentNode = (AFSDirectoryCB *)DirEntry->Type.Data.ShortNameTreeEntry.parentLink; + + __Enter + { + + if( (pRightNode == NULL) && (pLeftNode == NULL)) + { + + if( pParentNode != NULL) + { + + if( pParentNode->Type.Data.ShortNameTreeEntry.leftLink == DirEntry) + { + + pParentNode->Type.Data.ShortNameTreeEntry.leftLink = NULL; + } + else + { + + pParentNode->Type.Data.ShortNameTreeEntry.rightLink = NULL; + } + } + else + { + + // + // Removing the top node + // + + *RootNode = NULL; + } + } + else + { + + if( pRightNode != NULL) + { + + if( pParentNode != NULL) + { + + // Replace the parent node where this entry was. + if( pParentNode->Type.Data.ShortNameTreeEntry.rightLink == DirEntry) + { + + pParentNode->Type.Data.ShortNameTreeEntry.rightLink = pRightNode; + } + else + { + + pParentNode->Type.Data.ShortNameTreeEntry.leftLink = pRightNode; + } + } + else + { + + *RootNode = pRightNode; + + pRightNode->Type.Data.ShortNameTreeEntry.parentLink = NULL; + } + + pRightNode->Type.Data.ShortNameTreeEntry.parentLink = pParentNode; + } + + if( pLeftNode != NULL) + { + + // To connect the left node, we must walk the chain of the + // right nodes left side until we reach the end. + // At the end attach the leftNode + if( pRightNode != NULL) + { + + pCurrentNode = pRightNode; + + while( pCurrentNode->Type.Data.ShortNameTreeEntry.leftLink != NULL) + { + + pCurrentNode = (AFSDirectoryCB *)pCurrentNode->Type.Data.ShortNameTreeEntry.leftLink; + } + + pCurrentNode->Type.Data.ShortNameTreeEntry.leftLink = pLeftNode; + + pLeftNode->Type.Data.ShortNameTreeEntry.parentLink = pCurrentNode; + } + else + { + + if( pParentNode != NULL) + { + + // This is where we have a left node with no right node. + // So, attach the left node to the parent of + // the removed nodes branch + if( pParentNode->Type.Data.ShortNameTreeEntry.rightLink == DirEntry) + { + + pParentNode->Type.Data.ShortNameTreeEntry.rightLink = pLeftNode; + } + else + { + + pParentNode->Type.Data.ShortNameTreeEntry.leftLink = pLeftNode; + } + + pLeftNode->Type.Data.ShortNameTreeEntry.parentLink = pParentNode; + } + else + { + + *RootNode = pLeftNode; + + pLeftNode->Type.Data.ShortNameTreeEntry.parentLink = NULL; + } + } + } + } + + // + // Cleanup the just removed node + // + + DirEntry->Type.Data.ShortNameTreeEntry.leftLink = NULL; + DirEntry->Type.Data.ShortNameTreeEntry.parentLink = NULL; + DirEntry->Type.Data.ShortNameTreeEntry.rightLink = NULL; + + ntStatus = STATUS_SUCCESS; + } + + return ntStatus; +} + +NTSTATUS +AFSLocateHashEntry( IN AFSBTreeEntry *TopNode, + IN ULONGLONG HashIndex, + IN OUT AFSBTreeEntry **TreeEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSBTreeEntry *pEntry = NULL; + AFSBTreeEntry *pCurrentEntry = NULL; + + pCurrentEntry = TopNode; + + __Enter + { + + // + // If the rootnode passed is null then the directory is empty + // + + if( TopNode == NULL) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // If the requestor is looking for the root node itself, then return it. + // + + if( TopNode->HashIndex == HashIndex) + { + + *TreeEntry = TopNode; + + try_return( ntStatus); + } + + // + // Loop through the nodes in the tree + // + + while( pCurrentEntry != NULL) + { + + // + // Greater values are to the right link. + // + + if( HashIndex > pCurrentEntry->HashIndex) + { + + // + // Go to the next RIGHT entry, if there is one + // + + if( pCurrentEntry->rightLink != NULL) + { + + pCurrentEntry = (AFSBTreeEntry *)pCurrentEntry->rightLink; + } + else + { + + // + // Came to the end of the branch so bail + // + + pCurrentEntry = NULL; + + break; + } + } + else if( HashIndex < pCurrentEntry->HashIndex) + { + + // + // Go to the next LEFT entry, if one exists + // + + if( pCurrentEntry->leftLink != NULL) + { + + pCurrentEntry = (AFSBTreeEntry *)pCurrentEntry->leftLink; + } + else + { + + // + // End of the branch ... + // + + pCurrentEntry = NULL; + + break; + } + } + else + { + + // + // Found the entry. + // + + *TreeEntry = pCurrentEntry; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSInsertHashEntry( IN AFSBTreeEntry *TopNode, + IN AFSBTreeEntry *FileIDEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSBTreeEntry *pCurrentEntry = NULL; + + pCurrentEntry = TopNode; + + __Enter + { + + // + // If we have no root node then we can;t start the search. + // + + if( pCurrentEntry == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSInsertHashEntry Invalid root node\n"); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Locate the branch end to insert the node + // + + while( pCurrentEntry != NULL) + { + + // + // Greater vlued indices are to the right link + // + + if( FileIDEntry->HashIndex > pCurrentEntry->HashIndex) + { + + // + // Go to the next RIGHT entry, if it exists + // + + if( pCurrentEntry->rightLink != NULL) + { + pCurrentEntry = (AFSBTreeEntry *)pCurrentEntry->rightLink; + } + else + { + + // + // Located the end of the branch line so insert the node + // + + pCurrentEntry->rightLink = (void *)FileIDEntry; + + FileIDEntry->parentLink = (void *)pCurrentEntry; + + break; + } + } + else if( FileIDEntry->HashIndex < pCurrentEntry->HashIndex) + { + + // + // Go to the next LEFT entry, if it exists + // + + if( pCurrentEntry->leftLink != NULL) + { + pCurrentEntry = (AFSBTreeEntry *)pCurrentEntry->leftLink; + } + else + { + + // + // Located the branch line end so insert the node here + // + + pCurrentEntry->leftLink = (void *)FileIDEntry; + + FileIDEntry->parentLink = (void *)pCurrentEntry; + + break; + } + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSInsertHashEntry Attempt to re-insert a CRC %I64X\n", + FileIDEntry->HashIndex); + + ASSERT( FALSE); + + ntStatus = STATUS_UNSUCCESSFUL; + + break; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveHashEntry( IN AFSBTreeEntry **TopNode, + IN AFSBTreeEntry *FileIDEntry) +{ + + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + AFSBTreeEntry *pRightNode = NULL; + AFSBTreeEntry *pLeftNode = NULL; + AFSBTreeEntry *pCurrentNode = NULL; + AFSBTreeEntry *pParentNode = NULL; + + pRightNode = (AFSBTreeEntry *)FileIDEntry->rightLink; + pLeftNode = (AFSBTreeEntry *)FileIDEntry->leftLink; + pParentNode = (AFSBTreeEntry *)FileIDEntry->parentLink; + + __Enter + { + + if( (pRightNode == NULL) && (pLeftNode == NULL)) + { + + if( pParentNode != NULL) + { + + if( pParentNode->leftLink == FileIDEntry) + { + + pParentNode->leftLink = NULL; + } + else + { + + pParentNode->rightLink = NULL; + } + } + else + { + + // + // Removing the top node + // + + *TopNode = NULL; + } + } + else + { + + if( pRightNode != NULL) + { + + if( pParentNode != NULL) + { + + // Replace the parent node where this entry was. + if( pParentNode->rightLink == FileIDEntry) + { + + pParentNode->rightLink = pRightNode; + } + else + { + + pParentNode->leftLink = pRightNode; + } + } + else + { + + *TopNode = pRightNode; + + pRightNode->parentLink = NULL; + } + + pRightNode->parentLink = pParentNode; + } + + if( pLeftNode != NULL) + { + + // To connect the left node, we must walk the chain of the + // right nodes left side until we reach the end. + // At the end attach the leftNode + if( pRightNode != NULL) + { + + pCurrentNode = pRightNode; + + while( pCurrentNode->leftLink != NULL) + { + + pCurrentNode = (AFSBTreeEntry *)pCurrentNode->leftLink; + } + + pCurrentNode->leftLink = pLeftNode; + + pLeftNode->parentLink = pCurrentNode; + } + else + { + + if( pParentNode != NULL) + { + + // This is where we have a left node with no right node. + // So, attach the left node to the parent of + // the removed nodes branch + if( pParentNode->rightLink == FileIDEntry) + { + + pParentNode->rightLink = pLeftNode; + } + else + { + + pParentNode->leftLink = pLeftNode; + } + + pLeftNode->parentLink = pParentNode; + } + else + { + + *TopNode = pLeftNode; + + pLeftNode->parentLink = NULL; + } + } + } + } + + // + // Cleanup the just removed node + // + + FileIDEntry->leftLink = NULL; + FileIDEntry->parentLink = NULL; + FileIDEntry->rightLink = NULL; + + ntStatus = STATUS_SUCCESS; + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp new file mode 100644 index 0000000000..be8fedd8a9 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp @@ -0,0 +1,1151 @@ +/* + * 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: AFSCleanup.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSCleanup +// +// Description: +// +// This function is the IRP_MJ_CLEANUP dispatch handler +// +// Return: +// +// A status is returned for the handling of this request +// + +NTSTATUS +AFSCleanup( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = NULL; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + PFILE_OBJECT pFileObject = NULL; + AFSFcb *pRootFcb = NULL; + AFSDeviceExt *pControlDeviceExt = NULL; + IO_STATUS_BLOCK stIoSB; + AFSObjectInfoCB *pObjectInfo = NULL; + AFSFileCleanupCB stFileCleanup; + ULONG ulNotificationFlags = 0; + + __try + { + + if( AFSRDRDeviceObject == NULL) + { + + // + // Let this through, it's a cleanup on the library control device + // + + try_return( ntStatus); + } + + pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + // + // Set some initial variables to make processing easier + // + + pFileObject = pIrpSp->FileObject; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + if( pFcb == NULL) + { + try_return( ntStatus); + } + + pObjectInfo = pFcb->ObjectInformation; + + pRootFcb = pObjectInfo->VolumeCB->RootFcb; + + RtlZeroMemory( &stFileCleanup, + sizeof( AFSFileCleanupCB)); + + stFileCleanup.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + // + // Perform the cleanup functionality depending on the type of node it is + // + + switch( pFcb->Header.NodeTypeCode) + { + + case AFS_ROOT_ALL: + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Acquiring GlobalRoot lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + ASSERT( pFcb->OpenHandleCount != 0); + + InterlockedDecrement( &pFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (RootAll) Decrement handle count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenHandleCount); + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync, + &pControlDeviceExt->Specific.Control.DirNotifyList, + pCcb); + + break; + } + + case AFS_IOCTL_FCB: + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Acquiring PIOCtl lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + ASSERT( pFcb->OpenHandleCount != 0); + + InterlockedDecrement( &pFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (IOCtl) Decrement handle count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenHandleCount); + + // + // Decrement the open child handle count + // + + if( pObjectInfo->ParentObjectInformation != NULL && + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) + { + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (IOCtl) Decrement child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + } + + // + // And finally, release the Fcb if we acquired it. + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + break; + } + + // + // This Fcb represents a file + // + + case AFS_FILE_FCB: + { + + // + // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Acquiring Fcb lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + // + // Uninitialize the cache map. This call is unconditional. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Tearing down cache map for Fcb %08lX FileObject %08lX\n", + pFcb, + pFileObject); + + CcUninitializeCacheMap( pFileObject, + NULL, + NULL); + + // + // Unlock all outstanding locks on the file, again, unconditionally + // + + (VOID) FsRtlFastUnlockAll( &pFcb->Specific.File.FileLock, + pFileObject, + IoGetRequestorProcess( Irp), + NULL); + + // + // Tell the service to unlock all on the file + // + + ulNotificationFlags |= AFS_REQUEST_FLAG_BYTE_RANGE_UNLOCK_ALL; + + // + // Perform some final common processing + // + + ASSERT( pFcb->OpenHandleCount != 0); + + InterlockedDecrement( &pFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (File) Decrement handle count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenHandleCount); + + if( pFcb->ObjectInformation->ParentObjectInformation != NULL) + { + + stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; + } + + stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) + { + + stFileCleanup.AllocationSize = pObjectInfo->EndOfFile; + + stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) + { + + stFileCleanup.CreateTime = pObjectInfo->CreationTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) + { + + stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) + { + + stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME)) + { + + stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME | AFS_FCB_FLAG_UPDATE_WRITE_TIME); + } + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME)) + { + + stFileCleanup.LastWriteTime = pObjectInfo->LastWriteTime; + } + + // + // If the count has dropped to zero and there is a pending delete + // then delete the node + // + + if( pFcb->OpenHandleCount == 0 && + BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) + { + + // + // Stop anything possibly in process + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Acquiring Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + + pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED; + + KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete, + 0, + FALSE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Releasing Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource); + + // + // Before telling the server about the deleted file, tear down all extents for + // the file + // + + AFSTearDownFcbExtents( pFcb); + + ntStatus = STATUS_SUCCESS; + + ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; + + // + // Push the request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, + ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + &stFileCleanup, + sizeof( AFSFileCleanupCB), + NULL, + NULL); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCleanup Failed to notify service of deleted file %wZ Status %08lX\n", + &pCcb->FullFileName, + ntStatus); + + ntStatus = STATUS_SUCCESS; + + ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + else + { + + ntStatus = STATUS_SUCCESS; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Setting DELETE flag in file %wZ Dir Entry %p\n", + &pCcb->FullFileName, + pCcb->DirectoryCB); + + SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); + + ASSERT( pObjectInfo->ParentObjectInformation != NULL); + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + pCcb, + (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, + (ULONG)FILE_ACTION_REMOVED); + + // + // Now that the service has the entry has deleted we need to remove it from the parent + // tree so another lookup on the node will fail + // + + if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) + { + + AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, + pCcb->DirectoryCB); + + AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + } + } + else + { + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) + { + + ULONG ulNotifyFilter = 0; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); + + ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + pCcb, + (ULONG)ulNotifyFilter, + (ULONG)FILE_ACTION_MODIFIED); + } + + // + // Flush out any dirty pages on every handle close to reduce strain on the afs cache + // + + if( CcIsFileCached( pIrpSp->FileObject)) + { + + __try + { + + CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoSB); + + if( !NT_SUCCESS( stIoSB.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCleanup CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + &pCcb->FullFileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + stIoSB.Status, + stIoSB.Information); + + ntStatus = stIoSB.Status; + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + } + } + + // + // Attempt to flush any dirty extents to the server. This may be a little + // aggressive, to flush whenever the handle is closed, but it ensures + // coherency. + // + + if( pFcb->Specific.File.ExtentsDirtyCount) + { + + AFSFlushExtents( pFcb); + } + + if( pFcb->OpenHandleCount == 0) + { + + // + // Wait for any outstanding queued flushes to complete + // + + AFSWaitOnQueuedFlushes( pFcb); + + ulNotificationFlags |= AFS_REQUEST_FLAG_FLUSH_FILE; + } + + // + // Push the request to the service + // + + AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, + ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + &stFileCleanup, + sizeof( AFSFileCleanupCB), + NULL, + NULL); + } + + // + // Remove the share access at this time since we may not get the close for sometime on this FO. + // + + IoRemoveShareAccess( pFileObject, + &pFcb->ShareAccess); + + // + // We don't need the name array after the user closes the handle on the file + // + + if( pCcb->NameArray != NULL) + { + + AFSFreeNameArray( pCcb->NameArray); + + pCcb->NameArray = NULL; + } + + // + // Decrement the open child handle count + // + + if( pObjectInfo->ParentObjectInformation != NULL) + { + + ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (File) Decrement child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + } + + // + // And finally, release the Fcb if we acquired it. + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + break; + } + + // + // Root or directory node + // + + case AFS_ROOT_FCB: + { + + // + // Set the root Fcb to this node + // + + pRootFcb = pFcb; + + // + // Fall through to below + // + } + + case AFS_DIRECTORY_FCB: + { + + // + // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Acquiring Dcb lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + // + // Perform some final common processing + // + + ASSERT( pFcb->OpenHandleCount != 0); + + InterlockedDecrement( &pFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (Dir) Decrement handle count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenHandleCount); + + if( pFcb->ObjectInformation->ParentObjectInformation != NULL) + { + + stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; + } + + stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) + { + + stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) + { + + stFileCleanup.CreateTime = pObjectInfo->CreationTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) + { + + stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) + { + + stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); + } + } + + // + // If the count has dropped to zero and there is a pending delete + // then delete the node + // + + if( pFcb->OpenHandleCount == 0 && + BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) + { + + // + // Try to notify the service about the delete + // + + ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; + + // + // Push the request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, + ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + &stFileCleanup, + sizeof( AFSFileCleanupCB), + NULL, + NULL); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCleanup Failed to notify service of deleted directory %wZ Status %08lX\n", + &pCcb->FullFileName, + ntStatus); + + ntStatus = STATUS_SUCCESS; + + ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + else + { + + ntStatus = STATUS_SUCCESS; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Setting DELETE flag in directory %wZ Dir Entry %p\n", + &pCcb->FullFileName, + pCcb->DirectoryCB); + + SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); + + ASSERT( pObjectInfo->ParentObjectInformation != NULL); + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + pCcb, + (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, + (ULONG)FILE_ACTION_REMOVED); + + // + // Now that the service has the entry has deleted we need to remove it from the parent + // tree so another lookup on the node will fail + // + + if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) + { + + AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, + pCcb->DirectoryCB); + + AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + } + } + + // + // If there have been any updates to the node then push it to + // the service + // + + else + { + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) + { + + ULONG ulNotifyFilter = 0; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); + + if( pObjectInfo->ParentObjectInformation != NULL) + { + + ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + pCcb, + (ULONG)ulNotifyFilter, + (ULONG)FILE_ACTION_MODIFIED); + } + } + + AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, + ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + &stFileCleanup, + sizeof( AFSFileCleanupCB), + NULL, + NULL); + } + + // + // Release the notification for this directory if there is one + // + + FsRtlNotifyCleanup( pControlDeviceExt->Specific.Control.NotifySync, + &pControlDeviceExt->Specific.Control.DirNotifyList, + pCcb); + + // + // Remove the share access at this time since we may not get the close for sometime on this FO. + // + + IoRemoveShareAccess( pFileObject, + &pFcb->ShareAccess); + + // + // We don't need the name array after the user closes the handle on the file + // + + if( pCcb->NameArray != NULL) + { + + AFSFreeNameArray( pCcb->NameArray); + + pCcb->NameArray = NULL; + } + + // + // Decrement the open child handle count + // + + if( pObjectInfo->ParentObjectInformation != NULL) + { + + ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (Dir) Decrement child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + } + + // + // And finally, release the Fcb if we acquired it. + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + break; + } + + case AFS_SYMBOLIC_LINK_FCB: + case AFS_MOUNT_POINT_FCB: + case AFS_DFS_LINK_FCB: + { + + // + // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (MP/SL) Acquiring Dcb lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + // + // Perform some final common processing + // + + ASSERT( pFcb->OpenHandleCount != 0); + + InterlockedDecrement( &pFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (MP/SL) Decrement handle count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenHandleCount); + + if( pFcb->ObjectInformation->ParentObjectInformation != NULL) + { + + stFileCleanup.ParentId = pFcb->ObjectInformation->ParentObjectInformation->FileId; + } + + stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) + { + + stFileCleanup.FileAttributes = pObjectInfo->FileAttributes; + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME)) + { + + stFileCleanup.CreateTime = pObjectInfo->CreationTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CREATE_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME)) + { + + stFileCleanup.ChangeTime = pObjectInfo->ChangeTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + } + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME)) + { + + stFileCleanup.LastAccessTime = pObjectInfo->LastAccessTime; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_ACCESS_TIME); + } + } + + // + // If the count has dropped to zero and there is a pending delete + // then delete the node + // + + if( pFcb->OpenHandleCount == 0 && + BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) + { + + // + // Try to notify the service about the delete + // + + ulNotificationFlags |= AFS_REQUEST_FLAG_FILE_DELETED; + + // + // Push the request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, + ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + &stFileCleanup, + sizeof( AFSFileCleanupCB), + NULL, + NULL); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCleanup Failed to notify service of deleted MP/SL %wZ Status %08lX\n", + &pCcb->FullFileName, + ntStatus); + + ntStatus = STATUS_SUCCESS; + + ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + else + { + + ntStatus = STATUS_SUCCESS; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Setting DELETE flag in MP/SL %wZ Dir Entry %p\n", + &pCcb->FullFileName, + pCcb->DirectoryCB); + + SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED); + + ASSERT( pObjectInfo->ParentObjectInformation != NULL); + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + pCcb, + (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, + (ULONG)FILE_ACTION_REMOVED); + + // + // Now that the service has the entry has deleted we need to remove it from the parent + // tree so another lookup on the node will fail + // + + if( !BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) + { + + AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSRemoveNameEntry( pObjectInfo->ParentObjectInformation, + pCcb->DirectoryCB); + + AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + } + } + + // + // If there have been any updates to the node then push it to + // the service + // + + else + { + + if( BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED)) + { + + ULONG ulNotifyFilter = 0; + + ClearFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); + + if( pObjectInfo->ParentObjectInformation != NULL) + { + + ulNotifyFilter |= (FILE_NOTIFY_CHANGE_ATTRIBUTES); + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + pCcb, + (ULONG)ulNotifyFilter, + (ULONG)FILE_ACTION_MODIFIED); + } + } + + AFSProcessRequest( AFS_REQUEST_TYPE_CLEANUP_PROCESSING, + ulNotificationFlags | AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + &stFileCleanup, + sizeof( AFSFileCleanupCB), + NULL, + NULL); + } + + // + // Remove the share access at this time since we may not get the close for sometime on this FO. + // + + IoRemoveShareAccess( pFileObject, + &pFcb->ShareAccess); + + // + // We don't need the name array after the user closes the handle on the file + // + + if( pCcb->NameArray != NULL) + { + + AFSFreeNameArray( pCcb->NameArray); + + pCcb->NameArray = NULL; + } + + // + // Decrement the open child handle count + // + + if( pObjectInfo->ParentObjectInformation != NULL) + { + + ASSERT( pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0); + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (MP/SL) Decrement child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + } + + // + // And finally, release the Fcb if we acquired it. + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + break; + } + + case AFS_SPECIAL_SHARE_FCB: + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup Acquiring SPECIAL SHARE lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + ASSERT( pFcb->OpenHandleCount != 0); + + InterlockedDecrement( &pFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (Share) Decrement handle count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenHandleCount); + + // + // Decrement the open child handle count + // + + if( pObjectInfo->ParentObjectInformation != NULL && + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) + { + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCleanup (Share) Decrement child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + } + + // + // And finally, release the Fcb if we acquired it. + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSCleanup Processing unknown node type %d\n", + pFcb->Header.NodeTypeCode); + + break; + } + + +try_exit: + + if( pFileObject != NULL) + { + + // + // Setup the fileobject flags to indicate cleanup is complete. + // + + SetFlag( pFileObject->Flags, FO_CLEANUP_COMPLETE); + } + + // + // Complete the request + // + + AFSCompleteRequest( Irp, ntStatus); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSCleanup\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSClose.cpp b/src/WINNT/afsrdr/kernel/lib/AFSClose.cpp new file mode 100644 index 0000000000..b97d64f3d2 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSClose.cpp @@ -0,0 +1,688 @@ +/* + * 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: AFSClose.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSClose +// +// Description: +// +// This function is the IRP_MJ_CLOSE dispatch handler +// +// Return: +// +// A status is returned for the handling of this request +// + +NTSTATUS +AFSClose( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulRequestType = 0; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSDeviceExt *pDeviceExt = NULL; + AFSCcb *pCcb = NULL; + AFSObjectInfoCB *pObjectInfo = NULL; + AFSDirectoryCB *pDirCB = NULL; + + __try + { + + if( AFSRDRDeviceObject == NULL) + { + + // + // Let this through, it's an close on the library control device + // + + try_return( ntStatus); + } + + pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + if( pFcb == NULL) + { + try_return( ntStatus); + } + + pObjectInfo = pFcb->ObjectInformation; + + // + // Perform the close functionality depending on the type of node it is + // + + switch( pFcb->Header.NodeTypeCode) + { + + case AFS_IOCTL_FCB: + { + + AFSPIOCtlOpenCloseRequestCB stPIOCtlClose; + AFSFileID stParentFileId; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Acquiring GlobalRoot lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + // + // Send the close to the CM + // + + RtlZeroMemory( &stPIOCtlClose, + sizeof( AFSPIOCtlOpenCloseRequestCB)); + + stPIOCtlClose.RequestId = pCcb->RequestID; + + stPIOCtlClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId; + + RtlZeroMemory( &stParentFileId, + sizeof( AFSFileID)); + + stParentFileId = pObjectInfo->ParentObjectInformation->FileId; + + // + // Issue the close request to the service + // + + AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_CLOSE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + NULL, + &stParentFileId, + (void *)&stPIOCtlClose, + sizeof( AFSPIOCtlOpenCloseRequestCB), + NULL, + NULL); + + pDirCB = pCcb->DirectoryCB; + + // + // Remove the Ccb and de-allocate it + // + + ntStatus = AFSRemoveCcb( pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus); + + // + // We can't actually fail a close operation so reset the status + // + + ntStatus = STATUS_SUCCESS; + } + + ASSERT( pDirCB->OpenReferenceCount > 0); + + InterlockedDecrement( &pDirCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (IOCtl) Decrement count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirCB->NameInformation.FileName, + pDirCB, + pCcb, + pDirCB->OpenReferenceCount); + + // + // If this is not the root then decrement the open child reference count + // + + if( pObjectInfo->ParentObjectInformation != NULL && + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0) + { + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (IOCtl) Decrement child open ref count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + } + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + ASSERT( pFcb->OpenReferenceCount != 0); + + InterlockedDecrement( &pFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (IOCtl) Decrement count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenReferenceCount); + + break; + } + + case AFS_ROOT_ALL: + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Acquiring Special Root ALL lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + pDirCB = pCcb->DirectoryCB; + + // + // Remove the Ccb and de-allocate it + // + + ntStatus = AFSRemoveCcb( pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus); + + // + // We can't actually fail a close operation so reset the status + // + + ntStatus = STATUS_SUCCESS; + } + + ASSERT( pDirCB->OpenReferenceCount > 0); + + InterlockedDecrement( &pDirCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Decrement (Root ALL) count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirCB->NameInformation.FileName, + pDirCB, + pCcb, + pDirCB->OpenReferenceCount); + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + ASSERT( pFcb->OpenReferenceCount > 0); + + InterlockedDecrement( &pFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (RootAll) Decrement count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenReferenceCount); + + break; + } + + // + // Root, file or directory node + // + + case AFS_FILE_FCB: + case AFS_ROOT_FCB: + case AFS_DIRECTORY_FCB: + case AFS_SYMBOLIC_LINK_FCB: + case AFS_MOUNT_POINT_FCB: + case AFS_DFS_LINK_FCB: + { + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + // + // We may be performing some cleanup on the Fcb so grab it exclusive to ensure no collisions + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Acquiring Dcb lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + KeQueryTickCount( &pFcb->ObjectInformation->LastAccessCount); + + pDirCB = pCcb->DirectoryCB; + + // + // Remove the Ccb and de-allocate it + // + + ntStatus = AFSRemoveCcb( pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", + ntStatus); + + // + // We can't actually fail a close operation so reset the status + // + + ntStatus = STATUS_SUCCESS; + } + + // + // If this entry is deleted then remove the object from the volume tree + // + + if( BooleanFlagOn( pDirCB->Flags, AFS_DIR_ENTRY_DELETED)) + { + + if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + // + // Stop anything possibly in process + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Acquiring Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + + pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_FILE_DELETED; + + KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete, + 0, + FALSE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Releasing Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource); + } + + AFSAcquireExcl( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSAcquireExcl( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + if ( pDirCB->OpenReferenceCount == 0) + { + AFSDbgLogMsg( 0, + 0, + "AFSClose (Other) OpenReferenceCount is Zero on DE %08lX Ccb %08lX FileName %wZ\n", + pDirCB, + pCcb, + &pDirCB->NameInformation.FileName); + } + + ASSERT( pDirCB->OpenReferenceCount > 0); + + InterlockedDecrement( &pDirCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (Other) Decrement count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirCB->NameInformation.FileName, + pDirCB, + pCcb, + pDirCB->OpenReferenceCount); + + if( pDirCB->OpenReferenceCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Deleting dir etry %08lX (%08lX) for %wZ\n", + pDirCB, + pObjectInfo, + &pDirCB->NameInformation.FileName); + + // + // Remove and delete the directory entry from the parent list + // + + AFSDeleteDirEntry( pObjectInfo->ParentObjectInformation, + pDirCB); + + if( pObjectInfo->ObjectReferenceCount == 0) + { + + if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Removing object %08lX from volume tree\n", + pObjectInfo); + + AFSRemoveHashEntry( &pObjectInfo->VolumeCB->ObjectInfoTree.TreeHead, + &pObjectInfo->TreeEntry); + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE); + } + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DELETED); + } + } + + AFSReleaseResource( pObjectInfo->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSReleaseResource( pObjectInfo->VolumeCB->ObjectInfoTree.TreeLock); + } + else + { + + ASSERT( pDirCB->OpenReferenceCount > 0); + + InterlockedDecrement( &pDirCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (Other2) Decrement count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirCB->NameInformation.FileName, + pDirCB, + pCcb, + pDirCB->OpenReferenceCount); + } + + // + // If this is not the root then decrement the open child reference count + // + + if( pObjectInfo != NULL && + pObjectInfo->ParentObjectInformation != NULL && + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0) + { + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Decrement child open ref count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + } + + if( pFcb->OpenReferenceCount == 1 && + pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + SetFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED); + + // + // Attempt to tear down our extent list for the file + // If there are remaining dirty extents then attempt to + // flush them as well + // + + if( pFcb->Specific.File.ExtentsDirtyCount) + { + + AFSFlushExtents( pFcb); + } + + // + // Wait for any outstanding queued flushes to complete + // + + AFSWaitOnQueuedFlushes( pFcb); + + ASSERT( pFcb->Specific.File.ExtentsDirtyCount == 0 && + pFcb->Specific.File.QueuedFlushCount == 0); + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + // + // Tear 'em down, we'll not be needing them again + // + + if( AFSTearDownFcbExtents( pFcb)) + { + + // + // Indicate to the service that the file required complete flushing to the + // server. + // + + AFSProcessRequest( AFS_REQUEST_TYPE_FLUSH_FILE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + NULL, + &pFcb->ObjectInformation->FileId, + NULL, + 0, + NULL, + NULL); + } + } + else + { + + if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + if( pFcb->Specific.File.ExtentsDirtyCount) + { + + AFSFlushExtents( pFcb); + } + } + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + + // + // Decrement the reference count on the Fcb. this is protecting it from teardown. + // + + ASSERT( pFcb->OpenReferenceCount != 0); + + InterlockedDecrement( &pFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Decrement count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenReferenceCount); + + break; + } + + case AFS_SPECIAL_SHARE_FCB: + { + + AFSPipeOpenCloseRequestCB stPipeClose; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose Acquiring Special Share lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + pDirCB = pCcb->DirectoryCB; + + RtlZeroMemory( &stPipeClose, + sizeof( AFSPipeOpenCloseRequestCB)); + + stPipeClose.RequestId = pCcb->RequestID; + + stPipeClose.RootId = pObjectInfo->VolumeCB->ObjectInformation.FileId; + + // + // Issue the open request to the service + // + + /* + AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_CLOSE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pDirCB->NameInformation.FileName, + NULL, + (void *)&stPipeClose, + sizeof( AFSPipeOpenCloseRequestCB), + NULL, + NULL); + */ + + // + // Remove the Ccb and de-allocate it + // + + ntStatus = AFSRemoveCcb( pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSClose Failed to remove Ccb from Fcb Status %08lX\n", ntStatus); + + // + // We can't actually fail a close operation so reset the status + // + + ntStatus = STATUS_SUCCESS; + } + + ASSERT( pDirCB->OpenReferenceCount > 0); + + InterlockedDecrement( &pDirCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (Share) Decrement count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirCB->NameInformation.FileName, + pDirCB, + pCcb, + pDirCB->OpenReferenceCount); + + // + // If this is not the root then decrement the open child reference count + // + + if( pObjectInfo->ParentObjectInformation != NULL && + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0) + { + + InterlockedDecrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (Share) Decrement child open ref count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + } + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + ASSERT( pFcb->OpenReferenceCount != 0); + + InterlockedDecrement( &pFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSClose (Share) Decrement count on Fcb %08lX Cnt %d\n", + pFcb, + pFcb->OpenReferenceCount); + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSClose Processing unknown node type %d\n", + pFcb->Header.NodeTypeCode); + + break; + } + +try_exit: + + // + // Complete the request + // + + AFSCompleteRequest( Irp, + ntStatus); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSClose\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp new file mode 100644 index 0000000000..90e500e702 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp @@ -0,0 +1,2067 @@ +/* + * 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: AFSCommSupport.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSEnumerateDirectory( IN GUID *AuthGroup, + IN AFSObjectInfoCB *ObjectInfoCB, + IN BOOLEAN FastQuery) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + void *pBuffer = NULL; + ULONG ulResultLen = 0; + AFSDirQueryCB *pDirQueryCB; + AFSDirEnumEntry *pCurrentDirEntry = NULL; + AFSDirectoryCB *pDirNode = NULL; + ULONG ulEntryLength = 0; + AFSDirEnumResp *pDirEnumResponse = NULL; + UNICODE_STRING uniDirName, uniTargetName; + ULONG ulRequestFlags = AFS_REQUEST_FLAG_SYNCHRONOUS; + ULONG ulCRC = 0; + UNICODE_STRING uniGUID; + + __Enter + { + + uniGUID.Length = 0; + uniGUID.MaximumLength = 0; + uniGUID.Buffer = NULL; + + if( AuthGroup != NULL) + { + RtlStringFromGUID( *AuthGroup, + &uniGUID); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateDirectory Enumerating FID %08lX-%08lX-%08lX-%08lX AuthGroup %wZ\n", + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique, + &uniGUID); + + if( AuthGroup != NULL) + { + RtlFreeUnicodeString( &uniGUID); + } + + // + // Initialize the directory enumeration buffer for the directory + // + + pBuffer = AFSExAllocatePoolWithTag( PagedPool, + AFS_DIR_ENUM_BUFFER_LEN, + AFS_DIR_BUFFER_TAG); + + if( pBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pBuffer, + AFS_DIR_ENUM_BUFFER_LEN); + + ulResultLen = AFS_DIR_ENUM_BUFFER_LEN; + + // + // Use the payload buffer for information we will pass to the service + // + + pDirQueryCB = (AFSDirQueryCB *)pBuffer; + + pDirQueryCB->EnumHandle = 0; + + if( FastQuery) + { + + ulRequestFlags |= AFS_REQUEST_FLAG_FAST_REQUEST; + } + + // + // Loop on the information + // + + while( TRUE) + { + + // + // Go and retrieve the directory contents + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_DIR_ENUM, + ulRequestFlags, + AuthGroup, + NULL, + &ObjectInfoCB->FileId, + (void *)pDirQueryCB, + sizeof( AFSDirQueryCB), + pBuffer, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS || + ulResultLen == 0) + { + + if( ntStatus == STATUS_NO_MORE_FILES || + ntStatus == STATUS_NO_MORE_ENTRIES) + { + + ntStatus = STATUS_SUCCESS; + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSEnumerateDirectory Failed to enumerate directory Status %08lX\n", + ntStatus); + } + + break; + } + + pDirEnumResponse = (AFSDirEnumResp *)pBuffer; + + pCurrentDirEntry = (AFSDirEnumEntry *)pDirEnumResponse->Entry; + + // + // Remove the leading header from the processed length + // + + ulResultLen -= FIELD_OFFSET( AFSDirEnumResp, Entry); + + while( ulResultLen > 0) + { + + uniDirName.Length = (USHORT)pCurrentDirEntry->FileNameLength; + + uniDirName.MaximumLength = uniDirName.Length; + + uniDirName.Buffer = (WCHAR *)((char *)pCurrentDirEntry + pCurrentDirEntry->FileNameOffset); + + uniTargetName.Length = (USHORT)pCurrentDirEntry->TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)pCurrentDirEntry + pCurrentDirEntry->TargetNameOffset); + + // + // Be sure we don't have this entry in the case sensitive tree + // + + ulCRC = AFSGenerateCRC( &uniDirName, + FALSE); + + AFSLocateCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pDirNode); + + if( pDirNode != NULL) + { + + // + // Duplicate entry, skip it + // + + ulEntryLength = QuadAlign( sizeof( AFSDirEnumEntry) + + uniDirName.Length + + uniTargetName.Length); + + pCurrentDirEntry = (AFSDirEnumEntry *)((char *)pCurrentDirEntry + ulEntryLength); + + if( ulResultLen >= ulEntryLength) + { + ulResultLen -= ulEntryLength; + } + else + { + ulResultLen = 0; + } + + continue; + } + + pDirNode = AFSInitDirEntry( ObjectInfoCB, + &uniDirName, + &uniTargetName, + pCurrentDirEntry, + (ULONG)InterlockedIncrement( &ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.ContentIndex)); + + if( pDirNode == NULL) + { + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + + break; + } + + // + // Set up the entry length + // + + ulEntryLength = QuadAlign( sizeof( AFSDirEnumEntry) + + pCurrentDirEntry->FileNameLength + + pCurrentDirEntry->TargetNameLength); + + // + // Init the short name if we have one + // + + if( pCurrentDirEntry->ShortNameLength > 0) + { + + UNICODE_STRING uniShortName; + + pDirNode->NameInformation.ShortNameLength = pCurrentDirEntry->ShortNameLength; + + RtlCopyMemory( pDirNode->NameInformation.ShortName, + pCurrentDirEntry->ShortName, + pDirNode->NameInformation.ShortNameLength); + + // + // Generate the short name index + // + + uniShortName.Length = pDirNode->NameInformation.ShortNameLength; + uniShortName.Buffer = pDirNode->NameInformation.ShortName; + + pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, + TRUE); + } + + // + // Insert the node into the name tree + // + + ASSERT( ExIsResourceAcquiredExclusiveLite( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.TreeLock)); + + if( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead == NULL) + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = pDirNode; + } + else + { + + AFSInsertCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + pDirNode); + } + + if( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead == NULL) + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + } + else + { + + AFSInsertCaseInsensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + pDirNode); + } + + if( ObjectInfoCB->Specific.Directory.DirectoryNodeListHead == NULL) + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeListHead = pDirNode; + } + else + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeListTail->ListEntry.fLink = pDirNode; + + pDirNode->ListEntry.bLink = ObjectInfoCB->Specific.Directory.DirectoryNodeListTail; + } + + ObjectInfoCB->Specific.Directory.DirectoryNodeListTail = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_ENUM_LIST); + + InterlockedIncrement( &ObjectInfoCB->Specific.Directory.DirectoryNodeCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateDirectory Adding entry %wZ Inc Count %d to parent FID %08lX-%08lX-%08lX-%08lX\n", + &pDirNode->NameInformation.FileName, + ObjectInfoCB->Specific.Directory.DirectoryNodeCount, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + if( pDirNode->Type.Data.ShortNameTreeEntry.HashIndex != 0) + { + + // + // Insert the short name entry if we have a valid short name + // + + if( ObjectInfoCB->Specific.Directory.ShortNameTree == NULL) + { + + ObjectInfoCB->Specific.Directory.ShortNameTree = pDirNode; + } + else + { + + AFSInsertShortNameDirEntry( ObjectInfoCB->Specific.Directory.ShortNameTree, + pDirNode); + } + } + + // + // Next dir entry + // + + pCurrentDirEntry = (AFSDirEnumEntry *)((char *)pCurrentDirEntry + ulEntryLength); + + if( ulResultLen >= ulEntryLength) + { + ulResultLen -= ulEntryLength; + } + else + { + ulResultLen = 0; + } + } + + ulResultLen = AFS_DIR_ENUM_BUFFER_LEN; + + // + // Reset the information in the request buffer since it got trampled + // above + // + + pDirQueryCB->EnumHandle = pDirEnumResponse->EnumHandle; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateDirectory EnumHandle %08lX\n", + pDirQueryCB->EnumHandle); + + // + // If the enumeration handle is -1 then we are done + // + + if( ((ULONG)-1) == pDirQueryCB->EnumHandle ) + { + + break; + } + } + +try_exit: + + // + // Cleanup + // + + if( pBuffer != NULL) + { + + AFSExFreePool( pBuffer); + } + + // + // If the processing failed then we should reset the directory content in the event + // it is re-enumerated + // + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSEnumerateDirectory Resetting content for FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique, + ntStatus); + + AFSResetDirectoryContent( ObjectInfoCB); + } + } + + return ntStatus; +} + +NTSTATUS +AFSEnumerateDirectoryNoResponse( IN GUID *AuthGroup, + IN AFSFileID *FileId) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirQueryCB stDirQueryCB; + ULONG ulRequestFlags = 0; + + __Enter + { + + // + // Use the payload buffer for information we will pass to the service + // + + stDirQueryCB.EnumHandle = 0; + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_DIR_ENUM, + ulRequestFlags, + AuthGroup, + NULL, + FileId, + (void *)&stDirQueryCB, + sizeof( AFSDirQueryCB), + NULL, + NULL); + + if( ntStatus != STATUS_SUCCESS) + { + + if( ntStatus == STATUS_NO_MORE_FILES || + ntStatus == STATUS_NO_MORE_ENTRIES) + { + + ntStatus = STATUS_SUCCESS; + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSEnumerateDirectoryNoResponse Failed to enumerate directory Status %08lX\n", + ntStatus); + } + } + } + + return ntStatus; +} + +NTSTATUS +AFSVerifyDirectoryContent( IN AFSObjectInfoCB *ObjectInfoCB, + IN GUID *AuthGroup) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + void *pBuffer = NULL; + ULONG ulResultLen = 0; + AFSDirQueryCB *pDirQueryCB; + AFSDirEnumEntry *pCurrentDirEntry = NULL; + AFSDirectoryCB *pDirNode = NULL; + ULONG ulEntryLength = 0; + AFSDirEnumResp *pDirEnumResponse = NULL; + UNICODE_STRING uniDirName, uniTargetName; + ULONG ulRequestFlags = AFS_REQUEST_FLAG_SYNCHRONOUS | AFS_REQUEST_FLAG_FAST_REQUEST; + ULONG ulCRC = 0; + AFSObjectInfoCB *pObjectInfo = NULL; + ULONGLONG ullIndex = 0; + UNICODE_STRING uniGUID; + + __Enter + { + + uniGUID.Length = 0; + uniGUID.MaximumLength = 0; + uniGUID.Buffer = NULL; + + if( AuthGroup != NULL) + { + RtlStringFromGUID( *AuthGroup, + &uniGUID); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Verifying content for FID %08lX-%08lX-%08lX-%08lX AuthGroup %wZ\n", + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique, + &uniGUID); + + if( AuthGroup != NULL) + { + RtlFreeUnicodeString( &uniGUID); + } + + // + // Initialize the directory enumeration buffer for the directory + // + + pBuffer = AFSExAllocatePoolWithTag( PagedPool, + AFS_DIR_ENUM_BUFFER_LEN, + AFS_DIR_BUFFER_TAG); + + if( pBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pBuffer, + AFS_DIR_ENUM_BUFFER_LEN); + + ulResultLen = AFS_DIR_ENUM_BUFFER_LEN; + + // + // Use the payload buffer for information we will pass to the service + // + + pDirQueryCB = (AFSDirQueryCB *)pBuffer; + + pDirQueryCB->EnumHandle = 0; + + // + // Loop on the information + // + + while( TRUE) + { + + // + // Go and retrieve the directory contents + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_DIR_ENUM, + ulRequestFlags, + AuthGroup, + NULL, + &ObjectInfoCB->FileId, + (void *)pDirQueryCB, + sizeof( AFSDirQueryCB), + pBuffer, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS || + ulResultLen == 0) + { + + if( ntStatus == STATUS_NO_MORE_FILES || + ntStatus == STATUS_NO_MORE_ENTRIES) + { + + ntStatus = STATUS_SUCCESS; + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSVerifyDirectoryContent Failed to enumerate directory Status %08lX\n", + ntStatus); + } + + break; + } + + pDirEnumResponse = (AFSDirEnumResp *)pBuffer; + + pCurrentDirEntry = (AFSDirEnumEntry *)pDirEnumResponse->Entry; + + // + // Remove the leading header from the processed length + // + + ulResultLen -= FIELD_OFFSET( AFSDirEnumResp, Entry); + + while( ulResultLen > 0) + { + + uniDirName.Length = (USHORT)pCurrentDirEntry->FileNameLength; + + uniDirName.MaximumLength = uniDirName.Length; + + uniDirName.Buffer = (WCHAR *)((char *)pCurrentDirEntry + pCurrentDirEntry->FileNameOffset); + + uniTargetName.Length = (USHORT)pCurrentDirEntry->TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)pCurrentDirEntry + pCurrentDirEntry->TargetNameOffset); + + // + // Does this entry already exist in the directory? + // + + ulCRC = AFSGenerateCRC( &uniDirName, + FALSE); + + ASSERT( ExIsResourceAcquiredExclusiveLite( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.TreeLock)); + + AFSLocateCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pDirNode); + + // + // + // Set up the entry length + // + + ulEntryLength = QuadAlign( sizeof( AFSDirEnumEntry) + + pCurrentDirEntry->FileNameLength + + pCurrentDirEntry->TargetNameLength); + + if( pDirNode != NULL) + { + + // + // Check that the FIDs are the same + // + + if( AFSIsEqualFID( &pCurrentDirEntry->FileId, + &pDirNode->ObjectInformation->FileId)) + { + + AFSAcquireShared( ObjectInfoCB->VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + ullIndex = AFSCreateLowIndex( &pCurrentDirEntry->FileId); + + ntStatus = AFSLocateHashEntry( ObjectInfoCB->VolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfo); + + AFSReleaseResource( ObjectInfoCB->VolumeCB->ObjectInfoTree.TreeLock); + + if( NT_SUCCESS( ntStatus) && + pObjectInfo != NULL) + { + + // + // Indicate this is a valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Verified entry %wZ for parent FID %08lX-%08lX-%08lX-%08lX\n", + &uniDirName, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + + // + // Update the metadata for the entry + // + + if( pObjectInfo->DataVersion.QuadPart == 0 || + pObjectInfo->DataVersion.QuadPart != pCurrentDirEntry->DataVersion.QuadPart) + { + + AFSUpdateMetaData( pDirNode, + pCurrentDirEntry); + + if( pObjectInfo->FileType == AFS_FILE_TYPE_DIRECTORY) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Setting VERIFY on entry %wZ for FID %08lX-%08lX-%08lX-%08lX\n", + &uniDirName, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + pObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1; + pObjectInfo->Expiration.QuadPart = 0; + } + } + + // + // Next dir entry + // + + pCurrentDirEntry = (AFSDirEnumEntry *)((char *)pCurrentDirEntry + ulEntryLength); + + if( ulResultLen >= ulEntryLength) + { + ulResultLen -= ulEntryLength; + } + else + { + ulResultLen = 0; + } + + continue; + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Processing dir entry %wZ with different FID, same name in parent FID %08lX-%08lX-%08lX-%08lX\n", + &pDirNode->NameInformation.FileName, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + // + // Need to tear down this entry and rebuild it below + // + + if( pDirNode->OpenReferenceCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Deleting dir entry %wZ from parent FID %08lX-%08lX-%08lX-%08lX\n", + &pDirNode->NameInformation.FileName, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + AFSDeleteDirEntry( ObjectInfoCB, + pDirNode); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Setting dir entry %p name %wZ DELETED in parent FID %08lX-%08lX-%08lX-%08lX\n", + pDirNode, + &pDirNode->NameInformation.FileName, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_DELETED); + + AFSRemoveNameEntry( ObjectInfoCB, + pDirNode); + } + } + + pDirNode = AFSInitDirEntry( ObjectInfoCB, + &uniDirName, + &uniTargetName, + pCurrentDirEntry, + (ULONG)InterlockedIncrement( &ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.ContentIndex)); + + if( pDirNode == NULL) + { + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + + break; + } + + // + // Init the short name if we have one + // + + if( pCurrentDirEntry->ShortNameLength > 0) + { + + UNICODE_STRING uniShortName; + + pDirNode->NameInformation.ShortNameLength = pCurrentDirEntry->ShortNameLength; + + RtlCopyMemory( pDirNode->NameInformation.ShortName, + pCurrentDirEntry->ShortName, + pDirNode->NameInformation.ShortNameLength); + + // + // Generate the short name index + // + + uniShortName.Length = pDirNode->NameInformation.ShortNameLength; + uniShortName.Buffer = pDirNode->NameInformation.ShortName; + + pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, + TRUE); + } + + // + // Insert the node into the name tree + // + + ASSERT( ExIsResourceAcquiredExclusiveLite( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.TreeLock)); + + if( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead == NULL) + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = pDirNode; + } + else + { + + AFSInsertCaseSensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + pDirNode); + } + + if( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead == NULL) + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + } + else + { + + AFSInsertCaseInsensitiveDirEntry( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + pDirNode); + } + + if( ObjectInfoCB->Specific.Directory.DirectoryNodeListHead == NULL) + { + + ObjectInfoCB->Specific.Directory.DirectoryNodeListHead = pDirNode; + } + else + { + + (ObjectInfoCB->Specific.Directory.DirectoryNodeListTail)->ListEntry.fLink = pDirNode; + + pDirNode->ListEntry.bLink = ObjectInfoCB->Specific.Directory.DirectoryNodeListTail; + } + + ObjectInfoCB->Specific.Directory.DirectoryNodeListTail = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_ENUM_LIST); + + InterlockedIncrement( &ObjectInfoCB->Specific.Directory.DirectoryNodeCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyDirectoryContent Adding entry %wZ Inc Count %d to parent FID %08lX-%08lX-%08lX-%08lX\n", + &pDirNode->NameInformation.FileName, + ObjectInfoCB->Specific.Directory.DirectoryNodeCount, + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + + if( pDirNode->Type.Data.ShortNameTreeEntry.HashIndex != 0) + { + + // + // Insert the short name entry if we have a valid short name + // + + if( ObjectInfoCB->Specific.Directory.ShortNameTree == NULL) + { + + ObjectInfoCB->Specific.Directory.ShortNameTree = pDirNode; + } + else + { + + AFSInsertShortNameDirEntry( ObjectInfoCB->Specific.Directory.ShortNameTree, + pDirNode); + } + } + + // + // Next dir entry + // + + pCurrentDirEntry = (AFSDirEnumEntry *)((char *)pCurrentDirEntry + ulEntryLength); + + if( ulResultLen >= ulEntryLength) + { + ulResultLen -= ulEntryLength; + } + else + { + ulResultLen = 0; + } + } + + ulResultLen = AFS_DIR_ENUM_BUFFER_LEN; + + // + // Reset the information in the request buffer since it got trampled + // above + // + + pDirQueryCB->EnumHandle = pDirEnumResponse->EnumHandle; + + // + // If the enumeration handle is -1 then we are done + // + + if( ((ULONG)-1) == pDirQueryCB->EnumHandle ) + { + + break; + } + } + +try_exit: + + // + // Cleanup + // + + if( pBuffer != NULL) + { + + AFSExFreePool( pBuffer); + } + } + + return ntStatus; +} + +NTSTATUS +AFSNotifyFileCreate( IN GUID *AuthGroup, + IN AFSObjectInfoCB *ParentObjectInfo, + IN PLARGE_INTEGER FileSize, + IN ULONG FileAttributes, + IN UNICODE_STRING *FileName, + OUT AFSDirectoryCB **DirNode) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFileCreateCB stCreateCB; + AFSFileCreateResultCB *pResultCB = NULL; + ULONG ulResultLen = 0; + UNICODE_STRING uniTargetName; + AFSDirectoryCB *pDirNode = NULL; + ULONG ulCRC = 0; + LARGE_INTEGER liOldDataVersion; + + __Enter + { + + // + // Init the control block for the request + // + + RtlZeroMemory( &stCreateCB, + sizeof( AFSFileCreateCB)); + + stCreateCB.ParentId = ParentObjectInfo->FileId; + + stCreateCB.AllocationSize = *FileSize; + + stCreateCB.FileAttributes = FileAttributes; + + stCreateCB.EaSize = 0; + + liOldDataVersion = ParentObjectInfo->DataVersion; + + // + // Allocate our return buffer + // + + pResultCB = (AFSFileCreateResultCB *)AFSExAllocatePoolWithTag( PagedPool, + PAGE_SIZE, + AFS_GENERIC_MEMORY_1_TAG); + + if( pResultCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pResultCB, + PAGE_SIZE); + + ulResultLen = PAGE_SIZE; + + // + // Send the call to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CREATE_FILE, + AFS_REQUEST_FLAG_SYNCHRONOUS | AFS_REQUEST_FLAG_HOLD_FID, + AuthGroup, + FileName, + NULL, + &stCreateCB, + sizeof( AFSFileCreateCB), + pResultCB, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS) + { + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_DEVICE_NOT_READY; + } + + try_return( ntStatus); + } + + // + // We may have raced with an invalidation call and a subsequent re-enumeration of this parent + // and though we created the node, it is already in our list. If this is the case then + // look up the entry rather than create a new entry + // The check is to ensure the DV has been modified + // + + if( liOldDataVersion.QuadPart != pResultCB->ParentDataVersion.QuadPart - 1 || + liOldDataVersion.QuadPart != ParentObjectInfo->DataVersion.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNotifyFileCreate Raced with an invalidate call and a re-enumeration for entry %wZ\n", + FileName); + + // + // We raced so go and lookup the directory entry in the parent + // + + ulCRC = AFSGenerateCRC( FileName, + FALSE); + + AFSAcquireShared( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSLocateCaseSensitiveDirEntry( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pDirNode); + + AFSReleaseResource( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + + if( pDirNode != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNotifyFileCreate Located dir entry for file %wZ\n", + FileName); + + *DirNode = pDirNode; + + try_return( ntStatus = STATUS_REPARSE); + } + + // + // We are unsure of our current data so set the verify flag. It may already be set + // but no big deal to reset it + // + + SetFlag( ParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + + ParentObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1; + } + else + { + + // + // Update the parent data version + // + + ParentObjectInfo->DataVersion = pResultCB->ParentDataVersion; + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNotifyFileCreate Creating new entry %wZ\n", + FileName); + + // + // Initialize the directory entry + // + + uniTargetName.Length = (USHORT)pResultCB->DirEnum.TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)&pResultCB->DirEnum + pResultCB->DirEnum.TargetNameOffset); + + pDirNode = AFSInitDirEntry( ParentObjectInfo, + FileName, + &uniTargetName, + &pResultCB->DirEnum, + (ULONG)InterlockedIncrement( &ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.ContentIndex)); + + if( pDirNode == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Init the short name if we have one + // + + if( pResultCB->DirEnum.ShortNameLength > 0) + { + + UNICODE_STRING uniShortName; + + pDirNode->NameInformation.ShortNameLength = pResultCB->DirEnum.ShortNameLength; + + RtlCopyMemory( pDirNode->NameInformation.ShortName, + pResultCB->DirEnum.ShortName, + pDirNode->NameInformation.ShortNameLength); + + // + // Generate the short name index + // + + uniShortName.Length = pDirNode->NameInformation.ShortNameLength; + uniShortName.Buffer = pDirNode->NameInformation.ShortName; + + pDirNode->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, + TRUE); + } + + // + // Return the directory node + // + + *DirNode = pDirNode; + +try_exit: + + if( pResultCB != NULL) + { + + AFSExFreePool( pResultCB); + } + + if( !NT_SUCCESS( ntStatus)) + { + + } + } + + return ntStatus; +} + +NTSTATUS +AFSUpdateFileInformation( IN AFSFileID *ParentFid, + IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSFileUpdateCB stUpdateCB; + ULONG ulResultLen = 0; + AFSFileUpdateResultCB *pUpdateResultCB = NULL; + + __Enter + { + + // + // Init the control block for the request + // + + RtlZeroMemory( &stUpdateCB, + sizeof( AFSFileUpdateCB)); + + stUpdateCB.AllocationSize = ObjectInfo->EndOfFile; + + stUpdateCB.FileAttributes = ObjectInfo->FileAttributes; + + stUpdateCB.EaSize = ObjectInfo->EaSize; + + stUpdateCB.ParentId = *ParentFid; + + stUpdateCB.LastAccessTime = ObjectInfo->LastAccessTime; + + stUpdateCB.CreateTime = ObjectInfo->CreationTime; + + stUpdateCB.ChangeTime = ObjectInfo->ChangeTime; + + stUpdateCB.LastWriteTime = ObjectInfo->LastWriteTime; + + pUpdateResultCB = (AFSFileUpdateResultCB *)AFSExAllocatePoolWithTag( PagedPool, + PAGE_SIZE, + AFS_UPDATE_RESULT_TAG); + + if( pUpdateResultCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ulResultLen = PAGE_SIZE; + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_UPDATE_FILE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + AuthGroup, + NULL, + &ObjectInfo->FileId, + &stUpdateCB, + sizeof( AFSFileUpdateCB), + pUpdateResultCB, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSUpdateFileInformation failed FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + ObjectInfo->FileId.Cell, + ObjectInfo->FileId.Volume, + ObjectInfo->FileId.Vnode, + ObjectInfo->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + // + // Update the data version + // + + ObjectInfo->DataVersion = pUpdateResultCB->DirEnum.DataVersion; + +try_exit: + + if( pUpdateResultCB != NULL) + { + + AFSExFreePool( pUpdateResultCB); + } + } + + return ntStatus; +} + +NTSTATUS +AFSNotifyDelete( IN AFSDirectoryCB *DirectoryCB, + IN BOOLEAN CheckOnly) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulResultLen = 0; + AFSFileDeleteCB stDelete; + AFSFileDeleteResultCB stDeleteResult; + ULONG ulRequestFlags = AFS_REQUEST_FLAG_SYNCHRONOUS; + GUID *pAuthGroup = NULL; + + __Enter + { + + stDelete.ParentId = DirectoryCB->ObjectInformation->ParentObjectInformation->FileId; + + stDelete.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + ulResultLen = sizeof( AFSFileDeleteResultCB); + + if( CheckOnly) + { + ulRequestFlags |= AFS_REQUEST_FLAG_CHECK_ONLY; + } + + if( DirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &DirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_DELETE_FILE, + ulRequestFlags, + pAuthGroup, + &DirectoryCB->NameInformation.FileName, + &DirectoryCB->ObjectInformation->FileId, + &stDelete, + sizeof( AFSFileDeleteCB), + &stDeleteResult, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNotifyDelete failed FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &DirectoryCB->ObjectInformation->FileId.Cell, + &DirectoryCB->ObjectInformation->FileId.Volume, + &DirectoryCB->ObjectInformation->FileId.Vnode, + &DirectoryCB->ObjectInformation->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + if( !CheckOnly) + { + + // + // Update the parent data version + // + + if( DirectoryCB->ObjectInformation->ParentObjectInformation->DataVersion.QuadPart != stDeleteResult.ParentDataVersion.QuadPart) + { + + DirectoryCB->ObjectInformation->ParentObjectInformation->Flags |= AFS_OBJECT_FLAGS_VERIFY; + + DirectoryCB->ObjectInformation->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1; + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSNotifyRename( IN AFSObjectInfoCB *ObjectInfo, + IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSObjectInfoCB *TargetParentObjectInfo, + IN AFSDirectoryCB *DirectoryCB, + IN UNICODE_STRING *TargetName, + OUT AFSFileID *UpdatedFID) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFileRenameCB *pRenameCB = NULL; + AFSFileRenameResultCB *pRenameResultCB = NULL; + ULONG ulResultLen = 0; + GUID *pAuthGroup = NULL; + + __Enter + { + + // + // Init the control block for the request + // + + pRenameCB = (AFSFileRenameCB *)AFSExAllocatePoolWithTag( PagedPool, + PAGE_SIZE, + AFS_RENAME_REQUEST_TAG); + + if( pRenameCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pRenameCB, + PAGE_SIZE); + + pRenameCB->SourceParentId = ParentObjectInfo->FileId; + + pRenameCB->TargetParentId = TargetParentObjectInfo->FileId; + + pRenameCB->TargetNameLength = TargetName->Length; + + RtlCopyMemory( pRenameCB->TargetName, + TargetName->Buffer, + TargetName->Length); + + if( ObjectInfo->Fcb != NULL) + { + pAuthGroup = &ObjectInfo->Fcb->AuthGroup; + } + + // + // Use the same buffer for the result control block + // + + pRenameResultCB = (AFSFileRenameResultCB *)pRenameCB; + + ulResultLen = PAGE_SIZE; + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RENAME_FILE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + pAuthGroup, + &DirectoryCB->NameInformation.FileName, + &ObjectInfo->FileId, + pRenameCB, + sizeof( AFSFileRenameCB) + TargetName->Length, + pRenameResultCB, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNotifyRename failed FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + ObjectInfo->FileId.Cell, + ObjectInfo->FileId.Volume, + ObjectInfo->FileId.Vnode, + ObjectInfo->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + // + // Update the information from the returned data + // + + ParentObjectInfo->DataVersion = pRenameResultCB->SourceParentDataVersion; + + TargetParentObjectInfo->DataVersion = pRenameResultCB->TargetParentDataVersion; + + // + // Move over the short name + // + + DirectoryCB->NameInformation.ShortNameLength = pRenameResultCB->DirEnum.ShortNameLength; + + if( DirectoryCB->NameInformation.ShortNameLength > 0) + { + + RtlCopyMemory( DirectoryCB->NameInformation.ShortName, + pRenameResultCB->DirEnum.ShortName, + DirectoryCB->NameInformation.ShortNameLength); + } + + if( UpdatedFID != NULL) + { + + *UpdatedFID = pRenameResultCB->DirEnum.FileId; + } + +try_exit: + + if( pRenameCB != NULL) + { + + AFSExFreePool( pRenameCB); + } + } + + return ntStatus; +} + +NTSTATUS +AFSEvaluateTargetByID( IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup, + IN BOOLEAN FastCall, + OUT AFSDirEnumEntry **DirEnumEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSEvalTargetCB stTargetID; + ULONG ulResultBufferLength; + AFSDirEnumEntry *pDirEnumCB = NULL; + ULONG ulRequestFlags = AFS_REQUEST_FLAG_SYNCHRONOUS; + + __Enter + { + + RtlZeroMemory( &stTargetID, + sizeof( AFSEvalTargetCB)); + + if( ObjectInfo->ParentObjectInformation != NULL) + { + + stTargetID.ParentId = ObjectInfo->ParentObjectInformation->FileId; + } + + // + // Allocate our response buffer + // + + pDirEnumCB = (AFSDirEnumEntry *)AFSExAllocatePoolWithTag( PagedPool, + PAGE_SIZE, + AFS_GENERIC_MEMORY_2_TAG); + + if( pDirEnumCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Call to the service to evaluate the fid + // + + ulResultBufferLength = PAGE_SIZE; + + if( FastCall) + { + + ulRequestFlags |= AFS_REQUEST_FLAG_FAST_REQUEST; + } + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_EVAL_TARGET_BY_ID, + ulRequestFlags, + AuthGroup, + NULL, + &ObjectInfo->FileId, + &stTargetID, + sizeof( AFSEvalTargetCB), + pDirEnumCB, + &ulResultBufferLength); + + if( ntStatus != STATUS_SUCCESS) + { + + // + // If we received back a STATUS_INVALID_HANDLE then mark the parent as requiring + // verification + // + + if( ntStatus == STATUS_INVALID_HANDLE) + { + + if( ObjectInfo->ParentObjectInformation != NULL) + { + + SetFlag( ObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY); + } + } + + try_return( ntStatus); + } + + // + // Pass back the dir enum entry + // + + if( DirEnumEntry != NULL) + { + + *DirEnumEntry = pDirEnumCB; + } + else + { + + AFSExFreePool( pDirEnumCB); + } + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( pDirEnumCB != NULL) + { + + AFSExFreePool( pDirEnumCB); + } + + *DirEnumEntry = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSEvaluateTargetByName( IN GUID *AuthGroup, + IN AFSFileID *ParentFileId, + IN PUNICODE_STRING SourceName, + OUT AFSDirEnumEntry **DirEnumEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSEvalTargetCB stTargetID; + ULONG ulResultBufferLength; + AFSDirEnumEntry *pDirEnumCB = NULL; + + __Enter + { + + stTargetID.ParentId = *ParentFileId; + + // + // Allocate our response buffer + // + + pDirEnumCB = (AFSDirEnumEntry *)AFSExAllocatePoolWithTag( PagedPool, + PAGE_SIZE, + AFS_GENERIC_MEMORY_3_TAG); + + if( pDirEnumCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Call to the service to evaluate the fid + // + + ulResultBufferLength = PAGE_SIZE; + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_EVAL_TARGET_BY_NAME, + AFS_REQUEST_FLAG_SYNCHRONOUS, + AuthGroup, + SourceName, + NULL, + &stTargetID, + sizeof( AFSEvalTargetCB), + pDirEnumCB, + &ulResultBufferLength); + + if( ntStatus != STATUS_SUCCESS) + { + + try_return( ntStatus); + } + + // + // Pass back the dir enum entry + // + + *DirEnumEntry = pDirEnumCB; + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( pDirEnumCB != NULL) + { + + AFSExFreePool( pDirEnumCB); + } + + *DirEnumEntry = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSRetrieveVolumeInformation( IN GUID *AuthGroup, + IN AFSFileID *FileID, + OUT AFSVolumeInfoCB *VolumeInformation) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulResultLen = 0; + + __Enter + { + + ulResultLen = sizeof( AFSVolumeInfoCB); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_GET_VOLUME_INFO, + AFS_REQUEST_FLAG_SYNCHRONOUS, + AuthGroup, + NULL, + FileID, + NULL, + 0, + VolumeInformation, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS) + { + + try_return( ntStatus); + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSNotifyPipeTransceive( IN AFSCcb *Ccb, + IN ULONG InputLength, + IN ULONG OutputLength, + IN void *InputDataBuffer, + OUT void *OutputDataBuffer, + OUT ULONG *BytesReturned) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulResultLen = 0; + MDL *pInputMdl = NULL, *pOutputMdl = NULL; + void *pInputSystemBuffer = NULL, *pOutputSystemBuffer = NULL; + ULONG ulBufferLength = OutputLength; + AFSPipeIORequestCB *pIoRequest = NULL; + GUID *pAuthGroup = NULL; + + __Enter + { + + // + // Map the user buffer to a system address + // + + pInputSystemBuffer = AFSLockUserBuffer( InputDataBuffer, + InputLength, + &pInputMdl); + + if( pInputSystemBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSPipeIORequestCB) + + InputLength, + AFS_GENERIC_MEMORY_4_TAG); + + if( pIoRequest == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pIoRequest, + sizeof( AFSPipeIORequestCB) + InputLength); + + pIoRequest->RequestId = Ccb->RequestID; + + pIoRequest->RootId = Ccb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInformation.FileId; + + pIoRequest->BufferLength = InputLength; + + RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)), + pInputSystemBuffer, + InputLength); + + pOutputSystemBuffer = AFSLockUserBuffer( OutputDataBuffer, + OutputLength, + &pOutputMdl); + + if( pOutputSystemBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + if( Ccb->DirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &Ccb->DirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + + // + // Send the call to the service + // + + ulResultLen = OutputLength; + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_TRANSCEIVE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + pAuthGroup, + &Ccb->DirectoryCB->NameInformation.FileName, + NULL, + pIoRequest, + sizeof( AFSPipeIORequestCB) + InputLength, + pOutputSystemBuffer, + &ulResultLen); + + if( ntStatus != STATUS_SUCCESS && + ntStatus != STATUS_BUFFER_OVERFLOW) + { + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_DEVICE_NOT_READY; + } + + try_return( ntStatus); + } + + // + // Return the bytes processed + // + + *BytesReturned = ulResultLen; + +try_exit: + + if( pInputMdl != NULL) + { + + MmUnlockPages( pInputMdl); + + IoFreeMdl( pInputMdl); + } + + if( pOutputMdl != NULL) + { + + MmUnlockPages( pOutputMdl); + + IoFreeMdl( pOutputMdl); + } + + if( pIoRequest != NULL) + { + + AFSExFreePool( pIoRequest); + } + } + + return ntStatus; +} + +NTSTATUS +AFSNotifySetPipeInfo( IN AFSCcb *Ccb, + IN ULONG InformationClass, + IN ULONG InputLength, + IN void *DataBuffer) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSPipeInfoRequestCB *pInfoRequest = NULL; + GUID *pAuthGroup = NULL; + + __Enter + { + + pInfoRequest = (AFSPipeInfoRequestCB *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSPipeInfoRequestCB) + + InputLength, + AFS_GENERIC_MEMORY_5_TAG); + + if( pInfoRequest == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pInfoRequest, + sizeof( AFSPipeInfoRequestCB) + InputLength); + + pInfoRequest->RequestId = Ccb->RequestID; + + pInfoRequest->RootId = Ccb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInformation.FileId; + + pInfoRequest->BufferLength = InputLength; + + pInfoRequest->InformationClass = InformationClass; + + RtlCopyMemory( (void *)((char *)pInfoRequest + sizeof( AFSPipeInfoRequestCB)), + DataBuffer, + InputLength); + + if( Ccb->DirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &Ccb->DirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + + // + // Send the call to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_SET_INFO, + AFS_REQUEST_FLAG_SYNCHRONOUS, + pAuthGroup, + &Ccb->DirectoryCB->NameInformation.FileName, + NULL, + pInfoRequest, + sizeof( AFSPipeInfoRequestCB) + InputLength, + NULL, + NULL); + + if( ntStatus != STATUS_SUCCESS) + { + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_DEVICE_NOT_READY; + } + + try_return( ntStatus); + } + +try_exit: + + if( pInfoRequest != NULL) + { + + AFSExFreePool( pInfoRequest); + } + } + + return ntStatus; +} + +NTSTATUS +AFSNotifyQueryPipeInfo( IN AFSCcb *Ccb, + IN ULONG InformationClass, + IN ULONG OutputLength, + IN void *DataBuffer, + OUT ULONG *BytesReturned) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSPipeInfoRequestCB stInfoRequest; + ULONG ulBytesProcessed = 0; + GUID *pAuthGroup = NULL; + + __Enter + { + + RtlZeroMemory( &stInfoRequest, + sizeof( AFSPipeInfoRequestCB)); + + stInfoRequest.RequestId = Ccb->RequestID; + + stInfoRequest.RootId = Ccb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInformation.FileId; + + stInfoRequest.BufferLength = OutputLength; + + stInfoRequest.InformationClass = InformationClass; + + ulBytesProcessed = OutputLength; + + if( Ccb->DirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &Ccb->DirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + + // + // Send the call to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_QUERY_INFO, + AFS_REQUEST_FLAG_SYNCHRONOUS, + pAuthGroup, + &Ccb->DirectoryCB->NameInformation.FileName, + NULL, + &stInfoRequest, + sizeof( AFSPipeInfoRequestCB), + DataBuffer, + &ulBytesProcessed); + + if( ntStatus != STATUS_SUCCESS) + { + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_DEVICE_NOT_READY; + } + + try_return( ntStatus); + } + + *BytesReturned = ulBytesProcessed; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSReleaseFid( IN AFSFileID *FileId) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FID, + 0, + NULL, + NULL, + FileId, + NULL, + 0, + NULL, + NULL); + } + + return ntStatus; +} + +BOOLEAN +AFSIsExtentRequestQueued( IN AFSFileID *FileID, + IN LARGE_INTEGER *ExtentOffset, + IN ULONG Length) +{ + + BOOLEAN bRequestQueued = FALSE; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + AFSCommSrvcCB *pCommSrvc = NULL; + AFSPoolEntry *pPoolEntry = NULL; + AFSRequestExtentsCB *pRequestExtents = NULL; + + __Enter + { + + + pCommSrvc = &pControlDevExt->Specific.Control.CommServiceCB; + + AFSAcquireShared( &pCommSrvc->IrpPoolLock, + TRUE); + + pPoolEntry = pCommSrvc->RequestPoolHead; + + while( pPoolEntry != NULL) + { + + if( pPoolEntry->RequestType == AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS) + { + + if( AFSIsEqualFID( &pPoolEntry->FileId, FileID)) + { + + pRequestExtents = (AFSRequestExtentsCB *)pPoolEntry->Data; + + if( pRequestExtents->ByteOffset.QuadPart == ExtentOffset->QuadPart && + pRequestExtents->Length == Length) + { + + bRequestQueued = TRUE; + } + } + } + + pPoolEntry = pPoolEntry->fLink; + } + + AFSReleaseResource( &pCommSrvc->IrpPoolLock); + } + + return bRequestQueued; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp new file mode 100644 index 0000000000..72343c6ffe --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp @@ -0,0 +1,3714 @@ +/* + * 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: AFSCreate.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSCreate +// +// Description: +// +// This function is the dispatch handler for the IRP_MJ_CREATE requests. It makes the determination to +// which interface this request is destined. +// +// Return: +// +// A status is returned for the function. The Irp completion processing is handled in the specific +// interface handler. +// + +NTSTATUS +AFSCreate( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + FILE_OBJECT *pFileObject = NULL; + + __try + { + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + pFileObject = pIrpSp->FileObject; + + if( pFileObject == NULL || + pFileObject->FileName.Buffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate (%08lX) Processing control device open request\n", + Irp); + + ntStatus = AFSControlDeviceCreate( Irp); + + try_return( ntStatus); + } + + if( AFSRDRDeviceObject == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate (%08lX) Invalid request to open before library is initialized\n", + Irp); + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + ntStatus = AFSCommonCreate( AFSRDRDeviceObject, + Irp); + +try_exit: + + NOTHING; + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSCreate\n"); + + ntStatus = STATUS_ACCESS_DENIED; + } + + // + // Complete the request + // + + AFSCompleteRequest( Irp, + ntStatus); + + return ntStatus; +} + +NTSTATUS +AFSCommonCreate( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniFileName; + ULONG ulCreateDisposition = 0; + ULONG ulOptions = 0; + BOOLEAN bNoIntermediateBuffering = FALSE; + FILE_OBJECT *pFileObject = NULL; + IO_STACK_LOCATION *pIrpSp; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + AFSDeviceExt *pDeviceExt = NULL; + BOOLEAN bOpenTargetDirectory = FALSE, bReleaseVolume = FALSE; + PACCESS_MASK pDesiredAccess = NULL; + UNICODE_STRING uniComponentName, uniPathName, uniRootFileName, uniParsedFileName; + UNICODE_STRING uniSubstitutedPathName; + UNICODE_STRING uniRelativeName; + AFSNameArrayHdr *pNameArray = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSDirectoryCB *pParentDirectoryCB = NULL, *pDirectoryCB = NULL; + ULONG ulParseFlags = 0; + GUID stAuthGroup; + ULONG ulNameProcessingFlags = 0; + + __Enter + { + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + pDeviceExt = (AFSDeviceExt *)DeviceObject->DeviceExtension; + ulCreateDisposition = (pIrpSp->Parameters.Create.Options >> 24) & 0x000000ff; + ulOptions = pIrpSp->Parameters.Create.Options; + bNoIntermediateBuffering = BooleanFlagOn( ulOptions, FILE_NO_INTERMEDIATE_BUFFERING); + bOpenTargetDirectory = BooleanFlagOn( pIrpSp->Flags, SL_OPEN_TARGET_DIRECTORY); + pFileObject = pIrpSp->FileObject; + pDesiredAccess = &pIrpSp->Parameters.Create.SecurityContext->DesiredAccess; + + uniFileName.Length = uniFileName.MaximumLength = 0; + uniFileName.Buffer = NULL; + + uniRootFileName.Length = uniRootFileName.MaximumLength = 0; + uniRootFileName.Buffer = NULL; + + uniParsedFileName.Length = uniParsedFileName.MaximumLength = 0; + uniParsedFileName.Buffer = NULL; + + uniSubstitutedPathName.Buffer = NULL; + uniSubstitutedPathName.Length = 0; + + uniRelativeName.Buffer = NULL; + uniRelativeName.Length = 0; + + if( AFSGlobalRoot == NULL) + { + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + RtlZeroMemory( &stAuthGroup, + sizeof( GUID)); + + AFSRetrieveAuthGroupFnc( (ULONGLONG)PsGetCurrentProcessId(), + (ULONGLONG)PsGetCurrentThreadId(), + &stAuthGroup); + + if( !BooleanFlagOn( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + ntStatus = AFSEnumerateGlobalRoot( &stAuthGroup); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to enumerate global root Status %08lX\n", + ntStatus); + + try_return( ntStatus); + } + } + + // + // If we are in shutdown mode then fail the request + // + + if( BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSCommonCreate (%08lX) Open request after shutdown\n", + Irp); + + try_return( ntStatus = STATUS_TOO_LATE); + } + + // + // Go and parse the name for processing. + // If ulParseFlags is returned with AFS_PARSE_FLAG_FREE_FILE_BUFFER set, + // then we are responsible for releasing the uniRootFileName.Buffer. + // + + ntStatus = AFSParseName( Irp, + &stAuthGroup, + &uniFileName, + &uniParsedFileName, + &uniRootFileName, + &ulParseFlags, + &pVolumeCB, + &pParentDirectoryCB, + &pNameArray); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + uniFileName.Length > 0 ? AFS_TRACE_LEVEL_ERROR : AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%08lX) Failed to parse name \"%wZ\" Status %08lX\n", + Irp, + &uniFileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Check for STATUS_REPARSE + // + + if( ntStatus == STATUS_REPARSE) + { + + // + // Update the information and return + // + + Irp->IoStatus.Information = IO_REPARSE; + + try_return( ntStatus); + } + + // + // If the returned volume cb is NULL then we are dealing with the \\Server\GlobalRoot + // name + // + + if( pVolumeCB == NULL) + { + + // + // Remove any leading or trailing slashes + // + + if( uniFileName.Length >= sizeof( WCHAR) && + uniFileName.Buffer[ (uniFileName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + uniFileName.Length -= sizeof( WCHAR); + } + + if( uniFileName.Length >= sizeof( WCHAR) && + uniFileName.Buffer[ 0] == L'\\') + { + + uniFileName.Buffer = &uniFileName.Buffer[ 1]; + + uniFileName.Length -= sizeof( WCHAR); + } + + // + // If there is a remaining portion returned for this request then + // check if it is for the PIOCtl interface + // + + if( uniFileName.Length > 0) + { + + // + // We don't accept any other opens off of the AFS Root + // + + ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; + + // + // If this is an open on "_._AFS_IOCTL_._" then perform handling on it accordingly + // + + if( RtlCompareUnicodeString( &AFSPIOCtlName, + &uniFileName, + TRUE) == 0) + { + + ntStatus = AFSOpenIOCtlFcb( Irp, + &stAuthGroup, + AFSGlobalRoot->DirectoryCB, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to open root IOCtl Fcb Status %08lX\n", + ntStatus); + } + } + else if( pParentDirectoryCB != NULL && + pParentDirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_SPECIAL_SHARE_NAME) + { + + ntStatus = AFSOpenSpecialShareFcb( Irp, + &stAuthGroup, + pParentDirectoryCB, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to open special share Fcb Status %08lX\n", + ntStatus); + } + } + + try_return( ntStatus); + } + + ntStatus = AFSOpenAFSRoot( Irp, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to open root Status %08lX\n", + ntStatus); + + InterlockedDecrement( &AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement1 count on &wZ DE %p Ccb %p Cnt %d\n", + &AFSGlobalRoot->DirectoryCB->NameInformation.FileName, + AFSGlobalRoot->DirectoryCB, + NULL, + AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + } + + try_return( ntStatus); + } + + // + // We have our root node shared + // + + bReleaseVolume = TRUE; + + // + // Attempt to locate the node in the name tree if this is not a target + // open and the target is not the root + // + + uniComponentName.Length = 0; + uniComponentName.Buffer = NULL; + + if( uniFileName.Length > sizeof( WCHAR) || + uniFileName.Buffer[ 0] != L'\\') + { + + if( !AFSValidNameFormat( &uniFileName)) + { + + ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%08lX) Invalid name %wZ Status %08lX\n", + Irp, + &uniFileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Opening a reparse point directly? + // + + ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME; + + if( BooleanFlagOn( ulOptions, FILE_OPEN_REPARSE_POINT)) + { + ulNameProcessingFlags |= (AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL); + } + + uniSubstitutedPathName = uniRootFileName; + + ntStatus = AFSLocateNameEntry( &stAuthGroup, + pFileObject, + &uniRootFileName, + &uniParsedFileName, + pNameArray, + ulNameProcessingFlags, + &pVolumeCB, + &pParentDirectoryCB, + &pDirectoryCB, + &uniComponentName); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer) + { + uniSubstitutedPathName.Buffer = NULL; + } + + // + // The routine above released the root while walking the + // branch + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%08lX) Failed to locate name entry for %wZ Status %08lX\n", + Irp, + &uniFileName, + ntStatus); + + // + // We released any root volume locks in the above on failure + // + + bReleaseVolume = FALSE; + + try_return( ntStatus); + } + + // + // Check for STATUS_REPARSE + // + + if( ntStatus == STATUS_REPARSE) + { + + uniSubstitutedPathName.Buffer = NULL; + + // + // Update the information and return + // + + Irp->IoStatus.Information = IO_REPARSE; + + // + // We released the volume lock above + // + + bReleaseVolume = FALSE; + + try_return( ntStatus); + } + + // + // If we re-allocated the name, then update our substitute name + // + + if( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer) + { + + uniSubstitutedPathName = uniRootFileName; + } + else + { + + uniSubstitutedPathName.Buffer = NULL; + } + + // + // Check for a symlink access + // + + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND && + pParentDirectoryCB != NULL) + { + + UNICODE_STRING uniFinalComponent; + + uniFinalComponent.Length = 0; + uniFinalComponent.MaximumLength = 0; + uniFinalComponent.Buffer = NULL; + + AFSRetrieveFinalComponent( &uniFileName, + &uniFinalComponent); + + ntStatus = AFSCheckSymlinkAccess( pParentDirectoryCB, + &uniFinalComponent); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%08lX) Failing access to symlink %wZ Status %08lX\n", + Irp, + &uniFileName, + ntStatus); + + try_return( ntStatus); + } + } + } + + // + // If we have no parent then this is a root open, be sure there is a directory entry + // for the root + // + + else if( pParentDirectoryCB == NULL && + pDirectoryCB == NULL) + { + + pDirectoryCB = pVolumeCB->DirectoryCB; + } + + if( bOpenTargetDirectory) + { + + // + // If we have a directory cb for the entry then dereference it and reference the parent + // + + if( pDirectoryCB != NULL) + { + + // + // Perform in this order to prevent thrashing + // + + InterlockedIncrement( &pParentDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Increment1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + NULL, + pParentDirectoryCB->OpenReferenceCount); + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + + // + // The name array also contains a reference to the pDirectoryCB so we need to remove it + // Note that this could decrement the count to zero allowing it to be deleted, hence + // don't access the pointer contents beyond here. + // + + AFSBackupEntry( pNameArray); + } + + // + // OK, open the target directory + // + + if( uniComponentName.Length == 0) + { + AFSRetrieveFinalComponent( &uniFileName, + &uniComponentName); + } + + ntStatus = AFSOpenTargetDirectory( Irp, + pVolumeCB, + pParentDirectoryCB, + pDirectoryCB, + &uniComponentName, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to open target directory %wZ Status %08lX\n", + &pParentDirectoryCB->NameInformation.FileName, + ntStatus); + + // + // Decrement the reference on the parent + // + + InterlockedDecrement( &pParentDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement3 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + NULL, + pParentDirectoryCB->OpenReferenceCount); + } + + try_return( ntStatus); + } + + // + // Based on the options passed in, process the file accordingly. + // + + if( ulCreateDisposition == FILE_CREATE || + ( ( ulCreateDisposition == FILE_OPEN_IF || + ulCreateDisposition == FILE_OVERWRITE_IF) && + pDirectoryCB == NULL)) + { + + if( uniComponentName.Length == 0 || + pDirectoryCB != NULL) + { + + // + // We traversed the entire path so we found each entry, + // fail with collision + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate Object name collision on create of %wZ Status %08lX\n", + &pDirectoryCB->NameInformation.FileName, + ntStatus); + + if( pDirectoryCB != NULL) + { + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement4 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + } + else + { + + InterlockedDecrement( &pParentDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement5 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + NULL, + pParentDirectoryCB->OpenReferenceCount); + } + + try_return( ntStatus = STATUS_OBJECT_NAME_COLLISION); + } + + // + // OK, go and create the node + // + + ntStatus = AFSProcessCreate( Irp, + &stAuthGroup, + pVolumeCB, + pParentDirectoryCB, + &uniFileName, + &uniComponentName, + &uniRootFileName, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to create of %wZ in directory %wZ Status %08lX\n", + &uniComponentName, + &pParentDirectoryCB->NameInformation.FileName, + ntStatus); + } + else + { + + // + // Reference the new dir entry + // + + InterlockedIncrement( &pCcb->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Increment (Create) count on %wZ DE %p Ccb %p Cnt %d\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB, + pCcb, + pCcb->DirectoryCB->OpenReferenceCount); + } + + // + // Dereference the parent entry + // + + InterlockedDecrement( &pParentDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement6 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + NULL, + pParentDirectoryCB->OpenReferenceCount); + + try_return( ntStatus); + } + + // + // We should not have an extra component except for PIOCtl opens + // + + if( uniComponentName.Length > 0) + { + + // + // If this is an open on "_._AFS_IOCTL_._" then perform handling on it accordingly + // + + if( RtlCompareUnicodeString( &AFSPIOCtlName, + &uniComponentName, + TRUE) == 0) + { + + ntStatus = AFSOpenIOCtlFcb( Irp, + &stAuthGroup, + pParentDirectoryCB, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to IOCtl open on %wZ Status %08lX\n", + &uniComponentName, + ntStatus); + } + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate (%08lX) File %wZ name not found\n", + Irp, + &uniFileName); + + ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; + } + + if( !NT_SUCCESS( ntStatus)) + { + + // + // Dereference the parent entry + // + + if( pDirectoryCB != NULL) + { + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement7a count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + } + else + { + + InterlockedDecrement( &pParentDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement7b count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirectoryCB->NameInformation.FileName, + pParentDirectoryCB, + NULL, + pParentDirectoryCB->OpenReferenceCount); + } + } + + try_return( ntStatus); + } + + // + // For root opens the parent will be NULL + // + + if( pParentDirectoryCB == NULL) + { + + // + // Check for the delete on close flag for the root + // + + if( BooleanFlagOn( ulOptions, FILE_DELETE_ON_CLOSE )) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate (%08lX) Attempt to open root as delete on close\n", + Irp); + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement8 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + + try_return( ntStatus = STATUS_CANNOT_DELETE); + } + + // + // If this is the target directory, then bail + // + + if( bOpenTargetDirectory) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate (%08lX) Attempt to open root as target directory\n", + Irp); + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement9 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // Go and open the root of the volume + // + + ntStatus = AFSOpenRoot( Irp, + pVolumeCB, + &stAuthGroup, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed to open root (2) Status %08lX\n", + ntStatus); + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement10 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + } + + try_return( ntStatus); + } + + // + // At this point if we have no pDirectoryCB it was not found. + // + + if( pDirectoryCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failing access to %wZ\n", + &uniFileName); + + try_return( ntStatus = STATUS_OBJECT_NAME_NOT_FOUND); + } + + if( ulCreateDisposition == FILE_OVERWRITE || + ulCreateDisposition == FILE_SUPERSEDE || + ulCreateDisposition == FILE_OVERWRITE_IF) + { + + // + // Go process a file for overwrite or supersede. + // + + ntStatus = AFSProcessOverwriteSupersede( DeviceObject, + Irp, + pVolumeCB, + &stAuthGroup, + pParentDirectoryCB, + pDirectoryCB, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed overwrite/supersede on %wZ Status %08lX\n", + &pDirectoryCB->NameInformation.FileName, + ntStatus); + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement11 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + } + + try_return( ntStatus); + } + + // + // Trying to open the file + // + + ntStatus = AFSProcessOpen( Irp, + &stAuthGroup, + pVolumeCB, + pParentDirectoryCB, + pDirectoryCB, + &pFcb, + &pCcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate Failed open on %wZ Status %08lX\n", + &pDirectoryCB->NameInformation.FileName, + ntStatus); + + InterlockedDecrement( &pDirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Decrement12 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryCB->NameInformation.FileName, + pDirectoryCB, + NULL, + pDirectoryCB->OpenReferenceCount); + } + +try_exit: + + if( NT_SUCCESS( ntStatus) && + ntStatus != STATUS_REPARSE) + { + + if( pCcb != NULL) + { + + // + // If we have a substitute name, then use it + // + + if( uniSubstitutedPathName.Buffer != NULL) + { + + pCcb->FullFileName = uniSubstitutedPathName; + + SetFlag( pCcb->Flags, CCB_FLAG_FREE_FULL_PATHNAME); + + ClearFlag( ulParseFlags, AFS_PARSE_FLAG_FREE_FILE_BUFFER); + } + else + { + + pCcb->FullFileName = uniRootFileName; + + if( BooleanFlagOn( ulParseFlags, AFS_PARSE_FLAG_FREE_FILE_BUFFER)) + { + + SetFlag( pCcb->Flags, CCB_FLAG_FREE_FULL_PATHNAME); + + ClearFlag( ulParseFlags, AFS_PARSE_FLAG_FREE_FILE_BUFFER); + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCreate Count on %wZ DE %p Ccb %p Cnt %d\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB, + pCcb, + pCcb->DirectoryCB->OpenReferenceCount); + + ASSERT( pCcb->DirectoryCB->OpenReferenceCount > 0); + + pCcb->CurrentDirIndex = 0; + + if( !BooleanFlagOn( ulParseFlags, AFS_PARSE_FLAG_ROOT_ACCESS)) + { + + SetFlag( pCcb->Flags, CCB_FLAG_RETURN_RELATIVE_ENTRIES); + } + + // + // Save off the name array for this instance + // + + pCcb->NameArray = pNameArray; + + pNameArray = NULL; + } + + // + // If we make it here then init the FO for the request. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCommonCreate (%08lX) FileObject %08lX FsContext %08lX FsContext2 %08lX\n", + Irp, + pFileObject, + pFcb, + pCcb); + + pFileObject->FsContext = (void *)pFcb; + + pFileObject->FsContext2 = (void *)pCcb; + + if( pFcb != NULL) + { + + ASSERT( pFcb->OpenHandleCount > 0); + + ClearFlag( pFcb->Flags, AFS_FCB_FILE_CLOSED); + + RtlCopyMemory( &pFcb->AuthGroup, + &stAuthGroup, + sizeof( GUID)); + + // + // For files perform additional processing + // + + if( pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + pFileObject->SectionObjectPointer = &pFcb->NPFcb->SectionObjectPointers; + } + + // + // If the user did not request nobuffering then mark the FO as cacheable + // + + if( bNoIntermediateBuffering) + { + + pFileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; + } + else + { + + pFileObject->Flags |= FO_CACHE_SUPPORTED; + } + + // + // If the file was opened for execution then we need to set the bit in the FO + // + + if( BooleanFlagOn( *pDesiredAccess, + FILE_EXECUTE)) + { + + SetFlag( pFileObject->Flags, FO_FILE_FAST_IO_READ); + } + + // + // Update the last access time + // + + KeQuerySystemTime( &pFcb->ObjectInformation->LastAccessTime); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate (%08lX) Returning with NULL Fcb FileObject %08lX FsContext %08lX FsContext2 %08lX\n", + Irp, + pFileObject, + pFcb, + pCcb); + } + } + else + { + if( NT_SUCCESS( ntStatus) && + ntStatus == STATUS_REPARSE) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonCreate (%08lX) STATUS_REPARSE FileObject %08lX FsContext %08lX FsContext2 %08lX\n", + Irp, + pFileObject, + pFcb, + pCcb); + } + + // + // Free up the sub name if we have one + // + + if( uniSubstitutedPathName.Buffer != NULL) + { + + AFSExFreePool( uniSubstitutedPathName.Buffer); + + ClearFlag( ulParseFlags, AFS_PARSE_FLAG_FREE_FILE_BUFFER); + } + } + + // + // Free up the name array ... + // + + if( pNameArray != NULL) + { + + AFSFreeNameArray( pNameArray); + } + + if( BooleanFlagOn( ulParseFlags, AFS_PARSE_FLAG_FREE_FILE_BUFFER)) + { + + AFSExFreePool( uniRootFileName.Buffer); + } + + if( bReleaseVolume) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonCreate Decrement count on Volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + // + // Setup the Irp for completion, the Information has been set previously + // + + Irp->IoStatus.Status = ntStatus; + } + + return ntStatus; +} + +NTSTATUS +AFSOpenRedirector( IN PIRP Irp, + IN AFSFcb **Fcb, + IN AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenRedirector (%08lX) Failed to allocate Ccb\n", + Irp); + + try_return( ntStatus); + } + + // + // Setup the Ccb + // + + (*Ccb)->DirectoryCB = AFSRedirectorRoot->DirectoryCB; + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &AFSRedirectorRoot->RootFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenRedirector Increment count on Fcb %08lX Cnt %d\n", + AFSRedirectorRoot->RootFcb, + AFSRedirectorRoot->RootFcb->OpenReferenceCount); + + InterlockedIncrement( &AFSRedirectorRoot->RootFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenRedirector Increment handle count on Fcb %08lX Cnt %d\n", + AFSRedirectorRoot->RootFcb, + AFSRedirectorRoot->RootFcb->OpenHandleCount); + + *Fcb = AFSRedirectorRoot->RootFcb; + + InterlockedIncrement( &(*Ccb)->DirectoryCB->OpenReferenceCount); + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_OPENED; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSOpenAFSRoot( IN PIRP Irp, + IN AFSFcb **Fcb, + IN AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenAFSRoot (%08lX) Failed to allocate Ccb\n", + Irp); + + try_return( ntStatus); + } + + // + // Setup the Ccb + // + + (*Ccb)->DirectoryCB = AFSGlobalRoot->DirectoryCB; + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &AFSGlobalRoot->RootFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenAFSRoot Increment count on Fcb %08lX Cnt %d\n", + AFSGlobalRoot->RootFcb, + AFSGlobalRoot->RootFcb->OpenReferenceCount); + + InterlockedIncrement( &AFSGlobalRoot->RootFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenAFSRoot Increment handle count on Fcb %08lX Cnt %d\n", + AFSGlobalRoot->RootFcb, + AFSGlobalRoot->RootFcb->OpenHandleCount); + + *Fcb = AFSGlobalRoot->RootFcb; + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_OPENED; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSOpenRoot( IN PIRP Irp, + IN AFSVolumeCB *VolumeCB, + IN GUID *AuthGroup, + OUT AFSFcb **RootFcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_OBJECT pFileObject = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PACCESS_MASK pDesiredAccess = NULL; + USHORT usShareAccess; + BOOLEAN bAllocatedCcb = FALSE; + BOOLEAN bReleaseFcb = FALSE; + AFSFileOpenCB stOpenCB; + AFSFileOpenResultCB stOpenResultCB; + ULONG ulResultLen = 0; + + __Enter + { + + pDesiredAccess = &pIrpSp->Parameters.Create.SecurityContext->DesiredAccess; + usShareAccess = pIrpSp->Parameters.Create.ShareAccess; + + pFileObject = pIrpSp->FileObject; + + // + // Check if we should go and retrieve updated information for the node + // + + ntStatus = AFSValidateEntry( VolumeCB->DirectoryCB, + AuthGroup, + TRUE, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenRoot (%08lX) Failed to validate root entry Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + // + // Check with the service that we can open the file + // + + RtlZeroMemory( &stOpenCB, + sizeof( AFSFileOpenCB)); + + stOpenCB.DesiredAccess = *pDesiredAccess; + + stOpenCB.ShareAccess = usShareAccess; + + stOpenResultCB.GrantedAccess = 0; + + ulResultLen = sizeof( AFSFileOpenResultCB); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_OPEN_FILE, + AFS_REQUEST_FLAG_SYNCHRONOUS | AFS_REQUEST_FLAG_HOLD_FID, + AuthGroup, + NULL, + &VolumeCB->ObjectInformation.FileId, + (void *)&stOpenCB, + sizeof( AFSFileOpenCB), + (void *)&stOpenResultCB, + &ulResultLen); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenRoot (%08lX) Failed to open file in service Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + // + // If the entry is not initialized then do it now + // + + if( !BooleanFlagOn( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + AFSAcquireExcl( VolumeCB->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + if( !BooleanFlagOn( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + ntStatus = AFSEnumerateDirectory( AuthGroup, + &VolumeCB->ObjectInformation, + TRUE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( VolumeCB->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenRoot (%08lX) Failed to enumerate directory Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + SetFlag( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED); + } + + AFSReleaseResource( VolumeCB->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + // + // If the root fcb has been initialized then check access otherwise + // init the volume fcb + // + + if( VolumeCB->RootFcb == NULL) + { + + ntStatus = AFSInitRootFcb( (ULONGLONG)PsGetCurrentProcessId(), + VolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } + else + { + + AFSAcquireExcl( VolumeCB->RootFcb->Header.Resource, + TRUE); + } + + bReleaseFcb = TRUE; + + // + // If there are current opens on the Fcb, check the access. + // + + if( VolumeCB->RootFcb->OpenHandleCount > 0) + { + + ntStatus = IoCheckShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &VolumeCB->RootFcb->ShareAccess, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenRoot (%08lX) Access check failure Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenRoot (%08lX) Failed to allocate Ccb Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + // + // Setup the ccb + // + + (*Ccb)->DirectoryCB = VolumeCB->DirectoryCB; + + // + // OK, update the share access on the fileobject + // + + if( VolumeCB->RootFcb->OpenHandleCount > 0) + { + + IoUpdateShareAccess( pFileObject, + &VolumeCB->RootFcb->ShareAccess); + } + else + { + + // + // Set the access + // + + IoSetShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &VolumeCB->RootFcb->ShareAccess); + } + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &VolumeCB->RootFcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenRoot Increment count on Fcb %08lX Cnt %d\n", + VolumeCB->RootFcb, + VolumeCB->RootFcb->OpenReferenceCount); + + InterlockedIncrement( &VolumeCB->RootFcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenRoot Increment handle count on Fcb %08lX Cnt %d\n", + VolumeCB->RootFcb, + VolumeCB->RootFcb->OpenHandleCount); + + // + // Indicate the object is held + // + + SetFlag( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_HELD_IN_SERVICE); + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_OPENED; + + *RootFcb = VolumeCB->RootFcb; + +try_exit: + + if( bReleaseFcb) + { + + AFSReleaseResource( VolumeCB->RootFcb->Header.Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + + *Ccb = NULL; + } + + Irp->IoStatus.Information = 0; + } + } + + return ntStatus; +} + +NTSTATUS +AFSProcessCreate( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSVolumeCB *VolumeCB, + IN AFSDirectoryCB *ParentDirCB, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING ComponentName, + IN PUNICODE_STRING FullFileName, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_OBJECT pFileObject = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + ULONG ulOptions = 0; + ULONG ulShareMode = 0; + ULONG ulAccess = 0; + ULONG ulAttributes = 0; + LARGE_INTEGER liAllocationSize = {0,0}; + BOOLEAN bFileCreated = FALSE, bReleaseFcb = FALSE, bAllocatedCcb = FALSE; + BOOLEAN bAllocatedFcb = FALSE; + PACCESS_MASK pDesiredAccess = NULL; + USHORT usShareAccess; + AFSDirectoryCB *pDirEntry = NULL; + AFSObjectInfoCB *pParentObjectInfo = NULL; + AFSObjectInfoCB *pObjectInfo = NULL; + + __Enter + { + + pDesiredAccess = &pIrpSp->Parameters.Create.SecurityContext->DesiredAccess; + usShareAccess = pIrpSp->Parameters.Create.ShareAccess; + + pFileObject = pIrpSp->FileObject; + + // + // Extract out the options + // + + ulOptions = pIrpSp->Parameters.Create.Options; + + // + // We pass all attributes they want to apply to the file to the create + // + + ulAttributes = pIrpSp->Parameters.Create.FileAttributes; + + // + // If this is a directory create then set the attribute correctly + // + + if( ulOptions & FILE_DIRECTORY_FILE) + { + + ulAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate (%08lX) Creating file %wZ Attributes %08lX\n", + Irp, + FullFileName, + ulAttributes); + + if( BooleanFlagOn( VolumeCB->VolumeInformation.Characteristics, FILE_READ_ONLY_DEVICE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessCreate Request failed due to read only volume %wZ\n", + FullFileName); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + pParentObjectInfo = ParentDirCB->ObjectInformation; + + // + // Allocate and insert the direntry into the parent node + // + + ntStatus = AFSCreateDirEntry( AuthGroup, + pParentObjectInfo, + ParentDirCB, + FileName, + ComponentName, + ulAttributes, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessCreate (%08lX) Failed to create directory entry %wZ Status %08lX\n", + Irp, + FullFileName, + ntStatus); + + try_return( ntStatus); + } + + bFileCreated = TRUE; + + pObjectInfo = pDirEntry->ObjectInformation; + + // + // We may have raced and the Fcb is already created + // + + if( pObjectInfo->Fcb != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate (%08lX) Not allocating Fcb for file %wZ\n", + Irp, + FullFileName); + + *Fcb = pObjectInfo->Fcb; + + AFSAcquireExcl( &(*Fcb)->NPFcb->Resource, + TRUE); + } + else + { + + // + // Allocate and initialize the Fcb for the file. + // + + ntStatus = AFSInitFcb( pDirEntry, + Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessCreate (%08lX) Failed to initialize fcb %wZ Status %08lX\n", + Irp, + FullFileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedFcb = TRUE; + } + + bReleaseFcb = TRUE; + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessCreate (%08lX) Failed to initialize ccb %wZ Status %08lX\n", + Irp, + FullFileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + // + // Initialize the Ccb + // + + (*Ccb)->DirectoryCB = pDirEntry; + + // + // If this is a file, update the headers filesizes. + // + + if( (*Fcb)->Header.NodeTypeCode == AFS_FILE_FCB) + { + + // + // Update the sizes with the information passed in + // + + (*Fcb)->Header.AllocationSize.QuadPart = pObjectInfo->AllocationSize.QuadPart; + (*Fcb)->Header.FileSize.QuadPart = pObjectInfo->EndOfFile.QuadPart; + (*Fcb)->Header.ValidDataLength.QuadPart = pObjectInfo->EndOfFile.QuadPart; + + // + // Notify the system of the addition + // + + AFSFsRtlNotifyFullReportChange( pParentObjectInfo, + *Ccb, + (ULONG)FILE_NOTIFY_CHANGE_FILE_NAME, + (ULONG)FILE_ACTION_ADDED); + + (*Fcb)->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + else if( (*Fcb)->Header.NodeTypeCode == AFS_DIRECTORY_FCB) + { + + // + // This is a new directory node so indicate it has been enumerated + // + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED); + + // + // And the parent directory entry + // + + KeQuerySystemTime( &pParentObjectInfo->ChangeTime); + + // + // Notify the system of the addition + // + + AFSFsRtlNotifyFullReportChange( pParentObjectInfo, + *Ccb, + (ULONG)FILE_NOTIFY_CHANGE_DIR_NAME, + (ULONG)FILE_ACTION_ADDED); + } + else if( (*Fcb)->Header.NodeTypeCode == AFS_MOUNT_POINT_FCB || + (*Fcb)->Header.NodeTypeCode == AFS_SYMBOLIC_LINK_FCB || + (*Fcb)->Header.NodeTypeCode == AFS_DFS_LINK_FCB) + { + + // + // And the parent directory entry + // + + KeQuerySystemTime( &pParentObjectInfo->ChangeTime); + + // + // Notify the system of the addition + // + + AFSFsRtlNotifyFullReportChange( pParentObjectInfo, + *Ccb, + (ULONG)FILE_NOTIFY_CHANGE_DIR_NAME, + (ULONG)FILE_ACTION_ADDED); + } + + // + // Save off the access for the open + // + + IoSetShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &(*Fcb)->ShareAccess); + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &(*Fcb)->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate Increment count on Fcb %08lX Cnt %d\n", + *Fcb, + (*Fcb)->OpenReferenceCount); + + InterlockedIncrement( &(*Fcb)->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate Increment handle count on Fcb %08lX Cnt %d\n", + (*Fcb), + (*Fcb)->OpenHandleCount); + + // + // Increment the open reference and handle on the parent node + // + + InterlockedIncrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate Increment child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate Increment child open ref count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + if( ulOptions & FILE_DELETE_ON_CLOSE) + { + + // + // Mark it for delete on close + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessCreate (%08lX) Setting PENDING_DELETE flag in DirEntry %p Name %wZ\n", + Irp, + pDirEntry, + FullFileName); + + SetFlag( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + + // + // Indicate the object is locked in the service + // + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE); + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_CREATED; + +try_exit: + + // + // If we created the Fcb we need to release the resources + // + + if( bReleaseFcb) + { + + AFSReleaseResource( &(*Fcb)->NPFcb->Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bFileCreated) + { + + // + // Remove the dir entry from the parent + // + + AFSAcquireExcl( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSDeleteDirEntry( pParentObjectInfo, + pDirEntry); + + AFSReleaseResource( pParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + } + + if( bAllocatedFcb) + { + + AFSRemoveFcb( pObjectInfo->Fcb); + + pObjectInfo->Fcb = NULL; + } + + *Fcb = NULL; + + *Ccb = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSOpenTargetDirectory( IN PIRP Irp, + IN AFSVolumeCB *VolumeCB, + IN AFSDirectoryCB *ParentDirectoryCB, + IN AFSDirectoryCB *TargetDirectoryCB, + IN UNICODE_STRING *TargetName, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_OBJECT pFileObject = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PACCESS_MASK pDesiredAccess = NULL; + USHORT usShareAccess; + BOOLEAN bRemoveAccess = FALSE; + BOOLEAN bAllocatedCcb = FALSE; + BOOLEAN bReleaseFcb = FALSE, bAllocatedFcb = FALSE; + AFSObjectInfoCB *pParentObject = NULL, *pTargetObject = NULL; + UNICODE_STRING uniTargetName; + + __Enter + { + + pDesiredAccess = &pIrpSp->Parameters.Create.SecurityContext->DesiredAccess; + usShareAccess = pIrpSp->Parameters.Create.ShareAccess; + + pFileObject = pIrpSp->FileObject; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenTargetDirectory (%08lX) Processing file %wZ\n", + Irp, + TargetName); + + pParentObject = ParentDirectoryCB->ObjectInformation; + + if( pParentObject->FileType != AFS_FILE_TYPE_DIRECTORY) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // Make sure we have an Fcb for the access + // + + if( pParentObject->Fcb != NULL) + { + + *Fcb = pParentObject->Fcb; + + AFSAcquireExcl( &(*Fcb)->NPFcb->Resource, + TRUE); + } + else + { + + // + // Allocate and initialize the Fcb for the file. + // + + ntStatus = AFSInitFcb( ParentDirectoryCB, + Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessCreate (%08lX) Failed to initialize fcb %wZ Status %08lX\n", + Irp, + &ParentDirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedFcb = TRUE; + } + + bReleaseFcb = TRUE; + + // + // If there are current opens on the Fcb, check the access. + // + + if( pParentObject->Fcb->OpenHandleCount > 0) + { + + ntStatus = IoCheckShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &pParentObject->Fcb->ShareAccess, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenTargetDirectory (%08lX) Access check failure %wZ Status %08lX\n", + Irp, + &ParentDirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenTargetDirectory (%08lX) Failed to initialize ccb %wZ Status %08lX\n", + Irp, + &ParentDirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + // + // Initialize the Ccb + // + + (*Ccb)->DirectoryCB = ParentDirectoryCB; + + if( TargetDirectoryCB != NULL && + FsRtlAreNamesEqual( &TargetDirectoryCB->NameInformation.FileName, + TargetName, + FALSE, + NULL)) + { + + Irp->IoStatus.Information = FILE_EXISTS; + + uniTargetName = TargetDirectoryCB->NameInformation.FileName; + } + else + { + + Irp->IoStatus.Information = FILE_DOES_NOT_EXIST; + + uniTargetName = *TargetName; + } + + // + // Update the filename in the fileobject for rename processing + // + + RtlCopyMemory( pFileObject->FileName.Buffer, + uniTargetName.Buffer, + uniTargetName.Length); + + pFileObject->FileName.Length = uniTargetName.Length; + + // + // OK, update the share access on the fileobject + // + + if( pParentObject->Fcb->OpenHandleCount > 0) + { + + IoUpdateShareAccess( pFileObject, + &pParentObject->Fcb->ShareAccess); + } + else + { + + // + // Set the access + // + + IoSetShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &pParentObject->Fcb->ShareAccess); + } + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &pParentObject->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenTargetDirectory Increment count on Fcb %08lX Cnt %d\n", + pParentObject->Fcb, + pParentObject->Fcb->OpenReferenceCount); + + InterlockedIncrement( &pParentObject->Fcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenTargetDirectory Increment handle count on Fcb %08lX Cnt %d\n", + pParentObject->Fcb, + pParentObject->Fcb->OpenHandleCount); + + // + // Increment the open reference and handle on the parent node + // + + if( pParentObject->ParentObjectInformation != NULL) + { + + InterlockedIncrement( &pParentObject->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenTargetDirectory Increment child open handle count on Parent object %08lX Cnt %d\n", + pParentObject->ParentObjectInformation, + pParentObject->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pParentObject->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenTargetDirectory Increment child open ref count on Parent object %08lX Cnt %d\n", + pParentObject->ParentObjectInformation, + pParentObject->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + } + +try_exit: + + if( bReleaseFcb) + { + + AFSReleaseResource( &pParentObject->Fcb->NPFcb->Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + } + + *Ccb = NULL; + + if( bRemoveAccess) + { + + IoRemoveShareAccess( pFileObject, + &pParentObject->Fcb->ShareAccess); + } + + if( bAllocatedFcb) + { + + AFSRemoveFcb( pParentObject->Fcb); + + pParentObject->Fcb = NULL; + } + + *Fcb = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSProcessOpen( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSVolumeCB *VolumeCB, + IN AFSDirectoryCB *ParentDirCB, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_OBJECT pFileObject = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PACCESS_MASK pDesiredAccess = NULL; + USHORT usShareAccess; + BOOLEAN bAllocatedCcb = FALSE, bReleaseFcb = FALSE, bAllocatedFcb = FALSE; + ULONG ulAdditionalFlags = 0, ulOptions = 0; + AFSFileOpenCB stOpenCB; + AFSFileOpenResultCB stOpenResultCB; + ULONG ulResultLen = 0; + AFSObjectInfoCB *pParentObjectInfo = NULL; + AFSObjectInfoCB *pObjectInfo = NULL; + + __Enter + { + + pDesiredAccess = &pIrpSp->Parameters.Create.SecurityContext->DesiredAccess; + usShareAccess = pIrpSp->Parameters.Create.ShareAccess; + + pFileObject = pIrpSp->FileObject; + + pParentObjectInfo = ParentDirCB->ObjectInformation; + + pObjectInfo = DirectoryCB->ObjectInformation; + + // + // Check if the entry is pending a deletion + // + + if( BooleanFlagOn( DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) + { + + ntStatus = STATUS_DELETE_PENDING; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Entry pending delete %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Extract out the options + // + + ulOptions = pIrpSp->Parameters.Create.Options; + + // + // Check if we should go and retrieve updated information for the node + // + + ntStatus = AFSValidateEntry( DirectoryCB, + AuthGroup, + TRUE, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed to validate entry %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + // + // If this is marked for delete on close then be sure we can delete the entry + // + + if( BooleanFlagOn( ulOptions, FILE_DELETE_ON_CLOSE)) + { + + ntStatus = AFSNotifyDelete( DirectoryCB, + TRUE); + + if( !NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_CANNOT_DELETE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Cannot delete entry %wZ marked for delete on close Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Be sure we have an Fcb for the current object + // + + if( pObjectInfo->Fcb == NULL) + { + + ntStatus = AFSInitFcb( DirectoryCB, + &pObjectInfo->Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed to init fcb on %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedFcb = TRUE; + } + else + { + + AFSAcquireExcl( pObjectInfo->Fcb->Header.Resource, + TRUE); + } + + bReleaseFcb = TRUE; + + // + // Reference the Fcb so it won't go away while we call into the service for processing + // + + InterlockedIncrement( &pObjectInfo->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen Increment count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenReferenceCount); + + // + // Check access on the entry + // + + if( pObjectInfo->Fcb->OpenHandleCount > 0) + { + + ntStatus = IoCheckShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &pObjectInfo->Fcb->ShareAccess, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed to check share access on %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Additional checks + // + + if( pObjectInfo->Fcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + // + // If the caller is asking for write access then try to flush the image section + // + + if( FlagOn( *pDesiredAccess, FILE_WRITE_DATA) || + BooleanFlagOn(ulOptions, FILE_DELETE_ON_CLOSE)) + { + + if( !MmFlushImageSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + MmFlushForWrite)) + { + + ntStatus = BooleanFlagOn(ulOptions, FILE_DELETE_ON_CLOSE) ? STATUS_CANNOT_DELETE : + STATUS_SHARING_VIOLATION; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed to flush image section %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + } + + if( BooleanFlagOn( ulOptions, FILE_DIRECTORY_FILE)) + { + + ntStatus = STATUS_NOT_A_DIRECTORY; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Attempt to open file as directory %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + else if( pObjectInfo->Fcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB || + pObjectInfo->Fcb->Header.NodeTypeCode == AFS_ROOT_FCB) + { + + if( BooleanFlagOn( ulOptions, FILE_NON_DIRECTORY_FILE)) + { + + ntStatus = STATUS_FILE_IS_A_DIRECTORY; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Attempt to open directory as file %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + } + else if( pObjectInfo->Fcb->Header.NodeTypeCode == AFS_MOUNT_POINT_FCB || + pObjectInfo->Fcb->Header.NodeTypeCode == AFS_SYMBOLIC_LINK_FCB || + pObjectInfo->Fcb->Header.NodeTypeCode == AFS_DFS_LINK_FCB) + { + + } + else + { + ASSERT( FALSE); + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Check with the service that we can open the file + // + + stOpenCB.ParentId = pParentObjectInfo->FileId; + + stOpenCB.DesiredAccess = *pDesiredAccess; + + stOpenCB.ShareAccess = usShareAccess; + + stOpenResultCB.GrantedAccess = 0; + + ulResultLen = sizeof( AFSFileOpenResultCB); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_OPEN_FILE, + AFS_REQUEST_FLAG_SYNCHRONOUS | AFS_REQUEST_FLAG_HOLD_FID, + AuthGroup, + &DirectoryCB->NameInformation.FileName, + &pObjectInfo->FileId, + (void *)&stOpenCB, + sizeof( AFSFileOpenCB), + (void *)&stOpenResultCB, + &ulResultLen); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed open in service %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Check if there is a conflict + // + + if( !AFSCheckAccess( *pDesiredAccess, + stOpenResultCB.GrantedAccess, + BooleanFlagOn( DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY))) + { + + ntStatus = STATUS_ACCESS_DENIED; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed to check access from service Desired %08lX Granted %08lX Entry %wZ Status %08lX\n", + Irp, + *pDesiredAccess, + stOpenResultCB.GrantedAccess, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOpen (%08lX) Failed to initialize ccb %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + (*Ccb)->DirectoryCB = DirectoryCB; + + // + // Perform the access check on the target if this is a mount point or symlink + // + + if( pObjectInfo->Fcb->OpenHandleCount > 0) + { + + IoUpdateShareAccess( pFileObject, + &pObjectInfo->Fcb->ShareAccess); + } + else + { + + // + // Set the access + // + + IoSetShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &pObjectInfo->Fcb->ShareAccess); + } + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &pObjectInfo->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen Increment2 count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenReferenceCount); + + InterlockedIncrement( &pObjectInfo->Fcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen Increment handle count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenHandleCount); + + // + // Increment the open reference and handle on the parent node + // + + InterlockedIncrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen Increment child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen Increment child open ref count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + if( BooleanFlagOn( ulOptions, FILE_DELETE_ON_CLOSE)) + { + + // + // Mark it for delete on close + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen (%08lX) Setting PENDING_DELETE flag in DirEntry %p Name %wZ\n", + Irp, + DirectoryCB, + &DirectoryCB->NameInformation.FileName); + + SetFlag( DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + + // + // Indicate the object is held + // + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE); + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_OPENED; + + *Fcb = pObjectInfo->Fcb; + +try_exit: + + if( bReleaseFcb) + { + + // + // Remove the reference we added initially + // + + InterlockedDecrement( &pObjectInfo->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOpen Decrement count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenReferenceCount); + + AFSReleaseResource( pObjectInfo->Fcb->Header.Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + } + + *Ccb = NULL; + + if( bAllocatedFcb) + { + + AFSRemoveFcb( pObjectInfo->Fcb); + + pObjectInfo->Fcb = NULL; + } + + *Fcb = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSProcessOverwriteSupersede( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN AFSVolumeCB *VolumeCB, + IN GUID *AuthGroup, + IN AFSDirectoryCB *ParentDirCB, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = NULL; + LARGE_INTEGER liZero = {0,0}; + BOOLEAN bReleasePaging = FALSE, bReleaseFcb = FALSE; + ULONG ulAttributes = 0; + LARGE_INTEGER liTime; + ULONG ulCreateDisposition = 0; + BOOLEAN bAllocatedCcb = FALSE, bAllocatedFcb = FALSE; + PACCESS_MASK pDesiredAccess = NULL; + USHORT usShareAccess; + AFSObjectInfoCB *pParentObjectInfo = NULL; + AFSObjectInfoCB *pObjectInfo = NULL; + + __Enter + { + + pDesiredAccess = &pIrpSp->Parameters.Create.SecurityContext->DesiredAccess; + usShareAccess = pIrpSp->Parameters.Create.ShareAccess; + + pFileObject = pIrpSp->FileObject; + + ulAttributes = pIrpSp->Parameters.Create.FileAttributes; + + ulCreateDisposition = (pIrpSp->Parameters.Create.Options >> 24) & 0x000000ff; + + if( BooleanFlagOn( VolumeCB->VolumeInformation.Characteristics, FILE_READ_ONLY_DEVICE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede Request failed on %wZ due to read only volume\n", + Irp, + &DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + pParentObjectInfo = ParentDirCB->ObjectInformation; + + pObjectInfo = DirectoryCB->ObjectInformation; + + // + // Check if we should go and retrieve updated information for the node + // + + ntStatus = AFSValidateEntry( DirectoryCB, + AuthGroup, + TRUE, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede (%08lX) Failed to validate entry %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Be sure we have an Fcb for the object block + // + + if( pObjectInfo->Fcb == NULL) + { + + ntStatus = AFSInitFcb( DirectoryCB, + Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede (%08lX) Failed to initialize fcb %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedFcb = TRUE; + } + else + { + + AFSAcquireExcl( pObjectInfo->Fcb->Header.Resource, + TRUE); + } + + bReleaseFcb = TRUE; + + // + // Reference the Fcb so it won't go away while processing the request + // + + InterlockedIncrement( &pObjectInfo->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOverwriteSupersede Increment count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenReferenceCount); + + // + // Check access on the entry + // + + if( pObjectInfo->Fcb->OpenHandleCount > 0) + { + + ntStatus = IoCheckShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &pObjectInfo->Fcb->ShareAccess, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede (%08lX) Access check failure %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Before we actually truncate, check to see if the purge + // is going to fail. + // + + if( !MmCanFileBeTruncated( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + &liZero)) + { + + ntStatus = STATUS_USER_MAPPED_FILE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede (%08lX) File user mapped %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede (%08lX) Failed to initialize ccb %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + // + // Initialize the Ccb + // + + (*Ccb)->DirectoryCB = DirectoryCB; + + // + // Need to purge any data currently in the cache + // + + CcPurgeCacheSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + FALSE); + + pObjectInfo->Fcb->Header.FileSize.QuadPart = 0; + pObjectInfo->Fcb->Header.ValidDataLength.QuadPart = 0; + pObjectInfo->Fcb->Header.AllocationSize.QuadPart = 0; + + pObjectInfo->EndOfFile.QuadPart = 0; + pObjectInfo->AllocationSize.QuadPart = 0; + + // + // Trim down the extents. We do this BEFORE telling the service + // the file is truncated since there is a potential race between + // a worker thread releasing extents and us trimming + // + + AFSTrimExtents( pObjectInfo->Fcb, + &pObjectInfo->Fcb->Header.FileSize); + + KeQuerySystemTime( &pObjectInfo->ChangeTime); + + KeQuerySystemTime( &pObjectInfo->LastAccessTime); + + //KeQuerySystemTime( &pObjectInfo->CreationTime); + + KeQuerySystemTime( &pObjectInfo->LastWriteTime); + + ntStatus = AFSUpdateFileInformation( &pParentObjectInfo->FileId, + pObjectInfo, + AuthGroup); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessOverwriteSupersede (%08lX) Failed to update file information %wZ Status %08lX\n", + Irp, + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + AFSAcquireExcl( pObjectInfo->Fcb->Header.PagingIoResource, + TRUE); + + bReleasePaging = TRUE; + + pFileObject->SectionObjectPointer = &pObjectInfo->Fcb->NPFcb->SectionObjectPointers; + + pFileObject->FsContext = (void *)pObjectInfo->Fcb; + + pFileObject->FsContext2 = (void *)*Ccb; + + // + // Set the update flag accordingly + // + + SetFlag( pObjectInfo->Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | + AFS_FCB_FLAG_UPDATE_CREATE_TIME | + AFS_FCB_FLAG_UPDATE_CHANGE_TIME | + AFS_FCB_FLAG_UPDATE_ACCESS_TIME | + AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME); + + CcSetFileSizes( pFileObject, + (PCC_FILE_SIZES)&pObjectInfo->Fcb->Header.AllocationSize); + + AFSReleaseResource( pObjectInfo->Fcb->Header.PagingIoResource); + + bReleasePaging = FALSE; + + ulAttributes |= FILE_ATTRIBUTE_ARCHIVE; + + if( ulCreateDisposition == FILE_SUPERSEDE) + { + + pObjectInfo->FileAttributes = ulAttributes; + + } + else + { + + pObjectInfo->FileAttributes |= ulAttributes; + } + + // + // Save off the access for the open + // + + if( pObjectInfo->Fcb->OpenHandleCount > 0) + { + + IoUpdateShareAccess( pFileObject, + &pObjectInfo->Fcb->ShareAccess); + } + else + { + + // + // Set the access + // + + IoSetShareAccess( *pDesiredAccess, + usShareAccess, + pFileObject, + &pObjectInfo->Fcb->ShareAccess); + } + + // + // Return the correct action + // + + if( ulCreateDisposition == FILE_SUPERSEDE) + { + + Irp->IoStatus.Information = FILE_SUPERSEDED; + } + else + { + + Irp->IoStatus.Information = FILE_OVERWRITTEN; + } + + // + // Increment the open count on this Fcb. + // + + InterlockedIncrement( &pObjectInfo->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOverwriteSupersede Increment2 count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenReferenceCount); + + InterlockedIncrement( &pObjectInfo->Fcb->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOverwriteSupersede Increment handle count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenHandleCount); + + // + // Increment the open reference and handle on the parent node + // + + InterlockedIncrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOverwriteSupersede Increment child open handle count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOverwriteSupersede Increment child open ref count on Parent object %08lX Cnt %d\n", + pObjectInfo->ParentObjectInformation, + pObjectInfo->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + *Fcb = pObjectInfo->Fcb; + +try_exit: + + if( bReleasePaging) + { + + AFSReleaseResource( pObjectInfo->Fcb->Header.PagingIoResource); + } + + if( bReleaseFcb) + { + + // + // Remove the reference we added above to prevent tear down + // + + InterlockedDecrement( &pObjectInfo->Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessOverwriteSupersede Decrement count on Fcb %08lX Cnt %d\n", + pObjectInfo->Fcb, + pObjectInfo->Fcb->OpenReferenceCount); + + AFSReleaseResource( pObjectInfo->Fcb->Header.Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + } + + *Ccb = NULL; + + if( bAllocatedFcb) + { + + AFSRemoveFcb( pObjectInfo->Fcb); + + pObjectInfo->Fcb = NULL; + } + + *Fcb = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSControlDeviceCreate( IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + // + // For now, jsut let the open happen + // + + Irp->IoStatus.Information = FILE_OPENED; + } + + return ntStatus; +} + +NTSTATUS +AFSOpenIOCtlFcb( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSDirectoryCB *ParentDirCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_OBJECT pFileObject = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + BOOLEAN bReleaseFcb = FALSE, bAllocatedCcb = FALSE, bAllocatedFcb = FALSE; + UNICODE_STRING uniFullFileName; + AFSPIOCtlOpenCloseRequestCB stPIOCtlOpen; + AFSFileID stFileID; + AFSObjectInfoCB *pParentObjectInfo = NULL; + + __Enter + { + + pFileObject = pIrpSp->FileObject; + + pParentObjectInfo = ParentDirCB->ObjectInformation; + + // + // If we haven't initialized the PIOCtl DirectoryCB for this directory then do it now + // + + if( pParentObjectInfo->Specific.Directory.PIOCtlDirectoryCB == NULL) + { + + ntStatus = AFSInitPIOCtlDirectoryCB( pParentObjectInfo); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } + + if( pParentObjectInfo->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb == NULL) + { + + // + // Allocate and initialize the Fcb for the file. + // + + ntStatus = AFSInitFcb( pParentObjectInfo->Specific.Directory.PIOCtlDirectoryCB, + Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenIOCtlFcb (%08lX) Failed to initialize fcb Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedFcb = TRUE; + } + else + { + + *Fcb = pParentObjectInfo->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb; + + AFSAcquireExcl( &(*Fcb)->NPFcb->Resource, + TRUE); + } + + bReleaseFcb = TRUE; + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenIOCtlFcb (%08lX) Failed to initialize ccb Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + // + // Setup the Ccb + // + + (*Ccb)->DirectoryCB = pParentObjectInfo->Specific.Directory.PIOCtlDirectoryCB; + + // + // Set the PIOCtl index + // + + (*Ccb)->RequestID = InterlockedIncrement( &pParentObjectInfo->Specific.Directory.OpenRequestIndex); + + RtlZeroMemory( &stPIOCtlOpen, + sizeof( AFSPIOCtlOpenCloseRequestCB)); + + stPIOCtlOpen.RequestId = (*Ccb)->RequestID; + + stPIOCtlOpen.RootId = pParentObjectInfo->VolumeCB->ObjectInformation.FileId; + + RtlZeroMemory( &stFileID, + sizeof( AFSFileID)); + + // + // The parent directory FID of the node + // + + stFileID = pParentObjectInfo->FileId; + + // + // Issue the open request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_OPEN, + AFS_REQUEST_FLAG_SYNCHRONOUS, + AuthGroup, + NULL, + &stFileID, + (void *)&stPIOCtlOpen, + sizeof( AFSPIOCtlOpenCloseRequestCB), + NULL, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenIOCtlFcb (%08lX) Failed service open Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + // + // Reference the directory entry + // + + InterlockedIncrement( &((*Ccb)->DirectoryCB->OpenReferenceCount)); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenIOCtlFcb Increment count on %wZ DE %p Ccb %p Cnt %d\n", + &(*Ccb)->DirectoryCB->NameInformation.FileName, + (*Ccb)->DirectoryCB, + (*Ccb), + (*Ccb)->DirectoryCB->OpenReferenceCount); + + // + // Increment the open reference and handle on the node + // + + InterlockedIncrement( &(*Fcb)->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenIOCtlFcb Increment count on Fcb %08lX Cnt %d\n", + (*Fcb), + (*Fcb)->OpenReferenceCount); + + InterlockedIncrement( &(*Fcb)->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenIOCtlFcb Increment handle count on Fcb %08lX Cnt %d\n", + (*Fcb), + (*Fcb)->OpenHandleCount); + + // + // Increment the open reference and handle on the parent node + // + + InterlockedIncrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenIOCtlFcb Increment child open handle count on Parent object %08lX Cnt %d\n", + pParentObjectInfo, + pParentObjectInfo->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenIOCtlFcb Increment child open ref count on Parent object %08lX Cnt %d\n", + pParentObjectInfo, + pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount); + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_OPENED; + +try_exit: + + // + //Dereference the passed in parent since the returned dir entry + // is already referenced + // + + InterlockedDecrement( &ParentDirCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenIOCtlFcb Decrement count on %wZ DE %p Ccb %p Cnt %d\n", + &ParentDirCB->NameInformation.FileName, + ParentDirCB, + NULL, + ParentDirCB->OpenReferenceCount); + + // + // If we created the Fcb we need to release the resources + // + + if( bReleaseFcb) + { + + AFSReleaseResource( &(*Fcb)->NPFcb->Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + + *Ccb = NULL; + } + + if( bAllocatedFcb) + { + + // + // Need to tear down this Fcb since it is not in the tree for the worker thread + // + + AFSRemoveFcb( *Fcb); + + pParentObjectInfo->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb = NULL; + } + + *Fcb = NULL; + + *Ccb = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSOpenSpecialShareFcb( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_OBJECT pFileObject = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + BOOLEAN bReleaseFcb = FALSE, bAllocatedCcb = FALSE, bAllocateFcb = FALSE; + AFSObjectInfoCB *pParentObjectInfo = NULL; + AFSPipeOpenCloseRequestCB stPipeOpen; + + __Enter + { + + pFileObject = pIrpSp->FileObject; + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSOpenSpecialShareFcb (%08lX) Processing Share %wZ open\n", + Irp, + &DirectoryCB->NameInformation.FileName); + + pParentObjectInfo = DirectoryCB->ObjectInformation->ParentObjectInformation; + + if( DirectoryCB->ObjectInformation->Fcb == NULL) + { + + // + // Allocate and initialize the Fcb for the file. + // + + ntStatus = AFSInitFcb( DirectoryCB, + Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenSpecialShareFcb (%08lX) Failed to initialize fcb Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + bAllocateFcb = TRUE; + } + else + { + + *Fcb = DirectoryCB->ObjectInformation->Fcb; + + AFSAcquireExcl( &(*Fcb)->NPFcb->Resource, + TRUE); + } + + bReleaseFcb = TRUE; + + // + // Initialize the Ccb for the file. + // + + ntStatus = AFSInitCcb( Ccb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenSpecialShareFcb (%08lX) Failed to initialize ccb Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + bAllocatedCcb = TRUE; + + // + // Setup the Ccb + // + + (*Ccb)->DirectoryCB = DirectoryCB; + + // + // Call the service to open the share + // + + (*Ccb)->RequestID = InterlockedIncrement( &pParentObjectInfo->Specific.Directory.OpenRequestIndex); + + RtlZeroMemory( &stPipeOpen, + sizeof( AFSPipeOpenCloseRequestCB)); + + stPipeOpen.RequestId = (*Ccb)->RequestID; + + stPipeOpen.RootId = pParentObjectInfo->VolumeCB->ObjectInformation.FileId; + + // + // Issue the open request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_OPEN, + AFS_REQUEST_FLAG_SYNCHRONOUS, + AuthGroup, + &DirectoryCB->NameInformation.FileName, + NULL, + (void *)&stPipeOpen, + sizeof( AFSPipeOpenCloseRequestCB), + NULL, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSOpenSpecialShareFcb (%08lX) Failed service open Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + // + // Increment the open count on this Fcb + // + + InterlockedIncrement( &(*Fcb)->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenSpecialShareFcb Increment count on Fcb %08lX Cnt %d\n", + (*Fcb), + (*Fcb)->OpenReferenceCount); + + InterlockedIncrement( &(*Fcb)->OpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenSpecialShareFcb Increment handle count on Fcb %08lX Cnt %d\n", + (*Fcb), + (*Fcb)->OpenHandleCount); + + // + // Increment the open reference and handle on the parent node + // + + InterlockedIncrement( &pParentObjectInfo->Specific.Directory.ChildOpenHandleCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenSpecialShareFcb Increment child open handle count on Parent object %08lX Cnt %d\n", + pParentObjectInfo, + pParentObjectInfo->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSOpenSpecialShareFcb Increment child open ref count on Parent object %08lX Cnt %d\n", + pParentObjectInfo, + pParentObjectInfo->Specific.Directory.ChildOpenReferenceCount); + + // + // Return the open result for this file + // + + Irp->IoStatus.Information = FILE_OPENED; + +try_exit: + + if( bReleaseFcb) + { + + AFSReleaseResource( &(*Fcb)->NPFcb->Resource); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( bAllocatedCcb) + { + + AFSRemoveCcb( *Ccb); + + *Ccb = NULL; + } + + if( bAllocateFcb) + { + + // + // Need to tear down this Fcb since it is not in the tree for the worker thread + // + + AFSRemoveFcb( *Fcb); + + DirectoryCB->ObjectInformation->Fcb = NULL; + } + + *Fcb = NULL; + + *Ccb = NULL; + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSData.cpp b/src/WINNT/afsrdr/kernel/lib/AFSData.cpp new file mode 100644 index 0000000000..2a69e47287 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSData.cpp @@ -0,0 +1,119 @@ +/* + * 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: AFSData.cpp +// + +#define NO_EXTERN + +#include "AFSCommon.h" + +extern "C" { + +PDRIVER_OBJECT AFSLibraryDriverObject = NULL; + +PDEVICE_OBJECT AFSLibraryDeviceObject = NULL; + +PDEVICE_OBJECT AFSControlDeviceObject = NULL; + +PDEVICE_OBJECT AFSRDRDeviceObject = NULL; + +unsigned long AFSCRCTable[ 256]; + +UNICODE_STRING AFSRegistryPath; + +HANDLE AFSSysProcess = NULL; + +UNICODE_STRING AFSServerName; + +AFSVolumeCB *AFSGlobalRoot = NULL; + +AFSVolumeCB *AFSRedirectorRoot = NULL; + +UNICODE_STRING AFSPIOCtlName; + +UNICODE_STRING AFSGlobalRootName; + +ULONG AFSDebugFlags = 0; + +CACHE_MANAGER_CALLBACKS *AFSLibCacheManagerCallbacks = NULL; + +ULONG AFSLibControlFlags = 0; + +void *AFSLibCacheBaseAddress = NULL; + +LARGE_INTEGER AFSLibCacheLength = {0,0}; + +// +// List of 'special' share names we need to handle +// + +AFSDirectoryCB *AFSSpecialShareNames = NULL; + +// +// Global relative entries for enumerations +// + +AFSDirectoryCB *AFSGlobalDotDirEntry = NULL; + +AFSDirectoryCB *AFSGlobalDotDotDirEntry = NULL; + +// +// Callbacks in the framework +// + +PAFSProcessRequest AFSProcessRequest = NULL; + +PAFSDbgLogMsg AFSDbgLogMsg = AFSDefaultLogMsg; + +PAFSAddConnectionEx AFSAddConnectionEx = NULL; + +PAFSExAllocatePoolWithTag AFSExAllocatePoolWithTag = NULL; + +PAFSExFreePool AFSExFreePool = NULL; + +PAFSDumpTraceFiles AFSDumpTraceFilesFnc = AFSDumpTraceFiles_Default; + +PAFSRetrieveAuthGroup AFSRetrieveAuthGroupFnc = NULL; + +// +// Security descriptor routine +// + +PAFSRtlSetSaclSecurityDescriptor AFSRtlSetSaclSecurityDescriptor = NULL; + +SECURITY_DESCRIPTOR *AFSDefaultSD = NULL; + +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSDevControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSDevControl.cpp new file mode 100644 index 0000000000..3464552c20 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSDevControl.cpp @@ -0,0 +1,442 @@ +/* + * 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: AFSDevControl.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSDevControl +// +// Description: +// +// This is the dipatch handler for the IRP_MJ_DEVICE_CONTROL requests. +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSDevControl( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + ULONG ulIoControlCode; + + __try + { + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + ulIoControlCode = pIrpSp->Parameters.DeviceIoControl.IoControlCode; + + switch( ulIoControlCode) + { + + case IOCTL_AFS_INITIALIZE_LIBRARY_DEVICE: + { + + AFSLibraryInitCB *pLibInitCB = (AFSLibraryInitCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSLibraryInitCB)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSInitializeLibrary( pLibInitCB); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSDevControl AFSInitializeLibrary failure %08lX\n", + ntStatus); + + break; + } + + // + // Initialize our global entries + // + + ntStatus = AFSInitializeGlobalDirectoryEntries(); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSDevControl AFSInitializeGlobalDirectoryEntries failure %08lX\n", + ntStatus); + + break; + } + + ntStatus = AFSInitializeSpecialShareNameList(); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSDevControl AFSInitializeSpecialShareNameList failure %08lX\n", + ntStatus); + + break; + } + + break; + } + + case IOCTL_AFS_ADD_CONNECTION: + { + + AFSNetworkProviderConnectionCB *pConnectCB = (AFSNetworkProviderConnectionCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSNetworkProviderConnectionCB) || + pIrpSp->Parameters.DeviceIoControl.InputBufferLength < (ULONG)FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pConnectCB->RemoteNameLength || + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof( ULONG)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSAddConnection( pConnectCB, + (PULONG)Irp->AssociatedIrp.SystemBuffer, + &Irp->IoStatus.Information); + + break; + } + + case IOCTL_AFS_CANCEL_CONNECTION: + { + + AFSNetworkProviderConnectionCB *pConnectCB = (AFSNetworkProviderConnectionCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSNetworkProviderConnectionCB)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSCancelConnection( pConnectCB, + (AFSCancelConnectionResultCB *)Irp->AssociatedIrp.SystemBuffer, + &Irp->IoStatus.Information); + + break; + } + + case IOCTL_AFS_GET_CONNECTION: + { + + AFSNetworkProviderConnectionCB *pConnectCB = (AFSNetworkProviderConnectionCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSNetworkProviderConnectionCB) || + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSGetConnection( pConnectCB, + (WCHAR *)Irp->AssociatedIrp.SystemBuffer, + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, + &Irp->IoStatus.Information); + + break; + } + + case IOCTL_AFS_LIST_CONNECTIONS: + { + + if( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSListConnections( (AFSNetworkProviderConnectionCB *)Irp->AssociatedIrp.SystemBuffer, + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, + &Irp->IoStatus.Information); + + break; + } + + case IOCTL_AFS_GET_CONNECTION_INFORMATION: + { + + AFSNetworkProviderConnectionCB *pConnectCB = (AFSNetworkProviderConnectionCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSNetworkProviderConnectionCB) || + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSGetConnectionInfo( pConnectCB, + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, + &Irp->IoStatus.Information); + + break; + } + + case IOCTL_AFS_SET_FILE_EXTENTS: + { + + AFSSetFileExtentsCB *pExtents = (AFSSetFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer; + + // + // Check lengths twice so that if the buffer makes the + // count invalid we will not Accvio + // + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < + ( FIELD_OFFSET( AFSSetFileExtentsCB, ExtentCount) + sizeof(ULONG)) || + pIrpSp->Parameters.DeviceIoControl.InputBufferLength < + ( FIELD_OFFSET( AFSSetFileExtentsCB, ExtentCount) + sizeof(ULONG) + + sizeof (AFSFileExtentCB) * pExtents->ExtentCount)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSProcessSetFileExtents( pExtents ); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = ntStatus; + + break; + } + + case IOCTL_AFS_RELEASE_FILE_EXTENTS: + { + ntStatus = AFSProcessReleaseFileExtents( Irp); + break; + } + + case IOCTL_AFS_SET_FILE_EXTENT_FAILURE: + { + + ntStatus = AFSProcessExtentFailure( Irp); + + break; + } + + case IOCTL_AFS_INVALIDATE_CACHE: + { + + AFSInvalidateCacheCB *pInvalidate = (AFSInvalidateCacheCB*)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSInvalidateCacheCB)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSInvalidateCache( pInvalidate); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = ntStatus; + + break; + } + + case IOCTL_AFS_NETWORK_STATUS: + { + + AFSNetworkStatusCB *pNetworkStatus = (AFSNetworkStatusCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSNetworkStatusCB)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + // + // Set the network status + // + + ntStatus = AFSSetNetworkState( pNetworkStatus); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = ntStatus; + + break; + } + + case IOCTL_AFS_VOLUME_STATUS: + { + + AFSVolumeStatusCB *pVolumeStatus = (AFSVolumeStatusCB *)Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSVolumeStatusCB)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSSetVolumeState( pVolumeStatus); + + Irp->IoStatus.Information = 0; + Irp->IoStatus.Status = ntStatus; + + break; + } + + case IOCTL_AFS_STATUS_REQUEST: + { + + if( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof( AFSDriverStatusRespCB)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSGetDriverStatus( (AFSDriverStatusRespCB *)Irp->AssociatedIrp.SystemBuffer); + + Irp->IoStatus.Information = sizeof( AFSDriverStatusRespCB); + + break; + } + + case IOCTL_AFS_GET_OBJECT_INFORMATION: + { + + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSGetStatusInfoCB) || + pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof( AFSStatusInfoCB)) + + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + ntStatus = AFSGetObjectStatus( (AFSGetStatusInfoCB *)Irp->AssociatedIrp.SystemBuffer, + pIrpSp->Parameters.DeviceIoControl.InputBufferLength, + (AFSStatusInfoCB *)Irp->AssociatedIrp.SystemBuffer, + (ULONG *)&Irp->IoStatus.Information); + + break; + } + + case 0x140390: // IOCTL_LMR_DISABLE_LOCAL_BUFFERING + { + // + // See http://msdn.microsoft.com/en-us/library/ee210753%28v=vs.85%29.aspx + // + // The IOCTL_LMR_DISABLE_LOCAL_BUFFERING control code is defined internally by + // the system as 0x140390 and not in a public header file. It is used by + // special-purpose applications to disable local client-side in-memory + // caching of data when reading data from or writing data to a remote file. + // After local buffering is disabled, the setting remains in effect until all + // open handles to the file are closed and the redirector cleans up its internal + // data structures. + // + // General-purpose applications should not use IOCTL_LMR_DISABLE_LOCAL_BUFFERING, + // because it can result in excessive network traffic and associated loss of + // performance. The IOCTL_LMR_DISABLE_LOCAL_BUFFERING control code should be used + // only in specialized applications moving large amounts of data over the network + // while attempting to maximize use of network bandwidth. For example, the CopyFile + // and CopyFileEx functions use IOCTL_LMR_DISABLE_LOCAL_BUFFERING to improve large + // file copy performance. + // + // IOCTL_LMR_DISABLE_LOCAL_BUFFERING is not implemented by local file systems and + // will fail with the error ERROR_INVALID_FUNCTION. Issuing the + // IOCTL_LMR_DISABLE_LOCAL_BUFFERING control code on remote directory handles will + // fail with the error ERROR_NOT_SUPPORTED. + // + + ntStatus = STATUS_NOT_SUPPORTED; + + break; + } + + default: + { + + ntStatus = STATUS_NOT_IMPLEMENTED; + + break; + } + } + +//try_exit: + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation())) + { + + ntStatus = STATUS_UNSUCCESSFUL; + } + + Irp->IoStatus.Status = ntStatus; + + AFSCompleteRequest( Irp, + ntStatus); + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp new file mode 100644 index 0000000000..ca759ff5ed --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp @@ -0,0 +1,1696 @@ +/* + * 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; + 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); + + // + // Tell the service to prime the cache of the directory content + // + + ntStatus = AFSEnumerateDirectoryNoResponse( &pFcb->AuthGroup, + &pFcb->ObjectInformation->FileId); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryDirectory Enumerate directory failure for parent %wZ Mask %wZ Status %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + &pCcb->MaskName, + ntStatus); + + try_return( ntStatus); + } + } + 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); + } + + // + // Grab the directory node hdr tree lock shared while parsing the directory + // contents + // + + AFSAcquireShared( pFcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + bReleaseMain = TRUE; + + // + // We can now safely drop the lock on the node + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + + // + // 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); + + 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)) + { + + 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)) + { + + 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)) + { + + 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)) + { + + continue; + } + } + } + } + } + + // + // Be sure the information is valid + // We don't worry about entries while enumerating the directory + // + + AFSValidateEntry( pDirEntry, + &pFcb->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, + &stFileInfo))) + { + + 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--; + + 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; + } + 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); + + 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) + { + + try_return( ntStatus = STATUS_BUFFER_OVERFLOW); + } + + 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( 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; + + 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; + + 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; + + 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 + // + + 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); + } + 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++; + } + } + +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) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSSnapshotHdr *pSnapshotHdr = NULL; + AFSSnapshotEntry *pSnapshotEntry = NULL; + AFSDirectoryCB *pDirEntry = NULL; + + __Enter + { + + // + // 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; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSEa.cpp b/src/WINNT/afsrdr/kernel/lib/AFSEa.cpp new file mode 100644 index 0000000000..63100bd250 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSEa.cpp @@ -0,0 +1,127 @@ +/* + * 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: AFSEa.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSQueryEA +// +// Description: +// +// This function is the dipatch handler for the IRP_MJ_QUERY_EA request +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSQueryEA( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_EAS_NOT_SUPPORTED; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryEa Entry for FO %08lX\n", pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueryEA\n"); + } + + return ntStatus; +} + +// +// Function: AFSSetEA +// +// Description: +// +// This function is the dipatch handler for the IRP_MJ_SET_EA request +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSSetEA( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_EAS_NOT_SUPPORTED; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetEa Entry for FO %08lX\n", pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSSetEA\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSExtentsSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSExtentsSupport.cpp new file mode 100644 index 0000000000..7df75034a4 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSExtentsSupport.cpp @@ -0,0 +1,4104 @@ +/* + * 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: AFSCommSupport.cpp +// +#include "AFSCommon.h" + +#define AFS_MAX_FCBS_TO_DROP 10 + +static AFSExtent *ExtentFor( PLIST_ENTRY le, ULONG SkipList ); +static AFSExtent *NextExtent( AFSExtent *Extent, ULONG SkipList ); +static ULONG ExtentsMasks[AFS_NUM_EXTENT_LISTS] = AFS_EXTENTS_MASKS; +static VOID VerifyExtentsLists(AFSFcb *Fcb); +static AFSExtent *DirtyExtentFor(PLIST_ENTRY le); + +LIST_ENTRY * +AFSEntryForOffset( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset); + + +// +// Returns with Extents lock EX and no one using them. +// + +VOID +AFSLockForExtentsTrim( IN AFSFcb *Fcb) +{ + NTSTATUS ntStatus; + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLockForExtentsTrim Acuiring Fcb extents lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE ); + + return; +} + +// +// return FALSE *or* with Extents lock EX and noone using them +// +BOOLEAN +AFSLockForExtentsTrimNoWait( IN AFSFcb *Fcb) +{ + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLockForExtentsTrimNoWait Attempting to acquiring Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + if (!AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, FALSE )) + { + // + // Couldn't lock immediately + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLockForExtentsTrimNoWait Refused to wait for Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + return FALSE; + } + + return TRUE; +} +// +// Pull all the extents away from the FCB. +// +BOOLEAN +AFSTearDownFcbExtents( IN AFSFcb *Fcb ) +{ + BOOLEAN bFoundExtents = FALSE; + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + LIST_ENTRY *le; + AFSExtent *pEntry; + ULONG ulCount = 0, ulReleaseCount = 0, ulProcessCount = 0; + size_t sz; + AFSReleaseExtentsCB *pRelease = NULL; + BOOLEAN locked = FALSE; + NTSTATUS ntStatus; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + __Enter + { + + // + // Ensure that no one is working with the extents and grab the + // lock + // + + AFSLockForExtentsTrim( Fcb ); + + locked = TRUE; + + if (0 == Fcb->Specific.File.ExtentCount) + { + try_return ( ntStatus = STATUS_SUCCESS); + } + + // + // Release a max of 100 extents at a time + // + + sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )); + + pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool, + sz, + AFS_EXTENT_RELEASE_TAG); + if (NULL == pRelease) + { + + try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + + ulCount = Fcb->Specific.File.ExtentCount; + + while( ulReleaseCount < ulCount) + { + + bFoundExtents = TRUE; + + RtlZeroMemory( pRelease, + sizeof( AFSReleaseExtentsCB ) + + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB ))); + + if( ulCount - ulReleaseCount <= AFS_MAXIMUM_EXTENT_RELEASE_COUNT) + { + ulProcessCount = ulCount - ulReleaseCount; + } + else + { + ulProcessCount = AFS_MAXIMUM_EXTENT_RELEASE_COUNT; + } + + pRelease->Flags = AFS_EXTENT_FLAG_RELEASE; + pRelease->ExtentCount = ulProcessCount; + + // + // Update the metadata for this call + // + + pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile; + pRelease->CreateTime = Fcb->ObjectInformation->CreationTime; + pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime; + pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime; + pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime; + + ulProcessCount = 0; + + while (ulProcessCount < pRelease->ExtentCount) + { + pEntry = ExtentFor( le, AFS_EXTENTS_LIST ); + + pRelease->FileExtents[ulProcessCount].Flags = AFS_EXTENT_FLAG_RELEASE; + +#if GEN_MD5 + RtlCopyMemory( pRelease->FileExtents[ulProcessCount].MD5, + pEntry->MD5, + sizeof(pEntry->MD5)); + + pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_MD5_SET; +#endif + + if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY)) + { + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + if( BooleanFlagOn( pEntry->Flags, AFS_EXTENT_DIRTY)) + { + + LONG dirtyCount; + + AFSRemoveEntryDirtyList( Fcb, + pEntry); + + pRelease->FileExtents[ulProcessCount].Flags |= AFS_EXTENT_FLAG_DIRTY; + + dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount); + + ASSERT( dirtyCount >= 0); + } + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSTearDownFcbExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %08lX-%08lX Len %08lX\n", + pEntry, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + pEntry->FileOffset.HighPart, + pEntry->FileOffset.LowPart, + pEntry->Size); + + pRelease->FileExtents[ulProcessCount].Length = pEntry->Size; + pRelease->FileExtents[ulProcessCount].DirtyLength = pEntry->Size; + pRelease->FileExtents[ulProcessCount].DirtyOffset = 0; + pRelease->FileExtents[ulProcessCount].CacheOffset = pEntry->CacheOffset; + pRelease->FileExtents[ulProcessCount].FileOffset = pEntry->FileOffset; + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pEntry->Size/1024))); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pEntry->Size/1024))); + + ASSERT( pEntry->ActiveCount == 0); + + ulProcessCount ++; + le = le->Flink; + AFSExFreePool( pEntry); + + InterlockedDecrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0) + { + + KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent, + 0, + FALSE); + } + } + + // + // Send the request down. We cannot send this down + // asynchronously - if we did that we could request them + // back before the service got this request and then this + // request would be a corruption. + // + + sz = sizeof( AFSReleaseExtentsCB ) + (ulProcessCount * sizeof ( AFSFileExtentCB )); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &Fcb->AuthGroup, + NULL, + &Fcb->ObjectInformation->FileId, + pRelease, + sz, + NULL, + NULL); + + if( !NT_SUCCESS(ntStatus)) + { + + // + // Regardless of whether or not the AFSProcessRequest() succeeded, the extents + // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSTearDownFcbExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + ntStatus); + + } + + ulReleaseCount += ulProcessCount; + } + + // + // Reinitialize the skip lists + // + + ASSERT( Fcb->Specific.File.ExtentCount == 0); + + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i++) + { + InitializeListHead(&Fcb->Specific.File.ExtentsLists[i]); + } + + // + // Reinitialize the dirty list as well + // + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + ASSERT( Fcb->Specific.File.ExtentsDirtyCount == 0); + + Fcb->NPFcb->Specific.File.DirtyListHead = NULL; + Fcb->NPFcb->Specific.File.DirtyListTail = NULL; + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + + Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + +try_exit: + + if (locked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSTearDownFcbExtents Releasing Fcb extent lock %08lX thread %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource ); + } + + if (pRelease) { + AFSExFreePool( pRelease); + } + } + + return bFoundExtents; +} + +static PAFSExtent +ExtentForOffsetInList( IN AFSFcb *Fcb, + IN LIST_ENTRY *List, + IN ULONG ListNumber, + IN PLARGE_INTEGER Offset) +{ + // + // Return the extent that maps the offset, that + // - Contains the offset + // - or is immediately ahead of the offset (in this list) + // - otherwise return NULL. + // + + PLIST_ENTRY pLe = List; + AFSExtent *pPrevious = NULL; + + ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource )); + + while (pLe != &Fcb->Specific.File.ExtentsLists[ListNumber]) + { + AFSExtent *entry; + + entry = ExtentFor( pLe, ListNumber ); + + if( entry == NULL) + { + return entry; + } + + if (Offset->QuadPart < entry->FileOffset.QuadPart) + { + // + // Offset is ahead of entry. Return previous + // + return pPrevious; + } + + if (Offset->QuadPart >= (entry->FileOffset.QuadPart + entry->Size)) + { + // + // We start after this extent - carry on round + // + pPrevious = entry; + pLe = pLe->Flink; + continue; + } + + // + // Otherwise its a match + // + + return entry; + } + + // + // Got to the end. Return Previous + // + return pPrevious; +} + +BOOLEAN +AFSExtentContains( IN AFSExtent *Extent, IN PLARGE_INTEGER Offset) +{ + if (NULL == Extent) + { + return FALSE; + } + return (Extent->FileOffset.QuadPart <= Offset->QuadPart && + (Extent->FileOffset.QuadPart + Extent->Size) > Offset->QuadPart); +} + + +// +// Return the extent that contains the offset +// +PAFSExtent +AFSExtentForOffsetHint( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN BOOLEAN ReturnPrevious, + IN AFSExtent *Hint) +{ + AFSExtent *pPrevious = Hint; + LIST_ENTRY *pLe; + LONG i; + + ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource )); + +#if AFS_VALIDATE_EXTENTS + VerifyExtentsLists(Fcb); +#endif + + // + // So we will go across the skip lists until we find an + // appropriate entry (previous or direct match). If it's a match + // we are done, other wise we start on the next layer down + // + for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--) + { + if (NULL == pPrevious) + { + // + // We haven't found anything in the previous layers + // + pLe = Fcb->Specific.File.ExtentsLists[i].Flink; + } + else if (NULL == pPrevious->Lists[i].Flink) + { + ASSERT(AFS_EXTENTS_LIST != i); + // + // The hint doesn't exist at this level, next one down + // + continue; + } + else + { + // + // take the previous into the next + // + pLe = &pPrevious->Lists[i]; + } + + pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset); + + if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset)) + { + // + // Found it immediately. Stop here + // + return pPrevious; + } + } + + if (NULL == pPrevious || ReturnPrevious ) + { + return pPrevious; + } + + ASSERT( !AFSExtentContains(pPrevious, Offset) ); + + return NULL; +} + +LIST_ENTRY * +AFSEntryForOffset( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset) +{ + AFSExtent *pPrevious = NULL; + LIST_ENTRY *pLe; + LONG i; + + ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource )); + +#if AFS_VALIDATE_EXTENTS + VerifyExtentsLists(Fcb); +#endif + + // + // So we will go across the skip lists until we find an + // appropriate entry (previous or direct match). If it's a match + // we are done, other wise we start on the next layer down + // + for (i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--) + { + if (NULL == pPrevious) + { + // + // We haven't found anything in the previous layers + // + pLe = Fcb->Specific.File.ExtentsLists[i].Flink; + } + else if (NULL == pPrevious->Lists[i].Flink) + { + ASSERT(AFS_EXTENTS_LIST != i); + // + // The hint doesn't exist at this level, next one down + // + continue; + } + else + { + // + // take the previous into the next + // + pLe = &pPrevious->Lists[i]; + } + + pPrevious = ExtentForOffsetInList( Fcb, pLe, i, Offset); + + if (NULL != pPrevious && AFSExtentContains(pPrevious, Offset)) + { + // + // Found it immediately. Stop here + // + return pLe; + } + } + + return NULL; +} + +PAFSExtent +AFSExtentForOffset( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN BOOLEAN ReturnPrevious) +{ + return AFSExtentForOffsetHint(Fcb, Offset, ReturnPrevious, NULL); +} + + +BOOLEAN AFSDoExtentsMapRegion(IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Size, + IN OUT AFSExtent **FirstExtent, + OUT AFSExtent **LastExtent) +{ + // + // Return TRUE region is completely mapped. FALSE + // otherwise. If the region isn't mapped then the last + // extent to map part of the region is returned. + // + // *LastExtent as input is where to start looking. + // *LastExtent as output is either the extent which + // contains the Offset, or the last one which doesn't + // + AFSExtent *entry; + AFSExtent *newEntry; + BOOLEAN retVal = FALSE; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSDoExtentsMapRegion Acquiring Fcb extent lock %08lX SHARED %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE ); + + entry = AFSExtentForOffsetHint(Fcb, Offset, TRUE, *FirstExtent); + *FirstExtent = entry; + + if (NULL == entry || !AFSExtentContains(entry, Offset)) + { + try_return (retVal = FALSE); + } + + ASSERT(Offset->QuadPart >= entry->FileOffset.QuadPart); + + while (TRUE) + { + if ((entry->FileOffset.QuadPart + entry->Size) >= + (Offset->QuadPart + Size)) + { + // + // The end is inside the extent + // + try_return (retVal = TRUE); + } + + if (entry->Lists[AFS_EXTENTS_LIST].Flink == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST]) + { + // + // Run out of extents + // + try_return (retVal = FALSE); + } + + newEntry = NextExtent( entry, AFS_EXTENTS_LIST ); + + if (newEntry->FileOffset.QuadPart != + (entry->FileOffset.QuadPart + entry->Size)) + { + // + // Gap + // + try_return (retVal = FALSE); + } + + entry = newEntry; + } + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSDoExtentsMapRegion Releasing Fcb extent lock %08lX SHARED %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource ); + + *LastExtent = entry; + } + + return retVal; +} + +// +// Given an FCB and an Offset we look to see whether there extents to +// Map them all. If there are then we return TRUE to fullymapped +// and *FirstExtent points to the first extent to map the extent. +// If not then we return FALSE, but we request the extents to be mapped. +// Further *FirstExtent (if non null) is the last extent which doesn't +// map the extent. +// +// Finally on the way *in* if *FirstExtent is non null it is where we start looking +// + +NTSTATUS +AFSRequestExtents( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Size, + OUT BOOLEAN *FullyMapped) +{ + + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSExtent *pExtent; + AFSRequestExtentsCB request; + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + AFSExtent *pFirstExtent; + LARGE_INTEGER liAlignedOffset; + ULONG ulAlignedLength = 0; + LARGE_INTEGER liTimeOut; + + // + // Check our extents, then fire off a request if we need to. + // We start off knowing nothing about where we will go. + // + pFirstExtent = NULL; + pExtent = NULL; + + *FullyMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent ); + + if (*FullyMapped) + { + + ASSERT(AFSExtentContains(pFirstExtent, Offset)); + LARGE_INTEGER end = *Offset; + end.QuadPart += (Size-1); + ASSERT(AFSExtentContains(pExtent, &end)); + + return STATUS_SUCCESS; + } + + // + // So we need to queue a request. Since we will be clearing the + // ExtentsRequestComplete event we need to do with with the lock + // EX + // + + liTimeOut.QuadPart = -(50000000); + + while (TRUE) + { + if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus)) + { + + // + // If this isn't the same process which caused the failure then try to request them again + // + + if( Fcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)PsGetCurrentProcessId()) + { + ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus; + + break; + } + + pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + ntStatus = KeWaitForSingleObject( &pNPFcb->Specific.File.ExtentsRequestComplete, + Executive, + KernelMode, + FALSE, + &liTimeOut); + if (!NT_SUCCESS(ntStatus)) + { + + // + // try again + // + + continue; + } + + // + // Lock resource EX and look again + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtents Acquiring Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE ); + + if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus)) + { + + // + // If this isn't the same process which caused the failure then try to request them again + // + + if( Fcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)PsGetCurrentProcessId()) + { + ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + + break; + } + + pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + if( KeReadStateEvent( &pNPFcb->Specific.File.ExtentsRequestComplete) || + ntStatus == STATUS_TIMEOUT) + { + + ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus; + + if( !NT_SUCCESS( ntStatus)) + { + + // + // If this isn't the same process which caused the failure then try to request them again + // + + if( Fcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)PsGetCurrentProcessId()) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + } + else + { + + pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + + ntStatus = STATUS_SUCCESS; + } + } + + break; + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + } + + if (!NT_SUCCESS(ntStatus)) + { + + return ntStatus; + } + + __Enter + { + // + // We have the lock Ex and there is no filling going on. + // Check again to see whether things have moved since we last + // checked. Since we haven't locked against pinning, we will + // reset here. + // + + pFirstExtent = NULL; + + *FullyMapped = AFSDoExtentsMapRegion(Fcb, Offset, Size, &pFirstExtent, &pExtent); + + if (*FullyMapped) + { + + ASSERT(AFSExtentContains(pFirstExtent, Offset)); + LARGE_INTEGER end = *Offset; + end.QuadPart += (Size-1); + ASSERT(AFSExtentContains(pExtent, &end)); + + try_return (ntStatus = STATUS_SUCCESS); + } + + RtlZeroMemory( &request, + sizeof( AFSRequestExtentsCB)); + + // + // Align the request + // + + ulAlignedLength = Size; + + liAlignedOffset = *Offset; + + if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0) + { + + liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize); + + ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart); + } + + if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0) + { + + ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize); + } + + request.ByteOffset = liAlignedOffset; + request.Length = ulAlignedLength; + + if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId, + &request.ByteOffset, + request.Length)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtents Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + request.ByteOffset.LowPart, + request.Length, + PsGetCurrentThread()); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS, + 0, + &Fcb->AuthGroup, + NULL, + &Fcb->ObjectInformation->FileId, + &request, + sizeof( AFSRequestExtentsCB ), + NULL, + NULL); + + if( NT_SUCCESS( ntStatus)) + { + KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete ); + } + } + else + { + + KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete ); + } + +try_exit: + + if (NT_SUCCESS( ntStatus )) + { + KeQueryTickCount( &Fcb->Specific.File.LastExtentAccess ); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtents Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + } + + return ntStatus; +} + +NTSTATUS +AFSRequestExtentsAsync( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Size) +{ + + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSExtent *pExtent = NULL; + AFSRequestExtentsCB request; + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + AFSExtent *pFirstExtent = NULL; + LARGE_INTEGER liAlignedOffset; + ULONG ulAlignedLength = 0; + BOOLEAN bRegionMapped = FALSE; + + __Enter + { + + ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->Specific.File.ExtentsResource )); + + // + // If the service set a failure on the file since the last + // CreateFile was issued, return it now. + // + + if (!NT_SUCCESS( pNPFcb->Specific.File.ExtentsRequestStatus)) + { + + // + // If this isn't the same process which caused the failure then try to request them again + // + + if( Fcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)PsGetCurrentProcessId()) + { + try_return( ntStatus = pNPFcb->Specific.File.ExtentsRequestStatus); + } + + pNPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + // + // Check if we are already mapped + // + + bRegionMapped = AFSDoExtentsMapRegion( Fcb, Offset, Size, &pFirstExtent, &pExtent); + + if( bRegionMapped) + { + + try_return( ntStatus = STATUS_SUCCESS); + } + + // + // Align our request on extent size boundary + // + + ulAlignedLength = Size; + + liAlignedOffset = *Offset; + + if( liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0) + { + + liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)(liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize); + + ulAlignedLength += (ULONG)(Offset->QuadPart - liAlignedOffset.QuadPart); + } + + if( ulAlignedLength % pDevExt->Specific.RDR.CacheBlockSize != 0) + { + + ulAlignedLength = (ULONG)(((ulAlignedLength / pDevExt->Specific.RDR.CacheBlockSize) + 1) * pDevExt->Specific.RDR.CacheBlockSize); + } + + RtlZeroMemory( &request, + sizeof( AFSRequestExtentsCB)); + + request.ByteOffset = liAlignedOffset; + request.Length = ulAlignedLength; + + if( !AFSIsExtentRequestQueued( &Fcb->ObjectInformation->FileId, + &request.ByteOffset, + request.Length)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRequestExtentsAsync Request extents for fid %08lX-%08lX-%08lX-%08lX Offset %08lX Len %08lX Thread %08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + request.ByteOffset.LowPart, + request.Length, + PsGetCurrentThread()); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_REQUEST_FILE_EXTENTS, + 0, + &Fcb->AuthGroup, + NULL, + &Fcb->ObjectInformation->FileId, + &request, + sizeof( AFSRequestExtentsCB ), + NULL, + NULL); + + if( NT_SUCCESS( ntStatus)) + { + + KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete ); + } + } + else + { + + KeClearEvent( &pNPFcb->Specific.File.ExtentsRequestComplete ); + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSProcessExtentsResult( IN AFSFcb *Fcb, + IN ULONG Count, + IN AFSFileExtentCB *Result) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFileExtentCB *pFileExtents = Result; + AFSExtent *pExtent; + LIST_ENTRY *le; + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + ULONG fileExtentsUsed = 0; + BOOLEAN bFoundExtent = FALSE; + LIST_ENTRY *pSkipEntries[AFS_NUM_EXTENT_LISTS] = { 0 }; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + // + // Grab the extents exclusive for the duration + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentsResult Acquiring Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pNPFcb->Specific.File.ExtentsResource, TRUE ); + + __Enter + { + + // + // Find where to put the extents + // + for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++) + { + + pSkipEntries[i] = Fcb->Specific.File.ExtentsLists[i].Flink; + } + + le = pSkipEntries[AFS_EXTENTS_LIST]; + + if (le == &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST]) + { + // + // No extents. Insert at head of list (which is where the skip lists point!) + // + pExtent = NULL; + } + else if (0 != pFileExtents->FileOffset.QuadPart) + { + // + // We want to find the best extents immediately *behind* this offset + // + LARGE_INTEGER offset = pFileExtents->FileOffset; + + // + // Ask in the top skip list first, then work down + // + for (LONG i = AFS_NUM_EXTENT_LISTS-1; i >= AFS_EXTENTS_LIST; i--) + { + pExtent = ExtentForOffsetInList( Fcb, + pSkipEntries[i], + i, + &offset); + + if (NULL == pExtent) + { + // + // No dice. Header has to become the head of the list + // + pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i]; + // + // And as a loop invariant we should never have found an extent + // + ASSERT(!bFoundExtent); + } + else + { + // + // pExtent is where to start to insert at this level + // + pSkipEntries[i] = &pExtent->Lists[i]; + + // + // And also where to start to look at the next level + // + + if (i > AFS_EXTENTS_LIST) + { + pSkipEntries[i-1] = &pExtent->Lists[i-1]; + } + bFoundExtent = TRUE; + } + } + + if (NULL == pExtent) + { + pExtent = ExtentFor( le, AFS_EXTENTS_LIST); + le = le->Blink; + } + else + { + le = pExtent->Lists[AFS_EXTENTS_LIST].Blink; + } + } + else + { + // + // Looking at offset 0, so we must start at the beginning + // + + pExtent = ExtentFor(le, AFS_EXTENTS_LIST); + le = le->Blink; + + // + // And set up the skip lists + // + + for (ULONG i = AFS_EXTENTS_LIST; i < AFS_NUM_EXTENT_LISTS; i++) + { + pSkipEntries[i] = &Fcb->Specific.File.ExtentsLists[i]; + } + } + + while (fileExtentsUsed < Count) + { + + // + // Loop invariant - le points to where to insert after and + // pExtent points to le->fLink + // + + ASSERT (NULL == pExtent || + le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]); + + if (NULL == pExtent || + pExtent->FileOffset.QuadPart > pFileExtents->FileOffset.QuadPart) + { + // + // We need to insert a new extent at le. Start with + // some sanity check on spanning + // + if (NULL != pExtent && + ((pFileExtents->FileOffset.QuadPart + pFileExtents->Length) > + pExtent->FileOffset.QuadPart)) + { + // + // File Extents overlaps pExtent + // + ASSERT( (pFileExtents->FileOffset.QuadPart + pFileExtents->Length) <= + pExtent->FileOffset.QuadPart); + + try_return (ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // File offset is entirely in front of this extent. Create + // a new one (remember le is the previous list entry) + // + pExtent = (AFSExtent *) AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSExtent), + AFS_EXTENT_TAG ); + if (NULL == pExtent) + { + + ASSERT( FALSE); + + try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + RtlZeroMemory( pExtent, sizeof( AFSExtent )); + + pExtent->FileOffset = pFileExtents->FileOffset; + pExtent->CacheOffset = pFileExtents->CacheOffset; + pExtent->Size = pFileExtents->Length; + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentsResult Received extent for fid %08lX-%08lX-%08lX-%08lX File Offset %I64X Cache Offset %I64X Len %08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + pFileExtents->FileOffset.QuadPart, + pFileExtents->CacheOffset.QuadPart, + pFileExtents->Length); + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, (LONG)(pExtent->Size/1024)); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, (LONG)(pExtent->Size/1024)); + + InterlockedIncrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedIncrement( &pControlDevExt->Specific.Control.ExtentCount) == 1) + { + + KeClearEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent); + } + + // + // Insert into list + // + InsertHeadList(le, &pExtent->Lists[AFS_EXTENTS_LIST]); + ASSERT(le->Flink == &pExtent->Lists[AFS_EXTENTS_LIST]); + ASSERT(0 == (pExtent->FileOffset.LowPart & ExtentsMasks[AFS_EXTENTS_LIST])); + + // + // Do not move the cursor - we will do it next time + // + + // + // And into the (upper) skip lists - Again, do not move the cursor + // + for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--) + { + if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i])) + { + InsertHeadList(pSkipEntries[i], &pExtent->Lists[i]); +#if AFS_VALIDATE_EXTENTS + VerifyExtentsLists(Fcb); +#endif + } + } + } + else if (pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart) + { + + if (pExtent->Size != pFileExtents->Length) + { + + ASSERT (pExtent->Size == pFileExtents->Length); + + try_return (ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // Move both cursors forward. + // + // First the extent pointer + // + fileExtentsUsed++; + le = &pExtent->Lists[AFS_EXTENTS_LIST]; + + // + // Then the skip lists cursors forward if needed + // + for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--) + { + if (0 == (pExtent->FileOffset.LowPart & ExtentsMasks[i])) + { + // + // Check sanity before + // +#if AFS_VALIDATE_EXTENTS + VerifyExtentsLists(Fcb); +#endif + + // + // Skip list should point to us + // + //ASSERT(pSkipEntries[i] == &pExtent->Lists[i]); + // + // Move forward cursor + // + pSkipEntries[i] = pSkipEntries[i]->Flink; + // + // Check sanity before + // +#if AFS_VALIDATE_EXTENTS + VerifyExtentsLists(Fcb); +#endif + } + } + + // + // And then the cursor in the supplied array + // + + pFileExtents++; + + // + // setup pExtent if there is one + // + if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST]) + { + pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ; + } + else + { + pExtent = NULL; + } + } + else + { + + ASSERT( pExtent->FileOffset.QuadPart < pFileExtents->FileOffset.QuadPart ); + + // + // Sanity check on spanning + // + if ((pExtent->FileOffset.QuadPart + pExtent->Size) > + pFileExtents->FileOffset.QuadPart) + { + + ASSERT( (pExtent->FileOffset.QuadPart + pExtent->Size) <= + pFileExtents->FileOffset.QuadPart); + + try_return (ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // Move le and pExtent forward + // + le = &pExtent->Lists[AFS_EXTENTS_LIST]; + + /* + // + // Then the check the skip lists cursors + // + for (ULONG i = AFS_NUM_EXTENT_LISTS-1; i > AFS_EXTENTS_LIST; i--) + { + if (0 == (pFileExtents->FileOffset.LowPart & ExtentsMasks[i])) + { + // + // Three options: + // - empty list (pSkipEntries[i]->Flink == pSkipEntries[i]->Flink == fcb->lists[i] + // - We are the last on the list (pSkipEntries[i]->Flink == fcb->lists[i]) + // - We are not the last on the list. In that case we have to be strictly less than + // that extent. + if (pSkipEntries[i]->Flink != &Fcb->Specific.File.ExtentsLists[i]) { + + AFSExtent *otherExtent = ExtentFor(pSkipEntries[i]->Flink, i); + ASSERT(pFileExtents->FileOffset.QuadPart < otherExtent->FileOffset.QuadPart); + } + } + } + */ + + // + // setup pExtent if there is one + // + + if (le->Flink != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST]) + { + pExtent = NextExtent( pExtent, AFS_EXTENTS_LIST ) ; + } + else + { + pExtent = NULL; + } + } + } + + // + // All done, signal that we are done drop the lock, exit + // + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + // + // If we failed the service is going to drop all extents so trim away the + // set given to us + // + + AFSTrimSpecifiedExtents( Fcb, + Count, + Result); + } + +#if AFS_VALIDATE_EXTENTS + VerifyExtentsLists(Fcb); +#endif + + KeSetEvent( &pNPFcb->Specific.File.ExtentsRequestComplete, + 0, + FALSE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentsResult Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + } + + return ntStatus; +} + +NTSTATUS +AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents ) +{ + AFSFcb *pFcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + ULONGLONG ullIndex = 0; + AFSObjectInfoCB *pObjectInfo = NULL; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n", + &pDevExt->Specific.RDR.VolumeTreeLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX\n", + SetExtents->FileId.Cell, + SetExtents->FileId.Volume, + SetExtents->FileId.Vnode, + SetExtents->FileId.Unique); + + // + // Locate the volume node + // + + ullIndex = AFSCreateHighIndex( &SetExtents->FileId); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( pVolumeCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n", + pVolumeCB->ObjectInfoTree.TreeLock, + PsGetCurrentThread()); + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + } + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + if( !NT_SUCCESS( ntStatus) || + pVolumeCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessSetFileExtents Set extents for fid %08lX-%08lX-%08lX-%08lX Failed to locate volume Status %08lX\n", + SetExtents->FileId.Cell, + SetExtents->FileId.Volume, + SetExtents->FileId.Vnode, + SetExtents->FileId.Unique, + ntStatus); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + // + // Now locate the Object in this volume + // + + ullIndex = AFSCreateLowIndex( &SetExtents->FileId); + + ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfo); + + if( pObjectInfo != NULL) + { + + // + // Reference the node so it won't be torn down + // + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Increment count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( !NT_SUCCESS( ntStatus) || + pObjectInfo == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessSetFileExtents Set extents for hash %I64X fid %08lX-%08lX-%08lX-%08lX Failed to locate file in volume %08lX\n", + ullIndex, + SetExtents->FileId.Cell, + SetExtents->FileId.Volume, + SetExtents->FileId.Vnode, + SetExtents->FileId.Unique, + pVolumeCB); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + pFcb = pObjectInfo->Fcb; + + // + // If we have a result failure then don't bother trying to set the extents + // + + if( SetExtents->ResultStatus != STATUS_SUCCESS) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessSetFileExtents Set extents failure fid %08lX-%08lX-%08lX-%08lX ResultStatus %08lX\n", + SetExtents->FileId.Cell, + SetExtents->FileId.Volume, + SetExtents->FileId.Vnode, + SetExtents->FileId.Unique, + SetExtents->ResultStatus); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Acquiring Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + + pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED; + + KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete, + 0, + FALSE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource); + + try_return( ntStatus); + } + + ntStatus = AFSProcessExtentsResult ( pFcb, + SetExtents->ExtentCount, + SetExtents->FileExtents ); + +try_exit: + + if( pObjectInfo != NULL) + { + + InterlockedDecrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessSetFileExtents Decrement count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + } + + return ntStatus; +} + +// +// Helper fuctions for Usermode initiation of release of extents +// +NTSTATUS +AFSReleaseSpecifiedExtents( IN AFSReleaseFileExtentsCB *Extents, + IN AFSFcb *Fcb, + OUT AFSFileExtentCB *FileExtents, + IN ULONG BufferSize, + OUT ULONG *ExtentCount, + OUT BOOLEAN *DirtyExtents) +{ + AFSExtent *pExtent; + LIST_ENTRY *le; + LIST_ENTRY *leNext; + ULONG ulExtentCount = 0; + NTSTATUS ntStatus = STATUS_SUCCESS; + BOOLEAN bReleaseAll = FALSE; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + __Enter + { + ASSERT( ExIsResourceAcquiredExclusiveLite( &Fcb->NPFcb->Specific.File.ExtentsResource)); + + if (BufferSize < (Extents->ExtentCount * sizeof( AFSFileExtentCB))) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseSpecifiedExtents Buffer too small\n"); + + try_return( ntStatus = STATUS_BUFFER_TOO_SMALL); + } + + RtlZeroMemory( FileExtents, BufferSize); + *ExtentCount = 0; + + *DirtyExtents = FALSE; + + // + // iterate until we have dealt with all we were asked for or + // are at the end of the list. Note that this deals (albeit + // badly) with out of order extents + // + + pExtent = AFSExtentForOffset( Fcb, + &Extents->FileExtents[0].FileOffset, + FALSE); + + if (NULL == pExtent) + { + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + } + else + { + le = &pExtent->Lists[AFS_EXTENTS_LIST]; + } + ulExtentCount = 0; + + if( BooleanFlagOn( Extents->Flags, AFS_RELEASE_EXTENTS_FLAGS_RELEASE_ALL) || + ( Extents->FileId.Cell == 0 && + Extents->FileId.Volume == 0 && + Extents->FileId.Vnode == 0 && + Extents->FileId.Unique == 0)) + { + + bReleaseAll = TRUE; + } + + while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] && + ulExtentCount < Extents->ExtentCount) + + { + + pExtent = ExtentFor( le, AFS_EXTENTS_LIST); + + if( !bReleaseAll) + { + + if( pExtent->FileOffset.QuadPart < Extents->FileExtents[ulExtentCount].FileOffset.QuadPart) + { + // + // Skip forward through the extent list until we get + // to the one we want + // + le = le->Flink; + + continue; + } + else if (pExtent->FileOffset.QuadPart > Extents->FileExtents[ulExtentCount].FileOffset.QuadPart) + { + // + // We don't have the extent asked for so return UNKNOWN + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseSpecifiedExtents Located UNKNOWN extent Offset %I64X Len %08lX\n", + Extents->FileExtents[ulExtentCount].FileOffset.QuadPart, + Extents->FileExtents[ulExtentCount].Length); + + FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_UNKNOWN; + + FileExtents[*ExtentCount].Length = 0; + FileExtents[*ExtentCount].CacheOffset.QuadPart = 0; + FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset; + + *ExtentCount = (*ExtentCount) + 1; + + ulExtentCount++; + + // + // Reset where we are looking + // + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + + continue; + } + else if( pExtent->ActiveCount > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseSpecifiedExtents Located IN_USE extent Offset %I64X Len %08lX\n", + Extents->FileExtents[ulExtentCount].FileOffset.QuadPart, + Extents->FileExtents[ulExtentCount].Length); + + FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_IN_USE; + + FileExtents[*ExtentCount].Length = 0; + FileExtents[*ExtentCount].CacheOffset.QuadPart = 0; + FileExtents[*ExtentCount].FileOffset = Extents->FileExtents[ulExtentCount].FileOffset; + + *ExtentCount = (*ExtentCount) + 1; + + ulExtentCount++; + + // + // Reset where we are looking + // + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + + continue; + } + } + else + { + + // + // If the extent is currently active then skip it + // + + if( pExtent->ActiveCount > 0) + { + + le = le->Flink; + + continue; + } + } + + FileExtents[*ExtentCount].Flags = AFS_EXTENT_FLAG_RELEASE; + + FileExtents[*ExtentCount].Length = pExtent->Size; + FileExtents[*ExtentCount].DirtyLength = pExtent->Size; + FileExtents[*ExtentCount].DirtyOffset = 0; + FileExtents[*ExtentCount].CacheOffset = pExtent->CacheOffset; + FileExtents[*ExtentCount].FileOffset = pExtent->FileOffset; + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n", + pExtent, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + FileExtents[*ExtentCount].FileOffset.QuadPart, + FileExtents[*ExtentCount].Length); + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSAcquireExcl( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSRemoveEntryDirtyList( Fcb, + pExtent); + + FileExtents[*ExtentCount].Flags |= AFS_EXTENT_FLAG_DIRTY; + + InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount); + + *DirtyExtents = TRUE; + } + + AFSReleaseResource( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock); + } + + // + // move forward all three cursors + // + le = le->Flink; + ulExtentCount ++; + *ExtentCount = (*ExtentCount) + 1; + + // + // And unpick + // + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++) + { + if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i])) + { + RemoveEntryList( &pExtent->Lists[i] ); + } + } + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024))); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024))); + + // + // and free + // + AFSExFreePool( pExtent); + + InterlockedDecrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0) + { + + KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent, + 0, + FALSE); + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +AFSFcb* +AFSFindFcbToClean(ULONG IgnoreTime, AFSFcb *LastFcb, BOOLEAN Block) +{ + + AFSFcb *pFcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSDeviceExt *pRDRDeviceExt = NULL; + AFSDeviceExt *pControlDeviceExt = NULL; + BOOLEAN bLocatedEntry = FALSE; + AFSObjectInfoCB *pCurrentObject = NULL; + BOOLEAN bReleaseVolumeListLock = FALSE; + + pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFindFcbToClean Acquiring RDR VolumeListLock lock %08lX SHARED %08lX\n", + &pRDRDeviceExt->Specific.RDR.VolumeListLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock, + TRUE); + + bReleaseVolumeListLock = TRUE; + + pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead; + + while( pVolumeCB != NULL) + { + + // + // The Volume list may move under our feet. Lock it. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFindFcbToClean Acquiring VolumeRoot ObjectInfoTree lock %08lX SHARED %08lX\n", + pVolumeCB->ObjectInfoTree.TreeLock, + PsGetCurrentThread()); + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + + bReleaseVolumeListLock = FALSE; + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + if( NULL == LastFcb) + { + + pCurrentObject = pVolumeCB->ObjectInfoListHead; + } + else + { + + pCurrentObject = (AFSObjectInfoCB *)LastFcb->ObjectInformation->ListEntry.fLink; + } + + pFcb = NULL; + + while( pCurrentObject != NULL) + { + + pFcb = (AFSFcb *)pCurrentObject->Fcb; + + // + // If the FCB is a candidate we try to lock it (but without waiting - which + // means we are deadlock free + // + + if( pFcb != NULL && + pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + if( Block) + { + + AFSLockForExtentsTrim( pFcb); + } + else + { + + if( !AFSLockForExtentsTrimNoWait( pFcb)) + { + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + + pFcb = NULL; + + continue; + } + } + + // + // Need to be sure there are no current flushes in the queue + // + + if( pFcb->Specific.File.ExtentCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource); + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + + pFcb = NULL; + + continue; + } + + if( pFcb->Specific.File.QueuedFlushCount > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource); + + if( Block) + { + AFSWaitOnQueuedFlushes( pFcb); + } + else + { + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + } + + pFcb = NULL; + + continue; + } + + if( pFcb->OpenHandleCount > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFindFcbToClean Releasing Fcb extent lock %08lX thread %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource(&pFcb->NPFcb->Specific.File.ExtentsResource); + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + + pFcb = NULL; + + continue; + } + + // + // A hit a very palpable hit. Pin it + // + + InterlockedIncrement( &pCurrentObject->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFindFcbToClean Increment count on Fcb %08lX Cnt %d\n", + pCurrentObject, + pCurrentObject->ObjectReferenceCount); + + bLocatedEntry = TRUE; + + break; + } + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + + pFcb = NULL; + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( bLocatedEntry) + { + break; + } + + AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock, + TRUE); + + bReleaseVolumeListLock = TRUE; + + pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink; + } + + if( bReleaseVolumeListLock) + { + + AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + } + + return pFcb; +} + +NTSTATUS +AFSProcessExtentFailure( PIRP Irp) +{ + AFSExtentFailureCB *pFailureCB = NULL; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSVolumeCB *pVolumeCB = NULL; + ULONGLONG ullIndex = 0; + AFSObjectInfoCB *pObjectInfo = NULL; + + __Enter + { + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof( AFSExtentFailureCB)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessExtentFailure Input buffer too small\n"); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + pFailureCB = (AFSExtentFailureCB *)Irp->AssociatedIrp.SystemBuffer; + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessExtentFailure Service Reports Failure fid %08lX-%08lX-%08lX-%08lX Status %08lX\n", + pFailureCB->FileId.Cell, + pFailureCB->FileId.Volume, + pFailureCB->FileId.Vnode, + pFailureCB->FileId.Unique, + pFailureCB->FailureStatus); + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE); + + // + // Locate the volume node + // + + ullIndex = AFSCreateHighIndex( &pFailureCB->FileId); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( pVolumeCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentFailure Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n", + pVolumeCB->ObjectInfoTree.TreeLock, + PsGetCurrentThread()); + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + } + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + if( !NT_SUCCESS( ntStatus) || + pVolumeCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessExtentFailure Invalid volume index %I64X status %08X\n", + ullIndex, ntStatus); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + // + // Now locate the Object in this volume + // + + ullIndex = AFSCreateLowIndex( &pFailureCB->FileId); + + ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfo); + + if( pObjectInfo != NULL && + pObjectInfo->Fcb != NULL) + { + + // + // Reference the node so it won't be torn down + // + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentFailure Increment count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( !NT_SUCCESS( ntStatus) || + pObjectInfo == NULL || + pObjectInfo->Fcb == NULL) + { + + if( pObjectInfo == NULL) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessExtentFailure Invalid file index %I64X\n", + ullIndex); + } + else + { + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessExtentFailure Fcb dealocated for %I64X\n", + ullIndex); + } + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentFailure Acquiring Fcb extent lock %08lX EXCL %08lX\n", + &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + + pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestStatus = pFailureCB->FailureStatus; + + KeSetEvent( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsRequestComplete, + 0, + FALSE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentFailure Releasing Fcb extent lock %08lX EXCL %08lX\n", + &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Specific.File.ExtentsResource); + + InterlockedDecrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessExtentFailure Decrement count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSProcessReleaseFileExtents( IN PIRP Irp) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSDeviceExt *pDevExt; + AFSReleaseFileExtentsCB *pExtents; + AFSReleaseFileExtentsResultCB *pResult = NULL; + AFSReleaseFileExtentsResultFileCB *pFile = NULL; + ULONG ulSz = 0; + ULONGLONG ullIndex = 0; + AFSObjectInfoCB *pObjectInfo = NULL; + BOOLEAN bLocked = FALSE; + BOOLEAN bDirtyExtents = FALSE; + + __Enter + { + + pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + + pExtents = (AFSReleaseFileExtentsCB*) Irp->AssociatedIrp.SystemBuffer; + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < + sizeof( AFSReleaseFileExtentsCB)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents INPUT Buffer too small\n"); + + try_return( ntStatus = STATUS_INVALID_PARAMETER ); + } + + if ( pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < + sizeof(AFSReleaseFileExtentsResultCB)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents OUTPUT Buffer too small [1]\n"); + + // + // Must have space for one extent in one file + // + + try_return( ntStatus = STATUS_BUFFER_TOO_SMALL); + } + + if (pExtents->ExtentCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Extent count zero\n"); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + if (pExtents->FileId.Cell != 0 || + pExtents->FileId.Volume != 0 || + pExtents->FileId.Vnode != 0 || + pExtents->FileId.Unique != 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Processing FID %08lX:%08lX:%08lX:%08lX\n", + pExtents->FileId.Cell, + pExtents->FileId.Volume, + pExtents->FileId.Vnode, + pExtents->FileId.Unique); + + if( pIrpSp->Parameters.DeviceIoControl.InputBufferLength < + ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG)) || + pIrpSp->Parameters.DeviceIoControl.InputBufferLength < + ( FIELD_OFFSET( AFSReleaseFileExtentsCB, ExtentCount) + sizeof(ULONG) + + sizeof (AFSFileExtentCB) * pExtents->ExtentCount)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Buffer too small for FID %08lX:%08lx:%08lX:%08lX\n", + pExtents->FileId.Cell, + pExtents->FileId.Volume, + pExtents->FileId.Vnode, + pExtents->FileId.Unique); + + try_return( ntStatus = STATUS_INVALID_PARAMETER ); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n", + &pDevExt->Specific.RDR.VolumeTreeLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE); + + // + // Locate the volume node + // + + ullIndex = AFSCreateHighIndex( &pExtents->FileId); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( pVolumeCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Acquiring VolumeRoot FileIDTree.TreeLock lock %08lX SHARED %08lX\n", + pVolumeCB->ObjectInfoTree.TreeLock, + PsGetCurrentThread()); + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + } + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + if( !NT_SUCCESS( ntStatus) || + pVolumeCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Invalid volume index %I64X status %08X\n", + ullIndex, ntStatus); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + // + // Now locate the Object in this volume + // + + ullIndex = AFSCreateLowIndex( &pExtents->FileId); + + ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfo); + + if( pObjectInfo != NULL) + { + + // + // Reference the node so it won't be torn down + // + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Increment count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( !NT_SUCCESS( ntStatus) || + pObjectInfo == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Invalid file index %I64X\n", + ullIndex); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + pFcb = pObjectInfo->Fcb; + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Fcb not initialied (NO EXTENTS) for FID %08lX:%08lx:%08lX:%08lX\n", + pExtents->FileId.Cell, + pExtents->FileId.Volume, + pExtents->FileId.Vnode, + pExtents->FileId.Unique); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + AFSLockForExtentsTrim( pFcb ); + + bLocked = TRUE; + } + else + { + + // + // Locate an Fcb to trim down + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Searching for a Fcb to Trim Down\n"); + + pFcb = AFSFindFcbToClean( 0, NULL, FALSE); + + if( pFcb == NULL) + { + + pFcb = AFSFindFcbToClean( 0, NULL, TRUE); + } + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Failed to locate Fcb for release ...\n"); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + pObjectInfo = pFcb->ObjectInformation; + + bLocked = TRUE; + } + + // + // Allocate a scratch buffer to move in the extent information + // + + ulSz = (pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB); + ulSz += sizeof(AFSReleaseFileExtentsResultCB); + + if (ulSz > pIrpSp->Parameters.DeviceIoControl.OutputBufferLength) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents OUTPUT Buffer too small [2]\n"); + + try_return( ntStatus = STATUS_BUFFER_TOO_SMALL ); + } + + pResult = (AFSReleaseFileExtentsResultCB*) AFSExAllocatePoolWithTag( PagedPool, + ulSz, + AFS_EXTENTS_RESULT_TAG); + if (NULL == pResult) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Failed to allocate result block\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + // + // Set up the header (for an array of one) + // + pResult->FileCount = 1; + pResult->Flags = AFS_EXTENT_FLAG_RELEASE; + ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultCB, Files); + + // + // Setup the first (and only) file + // + pFile = pResult->Files; + pFile->FileId = pObjectInfo->FileId; + pFile->Flags = AFS_EXTENT_FLAG_RELEASE; + + // + // Stash away the auth group + // + + RtlCopyMemory( &pFile->AuthGroup, + &pFcb->AuthGroup, + sizeof( GUID)); + + // + // Update the metadata for this call + // + + pFile->AllocationSize = pFcb->ObjectInformation->EndOfFile; + pFile->CreateTime = pFcb->ObjectInformation->CreationTime; + pFile->ChangeTime = pFcb->ObjectInformation->ChangeTime; + pFile->LastAccessTime = pFcb->ObjectInformation->LastAccessTime; + pFile->LastWriteTime = pFcb->ObjectInformation->LastWriteTime; + + ulSz -= FIELD_OFFSET(AFSReleaseFileExtentsResultFileCB, FileExtents); + + ntStatus = AFSReleaseSpecifiedExtents( pExtents, + pFcb, + pFile->FileExtents, + ulSz, + &pFile->ExtentCount, + &bDirtyExtents); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessReleaseFileExtents Failed to release extents Status %08lX\n", + ntStatus); + + try_return( ntStatus ); + } + + if( pExtents->ExtentCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSProcessReleaseFileExtents Failed to release ANY extents\n"); + } + + ulSz = sizeof(AFSReleaseFileExtentsResultCB); + + if( pExtents->ExtentCount > 0) + { + ulSz += ((pExtents->ExtentCount-1) * sizeof(AFSFileExtentCB)); + } + + RtlCopyMemory( Irp->AssociatedIrp.SystemBuffer, + pResult, + ulSz); + +try_exit: + + if( bLocked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Releasing Fcb extent lock %08lX thread %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + } + + if( NULL != pResult && + Irp->AssociatedIrp.SystemBuffer != pResult) + { + + AFSExFreePool(pResult); + } + + if (NT_SUCCESS(ntStatus)) + { + Irp->IoStatus.Information = ulSz; + } + else + { + Irp->IoStatus.Information = 0; + } + + Irp->IoStatus.Status = ntStatus; + + if( pObjectInfo != NULL) + { + + InterlockedDecrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessReleaseFileExtents Decrement count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + } + + return ntStatus; +} + +NTSTATUS +AFSWaitForExtentMapping( AFSFcb *Fcb ) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + LARGE_INTEGER liTimeOut; + + __Enter + { + + ASSERT( !ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource )); + + if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus)) + { + + // + // If this isn't the same process which caused the failure then try to request them again + // + + if( Fcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)PsGetCurrentProcessId()) + { + try_return( ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus); + } + + Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + liTimeOut.QuadPart = -(50000000); + + ntStatus = KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.ExtentsRequestComplete, + Executive, + KernelMode, + FALSE, + &liTimeOut); + + if (!NT_SUCCESS( Fcb->NPFcb->Specific.File.ExtentsRequestStatus)) + { + + // + // If this isn't the same process which caused the failure then try to request them again + // + + if( Fcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)PsGetCurrentProcessId()) + { + try_return( ntStatus = Fcb->NPFcb->Specific.File.ExtentsRequestStatus); + } + + Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + if( ntStatus == STATUS_TIMEOUT) + { + + ntStatus = STATUS_SUCCESS; + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSFlushExtents( IN AFSFcb *Fcb) +{ + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + AFSExtent *pExtent, *pNextExtent; + LIST_ENTRY *le; + AFSReleaseExtentsCB *pRelease = NULL; + ULONG count = 0; + ULONG initialDirtyCount = 0; + BOOLEAN bExtentsLocked = FALSE; + ULONG total = 0; + ULONG sz = 0; + NTSTATUS ntStatus = STATUS_SUCCESS; + LARGE_INTEGER liLastFlush; + AFSExtent *pDirtyListHead = NULL, *pDirtyListTail = NULL; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB); + + // + // Save, then reset the flush time + // + + liLastFlush = Fcb->Specific.File.LastServerFlush; + + KeQueryTickCount( &Fcb->Specific.File.LastServerFlush); + + __Enter + { + + // + // Lock extents while we count and set up the array to send to + // the service + // + + AFSLockForExtentsTrim( Fcb); + + bExtentsLocked = TRUE; + + InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount); + + // + // Clear our queued flush event + // + + KeClearEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent); + + // + // Look for a start in the list to flush entries + // + + total = count; + + sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )); + + pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool, + sz, + AFS_EXTENT_RELEASE_TAG); + if( NULL == pRelease) + { + + try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + initialDirtyCount = Fcb->Specific.File.ExtentsDirtyCount; + + while( Fcb->Specific.File.ExtentsDirtyCount > 0) + { + + pRelease->Flags = AFS_EXTENT_FLAG_DIRTY; + + if( BooleanFlagOn( Fcb->Flags, AFS_FCB_FILE_CLOSED)) + { + + pRelease->Flags |= AFS_EXTENT_FLAG_FLUSH; + } + + // + // Update the metadata for this call + // + + pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile; + pRelease->CreateTime = Fcb->ObjectInformation->CreationTime; + pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime; + pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime; + pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime; + + count = 0; + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + pExtent = (AFSExtent *)pNPFcb->Specific.File.DirtyListHead; + + while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT) + { + + if ( pExtent == NULL) + { + + break; + } + + pNextExtent = (AFSExtent *)pExtent->DirtyList.fLink; + + if ( pExtent->ActiveCount > 0) + { + pExtent = pNextExtent; + continue; + } + + AFSRemoveEntryDirtyList( Fcb, pExtent); + + pExtent->DirtyList.fLink = NULL; + pExtent->DirtyList.bLink = NULL; + + InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount); + + // + // Clear the flag in advance of the write. If we do + // things this was we know that the clear is + // pessimistic (any write which happens from now on + // will set the flag dirty again). + // + + pExtent->Flags &= ~AFS_EXTENT_DIRTY; + + pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_DIRTY; + + pRelease->FileExtents[count].Length = pExtent->Size; + pRelease->FileExtents[count].DirtyLength = pExtent->Size; + pRelease->FileExtents[count].DirtyOffset = 0; + pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset; + pRelease->FileExtents[count].FileOffset = pExtent->FileOffset; + +#if GEN_MD5 + RtlCopyMemory( pRelease->FileExtents[count].MD5, + pExtent->MD5, + sizeof(pExtent->MD5)); + + pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET; +#endif + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFlushExtents Releasing DIRTY extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n", + pExtent, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + pExtent->FileOffset.QuadPart, + pExtent->Size); + + pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_RELEASE; + + // + // Need to pull this extent from the main list as well + // + + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++) + { + if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i])) + { + RemoveEntryList( &pExtent->Lists[i] ); + } + } + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024))); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024))); + + AFSExFreePool( pExtent); + + InterlockedDecrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0) + { + + KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent, + 0, + FALSE); + } + + count ++; + + pExtent = pNextExtent; + } + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + + // + // If we are done then get out + // + + if( count == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFlushExtents No more dirty extents found\n"); + + break; + } + + // + // Fire off the request synchronously + // + + sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB )); + + pRelease->ExtentCount = count; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFlushExtents Releasing(1) Fcb extents lock %08lX SHARED %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource); + bExtentsLocked = FALSE; + + KeSetEvent( &pNPFcb->Specific.File.FlushEvent, + 0, + FALSE); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &Fcb->AuthGroup, + NULL, + &Fcb->ObjectInformation->FileId, + pRelease, + sz, + NULL, + NULL); + + if( !NT_SUCCESS(ntStatus)) + { + + // + // Regardless of whether or not the AFSProcessRequest() succeeded, the extents + // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSFlushExtents AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + ntStatus); + + } + AFSLockForExtentsTrim( Fcb); + + bExtentsLocked = TRUE; + } + +try_exit: + + if( InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount) == 0) + { + + KeSetEvent( &pNPFcb->Specific.File.QueuedFlushEvent, + 0, + FALSE); + } + + KeSetEvent( &pNPFcb->Specific.File.FlushEvent, + 0, + FALSE); + + if (bExtentsLocked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFlushExtents Releasing(2) Fcb extents lock %08lX SHARED %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + } + + if (pRelease) + { + AFSExFreePool( pRelease); + } + } + + return ntStatus; +} + +NTSTATUS +AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb) +{ + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + AFSExtent *pExtent; + LIST_ENTRY *le; + AFSReleaseExtentsCB *pRelease = NULL; + ULONG count = 0; + ULONG initialDirtyCount = 0; + BOOLEAN bExtentsLocked = FALSE; + ULONG total = 0; + ULONG sz = 0; + NTSTATUS ntStatus = STATUS_SUCCESS; + LARGE_INTEGER liLastFlush; + ULONG ulRemainingExtentLength = 0; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + ASSERT( Fcb->Header.NodeTypeCode == AFS_FILE_FCB); + + // + // Save, then reset the flush time + // + + liLastFlush = Fcb->Specific.File.LastServerFlush; + + KeQueryTickCount( &Fcb->Specific.File.LastServerFlush); + + __Enter + { + + // + // Look for a start in the list to flush entries + // + + total = count; + + sz = sizeof( AFSReleaseExtentsCB ) + (AFS_MAXIMUM_EXTENT_RELEASE_COUNT * sizeof ( AFSFileExtentCB )); + + pRelease = (AFSReleaseExtentsCB*) AFSExAllocatePoolWithTag( NonPagedPool, + sz, + AFS_EXTENT_RELEASE_TAG); + if( NULL == pRelease) + { + + try_return ( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + if( Fcb->OpenHandleCount > 0) + { + + // + // Don't release everything ... + // + + // + // For now release everything + // + + //ulRemainingExtentLength = 1500; + } + + while( Fcb->Specific.File.ExtentLength > (LONG)ulRemainingExtentLength) + { + + AFSLockForExtentsTrim( Fcb); + + bExtentsLocked = TRUE; + + pRelease->Flags = AFS_EXTENT_FLAG_RELEASE; + + // + // Update the metadata for this call + // + + pRelease->AllocationSize = Fcb->ObjectInformation->EndOfFile; + pRelease->CreateTime = Fcb->ObjectInformation->CreationTime; + pRelease->ChangeTime = Fcb->ObjectInformation->ChangeTime; + pRelease->LastAccessTime = Fcb->ObjectInformation->LastAccessTime; + pRelease->LastWriteTime = Fcb->ObjectInformation->LastWriteTime; + + count = 0; + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + + while( count < AFS_MAXIMUM_EXTENT_RELEASE_COUNT && + le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST]) + { + + pExtent = ExtentFor( le, AFS_EXTENTS_LIST); + + le = le->Flink; + + if( pExtent->ActiveCount > 0) + { + + continue; + } + + pRelease->FileExtents[count].Flags = AFS_EXTENT_FLAG_RELEASE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseExtentsWithFlush Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n", + pExtent, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + pExtent->FileOffset.QuadPart, + pExtent->Size); + + pRelease->FileExtents[count].Length = pExtent->Size; + pRelease->FileExtents[count].DirtyLength = pExtent->Size; + pRelease->FileExtents[count].DirtyOffset = 0; + pRelease->FileExtents[count].CacheOffset = pExtent->CacheOffset; + pRelease->FileExtents[count].FileOffset = pExtent->FileOffset; + +#if GEN_MD5 + RtlCopyMemory( pRelease->FileExtents[count].MD5, + pExtent->MD5, + sizeof(pExtent->MD5)); + + pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_MD5_SET; +#endif + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSRemoveEntryDirtyList( Fcb, + pExtent); + + pRelease->FileExtents[count].Flags |= AFS_EXTENT_FLAG_DIRTY; + + InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount); + } + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + } + + // + // Need to pull this extent from the main list as well + // + + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++) + { + if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i])) + { + RemoveEntryList( &pExtent->Lists[i] ); + } + } + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024))); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024))); + + AFSExFreePool( pExtent); + + InterlockedDecrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0) + { + + KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent, + 0, + FALSE); + } + + count ++; + } + + // + // If we are done then get out + // + + if( count == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseExtentsWithFlush No more dirty extents found\n"); + + break; + } + + // + // Fire off the request synchronously + // + + sz = sizeof( AFSReleaseExtentsCB ) + (count * sizeof ( AFSFileExtentCB )); + + pRelease->ExtentCount = count; + + // + // Drop the extents lock for the duration of the call to + // the network. We have pinned the extents so, even + // though we might get extents added during this period, + // but none will be removed. Hence we can carry on from + // le. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %08lX thread %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource); + bExtentsLocked = FALSE; + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &Fcb->AuthGroup, + NULL, + &Fcb->ObjectInformation->FileId, + pRelease, + sz, + NULL, + NULL); + + if( !NT_SUCCESS(ntStatus)) + { + + // + // Regardless of whether or not the AFSProcessRequest() succeeded, the extents + // were released (if AFS_EXTENT_FLAG_RELEASE was set). Log the error so it is known. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSReleaseExtentsWithFlush AFS_REQUEST_TYPE_RELEASE_FILE_EXTENTS failed fid %08lX-%08lX-%08lX-%08lX Status %08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + ntStatus); + } + } + +try_exit: + + if (bExtentsLocked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseExtentsWithFlush Releasing Fcb extents lock %08lX thread %08lX\n", + &pNPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pNPFcb->Specific.File.ExtentsResource ); + } + + if (pRelease) + { + AFSExFreePool( pRelease); + } + } + + return ntStatus; +} + +VOID +AFSMarkDirty( IN AFSFcb *Fcb, + IN AFSExtent *StartExtent, + IN ULONG ExtentsCount, + IN LARGE_INTEGER *StartingByte) +{ + + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + AFSExtent *pExtent = StartExtent; + AFSExtent *pNextExtent, *pCurrentExtent = NULL; + ULONG ulCount = 0; + BOOLEAN bInsertTail = FALSE, bInsertHead = FALSE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSMarkDirty Acquiring Fcb extents lock %08lX SHARED %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE); + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + // + // Find the insertion point + // + + if( pNPFcb->Specific.File.DirtyListHead == NULL) + { + + bInsertTail = TRUE; + } + else if( StartingByte->QuadPart == 0) + { + + bInsertHead = TRUE; + } + else + { + + pCurrentExtent = pNPFcb->Specific.File.DirtyListHead; + + while( pCurrentExtent != NULL) + { + + if( pCurrentExtent->FileOffset.QuadPart + pCurrentExtent->Size >= StartingByte->QuadPart || + pCurrentExtent->DirtyList.fLink == NULL) + { + + break; + } + + pCurrentExtent = (AFSExtent *)pCurrentExtent->DirtyList.fLink; + } + } + + while( ulCount < ExtentsCount) + { + + pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST); + + if( !BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSMarkDirty Marking extent offset %I64X Length %08lX DIRTY\n", + pExtent->FileOffset.QuadPart, + pExtent->Size); + + pExtent->DirtyList.fLink = NULL; + pExtent->DirtyList.bLink = NULL; + + if( bInsertHead) + { + + pExtent->DirtyList.fLink = (void *)pNPFcb->Specific.File.DirtyListHead; + + pExtent->DirtyList.bLink = NULL; + + pNPFcb->Specific.File.DirtyListHead->DirtyList.bLink = (void *)pExtent; + + pNPFcb->Specific.File.DirtyListHead = pExtent; + + pCurrentExtent = pExtent; + + bInsertHead = FALSE; + } + else if( bInsertTail) + { + + if( pNPFcb->Specific.File.DirtyListHead == NULL) + { + + pNPFcb->Specific.File.DirtyListHead = pExtent; + } + else + { + + pNPFcb->Specific.File.DirtyListTail->DirtyList.fLink = (void *)pExtent; + + pExtent->DirtyList.bLink = (void *)pNPFcb->Specific.File.DirtyListTail; + } + + pNPFcb->Specific.File.DirtyListTail = pExtent; + } + else + { + + pExtent->DirtyList.fLink = pCurrentExtent->DirtyList.fLink; + pExtent->DirtyList.bLink = (void *)pCurrentExtent; + + if( pExtent->DirtyList.fLink == NULL) + { + + pNPFcb->Specific.File.DirtyListTail = pExtent; + } + else + { + + ((AFSExtent *)pExtent->DirtyList.fLink)->DirtyList.bLink = (void *)pExtent; + } + + pCurrentExtent->DirtyList.fLink = (void *)pExtent; + + pCurrentExtent = pExtent; + } + + pExtent->Flags |= AFS_EXTENT_DIRTY; + + // + // Up the dirty count + // + + InterlockedIncrement( &Fcb->Specific.File.ExtentsDirtyCount); + } + else + { + + pCurrentExtent = pExtent; + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSMarkDirty Decrement count on extent %08lX Cnt %d\n", + pExtent, + pExtent->ActiveCount); + + ASSERT( pExtent->ActiveCount > 0); + + InterlockedDecrement( &pExtent->ActiveCount); + + pExtent = pNextExtent; + + ulCount++; + } + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSMarkDirty Releasing Fcb extents lock %08lX SHARED %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource ); + + return; +} + +// +// Helper functions +// + +static AFSExtent *ExtentFor(PLIST_ENTRY le, ULONG SkipList) +{ + return CONTAINING_RECORD( le, AFSExtent, Lists[SkipList] ); +} + +static AFSExtent *NextExtent(AFSExtent *Extent, ULONG SkipList) +{ + return ExtentFor(Extent->Lists[SkipList].Flink, SkipList); +} + +static AFSExtent *DirtyExtentFor(PLIST_ENTRY le) +{ + return CONTAINING_RECORD( le, AFSExtent, DirtyList ); +} + +static VOID VerifyExtentsLists(AFSFcb *Fcb) +{ +#if DBG > 0 + // + // Check the ordering of the extents lists + // + ASSERT( ExIsResourceAcquiredLite( &Fcb->NPFcb->Specific.File.ExtentsResource )); + + ASSERT(Fcb->Specific.File.ExtentsLists[0].Flink != &Fcb->Specific.File.ExtentsLists[1]); + + for (ULONG listNo = 0; listNo < AFS_NUM_EXTENT_LISTS; listNo ++) + { + LARGE_INTEGER lastOffset; + + lastOffset.QuadPart = 0; + + for (PLIST_ENTRY pLe = Fcb->Specific.File.ExtentsLists[listNo].Flink; + pLe != &Fcb->Specific.File.ExtentsLists[listNo]; + pLe = pLe->Flink) + { + AFSExtent *pExtent; + + pExtent = ExtentFor(pLe, listNo); + + if (listNo == 0) { + ASSERT(pLe != &Fcb->Specific.File.ExtentsLists[1] && + pLe->Flink !=&Fcb->Specific.File.ExtentsLists[1] && + pLe->Blink !=&Fcb->Specific.File.ExtentsLists[1]); + } + + ASSERT(pLe->Flink->Blink == pLe); + ASSERT(pLe->Blink->Flink == pLe); + + // + // Should follow on from previous + // + ASSERT(pExtent->FileOffset.QuadPart >= lastOffset.QuadPart); + lastOffset.QuadPart = pExtent->FileOffset.QuadPart + pExtent->Size; + + // + // Should match alignment criteria + // + ASSERT( 0 == (pExtent->FileOffset.LowPart & ExtentsMasks[listNo]) ); + + // + // "lower" lists should be populated + // + for (LONG subListNo = listNo-1; subListNo > 0; subListNo --) + { + ASSERT( !IsListEmpty(&pExtent->Lists[subListNo])); + } + } + } +#endif +} + +void +AFSTrimExtents( IN AFSFcb *Fcb, + IN PLARGE_INTEGER FileSize) +{ + + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + LIST_ENTRY *le; + AFSExtent *pExtent; + BOOLEAN locked = FALSE; + NTSTATUS ntStatus = STATUS_SUCCESS; + LARGE_INTEGER liAlignedOffset = {0,0}; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + __Enter + { + + // + // Get an aligned offset + // + + if( FileSize != NULL) + { + + liAlignedOffset = *FileSize; + } + + if( liAlignedOffset.QuadPart > 0 && + liAlignedOffset.QuadPart % pDevExt->Specific.RDR.CacheBlockSize != 0) + { + + // + // Align UP to the next cache block size + // + + liAlignedOffset.QuadPart = (ULONGLONG)( (ULONGLONG)((liAlignedOffset.QuadPart / pDevExt->Specific.RDR.CacheBlockSize) + 1) * (ULONGLONG)pDevExt->Specific.RDR.CacheBlockSize); + } + + // + // Ensure that no one is working with the extents and grab the + // lock + // + + AFSLockForExtentsTrim( Fcb); + + locked = TRUE; + + if( 0 == Fcb->Specific.File.ExtentCount) + { + + // + // Update the request extent status + // + + Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + + try_return( ntStatus = STATUS_SUCCESS); + } + + // + // We are truncating from a specific length in the file. If the offset + // is non-zero then go find the first extent to remove + // + + if( 0 == FileSize->QuadPart) + { + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + } + else + { + + pExtent = AFSExtentForOffset( Fcb, + FileSize, + TRUE); + + if( NULL == pExtent) + { + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + } + else + { + le = &pExtent->Lists[AFS_EXTENTS_LIST]; + } + } + + while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST]) + { + + pExtent = ExtentFor( le, AFS_EXTENTS_LIST); + + // + // Only trim down extents beyond the aligned offset + // + + le = le->Flink; + + if( pExtent->FileOffset.QuadPart >= liAlignedOffset.QuadPart) + { + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + LONG dirtyCount; + + AFSRemoveEntryDirtyList( Fcb, + pExtent); + + dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount); + + ASSERT(dirtyCount >= 0); + } + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + } + + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++) + { + if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i])) + { + RemoveEntryList( &pExtent->Lists[i] ); + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSTrimExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n", + pExtent, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + pExtent->FileOffset.QuadPart, + pExtent->Size); + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024))); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024))); + + ASSERT( pExtent->ActiveCount == 0); + + // + // and free + // + AFSExFreePool( pExtent); + + InterlockedDecrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0) + { + + KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent, + 0, + FALSE); + } + } + } + + // + // Update the request extent status + // + + Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + +try_exit: + + if (locked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSTrimExtents Releasing Fcb extents lock %08lX thread %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource ); + } + } + + return; +} + +void +AFSTrimSpecifiedExtents( IN AFSFcb *Fcb, + IN ULONG Count, + IN AFSFileExtentCB *Result) +{ + + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + LIST_ENTRY *le; + AFSExtent *pExtent; + AFSFileExtentCB *pFileExtents = Result; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + __Enter + { + + le = Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST].Flink; + + while( le != &Fcb->Specific.File.ExtentsLists[AFS_EXTENTS_LIST] && + Count > 0) + { + + pExtent = ExtentFor( le, AFS_EXTENTS_LIST); + + // + // Only trim down extents beyond the aligned offset + // + + le = le->Flink; + + if( pExtent->FileOffset.QuadPart == pFileExtents->FileOffset.QuadPart) + { + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + AFSAcquireExcl( &pNPFcb->Specific.File.DirtyExtentsListLock, + TRUE); + + if( BooleanFlagOn( pExtent->Flags, AFS_EXTENT_DIRTY)) + { + + LONG dirtyCount; + + AFSRemoveEntryDirtyList( Fcb, + pExtent); + + dirtyCount = InterlockedDecrement( &Fcb->Specific.File.ExtentsDirtyCount); + + ASSERT( dirtyCount >= 0); + + } + + AFSReleaseResource( &pNPFcb->Specific.File.DirtyExtentsListLock); + + } + + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i ++) + { + if (NULL != pExtent->Lists[i].Flink && !IsListEmpty(&pExtent->Lists[i])) + { + RemoveEntryList( &pExtent->Lists[i] ); + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSTrimSpecifiedExtents Releasing extent %p fid %08lX-%08lX-%08lX-%08lX Offset %I64X Len %08lX\n", + pExtent, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + pExtent->FileOffset.QuadPart, + pExtent->Size); + + InterlockedExchangeAdd( &pControlDevExt->Specific.Control.ExtentsHeldLength, -((LONG)(pExtent->Size/1024))); + + InterlockedExchangeAdd( &Fcb->Specific.File.ExtentLength, -((LONG)(pExtent->Size/1024))); + + ASSERT( pExtent->ActiveCount == 0); + + // + // and free + // + AFSExFreePool( pExtent); + + InterlockedDecrement( &Fcb->Specific.File.ExtentCount); + + if( InterlockedDecrement( &pControlDevExt->Specific.Control.ExtentCount) == 0) + { + + KeSetEvent( &pControlDevExt->Specific.Control.ExtentsHeldEvent, + 0, + FALSE); + } + + // + // Next extent we are looking for + // + + pFileExtents++; + + Count--; + } + } + + // + // Update the request extent status + // + + Fcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + return; +} + +void +AFSReferenceActiveExtents( IN AFSExtent *StartExtent, + IN ULONG ExtentsCount) +{ + + AFSExtent *pExtent = StartExtent; + AFSExtent *pNextExtent; + ULONG ulCount = 0; + + while( ulCount < ExtentsCount) + { + + pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST); + + InterlockedIncrement( &pExtent->ActiveCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReferenceActiveExtents Increment count on extent %08lX Cnt %d\n", + pExtent, + pExtent->ActiveCount); + + pExtent = pNextExtent; + + ulCount++; + } + + return; +} + +void +AFSDereferenceActiveExtents( IN AFSExtent *StartExtent, + IN ULONG ExtentsCount) +{ + + AFSExtent *pExtent = StartExtent; + AFSExtent *pNextExtent; + ULONG ulCount = 0; + + while( ulCount < ExtentsCount) + { + + pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST); + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_ACTIVE_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSDereferenceActiveExtents Decrement count on extent %08lX Cnt %d\n", + pExtent, + pExtent->ActiveCount); + + ASSERT( pExtent->ActiveCount > 0); + + InterlockedDecrement( &pExtent->ActiveCount); + + pExtent = pNextExtent; + + ulCount++; + } + + return; +} + +void +AFSRemoveEntryDirtyList( IN AFSFcb *Fcb, + IN AFSExtent *Extent) +{ + + if( Extent->DirtyList.fLink == NULL) + { + + Fcb->NPFcb->Specific.File.DirtyListTail = (AFSExtent *)Extent->DirtyList.bLink; + + if( Fcb->NPFcb->Specific.File.DirtyListTail != NULL) + { + + Fcb->NPFcb->Specific.File.DirtyListTail->DirtyList.fLink = NULL; + } + } + else + { + + ((AFSExtent *)Extent->DirtyList.fLink)->DirtyList.bLink = Extent->DirtyList.bLink; + } + + if( Extent->DirtyList.bLink == NULL) + { + + Fcb->NPFcb->Specific.File.DirtyListHead = (AFSExtent *)Extent->DirtyList.fLink; + + if( Fcb->NPFcb->Specific.File.DirtyListHead != NULL) + { + + Fcb->NPFcb->Specific.File.DirtyListHead->DirtyList.bLink = NULL; + } + } + else + { + + ((AFSExtent *)Extent->DirtyList.bLink)->DirtyList.fLink = Extent->DirtyList.fLink; + } + + + return; +} + +#if GEN_MD5 +void +AFSSetupMD5Hash( IN AFSFcb *Fcb, + IN AFSExtent *StartExtent, + IN ULONG ExtentsCount, + IN void *SystemBuffer, + IN LARGE_INTEGER *ByteOffset, + IN ULONG ByteCount) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSNonPagedFcb *pNPFcb = Fcb->NPFcb; + AFSExtent *pExtent = StartExtent; + AFSExtent *pNextExtent, *pCurrentExtent = NULL; + ULONG ulCount = 0; + char *pCurrentBuffer = (char *)SystemBuffer; + char *pMD5Buffer = NULL; + ULONG ulCurrentLen = 0; + void *pExtentBuffer = NULL; + LARGE_INTEGER liByteOffset; + ULONG ulBytesRead = 0; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetupMD5Hash Acquiring Fcb extents lock %08lX SHARED %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &Fcb->NPFcb->Specific.File.ExtentsResource, TRUE); + + liByteOffset.QuadPart = ByteOffset->QuadPart; + + while( ulCount < ExtentsCount) + { + + RtlZeroMemory( pExtent->MD5, + sizeof( pExtent->MD5)); + + pNextExtent = NextExtent( pExtent, AFS_EXTENTS_LIST); + + if( liByteOffset.QuadPart == pExtent->FileOffset.QuadPart && + ByteCount < pExtent->Size) + { + + if( pExtentBuffer == NULL) + { + + pExtentBuffer = AFSExAllocatePoolWithTag( PagedPool, + pExtent->Size, + AFS_GENERIC_MEMORY_9_TAG); + + if( pExtentBuffer == NULL) + { + + break; + } + } + + RtlZeroMemory( pExtentBuffer, + pExtent->Size); + + RtlCopyMemory( pExtentBuffer, + pCurrentBuffer, + ByteCount); + + pMD5Buffer = (char *)pExtentBuffer; + + ulCurrentLen = ByteCount; + } + else if( liByteOffset.QuadPart != pExtent->FileOffset.QuadPart) + { + + pExtentBuffer = AFSExAllocatePoolWithTag( PagedPool, + pExtent->Size, + AFS_GENERIC_MEMORY_10_TAG); + + if( pExtentBuffer == NULL) + { + + break; + } + + RtlZeroMemory( pExtentBuffer, + pExtent->Size); + + if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE)) + { + +#ifdef AMD64 + RtlCopyMemory( pExtentBuffer, + ((char *)AFSLibCacheBaseAddress + pExtent->CacheOffset.QuadPart), + pExtent->Size); +#else + ASSERT( pExtent->CacheOffset.HighPart == 0); + RtlCopyMemory( pExtentBuffer, + ((char *)AFSLibCacheBaseAddress + pExtent->CacheOffset.LowPart), + pExtent->Size); +#endif + + ulBytesRead = pExtent->Size; + } + else + { + + ntStatus = AFSReadCacheFile( pExtentBuffer, + &pExtent->CacheOffset, + pExtent->Size, + &ulBytesRead); + + if( !NT_SUCCESS( ntStatus)) + { + break; + } + } + + pMD5Buffer = (char *)pExtentBuffer; + + ulCurrentLen = min( ByteCount, pExtent->Size - (ULONG)(liByteOffset.QuadPart - pExtent->FileOffset.QuadPart)); + + RtlCopyMemory( (void *)((char *)pExtentBuffer + (ULONG)(liByteOffset.QuadPart - pExtent->FileOffset.QuadPart)), + pCurrentBuffer, + ulCurrentLen); + } + else + { + + ulCurrentLen = pExtent->Size; + + pMD5Buffer = pCurrentBuffer; + } + + AFSGenerateMD5( pMD5Buffer, + pExtent->Size, + pExtent->MD5); + + pExtent = pNextExtent; + + ulCount++; + + ByteCount -= ulCurrentLen; + + pCurrentBuffer += ulCurrentLen; + + liByteOffset.QuadPart += ulCurrentLen; + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetupMD5Hash Releasing Fcb extents lock %08lX SHARED %08lX\n", + &Fcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &Fcb->NPFcb->Specific.File.ExtentsResource ); + + if( pExtentBuffer != NULL) + { + + AFSExFreePool( pExtentBuffer); + } + } + + return; +} +#endif + diff --git a/src/WINNT/afsrdr/kernel/lib/AFSFSControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSFSControl.cpp new file mode 100644 index 0000000000..e9e2bd6c2d --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSFSControl.cpp @@ -0,0 +1,739 @@ +/* + * 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: AFSFSControl.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSFSControl( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + switch( pIrpSp->MinorFunction) + { + + case IRP_MN_USER_FS_REQUEST: + + ntStatus = AFSProcessUserFsRequest( Irp); + + break; + + case IRP_MN_MOUNT_VOLUME: + + break; + + case IRP_MN_VERIFY_VOLUME: + + break; + + default: + + break; + } + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSFSControl\n"); + } + + return ntStatus; +} + +static BOOLEAN +AFSParseMountPointTarget( IN UNICODE_STRING *Target, + OUT USHORT *Type, + OUT UNICODE_STRING *Volume, + OUT UNICODE_STRING *Cell) +{ + // Targets are of the form [:] + + *Type = Target->Buffer[ 0]; + + // Extract the cell name (if any) + + Cell->Buffer = &Target->Buffer[ 1]; + + // Search for colon separator or end of counted string + + for ( Cell->Length = 0; Cell->Length < Target->Length - sizeof( WCHAR); Cell->Length += sizeof( WCHAR)) + { + + if ( Cell->Buffer[ Cell->Length / sizeof( WCHAR)] == L':') + { + break; + } + } + + // If a colon is not found, it means there is no cell + + if ( Cell->Buffer[ Cell->Length / sizeof( WCHAR)] == L':') + { + + Cell->MaximumLength = Cell->Length; + + if ( Cell->Length > Target->Length - 2 * sizeof( WCHAR)) + { + // Invalid target string if there is no room for + // the volume name. + + return FALSE; + } + + Volume->Length = Volume->MaximumLength = (Target->Length - Cell->Length - 2 * sizeof( WCHAR)); + + Volume->Buffer = &Target->Buffer[ Cell->Length / sizeof( WCHAR) + 2]; + } + else + { + // There is no cell + + Volume->Length = Volume->MaximumLength = Cell->Length; + + Volume->Buffer = Cell->Buffer; + + Cell->Length = Cell->MaximumLength = 0; + + Cell->Buffer = NULL; + } + + return TRUE; +} + +NTSTATUS +AFSProcessUserFsRequest( IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulFsControlCode; + AFSFcb *pFcb = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp ); + AFSCcb *pCcb = NULL; + ULONG ulOutputBufferLen, ulInputBufferLen; + + __Enter + { + + ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + if( pFcb == NULL || + pCcb->DirectoryCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Invalid Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + ntStatus = AFSProcessShareFsCtrl( Irp, + pFcb, + pCcb); + + try_return( ntStatus); + } + + ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength; + ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength; + + // + // Process the request + // + + switch( ulFsControlCode ) + { + + case FSCTL_REQUEST_OPLOCK_LEVEL_1: + case FSCTL_REQUEST_OPLOCK_LEVEL_2: + case FSCTL_REQUEST_BATCH_OPLOCK: + case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: + case FSCTL_OPBATCH_ACK_CLOSE_PENDING: + case FSCTL_OPLOCK_BREAK_NOTIFY: + case FSCTL_OPLOCK_BREAK_ACK_NO_2: + case FSCTL_REQUEST_FILTER_OPLOCK : + + // + // Note that implementing this call will probably need us + // to call the server as well as adding code in read and + // write and caching. Also that it is unlikely that + // anyone will ever call us at this point - RDR doesn't + // allow it + // + + ntStatus = STATUS_NOT_IMPLEMENTED; + + break; + + case FSCTL_LOCK_VOLUME: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n"); + + break; + + case FSCTL_UNLOCK_VOLUME: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n"); + + break; + + case FSCTL_DISMOUNT_VOLUME: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n"); + + break; + + case FSCTL_MARK_VOLUME_DIRTY: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n"); + + break; + + case FSCTL_IS_VOLUME_DIRTY: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n"); + + break; + + case FSCTL_IS_VOLUME_MOUNTED: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n"); + + break; + + case FSCTL_IS_PATHNAME_VALID: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n"); + + break; + + case FSCTL_GET_REPARSE_POINT: + { + + REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; + ULONG ulRemainingLen = ulOutputBufferLen; + AFSReparseTagInfo *pReparseInfo = NULL; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request\n"); + + if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + + Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer); + + break; + } + + ulRemainingLen -= FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer); + + // + // Check if we have the reparse entry set on the entry + // + + if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + { + + ntStatus = STATUS_NOT_A_REPARSE_POINT; + + break; + } + + // + // Populate the data in the reparse buffer + // + + pReparseBuffer->ReparseDataLength = 0; + + AFSAcquireExcl( &pCcb->DirectoryCB->NonPaged->Lock, + TRUE); + + if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) + { + + // + // We'll reset the DV to ensure we validate the metadata content + // + + pCcb->DirectoryCB->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1; + + SetFlag( pCcb->DirectoryCB->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB->ObjectInformation->FileId.Cell, + pCcb->DirectoryCB->ObjectInformation->FileId.Volume, + pCcb->DirectoryCB->ObjectInformation->FileId.Vnode, + pCcb->DirectoryCB->ObjectInformation->FileId.Unique); + + ntStatus = AFSVerifyEntry( &pFcb->AuthGroup, + pCcb->DirectoryCB); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessUserFsRequest Failed to verify symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB->ObjectInformation->FileId.Cell, + pCcb->DirectoryCB->ObjectInformation->FileId.Volume, + pCcb->DirectoryCB->ObjectInformation->FileId.Vnode, + pCcb->DirectoryCB->ObjectInformation->FileId.Unique, + ntStatus); + + AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock); + + break; + } + } + + pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0]; + + switch( pCcb->DirectoryCB->ObjectInformation->FileType) + { + + case AFS_FILE_TYPE_SYMLINK: + { + + if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) + { + + ntStatus = STATUS_ACCESS_DENIED; + + break; + } + + if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length) + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + + Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + + FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + + pCcb->DirectoryCB->NameInformation.TargetName.Length; + + break; + } + + pReparseInfo->SubTag = OPENAFS_SUBTAG_SYMLINK; + + pReparseInfo->AFSSymLink.RelativeLink = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName); + + pReparseInfo->AFSSymLink.SymLinkTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; + + RtlCopyMemory( pReparseInfo->AFSSymLink.Buffer, + pCcb->DirectoryCB->NameInformation.TargetName.Buffer, + pCcb->DirectoryCB->NameInformation.TargetName.Length); + + pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length); + + break; + } + + case AFS_FILE_TYPE_MOUNTPOINT: + { + UNICODE_STRING Cell, Volume; + USHORT Type; + + if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) + { + ntStatus = STATUS_ACCESS_DENIED; + + break; + } + + if ( !AFSParseMountPointTarget( &pCcb->DirectoryCB->NameInformation.TargetName, + &Type, + &Volume, + &Cell)) + { + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length) + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + + Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + + FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + + Volume.Length + Cell.Length; + + break; + } + + pReparseInfo->SubTag = OPENAFS_SUBTAG_MOUNTPOINT; + + pReparseInfo->AFSMountPoint.Type = Type; + + pReparseInfo->AFSMountPoint.MountPointCellLength = Cell.Length; + + pReparseInfo->AFSMountPoint.MountPointVolumeLength = Volume.Length; + + RtlCopyMemory( pReparseInfo->AFSMountPoint.Buffer, + Cell.Buffer, + Cell.Length); + + RtlCopyMemory( &pReparseInfo->AFSMountPoint.Buffer[ Cell.Length / sizeof( WCHAR)], + Volume.Buffer, + Volume.Length); + + pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, AFSMountPoint.Buffer) + Volume.Length + Cell.Length); + + break; + } + + case AFS_FILE_TYPE_DFSLINK: + { + + if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0) + { + + ntStatus = STATUS_ACCESS_DENIED; + + break; + } + + if( ulRemainingLen < (ULONG) FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length) + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + + Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + + FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + + pCcb->DirectoryCB->NameInformation.TargetName.Length; + + break; + } + + pReparseInfo->SubTag = OPENAFS_SUBTAG_UNC; + + pReparseInfo->UNCReferral.UNCTargetLength = pCcb->DirectoryCB->NameInformation.TargetName.Length; + + RtlCopyMemory( pReparseInfo->UNCReferral.Buffer, + pCcb->DirectoryCB->NameInformation.TargetName.Buffer, + pCcb->DirectoryCB->NameInformation.TargetName.Length); + + pReparseBuffer->ReparseDataLength = (FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) + pCcb->DirectoryCB->NameInformation.TargetName.Length); + + break; + } + + default: + + ntStatus = STATUS_NOT_A_REPARSE_POINT; + + break; + } + + if ( ntStatus == STATUS_SUCCESS) + { + + ulRemainingLen -= pReparseBuffer->ReparseDataLength; + + pReparseBuffer->ReparseTag = IO_REPARSE_TAG_OPENAFS_DFS; + + RtlCopyMemory( &pReparseBuffer->ReparseGuid, + &GUID_AFS_REPARSE_GUID, + sizeof( GUID)); + + Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + + pReparseBuffer->ReparseDataLength; + } + + AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock); + + break; + } + + case FSCTL_SET_REPARSE_POINT: + { + + REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request\n"); + + if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + // + // Check if we have the reparse entry set on the entry + // + + if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + { + + ntStatus = STATUS_NOT_A_REPARSE_POINT; + + break; + } + + if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS) + { + + ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH; + + break; + } + + if( RtlCompareMemory( &pReparseBuffer->ReparseGuid, + &GUID_AFS_REPARSE_GUID, + sizeof( GUID)) != sizeof( GUID)) + { + + ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT; + + break; + } + + // + // For now deny access on this call + // + + break; + } + + case FSCTL_DELETE_REPARSE_POINT: + { + + REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request\n"); + + if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer)) + { + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + + // + // Check if we have the reparse entry set on the entry + // + + if( !BooleanFlagOn( pCcb->DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + { + + ntStatus = STATUS_NOT_A_REPARSE_POINT; + + break; + } + + if( pReparseBuffer->ReparseTag != IO_REPARSE_TAG_OPENAFS_DFS) + { + + ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH; + + break; + } + + if( RtlCompareMemory( &pReparseBuffer->ReparseGuid, + &GUID_AFS_REPARSE_GUID, + sizeof( GUID)) != sizeof( GUID)) + { + + ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT; + + break; + } + + // + // For now deny access on this call + // + + ntStatus = STATUS_ACCESS_DENIED; + + break; + } + + default : + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSProcessUserFsRequest Processing default (%08lX) request\n", ulFsControlCode); + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSProcessShareFsCtrl( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + ULONG ulOutputBufferLen = 0, ulInputBufferLen; + ULONG ulFsControlCode; + + __Enter + { + + ulFsControlCode = pIrpSp->Parameters.FileSystemControl.FsControlCode; + + ulOutputBufferLen = pIrpSp->Parameters.FileSystemControl.OutputBufferLength; + ulInputBufferLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength; + + switch( ulFsControlCode) + { + + case FSCTL_PIPE_TRANSCEIVE: + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessShareFsCtrl On pipe %wZ Class FSCTL_PIPE_TRANSCEIVE\n", + &Ccb->DirectoryCB->NameInformation.FileName); + + ntStatus = AFSNotifyPipeTransceive( Ccb, + ulInputBufferLen, + ulOutputBufferLen, + pIrpSp->Parameters.FileSystemControl.Type3InputBuffer, + Irp->UserBuffer, + (ULONG *)&Irp->IoStatus.Information); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessShareFsCtrl Failure on pipe %wZ Class FSCTL_PIPE_TRANSCEIVE Status %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ntStatus); + } + + break; + } + + default: + { + + if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_SERVER_SERVICE)) + { + + //AFSPrint("AFSProcessShareFsCtrl (%08lX) For srvsvc input %08lX output %08lX\n", + // ulFsControlCode, + // ulInputBufferLen, + // ulOutputBufferLen); + } + else if( BooleanFlagOn( Ccb->DirectoryCB->Flags, AFS_DIR_ENTRY_WORKSTATION_SERVICE)) + { + + //AFSPrint("AFSProcessShareFsCtrl (%08lX) For wkssvc input %08lX output %08lX\n", + // ulFsControlCode, + // ulInputBufferLen, + // ulOutputBufferLen); + } + else + { + + //AFSPrint("AFSProcessShareFsCtrl (%08lX) For IPC$ input %08lX output %08lX\n", + // ulFsControlCode, + // ulInputBufferLen, + // ulOutputBufferLen); + } + + break; + } + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSFcbSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSFcbSupport.cpp new file mode 100644 index 0000000000..cc610184a2 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSFcbSupport.cpp @@ -0,0 +1,1219 @@ +/* + * 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: AFSFcbSupport.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSInitFcb +// +// Description: +// +// This function performs Fcb initialization +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSInitFcb( IN AFSDirectoryCB *DirEntry, + IN OUT AFSFcb **Fcb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSFcb *pFcb = NULL; + AFSNonPagedFcb *pNPFcb = NULL; + IO_STATUS_BLOCK stIoSb = {0,0}; + BOOLEAN bUninitFileLock = FALSE; + USHORT usFcbLength = 0; + ULONGLONG ullIndex = 0; + AFSDirEnumEntry *pDirEnumCB = NULL; + AFSObjectInfoCB *pObjectInfo = NULL, *pParentObjectInfo = NULL; + AFSVolumeCB *pVolumeCB = NULL; + + __Enter + { + + pObjectInfo = DirEntry->ObjectInformation; + + pParentObjectInfo = pObjectInfo->ParentObjectInformation; + + pVolumeCB = pObjectInfo->VolumeCB; + + // + // Allocate the Fcb and the nonpaged portion of the Fcb. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSInitFcb Initializing fcb for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + usFcbLength = sizeof( AFSFcb); + + pFcb = (AFSFcb *)AFSExAllocatePoolWithTag( PagedPool, + usFcbLength, + AFS_FCB_ALLOCATION_TAG); + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitFcb Failed to allocate fcb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pFcb, + usFcbLength); + + pFcb->Header.NodeByteSize = usFcbLength; + + pNPFcb = (AFSNonPagedFcb *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedFcb), + AFS_FCB_NP_ALLOCATION_TAG); + + if( pNPFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitFcb Failed to allocate non-paged fcb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pNPFcb, + sizeof( AFSNonPagedFcb)); + + pNPFcb->Size = sizeof( AFSNonPagedFcb); + pNPFcb->Type = AFS_NON_PAGED_FCB; + + // + // Initialize the advanced header + // + + ExInitializeFastMutex( &pNPFcb->AdvancedHdrMutex); + + FsRtlSetupAdvancedHeader( &pFcb->Header, &pNPFcb->AdvancedHdrMutex); + + // + // OK, initialize the entry + // + + ExInitializeResourceLite( &pNPFcb->Resource); + + ExInitializeResourceLite( &pNPFcb->PagingResource); + + pFcb->Header.Resource = &pNPFcb->Resource; + + pFcb->Header.PagingIoResource = &pNPFcb->PagingResource; + + // + // Grab the Fcb for processing + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitFcb Acquiring Fcb lock %08lX EXCL %08lX\n", + &pNPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pNPFcb->Resource, + TRUE); + + pFcb->NPFcb = pNPFcb; + + // + // Initialize some fields in the Fcb + // + + pFcb->ObjectInformation = pObjectInfo; + + pObjectInfo->Fcb = pFcb; + + // + // Set type specific information + // + + if( pObjectInfo->FileType == AFS_FILE_TYPE_DIRECTORY) + { + + // + // Reset the type to a directory type + // + + pFcb->Header.NodeTypeCode = AFS_DIRECTORY_FCB; + + // + // Initialize enumeration information + // + + KeInitializeEvent( &pFcb->NPFcb->Specific.Directory.DirectoryEnumEvent, + NotificationEvent, + FALSE); + } + else if( pObjectInfo->FileType == AFS_FILE_TYPE_FILE) + { + + pFcb->Header.NodeTypeCode = AFS_FILE_FCB; + + // + // Initialize the file specific information + // + + FsRtlInitializeFileLock( &pFcb->Specific.File.FileLock, + NULL, + NULL); + + bUninitFileLock = TRUE; + + // + // Initialize the header file sizes to our dir entry information + // + + pFcb->Header.AllocationSize.QuadPart = pObjectInfo->AllocationSize.QuadPart; + pFcb->Header.FileSize.QuadPart = pObjectInfo->EndOfFile.QuadPart; + pFcb->Header.ValidDataLength.QuadPart = pObjectInfo->EndOfFile.QuadPart; + + // + // Initialize the Extents resources and so forth. The + // quiescent state is that no one has the extents for + // IO (do the extents are not busy) and there is no + // extents request outstanding (and hence the "last + // one" is complete). + // + ExInitializeResourceLite( &pNPFcb->Specific.File.ExtentsResource ); + + KeInitializeEvent( &pNPFcb->Specific.File.ExtentsRequestComplete, + NotificationEvent, + TRUE ); + + for (ULONG i = 0; i < AFS_NUM_EXTENT_LISTS; i++) + { + InitializeListHead(&pFcb->Specific.File.ExtentsLists[i]); + } + + pNPFcb->Specific.File.DirtyListHead = NULL; + pNPFcb->Specific.File.DirtyListTail = NULL; + + ExInitializeResourceLite( &pNPFcb->Specific.File.DirtyExtentsListLock); + + KeInitializeEvent( &pNPFcb->Specific.File.FlushEvent, + SynchronizationEvent, + TRUE); + + KeInitializeEvent( &pNPFcb->Specific.File.QueuedFlushEvent, + NotificationEvent, + TRUE); + } + else if( pObjectInfo->FileType == AFS_FILE_TYPE_SPECIAL_SHARE_NAME) + { + + pFcb->Header.NodeTypeCode = AFS_SPECIAL_SHARE_FCB; + } + else if( pObjectInfo->FileType == AFS_FILE_TYPE_PIOCTL) + { + + pFcb->Header.NodeTypeCode = AFS_IOCTL_FCB; + } + else if( pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK) + { + + pFcb->Header.NodeTypeCode = AFS_SYMBOLIC_LINK_FCB; + } + else if( pObjectInfo->FileType == AFS_FILE_TYPE_MOUNTPOINT) + { + + pFcb->Header.NodeTypeCode = AFS_MOUNT_POINT_FCB; + } + else if( pObjectInfo->FileType == AFS_FILE_TYPE_DFSLINK) + { + pFcb->Header.NodeTypeCode = AFS_DFS_LINK_FCB; + } + else + { + ASSERT( FALSE); + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // And return the Fcb + // + + *Fcb = pFcb; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitFcb Initialized Fcb %08lX Name %wZ\n", + pFcb, + &DirEntry->NameInformation.FileName); + + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitFcb Failed to initialize fcb Status %08lX\n", + ntStatus); + + if( pFcb != NULL) + { + + if( bUninitFileLock) + { + + FsRtlUninitializeFileLock( &pFcb->Specific.File.FileLock); + } + + if( pNPFcb != NULL) + { + + AFSReleaseResource( &pNPFcb->Resource); + + ExDeleteResourceLite( &pNPFcb->PagingResource); + + ExDeleteResourceLite( &pNPFcb->Resource); + } + + AFSExFreePool( pFcb); + } + + if( pNPFcb != NULL) + { + + AFSExFreePool( pNPFcb); + } + + if( Fcb != NULL) + { + + *Fcb = NULL; + } + } + } + + return ntStatus; +} + +NTSTATUS +AFSInitVolume( IN GUID *AuthGroup, + IN AFSFileID *RootFid, + OUT AFSVolumeCB **VolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STATUS_BLOCK stIoStatus = {0,0}; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSNonPagedVolumeCB *pNonPagedVcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSNonPagedObjectInfoCB *pNonPagedObject = NULL; + ULONGLONG ullIndex = 0; + BOOLEAN bReleaseLocks = FALSE; + AFSVolumeInfoCB stVolumeInformation; + AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL; + + __Enter + { + + // + // Before grabbing any locks ask the service for the volume information + // This may be a waste but we need to get this information prior to + // taking any volume tree locks. Don't do this for any 'reserved' cell entries + // + + if( RootFid->Cell != 0) + { + + RtlZeroMemory( &stVolumeInformation, + sizeof( AFSVolumeInfoCB)); + + ntStatus = AFSRetrieveVolumeInformation( AuthGroup, + RootFid, + &stVolumeInformation); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitVolume AFSRetrieveVolumeInformation(RootFid) failure %08lX\n", + ntStatus); + + try_return( ntStatus); + } + + // + // Grab our tree locks and see if we raced with someone else + // + + AFSAcquireExcl( pDeviceExt->Specific.RDR.VolumeTree.TreeLock, + TRUE); + + AFSAcquireExcl( &pDeviceExt->Specific.RDR.VolumeListLock, + TRUE); + + bReleaseLocks = TRUE; + + ullIndex = AFSCreateHighIndex( RootFid); + + ntStatus = AFSLocateHashEntry( pDeviceExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( NT_SUCCESS( ntStatus) && + pVolumeCB != NULL) + { + + // + // So we don't lock with an invalidation call ... + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pDeviceExt->Specific.RDR.VolumeTree.TreeLock); + + AFSReleaseResource( &pDeviceExt->Specific.RDR.VolumeListLock); + + bReleaseLocks = FALSE; + + AFSAcquireExcl( pVolumeCB->VolumeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + *VolumeCB = pVolumeCB; + + try_return( ntStatus); + } + + // + // Revert our status from the above call back to success. + // + + ntStatus = STATUS_SUCCESS; + } + + // + // For the global root we allocate out volume node and insert it + // into the volume tree ... + // + + pVolumeCB = (AFSVolumeCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSVolumeCB), + AFS_VCB_ALLOCATION_TAG); + + if( pVolumeCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitVolume Failed to allocate the root volume cb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pVolumeCB, + sizeof( AFSVolumeCB)); + + // + // The non paged portion + // + + pNonPagedVcb = (AFSNonPagedVolumeCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedVolumeCB), + AFS_VCB_ALLOCATION_TAG); + + if( pNonPagedVcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitVolume Failed to allocate the root non paged volume cb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pNonPagedVcb, + sizeof( AFSNonPagedVolumeCB)); + + ExInitializeResourceLite( &pNonPagedVcb->VolumeLock); + + ExInitializeResourceLite( &pNonPagedVcb->ObjectInfoTreeLock); + + pNonPagedObject = (AFSNonPagedObjectInfoCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedObjectInfoCB), + AFS_VCB_ALLOCATION_TAG); + + if( pNonPagedObject == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitVolume Failed to allocate the root non paged object cb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pNonPagedObject, + sizeof( AFSNonPagedObjectInfoCB)); + + ExInitializeResourceLite( &pNonPagedObject->DirectoryNodeHdrLock); + + pVolumeCB->NonPagedVcb = pNonPagedVcb; + + pVolumeCB->ObjectInformation.NonPagedInfo = pNonPagedObject; + + pVolumeCB->VolumeLock = &pNonPagedVcb->VolumeLock; + + pVolumeCB->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock = &pNonPagedObject->DirectoryNodeHdrLock; + + pVolumeCB->ObjectInfoTree.TreeLock = &pNonPagedVcb->ObjectInfoTreeLock; + + // + // Bias our reference by 1 + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitVolume Initializing count (1) on volume %08lX\n", + pVolumeCB); + + pVolumeCB->VolumeReferenceCount = 1; + + AFSAcquireExcl( pVolumeCB->VolumeLock, + TRUE); + + pVolumeCB->DirectoryCB = (AFSDirectoryCB *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSDirectoryCB) + sizeof( WCHAR), + AFS_DIR_ENTRY_TAG); + + if( pVolumeCB->DirectoryCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pVolumeCB->DirectoryCB, + sizeof( AFSDirectoryCB) + sizeof( WCHAR)); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pVolumeCB->DirectoryCB->NonPaged = pNonPagedDirEntry; + + // + // Initialize the non-paged portion of the directory entry + // + + KeQuerySystemTime( &pVolumeCB->ObjectInformation.CreationTime); + KeQuerySystemTime( &pVolumeCB->ObjectInformation.LastWriteTime); + KeQuerySystemTime( &pVolumeCB->ObjectInformation.LastAccessTime); + + pVolumeCB->ObjectInformation.FileType = AFS_FILE_TYPE_DIRECTORY; + + SetFlag( pVolumeCB->ObjectInformation.Flags, AFS_OBJECT_ROOT_VOLUME); + + pVolumeCB->ObjectInformation.FileId.Cell = RootFid->Cell; + pVolumeCB->ObjectInformation.FileId.Volume = RootFid->Volume; + pVolumeCB->ObjectInformation.FileId.Vnode = RootFid->Vnode; + pVolumeCB->ObjectInformation.FileId.Unique = RootFid->Unique; + pVolumeCB->ObjectInformation.FileId.Hash = RootFid->Hash; + + pVolumeCB->ObjectInformation.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + + pVolumeCB->DirectoryCB->NameInformation.FileName.Length = sizeof( WCHAR); + + pVolumeCB->DirectoryCB->NameInformation.FileName.MaximumLength = pVolumeCB->DirectoryCB->NameInformation.FileName.Length; + + pVolumeCB->DirectoryCB->NameInformation.FileName.Buffer = (WCHAR *)((char *)pVolumeCB->DirectoryCB + sizeof( AFSDirectoryCB)); + + RtlCopyMemory( pVolumeCB->DirectoryCB->NameInformation.FileName.Buffer, + L"\\", + sizeof( WCHAR)); + + // + // Copy in the volume information retrieved above + // + + RtlCopyMemory( &pVolumeCB->VolumeInformation, + &stVolumeInformation, + sizeof( AFSVolumeInfoCB)); + + // + // Setup pointers + // + + pVolumeCB->DirectoryCB->ObjectInformation = &pVolumeCB->ObjectInformation; + + pVolumeCB->DirectoryCB->ObjectInformation->VolumeCB = pVolumeCB; + + // + // Insert the volume into our volume tree. Don't insert any reserved entries + // + + if( RootFid->Cell != 0) + { + + pVolumeCB->TreeEntry.HashIndex = ullIndex; + + if( pDeviceExt->Specific.RDR.VolumeTree.TreeHead == NULL) + { + + pDeviceExt->Specific.RDR.VolumeTree.TreeHead = &pVolumeCB->TreeEntry; + } + else + { + + AFSInsertHashEntry( pDeviceExt->Specific.RDR.VolumeTree.TreeHead, + &pVolumeCB->TreeEntry); + } + + SetFlag( pVolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE); + + if( pDeviceExt->Specific.RDR.VolumeListHead == NULL) + { + + pDeviceExt->Specific.RDR.VolumeListHead = pVolumeCB; + } + else + { + + pDeviceExt->Specific.RDR.VolumeListTail->ListEntry.fLink = (void *)pVolumeCB; + + pVolumeCB->ListEntry.bLink = pDeviceExt->Specific.RDR.VolumeListTail; + } + + pDeviceExt->Specific.RDR.VolumeListTail = pVolumeCB; + } + + *VolumeCB = pVolumeCB; + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( pNonPagedVcb != NULL) + { + + AFSReleaseResource( pVolumeCB->VolumeLock); + + ExDeleteResourceLite( &pNonPagedVcb->VolumeLock); + + ExDeleteResourceLite( &pNonPagedVcb->ObjectInfoTreeLock); + + AFSExFreePool( pNonPagedVcb); + } + + if( pNonPagedObject != NULL) + { + + ExDeleteResourceLite( &pNonPagedObject->DirectoryNodeHdrLock); + + AFSExFreePool( pNonPagedObject); + } + + if( pVolumeCB != NULL) + { + + if( pVolumeCB->DirectoryCB != NULL) + { + + AFSExFreePool( pVolumeCB->DirectoryCB); + } + + AFSExFreePool( pVolumeCB); + } + + if( pNonPagedDirEntry != NULL) + { + + ExDeleteResourceLite( &pNonPagedDirEntry->Lock); + + AFSExFreePool( pNonPagedDirEntry); + } + } + + if( bReleaseLocks) + { + + AFSReleaseResource( pDeviceExt->Specific.RDR.VolumeTree.TreeLock); + + AFSReleaseResource( &pDeviceExt->Specific.RDR.VolumeListLock); + } + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveVolume( IN AFSVolumeCB *VolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + // + // Remove the volume from the tree and list + // Don't process the list information for reserved entries + // + + if( VolumeCB->ObjectInformation.FileId.Cell != 0) + { + + if( BooleanFlagOn( VolumeCB->Flags, AFS_VOLUME_INSERTED_HASH_TREE)) + { + + AFSRemoveHashEntry( &pDeviceExt->Specific.RDR.VolumeTree.TreeHead, + &VolumeCB->TreeEntry); + } + + if( VolumeCB->ListEntry.fLink == NULL) + { + + pDeviceExt->Specific.RDR.VolumeListTail = (AFSVolumeCB *)VolumeCB->ListEntry.bLink; + + if( pDeviceExt->Specific.RDR.VolumeListTail != NULL) + { + + pDeviceExt->Specific.RDR.VolumeListTail->ListEntry.fLink = NULL; + } + } + else + { + + ((AFSVolumeCB *)(VolumeCB->ListEntry.fLink))->ListEntry.bLink = VolumeCB->ListEntry.bLink; + } + + if( VolumeCB->ListEntry.bLink == NULL) + { + + pDeviceExt->Specific.RDR.VolumeListHead = (AFSVolumeCB *)VolumeCB->ListEntry.fLink; + + if( pDeviceExt->Specific.RDR.VolumeListHead != NULL) + { + + pDeviceExt->Specific.RDR.VolumeListHead->ListEntry.bLink = NULL; + } + } + else + { + + ((AFSVolumeCB *)(VolumeCB->ListEntry.bLink))->ListEntry.fLink = VolumeCB->ListEntry.fLink; + } + } + + // + // Remove any PIOctl objects we have + // + + if( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB != NULL) + { + + if( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb != NULL) + { + + AFSRemoveFcb( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb); + } + + AFSDeleteObjectInfo( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB->ObjectInformation); + + AFSExFreePool( VolumeCB->ObjectInformation.Specific.Directory.PIOCtlDirectoryCB); + } + + if( BooleanFlagOn( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_HELD_IN_SERVICE)) + { + + // + // Release the fid in the service + // + + AFSReleaseFid( &VolumeCB->ObjectInformation.FileId); + } + + // + // Free up the memory + // + + if( VolumeCB->NonPagedVcb != NULL) + { + + if( ExIsResourceAcquiredLite( VolumeCB->VolumeLock)) + { + + AFSReleaseResource( VolumeCB->VolumeLock); + } + + ExDeleteResourceLite( &VolumeCB->NonPagedVcb->VolumeLock); + + ExDeleteResourceLite( &VolumeCB->NonPagedVcb->ObjectInfoTreeLock); + + AFSExFreePool( VolumeCB->NonPagedVcb); + } + + if( VolumeCB->ObjectInformation.NonPagedInfo != NULL) + { + + ExDeleteResourceLite( &VolumeCB->ObjectInformation.NonPagedInfo->DirectoryNodeHdrLock); + + AFSExFreePool( VolumeCB->ObjectInformation.NonPagedInfo); + } + + if( VolumeCB->DirectoryCB != NULL) + { + + if( VolumeCB->DirectoryCB->NonPaged != NULL) + { + + ExDeleteResourceLite( &VolumeCB->DirectoryCB->NonPaged->Lock); + + AFSExFreePool( VolumeCB->DirectoryCB->NonPaged); + } + + AFSExFreePool( VolumeCB->DirectoryCB); + } + + AFSExFreePool( VolumeCB); + } + + return ntStatus; +} + + +// +// Function: AFSInitRootFcb +// +// Description: +// +// This function performs Root node Fcb initialization +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSInitRootFcb( IN ULONGLONG ProcessID, + IN AFSVolumeCB *VolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFcb *pFcb = NULL; + AFSNonPagedFcb *pNPFcb = NULL; + IO_STATUS_BLOCK stIoStatus = {0,0}; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + // + // Initialize the root fcb + // + + pFcb = (AFSFcb *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSFcb), + AFS_FCB_ALLOCATION_TAG); + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitRootFcb Failed to allocate the root fcb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pFcb, + sizeof( AFSFcb)); + + pFcb->Header.NodeByteSize = sizeof( AFSFcb); + pFcb->Header.NodeTypeCode = AFS_ROOT_FCB; + + pNPFcb = (AFSNonPagedFcb *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedFcb), + AFS_FCB_NP_ALLOCATION_TAG); + + if( pNPFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitRootFcb Failed to allocate the non-paged fcb\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pNPFcb, + sizeof( AFSNonPagedFcb)); + + pNPFcb->Size = sizeof( AFSNonPagedFcb); + pNPFcb->Type = AFS_NON_PAGED_FCB; + + // + // OK, initialize the entry + // + + ExInitializeFastMutex( &pNPFcb->AdvancedHdrMutex); + + FsRtlSetupAdvancedHeader( &pFcb->Header, &pNPFcb->AdvancedHdrMutex); + + ExInitializeResourceLite( &pNPFcb->Resource); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitRootFcb Acquiring Fcb lock %08lX EXCL %08lX\n", + &pNPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pNPFcb->Resource, + TRUE); + + ExInitializeResourceLite( &pNPFcb->PagingResource); + + pFcb->Header.Resource = &pNPFcb->Resource; + + pFcb->Header.PagingIoResource = &pNPFcb->PagingResource; + + pFcb->NPFcb = pNPFcb; + + // + // Initialize enumeration information + // + + KeInitializeEvent( &pFcb->NPFcb->Specific.Directory.DirectoryEnumEvent, + NotificationEvent, + FALSE); + + // + // Save the root Fcb in the VolumeCB + // + + VolumeCB->ObjectInformation.Fcb = pFcb; + + VolumeCB->ObjectInformation.VolumeCB = VolumeCB; + + VolumeCB->RootFcb = pFcb; + + pFcb->ObjectInformation = &VolumeCB->ObjectInformation; + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( pFcb != NULL) + { + + AFSRemoveRootFcb( pFcb); + } + } + } + + return ntStatus; +} + +// +// Function: AFSRemoveRootFcb +// +// Description: +// +// This function performs root Fcb removal/deallocation +// +// Return: +// +// A status is returned for the function +// + +void +AFSRemoveRootFcb( IN AFSFcb *RootFcb) +{ + + AFSDirectoryCB *pCurrentDirEntry = NULL; + AFSVolumeCB *pVolumeCB = RootFcb->ObjectInformation->VolumeCB; + + if( RootFcb->NPFcb != NULL) + { + + // + // Now the resource + // + + ExDeleteResourceLite( &RootFcb->NPFcb->Resource); + + ExDeleteResourceLite( &RootFcb->NPFcb->PagingResource); + + // + // The non paged region + // + + AFSExFreePool( RootFcb->NPFcb); + } + + // + // And the Fcb itself + // + + AFSExFreePool( RootFcb); + + return; +} + +// +// Function: AFSRemoveFcb +// +// Description: +// +// This function performs Fcb removal/deallocation +// +// Return: +// +// A status is returned for the function +// + +void +AFSRemoveFcb( IN AFSFcb *Fcb) +{ + + // + // Uninitialize the file lock if it is a file + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveFcb Removing Fcb %08lX\n", + Fcb); + + if( Fcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + FsRtlUninitializeFileLock( &Fcb->Specific.File.FileLock); + + // + // The resource we allocated + // + + ExDeleteResourceLite( &Fcb->NPFcb->Specific.File.ExtentsResource ); + + ExDeleteResourceLite( &Fcb->NPFcb->Specific.File.DirtyExtentsListLock); + + } + else if( Fcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB) + { + + + } + + // + // Tear down the FM specific contexts + // + + FsRtlTeardownPerStreamContexts( &Fcb->Header); + + // + // Delete the resources + // + + ExDeleteResourceLite( &Fcb->NPFcb->Resource); + + ExDeleteResourceLite( &Fcb->NPFcb->PagingResource); + + + + // + // The non paged region + // + + AFSExFreePool( Fcb->NPFcb); + + // + // And the Fcb itself, which includes the name + // + + AFSExFreePool( Fcb); + + return; +} + +NTSTATUS +AFSInitCcb( IN OUT AFSCcb **Ccb) +{ + + NTSTATUS Status = STATUS_SUCCESS; + AFSCcb *pCcb = NULL; + + __Enter + { + + // + // Allocate our context control block + // + + pCcb = (AFSCcb *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSCcb), + AFS_CCB_ALLOCATION_TAG); + + if( pCcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitCcb Failed to allocate Ccb\n"); + + try_return( Status = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pCcb, + sizeof( AFSCcb)); + + pCcb->Size = sizeof( AFSCcb); + pCcb->Type = AFS_CCB; + + // + // Return the Ccb + // + + *Ccb = pCcb; + +try_exit: + + if( !NT_SUCCESS( Status)) + { + + if( pCcb != NULL) + { + + AFSExFreePool( pCcb); + } + + *Ccb = NULL; + } + } + + return Status; +} + +// +// Function: AFSRemoveCcb +// +// Description: +// +// This function performs Ccb removal/deallocation +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSRemoveCcb( IN AFSCcb *Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if( Ccb->MaskName.Buffer != NULL) + { + + AFSExFreePool( Ccb->MaskName.Buffer); + } + + if( BooleanFlagOn( Ccb->Flags, CCB_FLAG_FREE_FULL_PATHNAME)) + { + + AFSExFreePool( Ccb->FullFileName.Buffer); + } + + // + // If we have a name array then delete it + // + + if( Ccb->NameArray != NULL) + { + + AFSFreeNameArray( Ccb->NameArray); + + Ccb->NameArray = NULL; + } + + if( Ccb->DirectorySnapshot != NULL) + { + + AFSExFreePool( Ccb->DirectorySnapshot); + + Ccb->DirectorySnapshot = NULL; + } + + if( Ccb->NotifyMask.Buffer != NULL) + { + + AFSExFreePool( Ccb->NotifyMask.Buffer); + } + + // + // Free up the Ccb + // + + AFSExFreePool( Ccb); + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp b/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp new file mode 100644 index 0000000000..cad48b82f5 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp @@ -0,0 +1,3220 @@ +/* + * 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: AFSFileInfo.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSQueryFileInfo +// +// Description: +// +// This function is the dispatch handler for the IRP_MJ_QUERY_FILE_INFORMATION request +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSQueryFileInfo( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + ULONG ulRequestType = 0; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + PFILE_OBJECT pFileObject; + BOOLEAN bReleaseMain = FALSE; + LONG lLength; + FILE_INFORMATION_CLASS stFileInformationClass; + PVOID pBuffer; + + __try + { + + // + // Determine the type of request this request is + // + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryFileInfo Attempted access (%08lX) when pFcb == NULL\n", + Irp); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + lLength = (LONG)pIrpSp->Parameters.QueryFile.Length; + stFileInformationClass = pIrpSp->Parameters.QueryFile.FileInformationClass; + pBuffer = Irp->AssociatedIrp.SystemBuffer; + + // + // Grab the main shared right off the bat + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueryFileInfo Acquiring Fcb lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + bReleaseMain = TRUE; + + // + // Don't allow requests against IOCtl nodes + // + + if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueryFileInfo Processing request against SpecialShare Fcb\n"); + + ntStatus = AFSProcessShareQueryInfo( Irp, + pFcb, + pCcb); + + try_return( ntStatus); + } + else if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueryFileInfo request against PIOCtl Fcb\n"); + + ntStatus = AFSProcessPIOCtlQueryInfo( Irp, + pFcb, + pCcb, + &lLength); + + try_return( ntStatus); + } + + // + // Process the request + // + + switch( stFileInformationClass) + { + + case FileAllInformation: + { + + PFILE_ALL_INFORMATION pAllInfo; + + // + // For the all information class we'll typecast a local + // pointer to the output buffer and then call the + // individual routines to fill in the buffer. + // + + pAllInfo = (PFILE_ALL_INFORMATION)pBuffer; + + ntStatus = AFSQueryBasicInfo( Irp, + pCcb->DirectoryCB, + &pAllInfo->BasicInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryStandardInfo( Irp, + pCcb->DirectoryCB, + &pAllInfo->StandardInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryInternalInfo( Irp, + pFcb, + &pAllInfo->InternalInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryEaInfo( Irp, + pCcb->DirectoryCB, + &pAllInfo->EaInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryAccess( Irp, + pFcb, + &pAllInfo->AccessInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryPositionInfo( Irp, + pFcb, + &pAllInfo->PositionInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryMode( Irp, + pFcb, + &pAllInfo->ModeInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryAlignment( Irp, + pFcb, + &pAllInfo->AlignmentInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + ntStatus = AFSQueryNameInfo( Irp, + pCcb->DirectoryCB, + &pAllInfo->NameInformation, + &lLength); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + break; + } + + case FileBasicInformation: + { + + ntStatus = AFSQueryBasicInfo( Irp, + pCcb->DirectoryCB, + (PFILE_BASIC_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileStandardInformation: + { + + ntStatus = AFSQueryStandardInfo( Irp, + pCcb->DirectoryCB, + (PFILE_STANDARD_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileInternalInformation: + { + + ntStatus = AFSQueryInternalInfo( Irp, + pFcb, + (PFILE_INTERNAL_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileEaInformation: + { + + ntStatus = AFSQueryEaInfo( Irp, + pCcb->DirectoryCB, + (PFILE_EA_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FilePositionInformation: + { + + ntStatus = AFSQueryPositionInfo( Irp, + pFcb, + (PFILE_POSITION_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileNameInformation: + { + + ntStatus = AFSQueryNameInfo( Irp, + pCcb->DirectoryCB, + (PFILE_NAME_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileAlternateNameInformation: + { + + ntStatus = AFSQueryShortNameInfo( Irp, + pCcb->DirectoryCB, + (PFILE_NAME_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileNetworkOpenInformation: + { + + ntStatus = AFSQueryNetworkInfo( Irp, + pCcb->DirectoryCB, + (PFILE_NETWORK_OPEN_INFORMATION)pBuffer, + &lLength); + + break; + } + + case FileStreamInformation: + { + + ntStatus = AFSQueryStreamInfo( Irp, + pCcb->DirectoryCB, + (FILE_STREAM_INFORMATION *)pBuffer, + &lLength); + + break; + } + + + case FileAttributeTagInformation: + { + + ntStatus = AFSQueryAttribTagInfo( Irp, + pCcb->DirectoryCB, + (FILE_ATTRIBUTE_TAG_INFORMATION *)pBuffer, + &lLength); + + break; + } + + case FileRemoteProtocolInformation: + { + + ntStatus = AFSQueryRemoteProtocolInfo( Irp, + pCcb->DirectoryCB, + (FILE_REMOTE_PROTOCOL_INFORMATION *)pBuffer, + &lLength); + + break; + } + + default: + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + +try_exit: + + Irp->IoStatus.Information = pIrpSp->Parameters.QueryFile.Length - lLength; + + if( bReleaseMain) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_INVALID_PARAMETER && + ntStatus != STATUS_BUFFER_OVERFLOW) + { + + if( pCcb != NULL && + pCcb->DirectoryCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryFileInfo Failed to process request for %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB->ObjectInformation->FileId.Cell, + pCcb->DirectoryCB->ObjectInformation->FileId.Volume, + pCcb->DirectoryCB->ObjectInformation->FileId.Vnode, + pCcb->DirectoryCB->ObjectInformation->FileId.Unique, + ntStatus); + } + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueryFileInfo\n"); + + ntStatus = STATUS_UNSUCCESSFUL; + + if( bReleaseMain) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + } + + AFSCompleteRequest( Irp, + ntStatus); + + return ntStatus; +} + +// +// Function: AFSSetFileInfo +// +// Description: +// +// This function is the dispatch handler for the IRP_MJ_SET_FILE_INFORMATION request +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSSetFileInfo( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + BOOLEAN bCompleteRequest = TRUE; + FILE_INFORMATION_CLASS FileInformationClass; + BOOLEAN bCanQueueRequest = FALSE; + PFILE_OBJECT pFileObject = NULL; + BOOLEAN bReleaseMain = FALSE; + BOOLEAN bUpdateFileInfo = FALSE; + AFSFileID stParentFileId; + + __try + { + + pFileObject = pIrpSp->FileObject; + + pFcb = (AFSFcb *)pFileObject->FsContext; + pCcb = (AFSCcb *)pFileObject->FsContext2; + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetFileInfo Attempted access (%08lX) when pFcb == NULL\n", + Irp); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + bCanQueueRequest = !(IoIsOperationSynchronous( Irp) | (KeGetCurrentIrql() != PASSIVE_LEVEL)); + FileInformationClass = pIrpSp->Parameters.SetFile.FileInformationClass; + + // + // Grab the Fcb EXCL + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetFileInfo Acquiring Fcb lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + bReleaseMain = TRUE; + + // + // Don't allow requests against IOCtl nodes + // + + if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetFileInfo Failing request against PIOCtl Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetFileInfo Processing request against SpecialShare Fcb\n"); + + ntStatus = AFSProcessShareSetInfo( Irp, + pFcb, + pCcb); + + try_return( ntStatus); + } + + if( BooleanFlagOn( pFcb->ObjectInformation->VolumeCB->VolumeInformation.Characteristics, FILE_READ_ONLY_DEVICE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetFileInfo Request failed due to read only volume\n", + Irp); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + // + // Ensure rename operations are synchronous + // + + if( FileInformationClass == FileRenameInformation) + { + + bCanQueueRequest = FALSE; + } + + // + // Store away the parent fid + // + + RtlZeroMemory( &stParentFileId, + sizeof( AFSFileID)); + + if( pFcb->ObjectInformation->ParentObjectInformation != NULL) + { + stParentFileId = pFcb->ObjectInformation->ParentObjectInformation->FileId; + } + + // + // Process the request + // + + switch( FileInformationClass) + { + + case FileBasicInformation: + { + + bUpdateFileInfo = TRUE; + + ntStatus = AFSSetBasicInfo( Irp, + pCcb->DirectoryCB); + + break; + } + + case FileDispositionInformation: + { + + ntStatus = AFSSetDispositionInfo( Irp, + pCcb->DirectoryCB); + + break; + } + + case FileRenameInformation: + { + + ntStatus = AFSSetRenameInfo( Irp); + + break; + } + + case FilePositionInformation: + { + + ntStatus = AFSSetPositionInfo( Irp, + pCcb->DirectoryCB); + + break; + } + + case FileLinkInformation: + { + + ntStatus = STATUS_INVALID_DEVICE_REQUEST; + + break; + } + + case FileAllocationInformation: + { + + ntStatus = AFSSetAllocationInfo( Irp, + pCcb->DirectoryCB); + + break; + } + + case FileEndOfFileInformation: + { + + ntStatus = AFSSetEndOfFileInfo( Irp, + pCcb->DirectoryCB); + + break; + } + + default: + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + +try_exit: + + if( bReleaseMain) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + + if( NT_SUCCESS( ntStatus) && + bUpdateFileInfo) + { + + ntStatus = AFSUpdateFileInformation( &stParentFileId, + pFcb->ObjectInformation, + &pFcb->AuthGroup); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSAcquireExcl( &pFcb->NPFcb->Resource, + TRUE); + + // + // Unwind the update and fail the request + // + + AFSUnwindFileInfo( pFcb, + pCcb); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetFileInfo Failed to send file info update to service request for %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB->ObjectInformation->FileId.Cell, + pCcb->DirectoryCB->ObjectInformation->FileId.Volume, + pCcb->DirectoryCB->ObjectInformation->FileId.Vnode, + pCcb->DirectoryCB->ObjectInformation->FileId.Unique, + ntStatus); + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( pCcb != NULL && + pCcb->DirectoryCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetFileInfo Failed to process request for %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pCcb->DirectoryCB->ObjectInformation->FileId.Cell, + pCcb->DirectoryCB->ObjectInformation->FileId.Volume, + pCcb->DirectoryCB->ObjectInformation->FileId.Vnode, + pCcb->DirectoryCB->ObjectInformation->FileId.Unique, + ntStatus); + } + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSSetFileInfo\n"); + + ntStatus = STATUS_UNSUCCESSFUL; + } + + AFSCompleteRequest( Irp, + ntStatus); + + return ntStatus; +} + +// +// Function: AFSQueryBasicInfo +// +// Description: +// +// This function is the handler for the query basic information request +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSQueryBasicInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_BASIC_INFORMATION Buffer, + IN OUT PLONG Length) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + if( *Length >= sizeof( FILE_BASIC_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->CreationTime = DirectoryCB->ObjectInformation->CreationTime; + Buffer->LastAccessTime = DirectoryCB->ObjectInformation->LastAccessTime; + Buffer->LastWriteTime = DirectoryCB->ObjectInformation->LastWriteTime; + Buffer->ChangeTime = DirectoryCB->ObjectInformation->ChangeTime; + Buffer->FileAttributes = DirectoryCB->ObjectInformation->FileAttributes; + + if( DirectoryCB->NameInformation.FileName.Buffer[ 0] == L'.' && + BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES)) + { + + if ( Buffer->FileAttributes != FILE_ATTRIBUTE_NORMAL) + { + + Buffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + else + { + + Buffer->FileAttributes = FILE_ATTRIBUTE_HIDDEN; + } + } + + *Length -= sizeof( FILE_BASIC_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryStandardInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_STANDARD_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFileInfoCB stFileInformation; + AFSCcb *pCcb = NULL; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + if( *Length >= sizeof( FILE_STANDARD_INFORMATION)) + { + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + RtlZeroMemory( Buffer, + *Length); + + Buffer->NumberOfLinks = 1; + Buffer->DeletePending = BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + + RtlZeroMemory( &stFileInformation, + sizeof( AFSFileInfoCB)); + + Buffer->AllocationSize.QuadPart = (ULONGLONG)((DirectoryCB->ObjectInformation->AllocationSize.QuadPart/PAGE_SIZE) + 1) * PAGE_SIZE; + + Buffer->EndOfFile = DirectoryCB->ObjectInformation->EndOfFile; + + Buffer->Directory = BooleanFlagOn( DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY); + + *Length -= sizeof( FILE_STANDARD_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryInternalInfo( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_INTERNAL_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if( *Length >= sizeof( FILE_INTERNAL_INFORMATION)) + { + + Buffer->IndexNumber.HighPart = Fcb->ObjectInformation->FileId.Volume; + + Buffer->IndexNumber.LowPart = Fcb->ObjectInformation->FileId.Vnode; + + *Length -= sizeof( FILE_INTERNAL_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryEaInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_EA_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= sizeof( FILE_EA_INFORMATION)) + { + + Buffer->EaSize = 0; + + *Length -= sizeof( FILE_EA_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryPositionInfo( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_POSITION_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + if( *Length >= sizeof( FILE_POSITION_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->CurrentByteOffset.QuadPart = pIrpSp->FileObject->CurrentByteOffset.QuadPart; + + *Length -= sizeof( FILE_POSITION_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryAccess( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_ACCESS_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if( *Length >= sizeof( FILE_ACCESS_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->AccessFlags = 0; + + *Length -= sizeof( FILE_ACCESS_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryMode( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_MODE_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if( *Length >= sizeof( FILE_MODE_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->Mode = 0; + + *Length -= sizeof( FILE_MODE_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryAlignment( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_ALIGNMENT_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if( *Length >= sizeof( FILE_ALIGNMENT_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->AlignmentRequirement = 1; + + *Length -= sizeof( FILE_ALIGNMENT_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryNameInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_NAME_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulCopyLength = 0; + ULONG cchCopied = 0; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + BOOLEAN bAddLeadingSlash = FALSE; + BOOLEAN bAddTrailingSlash = FALSE; + USHORT usFullNameLength = 0; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + if( *Length >= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName)) + { + + RtlZeroMemory( Buffer, + *Length); + + if( pCcb->FullFileName.Length == 0 || + pCcb->FullFileName.Buffer[ 0] != L'\\') + { + bAddLeadingSlash = TRUE; + } + + if( pFcb->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY && + pCcb->FullFileName.Length > 0 && + pCcb->FullFileName.Buffer[ (pCcb->FullFileName.Length/sizeof( WCHAR)) - 1] != L'\\') + { + bAddTrailingSlash = TRUE; + } + + usFullNameLength = sizeof( WCHAR) + + AFSServerName.Length + + pCcb->FullFileName.Length; + + if( bAddLeadingSlash) + { + usFullNameLength += sizeof( WCHAR); + } + + if( bAddTrailingSlash) + { + usFullNameLength += sizeof( WCHAR); + } + + if( *Length >= (LONG)(FIELD_OFFSET( FILE_NAME_INFORMATION, FileName) + (LONG)usFullNameLength)) + { + + ulCopyLength = (LONG)usFullNameLength; + } + else + { + + ulCopyLength = *Length - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + Buffer->FileNameLength = (ULONG)usFullNameLength; + + *Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + if( ulCopyLength > 0) + { + + Buffer->FileName[ 0] = L'\\'; + ulCopyLength -= sizeof( WCHAR); + + *Length -= sizeof( WCHAR); + cchCopied += 1; + + if( ulCopyLength >= AFSServerName.Length) + { + + RtlCopyMemory( &Buffer->FileName[ 1], + AFSServerName.Buffer, + AFSServerName.Length); + + ulCopyLength -= AFSServerName.Length; + *Length -= AFSServerName.Length; + cchCopied += AFSServerName.Length/sizeof( WCHAR); + + if ( ulCopyLength > 0 && + bAddLeadingSlash) + { + + Buffer->FileName[ cchCopied] = L'\\'; + + ulCopyLength -= sizeof( WCHAR); + *Length -= sizeof( WCHAR); + cchCopied++; + } + + if( ulCopyLength >= pCcb->FullFileName.Length) + { + + RtlCopyMemory( &Buffer->FileName[ cchCopied], + pCcb->FullFileName.Buffer, + pCcb->FullFileName.Length); + + ulCopyLength -= pCcb->FullFileName.Length; + *Length -= pCcb->FullFileName.Length; + cchCopied += pCcb->FullFileName.Length/sizeof( WCHAR); + + if( ulCopyLength > 0 && + bAddTrailingSlash) + { + Buffer->FileName[ cchCopied] = L'\\'; + + *Length -= sizeof( WCHAR); + } + } + else + { + + RtlCopyMemory( &Buffer->FileName[ cchCopied], + pCcb->FullFileName.Buffer, + ulCopyLength); + + *Length -= ulCopyLength; + } + } + } + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryShortNameInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_NAME_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL; + ULONG ulCopyLength = 0; + + RtlZeroMemory( Buffer, + *Length); + + if( DirectoryCB->NameInformation.ShortNameLength == 0) + { + + // + // The short name IS the long name + // + + if( *Length >= (LONG)FIELD_OFFSET( FILE_NAME_INFORMATION, FileName)) + { + + if( *Length >= (LONG)(FIELD_OFFSET( FILE_NAME_INFORMATION, FileName) + (LONG)DirectoryCB->NameInformation.FileName.Length)) + { + + ulCopyLength = (LONG)DirectoryCB->NameInformation.FileName.Length; + + ntStatus = STATUS_SUCCESS; + } + else + { + + ulCopyLength = *Length - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + Buffer->FileNameLength = DirectoryCB->NameInformation.FileName.Length; + + *Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + if( ulCopyLength > 0) + { + + RtlCopyMemory( Buffer->FileName, + DirectoryCB->NameInformation.FileName.Buffer, + ulCopyLength); + + *Length -= ulCopyLength; + } + } + } + else + { + + if( *Length >= (LONG)FIELD_OFFSET( FILE_NAME_INFORMATION, FileName)) + { + + if( *Length >= (LONG)(FIELD_OFFSET( FILE_NAME_INFORMATION, FileName) + (LONG)DirectoryCB->NameInformation.FileName.Length)) + { + + ulCopyLength = (LONG)DirectoryCB->NameInformation.ShortNameLength; + + ntStatus = STATUS_SUCCESS; + } + else + { + + ulCopyLength = *Length - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + Buffer->FileNameLength = DirectoryCB->NameInformation.ShortNameLength; + + *Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + if( ulCopyLength > 0) + { + + RtlCopyMemory( Buffer->FileName, + DirectoryCB->NameInformation.ShortName, + Buffer->FileNameLength); + + *Length -= ulCopyLength; + } + } + } + + return ntStatus; +} + +NTSTATUS +AFSQueryNetworkInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= sizeof( FILE_NETWORK_OPEN_INFORMATION)) + { + + Buffer->CreationTime.QuadPart = DirectoryCB->ObjectInformation->CreationTime.QuadPart; + Buffer->LastAccessTime.QuadPart = DirectoryCB->ObjectInformation->LastAccessTime.QuadPart; + Buffer->LastWriteTime.QuadPart = DirectoryCB->ObjectInformation->LastWriteTime.QuadPart; + Buffer->ChangeTime.QuadPart = DirectoryCB->ObjectInformation->ChangeTime.QuadPart; + + Buffer->AllocationSize.QuadPart = DirectoryCB->ObjectInformation->AllocationSize.QuadPart; + Buffer->EndOfFile.QuadPart = DirectoryCB->ObjectInformation->EndOfFile.QuadPart; + + Buffer->FileAttributes = DirectoryCB->ObjectInformation->FileAttributes; + + if( DirectoryCB->NameInformation.FileName.Buffer[ 0] == L'.' && + BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES)) + { + + if ( Buffer->FileAttributes != FILE_ATTRIBUTE_NORMAL) + { + + Buffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + else + { + + Buffer->FileAttributes = FILE_ATTRIBUTE_HIDDEN; + } + } + + *Length -= sizeof( FILE_NETWORK_OPEN_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryStreamInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT FILE_STREAM_INFORMATION *Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL; + ULONG ulCopyLength = 0; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + if( *Length >= FIELD_OFFSET( FILE_STREAM_INFORMATION, StreamName)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->NextEntryOffset = 0; + + + if( !BooleanFlagOn( DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + + if( *Length >= (LONG)(FIELD_OFFSET( FILE_STREAM_INFORMATION, StreamName) + 14)) // ::$DATA + { + + ulCopyLength = 14; + + ntStatus = STATUS_SUCCESS; + } + else + { + + ulCopyLength = *Length - FIELD_OFFSET( FILE_STREAM_INFORMATION, StreamName); + + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + Buffer->StreamNameLength = 14; // ::$DATA + + Buffer->StreamSize.QuadPart = DirectoryCB->ObjectInformation->EndOfFile.QuadPart; + + Buffer->StreamAllocationSize.QuadPart = DirectoryCB->ObjectInformation->AllocationSize.QuadPart; + + *Length -= FIELD_OFFSET( FILE_STREAM_INFORMATION, StreamName); + + if( ulCopyLength > 0) + { + + RtlCopyMemory( Buffer->StreamName, + L"::$DATA", + ulCopyLength); + + *Length -= ulCopyLength; + } + } + else + { + + Buffer->StreamNameLength = 0; // No stream for a directory + + // The response size is zero + + ntStatus = STATUS_SUCCESS; + } + } + + return ntStatus; +} + +NTSTATUS +AFSQueryAttribTagInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT FILE_ATTRIBUTE_TAG_INFORMATION *Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL; + ULONG ulCopyLength = 0; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + if( *Length >= sizeof( FILE_ATTRIBUTE_TAG_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->FileAttributes = DirectoryCB->ObjectInformation->FileAttributes; + + if( DirectoryCB->NameInformation.FileName.Buffer[ 0] == L'.' && + BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_HIDE_DOT_NAMES)) + { + + if ( Buffer->FileAttributes != FILE_ATTRIBUTE_NORMAL) + { + + Buffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN; + } + else + { + + Buffer->FileAttributes = FILE_ATTRIBUTE_HIDDEN; + } + } + + if( BooleanFlagOn( DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) + { + Buffer->ReparseTag = IO_REPARSE_TAG_OPENAFS_DFS; + } + + *Length -= sizeof( FILE_ATTRIBUTE_TAG_INFORMATION); + + ntStatus = STATUS_SUCCESS; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryRemoteProtocolInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT FILE_REMOTE_PROTOCOL_INFORMATION *Buffer, + IN OUT PLONG Length) +{ + + NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL; + ULONG ulCopyLength = 0; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + if( *Length >= sizeof( FILE_REMOTE_PROTOCOL_INFORMATION)) + { + + RtlZeroMemory( Buffer, + *Length); + + Buffer->StructureVersion = 1; + + Buffer->StructureSize = sizeof(FILE_REMOTE_PROTOCOL_INFORMATION); + + Buffer->Protocol = WNNC_NET_OPENAFS; + + Buffer->ProtocolMajorVersion = 3; + + Buffer->ProtocolMinorVersion = 0; + + Buffer->ProtocolRevision = 0; + + *Length -= sizeof( FILE_REMOTE_PROTOCOL_INFORMATION); + + ntStatus = STATUS_SUCCESS; + } + + return ntStatus; +} + +NTSTATUS +AFSSetBasicInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_BASIC_INFORMATION pBuffer; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + ULONG ulNotifyFilter = 0; + AFSCcb *pCcb = NULL; + + __Enter + { + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + pBuffer = (PFILE_BASIC_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pCcb->FileUnwindInfo.FileAttributes = (ULONG)-1; + + if( pBuffer->FileAttributes != (ULONGLONG)0) + { + + if( DirectoryCB->ObjectInformation->Fcb->Header.NodeTypeCode == AFS_FILE_FCB && + BooleanFlagOn( pBuffer->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + if( DirectoryCB->ObjectInformation->Fcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB) + { + + pBuffer->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY; + } + + if( DirectoryCB->ObjectInformation->Fcb->Header.NodeTypeCode == AFS_SYMBOLIC_LINK_FCB || + DirectoryCB->ObjectInformation->Fcb->Header.NodeTypeCode == AFS_MOUNT_POINT_FCB || + DirectoryCB->ObjectInformation->Fcb->Header.NodeTypeCode == AFS_DFS_LINK_FCB) + { + pBuffer->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + } + + pCcb->FileUnwindInfo.FileAttributes = DirectoryCB->ObjectInformation->FileAttributes; + + DirectoryCB->ObjectInformation->FileAttributes = pBuffer->FileAttributes; + + ulNotifyFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + + SetFlag( DirectoryCB->ObjectInformation->Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED); + } + + pCcb->FileUnwindInfo.CreationTime.QuadPart = (ULONGLONG)-1; + + if( pBuffer->CreationTime.QuadPart != (ULONGLONG)-1 && + pBuffer->CreationTime.QuadPart != (ULONGLONG)0) + { + + pCcb->FileUnwindInfo.CreationTime.QuadPart = DirectoryCB->ObjectInformation->CreationTime.QuadPart; + + DirectoryCB->ObjectInformation->CreationTime.QuadPart = pBuffer->CreationTime.QuadPart; + + ulNotifyFilter |= FILE_NOTIFY_CHANGE_CREATION; + + SetFlag( DirectoryCB->ObjectInformation->Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CREATE_TIME); + } + + pCcb->FileUnwindInfo.LastAccessTime.QuadPart = (ULONGLONG)-1; + + if( pBuffer->LastAccessTime.QuadPart != (ULONGLONG)-1 && + pBuffer->LastAccessTime.QuadPart != (ULONGLONG)0) + { + + pCcb->FileUnwindInfo.LastAccessTime.QuadPart = DirectoryCB->ObjectInformation->LastAccessTime.QuadPart; + + DirectoryCB->ObjectInformation->LastAccessTime.QuadPart = pBuffer->LastAccessTime.QuadPart; + + ulNotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + + SetFlag( DirectoryCB->ObjectInformation->Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_ACCESS_TIME); + } + + pCcb->FileUnwindInfo.LastWriteTime.QuadPart = (ULONGLONG)-1; + + if( pBuffer->LastWriteTime.QuadPart != (ULONGLONG)-1 && + pBuffer->LastWriteTime.QuadPart != (ULONGLONG)0) + { + + pCcb->FileUnwindInfo.LastWriteTime.QuadPart = DirectoryCB->ObjectInformation->LastWriteTime.QuadPart; + + DirectoryCB->ObjectInformation->LastWriteTime.QuadPart = pBuffer->LastWriteTime.QuadPart; + + ulNotifyFilter |= FILE_NOTIFY_CHANGE_LAST_WRITE; + + SetFlag( DirectoryCB->ObjectInformation->Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME); + } + + pCcb->FileUnwindInfo.ChangeTime.QuadPart = (ULONGLONG)-1; + + if( pBuffer->ChangeTime.QuadPart != (ULONGLONG)-1 && + pBuffer->ChangeTime.QuadPart != (ULONGLONG)0) + { + + pCcb->FileUnwindInfo.ChangeTime.QuadPart = DirectoryCB->ObjectInformation->ChangeTime.QuadPart; + + DirectoryCB->ObjectInformation->ChangeTime.QuadPart = pBuffer->ChangeTime.QuadPart; + + ulNotifyFilter |= FILE_NOTIFY_CHANGE_LAST_ACCESS; + + SetFlag( DirectoryCB->ObjectInformation->Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + } + + if( ulNotifyFilter > 0) + { + + if( DirectoryCB->ObjectInformation->ParentObjectInformation != NULL) + { + + AFSFsRtlNotifyFullReportChange( DirectoryCB->ObjectInformation->ParentObjectInformation, + pCcb, + (ULONG)ulNotifyFilter, + (ULONG)FILE_ACTION_MODIFIED); + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSSetDispositionInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_DISPOSITION_INFORMATION pBuffer; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + + __Enter + { + + pBuffer = (PFILE_DISPOSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + // + // Can't delete the root + // + + if( pFcb->Header.NodeTypeCode == AFS_ROOT_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetDispositionInfo Attempt to delete root entry\n"); + + try_return( ntStatus = STATUS_CANNOT_DELETE); + } + + // + // If the file is read only then do not allow the delete + // + + if( BooleanFlagOn( DirectoryCB->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_READONLY)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetDispositionInfo Attempt to delete read only entry %wZ\n", + &DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_CANNOT_DELETE); + } + + if( pBuffer->DeleteFile) + { + + // + // Check if the caller can delete the file + // + + ntStatus = AFSNotifyDelete( DirectoryCB, + TRUE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetDispositionInfo Cannot delete entry %wZ Status %08lX\n", + &DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + if( pFcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB) + { + + // + // Check if this is a directory that there are not currently other opens + // + + if( pFcb->ObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetDispositionInfo Attempt to delete directory %wZ with open %u handles\n", + &DirectoryCB->NameInformation.FileName, + pFcb->ObjectInformation->Specific.Directory.ChildOpenHandleCount); + + try_return( ntStatus = STATUS_DIRECTORY_NOT_EMPTY); + } + + if( !AFSIsDirectoryEmptyForDelete( pFcb)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetDispositionInfo Attempt to delete non-empty directory %wZ\n", + &DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_DIRECTORY_NOT_EMPTY); + } + } + else + { + + // + // Attempt to flush any outstanding data + // + + if( !MmFlushImageSection( &pFcb->NPFcb->SectionObjectPointers, + MmFlushForDelete)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetDispositionInfo Failed to flush image section for delete Entry %wZ\n", + &DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_CANNOT_DELETE); + } + + // + // Purge the cache as well + // + + if( pFcb->NPFcb->SectionObjectPointers.DataSectionObject != NULL) + { + + CcPurgeCacheSection( &pFcb->NPFcb->SectionObjectPointers, + NULL, + 0, + TRUE); + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetDispositionInfo Setting PENDING_DELETE on DirEntry %p Name %wZ\n", + DirectoryCB, + &DirectoryCB->NameInformation.FileName); + + SetFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + else + { + + ClearFlag( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_PENDING_DELETE); + } + + // + // OK, should be good to go, set the flag in the file object + // + + pIrpSp->FileObject->DeletePending = pBuffer->DeleteFile; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSSetRenameInfo( IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + IO_STATUS_BLOCK stIoSb = {0,0}; + AFSFcb *pSrcFcb = NULL, *pTargetDcb = NULL, *pTargetFcb = NULL; + AFSCcb *pSrcCcb = NULL, *pTargetDirCcb = NULL; + PFILE_OBJECT pSrcFileObj = pIrpSp->FileObject; + PFILE_OBJECT pTargetFileObj = pIrpSp->Parameters.SetFile.FileObject; + PFILE_RENAME_INFORMATION pRenameInfo = NULL; + UNICODE_STRING uniTargetName, uniSourceName; + BOOLEAN bReplaceIfExists = FALSE; + UNICODE_STRING uniShortName; + AFSDirectoryCB *pTargetDirEntry = NULL; + ULONG ulTargetCRC = 0; + BOOLEAN bTargetEntryExists = FALSE; + 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; + + __Enter + { + + bReplaceIfExists = pIrpSp->Parameters.SetFile.ReplaceIfExists; + + pSrcFcb = (AFSFcb *)pSrcFileObj->FsContext; + pSrcCcb = (AFSCcb *)pSrcFileObj->FsContext2; + + pSrcObject = pSrcFcb->ObjectInformation; + + uniTmpTargetName.Length = 0; + uniTmpTargetName.MaximumLength = 0; + uniTmpTargetName.Buffer = NULL; + + // + // Perform some basic checks to ensure FS integrity + // + + if( pSrcFcb->Header.NodeTypeCode == AFS_ROOT_FCB) + { + + // + // Can't rename the root directory + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Attempt to rename root entry\n"); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + if( pSrcFcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB) + { + + // + // If there are any open children then fail the rename + // + + if( pSrcFcb->ObjectInformation->Specific.Directory.ChildOpenHandleCount > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Attempt to rename directory with open children %wZ\n", + &pSrcCcb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + } + else + { + + if( pSrcFcb->OpenHandleCount > 1) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Attempt to rename directory with open references %wZ\n", + &pSrcCcb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + } + + // + // Resolve the target fileobject + // + + if( pTargetFileObj == NULL) + { + + // + // This is a simple rename. Here the target directory is the same as the source parent directory + // and the name is retrieved from the system buffer information + // + + pRenameInfo = (PFILE_RENAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pTargetParentObject = pSrcFcb->ObjectInformation->ParentObjectInformation; + + pTargetDcb = pTargetParentObject->Fcb; + + uniTargetName.Length = (USHORT)pRenameInfo->FileNameLength; + uniTargetName.Buffer = (PWSTR)&pRenameInfo->FileName; + } + else + { + + // + // So here we have the target directory taken from the targetfile object + // + + pTargetDcb = (AFSFcb *)pTargetFileObj->FsContext; + + pTargetDirCcb = (AFSCcb *)pTargetFileObj->FsContext2; + + pTargetParentObject = (AFSObjectInfoCB *)pTargetDcb->ObjectInformation; + + // + // Grab the target name which we setup in the IRP_MJ_CREATE handler. By how we set this up + // it is only the target component of the rename operation + // + + uniTargetName = *((PUNICODE_STRING)&pTargetFileObj->FileName); + } + + // + // We do not allow cross-volume renames to occur + // + + if( pTargetParentObject->VolumeCB != pSrcObject->VolumeCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Attempt to rename directory to different volume %wZ\n", + &pSrcCcb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_NOT_SAME_DEVICE); + } + + // + // If the target exists be sure the ReplaceIfExists flag is set + // + + AFSAcquireShared( pTargetParentObject->VolumeCB->VolumeLock, + TRUE); + + ulTargetCRC = AFSGenerateCRC( &uniTargetName, + FALSE); + + AFSAcquireShared( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSLocateCaseSensitiveDirEntry( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulTargetCRC, + &pTargetDirEntry); + + if( pTargetDirEntry == NULL) + { + + // + // Missed so perform a case insensitive lookup + // + + ulTargetCRC = AFSGenerateCRC( &uniTargetName, + TRUE); + + AFSLocateCaseInsensitiveDirEntry( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + ulTargetCRC, + &pTargetDirEntry); + } + + // + // Increment our ref count on the dir entry + // + + if( pTargetDirEntry != NULL) + { + InterlockedIncrement( &pTargetDirEntry->OpenReferenceCount); + } + + AFSReleaseResource( pTargetParentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + if( pTargetDirEntry != NULL) + { + + 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", + &pSrcCcb->DirectoryCB->NameInformation.FileName, + &pTargetDirEntry->NameInformation.FileName); + + try_return( ntStatus = STATUS_OBJECT_NAME_COLLISION); + } + + bTargetEntryExists = TRUE; + } + + AFSReleaseResource( pTargetParentObject->VolumeCB->VolumeLock); + + // + // Extract off the final component name from the Fcb + // + + uniSourceName.Length = (USHORT)pSrcCcb->DirectoryCB->NameInformation.FileName.Length; + uniSourceName.MaximumLength = uniSourceName.Length; + + uniSourceName.Buffer = pSrcCcb->DirectoryCB->NameInformation.FileName.Buffer; + + // + // The quick check to see if they are not really performing a rename + // Do the names match? Only do this where the parent directories are + // the same + // + + if( pTargetParentObject == pSrcFcb->ObjectInformation->ParentObjectInformation) + { + + bCommonParent = TRUE; + + if( FsRtlAreNamesEqual( &uniTargetName, + &uniSourceName, + TRUE, + 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); + } + } + else + { + + bCommonParent = FALSE; + } + + // + // 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); + + if( !bCommonParent) + { + + // + // 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 ... We do this + // here to cover any failures which might occur below + // + + pSrcCcb->DirectoryCB->FileIndex = + (ULONG)InterlockedIncrement( &pSrcFcb->ObjectInformation->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.ContentIndex); + } + + // + // OK, this is a simple rename. Issue the rename + // request to the service. + // + + ntStatus = AFSNotifyRename( pSrcFcb->ObjectInformation, + pSrcFcb->ObjectInformation->ParentObjectInformation, + pTargetDcb->ObjectInformation, + pSrcCcb->DirectoryCB, + &uniTargetName, + &stNewFid); + + if( !NT_SUCCESS( ntStatus)) + { + + // + // Attempt to re-insert the directory entry + // + + AFSInsertDirectoryNode( pSrcFcb->ObjectInformation->ParentObjectInformation, + pSrcCcb->DirectoryCB, + !bCommonParent); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Failed rename of %wZ to target %wZ Status %08lX\n", + &pSrcCcb->DirectoryCB->NameInformation.FileName, + &uniTargetName, + ntStatus); + + try_return( ntStatus); + } + + // + // Set the notification up for the source file + // + + if( pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation == pTargetParentObject && + !bReplaceTmpTargetEntry) + { + + ulNotificationAction = FILE_ACTION_RENAMED_OLD_NAME; + } + else + { + + ulNotificationAction = FILE_ACTION_REMOVED; + } + + if( pSrcCcb->DirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY) + { + + ulNotifyFilter = FILE_NOTIFY_CHANGE_DIR_NAME; + } + else + { + + ulNotifyFilter = FILE_NOTIFY_CHANGE_FILE_NAME; + } + + AFSFsRtlNotifyFullReportChange( pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation, + pSrcCcb, + (ULONG)ulNotifyFilter, + (ULONG)ulNotificationAction); + + // + // Update the name in the dir entry. + // + + ntStatus = AFSUpdateDirEntryName( pSrcCcb->DirectoryCB, + &uniTargetName); + + if( !NT_SUCCESS( ntStatus)) + { + + // + // Attempt to re-insert the directory entry + // + + AFSInsertDirectoryNode( pSrcFcb->ObjectInformation->ParentObjectInformation, + pSrcCcb->DirectoryCB, + !bCommonParent); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Failed update of dir entry %wZ to target %wZ Status %08lX\n", + &pSrcCcb->DirectoryCB->NameInformation.FileName, + &uniTargetName, + ntStatus); + + try_return( ntStatus); + } + + // + // Update the object information block, if needed + // + + if( !AFSIsEqualFID( &pSrcObject->FileId, + &stNewFid)) + { + + // + // Remove the old information entry + // + + AFSAcquireExcl( pSrcObject->VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + AFSRemoveHashEntry( &pSrcObject->VolumeCB->ObjectInfoTree.TreeHead, + &pSrcObject->TreeEntry); + + RtlCopyMemory( &pSrcObject->FileId, + &stNewFid, + sizeof( AFSFileID)); + + // + // Insert the entry into the new object table. + // + + pSrcObject->TreeEntry.HashIndex = AFSCreateLowIndex( &pSrcObject->FileId); + + if( pSrcObject->VolumeCB->ObjectInfoTree.TreeHead == NULL) + { + + pSrcObject->VolumeCB->ObjectInfoTree.TreeHead = &pSrcObject->TreeEntry; + } + else + { + + AFSInsertHashEntry( pSrcObject->VolumeCB->ObjectInfoTree.TreeHead, + &pSrcObject->TreeEntry); + } + + AFSReleaseResource( pSrcObject->VolumeCB->ObjectInfoTree.TreeLock); + } + + // + // Update the hash values for the name trees. + // + + pSrcCcb->DirectoryCB->CaseSensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pSrcCcb->DirectoryCB->NameInformation.FileName, + FALSE); + + pSrcCcb->DirectoryCB->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pSrcCcb->DirectoryCB->NameInformation.FileName, + TRUE); + + if( pSrcCcb->DirectoryCB->NameInformation.ShortNameLength > 0) + { + + uniShortName.Length = pSrcCcb->DirectoryCB->NameInformation.ShortNameLength; + uniShortName.Buffer = pSrcCcb->DirectoryCB->NameInformation.ShortName; + + pSrcCcb->DirectoryCB->Type.Data.ShortNameTreeEntry.HashIndex = AFSGenerateCRC( &uniShortName, + TRUE); + } + else + { + + pSrcCcb->DirectoryCB->Type.Data.ShortNameTreeEntry.HashIndex = 0; + } + + if( !bCommonParent) + { + + // + // Update the file index for the object in the new parent + // + + pSrcCcb->DirectoryCB->FileIndex = (ULONG)InterlockedIncrement( &pTargetParentObject->Specific.Directory.DirectoryNodeHdr.ContentIndex); + } + + // + // Re-insert the directory entry + // + + AFSInsertDirectoryNode( pTargetParentObject, + pSrcCcb->DirectoryCB, + !bCommonParent); + + // + // Update the parent pointer in the source object if they are different + // + + if( pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation != pTargetParentObject) + { + + InterlockedDecrement( &pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation->Specific.Directory.ChildOpenHandleCount); + + InterlockedDecrement( &pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation->Specific.Directory.ChildOpenReferenceCount); + + InterlockedIncrement( &pTargetParentObject->Specific.Directory.ChildOpenHandleCount); + + InterlockedIncrement( &pTargetParentObject->Specific.Directory.ChildOpenReferenceCount); + + pSrcCcb->DirectoryCB->ObjectInformation->ParentObjectInformation = pTargetParentObject; + + ulNotificationAction = FILE_ACTION_ADDED; + } + else + { + + ulNotificationAction = FILE_ACTION_RENAMED_NEW_NAME; + } + + // + // Now update the notification for the target file + // + + AFSFsRtlNotifyFullReportChange( pTargetParentObject->ParentObjectInformation, + pSrcCcb, + (ULONG)ulNotifyFilter, + (ULONG)ulNotificationAction); + + // + // If we performed the rename of the target because it existed, we now need to + // delete the tmp target we created above + // + + if( bReplaceTmpTargetEntry) + { + + 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 to tmp %wZ\n", + pTargetDirEntry, + &pTargetDirEntry->NameInformation.FileName, + &uniTmpTargetName); + + SetFlag( pTargetDirEntry->Flags, AFS_DIR_ENTRY_DELETED); + + // + // Try and purge the cache map if this is a file + // + + if( pTargetDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE && + pTargetDirEntry->ObjectInformation->Fcb != NULL && + pTargetDirEntry->OpenReferenceCount > 1) + { + + pTargetFcb = pTargetDirEntry->ObjectInformation->Fcb; + + AFSAcquireExcl( &pTargetFcb->NPFcb->Resource, + TRUE); + + // + // Try and flush the cache map + // + + if( !MmFlushImageSection( &pTargetFcb->NPFcb->SectionObjectPointers, + MmFlushForDelete)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetRenameInfo Failed to flush section for deleted temp file %wZ\n", + &pTargetDirEntry->NameInformation.FileName); + } + + AFSReleaseResource( &pTargetFcb->NPFcb->Resource); + } + + ASSERT( pTargetDirEntry->OpenReferenceCount > 0); + + InterlockedDecrement( &pTargetDirEntry->OpenReferenceCount); + + 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, + 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); + + AFSExFreePool( pTargetDirEntry); + } + + pTargetDirEntry = NULL; + } + +try_exit: + + + if( !NT_SUCCESS( ntStatus)) + { + + if( bReplaceTmpTargetEntry) + { + + 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); + } + } + + if( pTargetDirEntry != NULL) + { + + InterlockedDecrement( &pTargetDirEntry->OpenReferenceCount); + } + + if( uniTmpTargetName.Buffer != NULL) + { + + AFSExFreePool( uniTmpTargetName.Buffer); + } + } + + return ntStatus; +} + +NTSTATUS +AFSSetPositionInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_POSITION_INFORMATION pBuffer; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + pBuffer = (PFILE_POSITION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pIrpSp->FileObject->CurrentByteOffset.QuadPart = pBuffer->CurrentByteOffset.QuadPart; + + return ntStatus; +} + +NTSTATUS +AFSSetAllocationInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_ALLOCATION_INFORMATION pBuffer; + BOOLEAN bReleasePaging = FALSE; + BOOLEAN bTellCc = FALSE; + BOOLEAN bTellService = FALSE; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + LARGE_INTEGER liSaveAlloc; + LARGE_INTEGER liSaveFileSize; + LARGE_INTEGER liSaveVDL; + + pBuffer = (PFILE_ALLOCATION_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + // + // save values to put back + // + liSaveAlloc = pFcb->Header.AllocationSize; + liSaveFileSize = pFcb->Header.FileSize; + liSaveVDL = pFcb->Header.ValidDataLength; + + if( pFcb->Header.AllocationSize.QuadPart == pBuffer->AllocationSize.QuadPart || + pIrpSp->Parameters.SetFile.AdvanceOnly) + { + return STATUS_SUCCESS ; + } + + if( pFcb->Header.AllocationSize.QuadPart > pBuffer->AllocationSize.QuadPart) + { + // + // Truncating the file + // + if( !MmCanFileBeTruncated( pFileObject->SectionObjectPointer, + &pBuffer->AllocationSize)) + { + + ntStatus = STATUS_USER_MAPPED_FILE ; + } + else + { + // + // If this is a truncation we need to grab the paging IO resource. + // + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetAllocationInfo Acquiring Fcb PagingIo lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->PagingResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->PagingResource, + TRUE); + + bReleasePaging = TRUE; + + + pFcb->Header.AllocationSize = pBuffer->AllocationSize; + + pFcb->ObjectInformation->AllocationSize = pBuffer->AllocationSize; + + // + // Tell Cc that Allocation is moved. + // + bTellCc = TRUE; + + if( pFcb->Header.FileSize.QuadPart > pBuffer->AllocationSize.QuadPart) + { + // + // We are pulling the EOF back as well so we need to tell + // the service. + // + bTellService = TRUE; + + pFcb->Header.FileSize = pBuffer->AllocationSize; + + pFcb->ObjectInformation->EndOfFile = pBuffer->AllocationSize; + } + + } + } + else + { + // + // Tell Cc if allocation is increased. + // + bTellCc = pBuffer->AllocationSize.QuadPart > pFcb->Header.AllocationSize.QuadPart; + + pFcb->Header.AllocationSize = pBuffer->AllocationSize; + + pFcb->ObjectInformation->AllocationSize = pBuffer->AllocationSize; + } + + // + // Now Tell the server if we have to + // + if (bTellService) + { + ntStatus = AFSUpdateFileInformation( &pFcb->ObjectInformation->ParentObjectInformation->FileId, + pFcb->ObjectInformation, + &pFcb->AuthGroup); + } + + if (NT_SUCCESS(ntStatus)) + { + // + // Trim extents if we told the service - the update has done an implicit + // trim at the service. + // + if (bTellService) + { + AFSTrimExtents( pFcb, + &pFcb->Header.FileSize); + } + + KeQuerySystemTime( &pFcb->ObjectInformation->ChangeTime); + + SetFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + + if (bTellCc && + CcIsFileCached( pFileObject)) + { + CcSetFileSizes( pFileObject, + (PCC_FILE_SIZES)&pFcb->Header.AllocationSize); + } + } + else + { + // + // Put the saved values back + // + pFcb->Header.ValidDataLength = liSaveVDL; + pFcb->Header.FileSize = liSaveFileSize; + pFcb->Header.AllocationSize = liSaveAlloc; + pFcb->ObjectInformation->EndOfFile = liSaveFileSize; + pFcb->ObjectInformation->AllocationSize = liSaveAlloc; + } + + if( bReleasePaging) + { + + AFSReleaseResource( &pFcb->NPFcb->PagingResource); + } + + return ntStatus; +} + +NTSTATUS +AFSSetEndOfFileInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PFILE_END_OF_FILE_INFORMATION pBuffer; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + LARGE_INTEGER liSaveSize; + LARGE_INTEGER liSaveVDL; + LARGE_INTEGER liSaveAlloc; + BOOLEAN bModified = FALSE; + BOOLEAN bReleasePaging = FALSE; + BOOLEAN bTruncated = FALSE; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + pBuffer = (PFILE_END_OF_FILE_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + liSaveSize = pFcb->Header.FileSize; + liSaveAlloc = pFcb->Header.AllocationSize; + liSaveVDL = pFcb->Header.ValidDataLength; + + if( pFcb->Header.FileSize.QuadPart != pBuffer->EndOfFile.QuadPart && + !pIrpSp->Parameters.SetFile.AdvanceOnly) + { + + if( pBuffer->EndOfFile.QuadPart < pFcb->Header.FileSize.QuadPart) + { + + // Truncating the file + if( !MmCanFileBeTruncated( pFileObject->SectionObjectPointer, + &pBuffer->EndOfFile)) + { + + ntStatus = STATUS_USER_MAPPED_FILE; + } + else + { + // + // If this is a truncation we need to grab the paging + // IO resource. + // + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetAllocationInfo Acquiring Fcb PagingIo lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->PagingResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->PagingResource, + TRUE); + + bReleasePaging = TRUE; + + pFcb->Header.AllocationSize = pBuffer->EndOfFile; + + pFcb->Header.FileSize = pBuffer->EndOfFile; + + pFcb->ObjectInformation->EndOfFile = pBuffer->EndOfFile; + + pFcb->ObjectInformation->AllocationSize = pBuffer->EndOfFile; + + if( pFcb->Header.ValidDataLength.QuadPart > pFcb->Header.FileSize.QuadPart) + { + + pFcb->Header.ValidDataLength = pFcb->Header.FileSize; + } + + bTruncated = TRUE; + + bModified = TRUE; + } + } + else + { + // + // extending the file, move EOF + // + + pFcb->Header.FileSize = pBuffer->EndOfFile; + + pFcb->ObjectInformation->EndOfFile = pBuffer->EndOfFile; + + if (pFcb->Header.FileSize.QuadPart > pFcb->Header.AllocationSize.QuadPart) + { + // + // And Allocation as needed. + // + pFcb->Header.AllocationSize = pBuffer->EndOfFile; + + pFcb->ObjectInformation->AllocationSize = pBuffer->EndOfFile; + } + + bModified = TRUE; + } + } + + if (bModified) + { + + KeQuerySystemTime( &pFcb->ObjectInformation->ChangeTime); + + SetFlag( pFcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + + // + // Tell the server + // + + ntStatus = AFSUpdateFileInformation( &pFcb->ObjectInformation->ParentObjectInformation->FileId, + pFcb->ObjectInformation, + &pFcb->AuthGroup); + + if( NT_SUCCESS(ntStatus)) + { + // + // We are now good to go so tell CC. + // + CcSetFileSizes( pFileObject, + (PCC_FILE_SIZES)&pFcb->Header.AllocationSize); + + // + // And give up those extents + // + if( bTruncated) + { + + AFSTrimExtents( pFcb, + &pFcb->Header.FileSize); + } + } + else + { + pFcb->Header.ValidDataLength = liSaveVDL; + pFcb->Header.FileSize = liSaveSize; + pFcb->Header.AllocationSize = liSaveAlloc; + pFcb->ObjectInformation->EndOfFile = liSaveSize; + pFcb->ObjectInformation->AllocationSize = liSaveAlloc; + } + } + + if( bReleasePaging) + { + + AFSReleaseResource( &pFcb->NPFcb->PagingResource); + } + + return ntStatus; +} + +NTSTATUS +AFSProcessShareSetInfo( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + ULONG ulOutputBufferLen = 0, ulInputBufferLen; + FILE_INFORMATION_CLASS ulFileInformationClass; + void *pPipeInfo = NULL; + + __Enter + { + ulFileInformationClass = pIrpSp->Parameters.SetFile.FileInformationClass; + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessShareSetInfo On pipe %wZ Class %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ulFileInformationClass); + + pPipeInfo = AFSLockSystemBuffer( Irp, + pIrpSp->Parameters.SetFile.Length); + + if( pPipeInfo == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessShareSetInfo Failed to lock buffer on pipe %wZ\n", + &Ccb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Send the request to the service + // + + ntStatus = AFSNotifySetPipeInfo( Ccb, + (ULONG)ulFileInformationClass, + pIrpSp->Parameters.SetFile.Length, + pPipeInfo); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessShareSetInfo Failed to send request to service on pipe %wZ Status %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessShareSetInfo Completed request on pipe %wZ Class %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ulFileInformationClass); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSProcessShareQueryInfo( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + ULONG ulOutputBufferLen = 0, ulInputBufferLen; + FILE_INFORMATION_CLASS ulFileInformationClass; + void *pPipeInfo = NULL; + + __Enter + { + + ulFileInformationClass = pIrpSp->Parameters.QueryFile.FileInformationClass; + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessShareQueryInfo On pipe %wZ Class %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ulFileInformationClass); + + pPipeInfo = AFSLockSystemBuffer( Irp, + pIrpSp->Parameters.QueryFile.Length); + + if( pPipeInfo == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessShareQueryInfo Failed to lock buffer on pipe %wZ\n", + &Ccb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Send the request to the service + // + + ntStatus = AFSNotifyQueryPipeInfo( Ccb, + (ULONG)ulFileInformationClass, + pIrpSp->Parameters.QueryFile.Length, + pPipeInfo, + (ULONG *)&Irp->IoStatus.Information); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessShareQueryInfo Failed to send request to service on pipe %wZ Status %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ntStatus); + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessShareQueryInfo Completed request on pipe %wZ Class %08lX\n", + &Ccb->DirectoryCB->NameInformation.FileName, + ulFileInformationClass); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSProcessPIOCtlQueryInfo( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb, + IN OUT LONG *Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + FILE_INFORMATION_CLASS ulFileInformationClass; + + __Enter + { + + ulFileInformationClass = pIrpSp->Parameters.QueryFile.FileInformationClass; + + switch( ulFileInformationClass) + { + + case FileBasicInformation: + { + + if ( *Length >= sizeof( FILE_BASIC_INFORMATION)) + { + PFILE_BASIC_INFORMATION pBasic = (PFILE_BASIC_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pBasic->CreationTime.QuadPart = 0; + pBasic->LastAccessTime.QuadPart = 0; + pBasic->ChangeTime.QuadPart = 0; + pBasic->LastWriteTime.QuadPart = 0; + pBasic->FileAttributes = FILE_ATTRIBUTE_SYSTEM; + + *Length -= sizeof( FILE_BASIC_INFORMATION); + } + else + { + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + break; + } + + case FileStandardInformation: + { + + if ( *Length >= sizeof( FILE_STANDARD_INFORMATION)) + { + PFILE_STANDARD_INFORMATION pStandard = (PFILE_STANDARD_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + pStandard->NumberOfLinks = 1; + pStandard->DeletePending = 0; + pStandard->AllocationSize.QuadPart = 4096; + pStandard->EndOfFile.QuadPart = 4096; + pStandard->Directory = 0; + + *Length -= sizeof( FILE_STANDARD_INFORMATION); + } + else + { + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + break; + } + + case FileNameInformation: + { + + ULONG ulCopyLength = 0; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + USHORT usFullNameLength = 0; + PFILE_NAME_INFORMATION pNameInfo = (PFILE_NAME_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + UNICODE_STRING uniName; + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + if( *Length < FIELD_OFFSET( FILE_NAME_INFORMATION, FileName)) + { + ntStatus = STATUS_BUFFER_TOO_SMALL; + break; + } + + RtlZeroMemory( pNameInfo, + *Length); + + usFullNameLength = sizeof( WCHAR) + + AFSServerName.Length + + pCcb->FullFileName.Length; + + if( *Length >= (LONG)(FIELD_OFFSET( FILE_NAME_INFORMATION, FileName) + (LONG)usFullNameLength)) + { + ulCopyLength = (LONG)usFullNameLength; + } + else + { + ulCopyLength = *Length - FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + pNameInfo->FileNameLength = (ULONG)usFullNameLength; + + *Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName); + + if( ulCopyLength > 0) + { + + pNameInfo->FileName[ 0] = L'\\'; + ulCopyLength -= sizeof( WCHAR); + + *Length -= sizeof( WCHAR); + + if( ulCopyLength >= AFSServerName.Length) + { + + RtlCopyMemory( &pNameInfo->FileName[ 1], + AFSServerName.Buffer, + AFSServerName.Length); + + ulCopyLength -= AFSServerName.Length; + *Length -= AFSServerName.Length; + + if( ulCopyLength >= pCcb->FullFileName.Length) + { + + RtlCopyMemory( &pNameInfo->FileName[ 1 + (AFSServerName.Length/sizeof( WCHAR))], + pCcb->FullFileName.Buffer, + pCcb->FullFileName.Length); + + ulCopyLength -= pCcb->FullFileName.Length; + *Length -= pCcb->FullFileName.Length; + + uniName.Length = (USHORT)pNameInfo->FileNameLength; + uniName.MaximumLength = uniName.Length; + uniName.Buffer = pNameInfo->FileName; + } + else + { + + RtlCopyMemory( &pNameInfo->FileName[ 1 + (AFSServerName.Length/sizeof( WCHAR))], + pCcb->FullFileName.Buffer, + ulCopyLength); + + *Length -= ulCopyLength; + + uniName.Length = (USHORT)(sizeof( WCHAR) + AFSServerName.Length + ulCopyLength); + uniName.MaximumLength = uniName.Length; + uniName.Buffer = pNameInfo->FileName; + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIOCTL_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessPIOCtlQueryInfo (FileNameInformation) Returning %wZ\n", + &uniName); + } + } + + break; + } + + case FileInternalInformation: + { + + PFILE_INTERNAL_INFORMATION pInternalInfo = (PFILE_INTERNAL_INFORMATION)Irp->AssociatedIrp.SystemBuffer; + + if( *Length >= sizeof( FILE_INTERNAL_INFORMATION)) + { + + pInternalInfo->IndexNumber.HighPart = 0; + + pInternalInfo->IndexNumber.LowPart = 0; + + *Length -= sizeof( FILE_INTERNAL_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + break; + } + + default: + { + ntStatus = STATUS_INVALID_PARAMETER; + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIOCTL_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSProcessPIOCtlQueryInfo Not handling request %08lX\n", + ulFileInformationClass); + + break; + } + } + } + + return ntStatus; +} + diff --git a/src/WINNT/afsrdr/kernel/lib/AFSFlushBuffers.cpp b/src/WINNT/afsrdr/kernel/lib/AFSFlushBuffers.cpp new file mode 100644 index 0000000000..f4805162df --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSFlushBuffers.cpp @@ -0,0 +1,138 @@ +/* + * 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: AFSFlushBuffers.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSFlushBuffers( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = (AFSFcb *)pFileObject->FsContext; + AFSCcb *pCcb = (AFSCcb *)pFileObject->FsContext2; + IO_STATUS_BLOCK iosb = {0}; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __Enter + { + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSFlushBuffers Attempted access (%08lX) when pFcb == NULL\n", + Irp); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + if( pFcb->Header.NodeTypeCode == AFS_ROOT_FCB || + pFcb->Header.NodeTypeCode == AFS_ROOT_ALL ) + { + + // + // Once we support ADS's on directories we need to perform a flush ehre + // + + try_return( ntStatus = STATUS_SUCCESS); + + } + else if (pFcb->Header.NodeTypeCode != AFS_FILE_FCB) + { + // + // Nothing to flush Everything but files are write through + // + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + // + // The flush consists of two parts. We firstly flush our + // cache (if we have one), then we tell the service to write + // to the remote server + // + __try + { + + CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, NULL, 0, &iosb); + + if (!NT_SUCCESS( iosb.Status )) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSFlushBuffers CcFlushCache [1] failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + iosb.Status, + iosb.Information); + + try_return( ntStatus = iosb.Status ); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + try_return( ntStatus = GetExceptionCode()); + } + // + // Now, flush to the server - if there is stuff to do + // + + ntStatus = AFSFlushExtents( pFcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseExtentsWithFlush( pFcb); + + ntStatus = STATUS_SUCCESS; + } + +try_exit: + + AFSCompleteRequest( Irp, ntStatus); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp b/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp new file mode 100644 index 0000000000..54b3b4fb23 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp @@ -0,0 +1,8135 @@ +/* + * 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: AFSGeneric.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSExceptionFilter +// +// Description: +// +// This function is the exception handler +// +// Return: +// +// A status is returned for the function +// + +ULONG +AFSExceptionFilter( IN ULONG Code, + IN PEXCEPTION_POINTERS ExceptPtrs) +{ + + PEXCEPTION_RECORD ExceptRec; + PCONTEXT Context; + + __try + { + + ExceptRec = ExceptPtrs->ExceptionRecord; + + Context = ExceptPtrs->ContextRecord; + + AFSDbgLogMsg( 0, + 0, + "AFSExceptionFilter (Library) - EXR %p CXR %p Code %08lX Address %p Routine %p\n", + ExceptRec, + Context, + ExceptRec->ExceptionCode, + ExceptRec->ExceptionAddress, + (void *)AFSExceptionFilter); + + DbgPrint("**** Exception Caught in AFS Redirector Library ****\n"); + + DbgPrint("\n\nPerform the following WnDbg Cmds:\n"); + DbgPrint("\n\t.exr %p ; .cxr %p\n\n", ExceptRec, Context); + + DbgPrint("**** Exception Complete from AFS Redirector Library ****\n"); + + if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_BUGCHECK_EXCEPTION)) + { + + KeBugCheck( (ULONG)-2); + } + else + { + + AFSBreakPoint(); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + NOTHING; + } + + return EXCEPTION_EXECUTE_HANDLER; +} + +// +// Function: AFSLibExAllocatePoolWithTag() +// +// Purpose: Allocate Pool Memory. If BugCheck Exception flag +// is configured on, then bugcheck the system if +// a memory allocation fails. The routine should be +// used for all memory allocations that are to be freed +// when the library is unloaded. Memory allocations that +// are to survive library unload and reload should be +// performed using AFSExAllocatePoolWithTag() which is +// provided by the AFS Framework. +// +// Parameters: +// POOL_TYPE PoolType - Paged or NonPaged +// SIZE_T NumberOfBytes - requested allocation size +// ULONG Tag - Pool Allocation Tag to be applied for tracking +// +// Return: +// void * - the memory allocation +// + +void * +AFSLibExAllocatePoolWithTag( IN POOL_TYPE PoolType, + IN SIZE_T NumberOfBytes, + IN ULONG Tag) +{ + + void *pBuffer = NULL; + + pBuffer = ExAllocatePoolWithTag( PoolType, + NumberOfBytes, + Tag); + + if( pBuffer == NULL) + { + + if( BooleanFlagOn( AFSDebugFlags, AFS_DBG_BUGCHECK_EXCEPTION)) + { + + KeBugCheck( (ULONG)-2); + } + else + { + + AFSDbgLogMsg( 0, + 0, + "AFSLibExAllocatePoolWithTag failure Type %08lX Size %08lX Tag %08lX %08lX\n", + PoolType, + NumberOfBytes, + Tag, + PsGetCurrentThread()); + + AFSBreakPoint(); + } + } + + return pBuffer; +} + +// +// Function: AFSAcquireExcl() +// +// Purpose: Called to acquire a resource exclusive with optional wait +// +// Parameters: +// PERESOURCE Resource - Resource to acquire +// BOOLEAN Wait - Whether to block +// +// Return: +// BOOLEAN - Whether the mask was acquired +// + +BOOLEAN +AFSAcquireExcl( IN PERESOURCE Resource, + IN BOOLEAN wait) +{ + + BOOLEAN bStatus = FALSE; + + // + // Normal kernel APCs must be disabled before calling + // ExAcquireResourceExclusiveLite. Otherwise a bugcheck occurs. + // + + KeEnterCriticalRegion(); + + bStatus = ExAcquireResourceExclusiveLite( Resource, + wait); + + if( !bStatus) + { + + KeLeaveCriticalRegion(); + } + + return bStatus; +} + +BOOLEAN +AFSAcquireSharedStarveExclusive( IN PERESOURCE Resource, + IN BOOLEAN Wait) +{ + + BOOLEAN bStatus = FALSE; + + KeEnterCriticalRegion(); + + bStatus = ExAcquireSharedStarveExclusive( Resource, + Wait); + + if( !bStatus) + { + + KeLeaveCriticalRegion(); + } + + return bStatus; +} + +// +// Function: AFSAcquireShared() +// +// Purpose: Called to acquire a resource shared with optional wait +// +// Parameters: +// PERESOURCE Resource - Resource to acquire +// BOOLEAN Wait - Whether to block +// +// Return: +// BOOLEAN - Whether the mask was acquired +// + +BOOLEAN +AFSAcquireShared( IN PERESOURCE Resource, + IN BOOLEAN wait) +{ + + BOOLEAN bStatus = FALSE; + + KeEnterCriticalRegion(); + + bStatus = ExAcquireResourceSharedLite( Resource, + wait); + + if( !bStatus) + { + + KeLeaveCriticalRegion(); + } + + return bStatus; +} + +// +// Function: AFSReleaseResource() +// +// Purpose: Called to release a resource +// +// Parameters: +// PERESOURCE Resource - Resource to release +// +// Return: +// None +// + +void +AFSReleaseResource( IN PERESOURCE Resource) +{ + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReleaseResource Releasing lock %08lX Thread %08lX\n", + Resource, + PsGetCurrentThread()); + + ExReleaseResourceLite( Resource); + + KeLeaveCriticalRegion(); + + return; +} + +void +AFSConvertToShared( IN PERESOURCE Resource) +{ + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSConvertToShared Converting lock %08lX Thread %08lX\n", + Resource, + PsGetCurrentThread()); + + ExConvertExclusiveToSharedLite( Resource); + + return; +} + +// +// Function: AFSCompleteRequest +// +// Description: +// +// This function completes irps +// +// Return: +// +// A status is returned for the function +// + +void +AFSCompleteRequest( IN PIRP Irp, + IN ULONG Status) +{ + + Irp->IoStatus.Status = Status; + + IoCompleteRequest( Irp, + IO_NO_INCREMENT); + + return; +} + +// +// Function: AFSBuildCRCTable +// +// Description: +// +// This function builds the CRC table for mapping filenames to a CRC value. +// +// Return: +// +// A status is returned for the function +// + +void +AFSBuildCRCTable() +{ + ULONG crc; + int i, j; + + for ( i = 0; i <= 255; i++) + { + crc = i; + for ( j = 8; j > 0; j--) + { + if (crc & 1) + { + crc = ( crc >> 1 ) ^ CRC32_POLYNOMIAL; + } + else + { + crc >>= 1; + } + } + + AFSCRCTable[ i ] = crc; + } +} + +// +// Function: AFSGenerateCRC +// +// Description: +// +// Given a device and filename this function generates a CRC +// +// Return: +// +// A status is returned for the function +// + +ULONG +AFSGenerateCRC( IN PUNICODE_STRING FileName, + IN BOOLEAN UpperCaseName) +{ + + ULONG crc; + ULONG temp1, temp2; + UNICODE_STRING UpcaseString; + WCHAR *lpbuffer; + USHORT size = 0; + + if( !AFSCRCTable[1]) + { + AFSBuildCRCTable(); + } + + crc = 0xFFFFFFFFL; + + if( UpperCaseName) + { + + RtlUpcaseUnicodeString( &UpcaseString, + FileName, + TRUE); + + lpbuffer = UpcaseString.Buffer; + + size = (UpcaseString.Length/sizeof( WCHAR)); + } + else + { + + lpbuffer = FileName->Buffer; + + size = (FileName->Length/sizeof( WCHAR)); + } + + while (size--) + { + temp1 = (crc >> 8) & 0x00FFFFFFL; + temp2 = AFSCRCTable[((int)crc ^ *lpbuffer++) & 0xff]; + crc = temp1 ^ temp2; + } + + if( UpperCaseName) + { + + RtlFreeUnicodeString( &UpcaseString); + } + + crc ^= 0xFFFFFFFFL; + + return crc; +} + +void * +AFSLockSystemBuffer( IN PIRP Irp, + IN ULONG Length) +{ + + NTSTATUS Status = STATUS_SUCCESS; + void *pAddress = NULL; + + if( Irp->MdlAddress != NULL) + { + + pAddress = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, + NormalPagePriority); + } + else if( Irp->AssociatedIrp.SystemBuffer != NULL) + { + + pAddress = Irp->AssociatedIrp.SystemBuffer; + } + else if( Irp->UserBuffer != NULL) + { + + Irp->MdlAddress = IoAllocateMdl( Irp->UserBuffer, + Length, + FALSE, + FALSE, + Irp); + + if( Irp->MdlAddress != NULL) + { + + // + // Lock the new Mdl in memory. + // + + __try + { + PIO_STACK_LOCATION pIoStack; + pIoStack = IoGetCurrentIrpStackLocation( Irp); + + + MmProbeAndLockPages( Irp->MdlAddress, KernelMode, + (pIoStack->MajorFunction == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess); + + pAddress = MmGetSystemAddressForMdlSafe( Irp->MdlAddress, NormalPagePriority ); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + IoFreeMdl( Irp->MdlAddress ); + Irp->MdlAddress = NULL; + pAddress = NULL; + } + } + } + + return pAddress; +} + +void * +AFSLockUserBuffer( IN void *UserBuffer, + IN ULONG BufferLength, + OUT MDL ** Mdl) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + void *pAddress = NULL; + MDL *pMdl = NULL; + + __Enter + { + + pMdl = IoAllocateMdl( UserBuffer, + BufferLength, + FALSE, + FALSE, + NULL); + + if( pMdl == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Lock the new Mdl in memory. + // + + __try + { + + MmProbeAndLockPages( pMdl, + KernelMode, + IoWriteAccess); + + pAddress = MmGetSystemAddressForMdlSafe( pMdl, + NormalPagePriority); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + IoFreeMdl( pMdl); + pMdl = NULL; + pAddress = NULL; + } + + if( pMdl != NULL) + { + + *Mdl = pMdl; + } + +try_exit: + + NOTHING; + } + + return pAddress; +} + +void * +AFSMapToService( IN PIRP Irp, + IN ULONG ByteCount) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + void *pMappedBuffer = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + KAPC stApcState; + + __Enter + { + + if( pDevExt->Specific.Control.ServiceProcess == NULL) + { + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + if( Irp->MdlAddress == NULL) + { + + if( AFSLockSystemBuffer( Irp, + ByteCount) == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + } + + // + // Attach to the service process for mapping + // + + KeStackAttachProcess( pDevExt->Specific.Control.ServiceProcess, + (PRKAPC_STATE)&stApcState); + + pMappedBuffer = MmMapLockedPagesSpecifyCache( Irp->MdlAddress, + UserMode, + MmCached, + NULL, + FALSE, + NormalPagePriority); + + KeUnstackDetachProcess( (PRKAPC_STATE)&stApcState); + +try_exit: + + NOTHING; + } + + return pMappedBuffer; +} + +NTSTATUS +AFSUnmapServiceMappedBuffer( IN void *MappedBuffer, + IN PMDL Mdl) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + void *pMappedBuffer = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + KAPC stApcState; + + __Enter + { + + if( pDevExt->Specific.Control.ServiceProcess == NULL) + { + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + if( Mdl != NULL) + { + + // + // Attach to the service process for mapping + // + + KeStackAttachProcess( pDevExt->Specific.Control.ServiceProcess, + (PRKAPC_STATE)&stApcState); + + MmUnmapLockedPages( MappedBuffer, + Mdl); + + KeUnstackDetachProcess( (PRKAPC_STATE)&stApcState); + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSInitializeLibraryDevice() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = NULL; + + __Enter + { + + pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + // + // The PIOCtl file name + // + + RtlInitUnicodeString( &AFSPIOCtlName, + AFS_PIOCTL_FILE_INTERFACE_NAME); + + // + // And the global root share name + // + + RtlInitUnicodeString( &AFSGlobalRootName, + AFS_GLOBAL_ROOT_SHARE_NAME); + + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveLibraryDevice() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + } + + return ntStatus; +} + +NTSTATUS +AFSDefaultDispatch( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + AFSCompleteRequest( Irp, + ntStatus); + + return ntStatus; +} + +NTSTATUS +AFSInitializeGlobalDirectoryEntries() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pDirNode = NULL; + ULONG ulEntryLength = 0; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSObjectInfoCB *pObjectInfoCB = NULL; + AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL; + + __Enter + { + + // + // Initialize the global . entry + // + + pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation, + 0); + + if( pObjectInfoCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeGlobalDirectory AFSAllocateObjectInfo failure %08lX\n", + ntStatus); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + InterlockedIncrement( &pObjectInfoCB->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitializeGlobalDirectoryEntries Increment count on object %08lX Cnt %d\n", + pObjectInfoCB, + pObjectInfoCB->ObjectReferenceCount); + + ntStatus = STATUS_SUCCESS; + + ulEntryLength = sizeof( AFSDirectoryCB) + + sizeof( WCHAR); + + pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + AFSDeleteObjectInfo( pObjectInfoCB); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeGlobalDirectory AFS_DIR_ENTRY_TAG allocation failure\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + ExFreePool( pDirNode); + + AFSDeleteObjectInfo( pObjectInfoCB); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeGlobalDirectory AFS_DIR_ENTRY_NP_TAG allocation failure\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE | AFS_DIR_ENTRY_FAKE | AFS_DIR_ENTRY_VALID); + + pDirNode->FileIndex = (ULONG)AFS_DIR_ENTRY_DOT_INDEX; + + // + // Setup the names in the entry + // + + pDirNode->NameInformation.FileName.Length = sizeof( WCHAR); + + pDirNode->NameInformation.FileName.MaximumLength = sizeof( WCHAR); + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + pDirNode->NameInformation.FileName.Buffer[ 0] = L'.'; + + // + // Populate the rest of the data + // + + pObjectInfoCB->FileType = AFS_FILE_TYPE_DIRECTORY; + + pObjectInfoCB->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + + AFSGlobalDotDirEntry = pDirNode; + + // + // Now the .. entry + // + + pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation, + 0); + + if( pObjectInfoCB == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeGlobalDirectory AFSAllocateObjectInfo (2) failure %08lX\n", + ntStatus); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + InterlockedIncrement( &pObjectInfoCB->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitializeGlobalDirectoryEntries Increment count on object %08lX Cnt %d\n", + pObjectInfoCB, + pObjectInfoCB->ObjectReferenceCount); + + ntStatus = STATUS_SUCCESS; + + ulEntryLength = sizeof( AFSDirectoryCB) + + ( 2 * sizeof( WCHAR)); + + pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + ExFreePool( pDirNode); + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE | AFS_DIR_ENTRY_FAKE | AFS_DIR_ENTRY_VALID); + + pDirNode->FileIndex = (ULONG)AFS_DIR_ENTRY_DOT_DOT_INDEX; + + // + // Setup the names in the entry + // + + pDirNode->NameInformation.FileName.Length = 2 * sizeof( WCHAR); + + pDirNode->NameInformation.FileName.MaximumLength = 2 * sizeof( WCHAR); + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + pDirNode->NameInformation.FileName.Buffer[ 0] = L'.'; + + pDirNode->NameInformation.FileName.Buffer[ 1] = L'.'; + + // + // Populate the rest of the data + // + + pObjectInfoCB->FileType = AFS_FILE_TYPE_DIRECTORY; + + pObjectInfoCB->FileAttributes = FILE_ATTRIBUTE_DIRECTORY; + + AFSGlobalDotDotDirEntry = pDirNode; + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( AFSGlobalDotDirEntry != NULL) + { + + AFSDeleteObjectInfo( AFSGlobalDotDirEntry->ObjectInformation); + + ExDeleteResourceLite( &AFSGlobalDotDirEntry->NonPaged->Lock); + + ExFreePool( AFSGlobalDotDirEntry->NonPaged); + + ExFreePool( AFSGlobalDotDirEntry); + + AFSGlobalDotDirEntry = NULL; + } + + if( AFSGlobalDotDotDirEntry != NULL) + { + + AFSDeleteObjectInfo( AFSGlobalDotDotDirEntry->ObjectInformation); + + ExDeleteResourceLite( &AFSGlobalDotDotDirEntry->NonPaged->Lock); + + ExFreePool( AFSGlobalDotDotDirEntry->NonPaged); + + ExFreePool( AFSGlobalDotDotDirEntry); + + AFSGlobalDotDotDirEntry = NULL; + } + } + } + + return ntStatus; +} + +AFSDirectoryCB * +AFSInitDirEntry( IN AFSObjectInfoCB *ParentObjectInfo, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING TargetName, + IN AFSDirEnumEntry *DirEnumEntry, + IN ULONG FileIndex) +{ + + AFSDirectoryCB *pDirNode = NULL; + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulEntryLength = 0; + AFSDirEnumEntry *pDirEnumCB = NULL; + AFSFileID stTargetFileID; + AFSFcb *pVcb = NULL; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSObjectInfoCB *pObjectInfoCB = NULL; + BOOLEAN bAllocatedObjectCB = FALSE; + ULONGLONG ullIndex = 0; + AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitDirEntry Initializing entry %wZ parent FID %08lX-%08lX-%08lX-%08lX\n", + FileName, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique); + + // + // First thing is to locate/create our object information block + // for this entry + // + + AFSAcquireExcl( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + ullIndex = AFSCreateLowIndex( &DirEnumEntry->FileId); + + ntStatus = AFSLocateHashEntry( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfoCB); + + if( !NT_SUCCESS( ntStatus) || + pObjectInfoCB == NULL) + { + + // + // Allocate our object info cb + // + + pObjectInfoCB = AFSAllocateObjectInfo( ParentObjectInfo, + ullIndex); + + if( pObjectInfoCB == NULL) + { + + AFSReleaseResource( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeLock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + bAllocatedObjectCB = TRUE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitDirEntry initialized object %08lX Parent Object %08lX for %wZ\n", + pObjectInfoCB, + ParentObjectInfo, + FileName); + } + + InterlockedIncrement( &pObjectInfoCB->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitDirEntry Increment count on object %08lX Cnt %d\n", + pObjectInfoCB, + pObjectInfoCB->ObjectReferenceCount); + + AFSReleaseResource( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeLock); + + ntStatus = STATUS_SUCCESS; + + ulEntryLength = sizeof( AFSDirectoryCB) + + FileName->Length; + + if( TargetName != NULL) + { + + ulEntryLength += TargetName->Length; + } + + pDirNode = (AFSDirectoryCB *)AFSExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID); + + pDirNode->FileIndex = FileIndex; + + // + // Setup the names in the entry + // + + if( FileName->Length > 0) + { + + pDirNode->NameInformation.FileName.Length = FileName->Length; + + pDirNode->NameInformation.FileName.MaximumLength = FileName->Length; + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + RtlCopyMemory( pDirNode->NameInformation.FileName.Buffer, + FileName->Buffer, + pDirNode->NameInformation.FileName.Length); + + // + // Create a CRC for the file + // + + pDirNode->CaseSensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName, + FALSE); + + pDirNode->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName, + TRUE); + } + + if( TargetName != NULL && + TargetName->Length > 0) + { + + pDirNode->NameInformation.TargetName.Length = TargetName->Length; + + pDirNode->NameInformation.TargetName.MaximumLength = pDirNode->NameInformation.TargetName.Length; + + pDirNode->NameInformation.TargetName.Buffer = (WCHAR *)((char *)pDirNode + + sizeof( AFSDirectoryCB) + + pDirNode->NameInformation.FileName.Length); + + RtlCopyMemory( pDirNode->NameInformation.TargetName.Buffer, + TargetName->Buffer, + pDirNode->NameInformation.TargetName.Length); + } + + // + // If we allocated the object information cb then update the information + // + + if( bAllocatedObjectCB) + { + + // + // Populate the rest of the data + // + + pObjectInfoCB->FileId = DirEnumEntry->FileId; + + pObjectInfoCB->TargetFileId = DirEnumEntry->TargetFileId; + + pObjectInfoCB->FileType = DirEnumEntry->FileType; + + pObjectInfoCB->CreationTime = DirEnumEntry->CreationTime; + + pObjectInfoCB->LastAccessTime = DirEnumEntry->LastAccessTime; + + pObjectInfoCB->LastWriteTime = DirEnumEntry->LastWriteTime; + + pObjectInfoCB->ChangeTime = DirEnumEntry->ChangeTime; + + pObjectInfoCB->EndOfFile = DirEnumEntry->EndOfFile; + + pObjectInfoCB->AllocationSize = DirEnumEntry->AllocationSize; + + pObjectInfoCB->FileAttributes = DirEnumEntry->FileAttributes; + + if( pObjectInfoCB->FileType == AFS_FILE_TYPE_MOUNTPOINT || + pObjectInfoCB->FileType == AFS_FILE_TYPE_SYMLINK || + pObjectInfoCB->FileType == AFS_FILE_TYPE_DFSLINK) + { + + pObjectInfoCB->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + } + + pObjectInfoCB->EaSize = DirEnumEntry->EaSize; + + // + // Object specific information + // + + pObjectInfoCB->Links = DirEnumEntry->Links; + + pObjectInfoCB->Expiration = DirEnumEntry->Expiration; + + pObjectInfoCB->DataVersion = DirEnumEntry->DataVersion; + + // + // Check for the case where we have a filetype of SymLink but both the TargetFid and the + // TargetName are empty. In this case set the filetype to zero so we evaluate it later in + // the code + // + + if( pObjectInfoCB->FileType == AFS_FILE_TYPE_SYMLINK && + pObjectInfoCB->TargetFileId.Vnode == 0 && + pObjectInfoCB->TargetFileId.Unique == 0 && + pDirNode->NameInformation.TargetName.Length == 0) + { + + // + // This will ensure we perform a validation on the node + // + + pObjectInfoCB->FileType = AFS_FILE_TYPE_UNKNOWN; + } + + if( pObjectInfoCB->FileType == AFS_FILE_TYPE_UNKNOWN) + { + + SetFlag( pObjectInfoCB->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED); + } + } + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( pNonPagedDirEntry != NULL) + { + + ExDeleteResourceLite( &pNonPagedDirEntry->Lock); + + AFSExFreePool( pNonPagedDirEntry); + } + + if( pDirNode != NULL) + { + + AFSExFreePool( pDirNode); + + pDirNode = NULL; + } + + // + // Dereference our object info block if we have one + // + + if( pObjectInfoCB != NULL) + { + + InterlockedDecrement( &pObjectInfoCB->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitDirEntry Decrement count on object %08lX Cnt %d\n", + pObjectInfoCB, + pObjectInfoCB->ObjectReferenceCount); + + if( bAllocatedObjectCB) + { + + ASSERT( pObjectInfoCB->ObjectReferenceCount == 0); + + AFSDeleteObjectInfo( pObjectInfoCB); + } + } + } + } + + return pDirNode; +} + +BOOLEAN +AFSCheckForReadOnlyAccess( IN ACCESS_MASK DesiredAccess, + IN BOOLEAN DirectoryEntry) +{ + + BOOLEAN bReturn = TRUE; + ACCESS_MASK stAccessMask = 0; + + // + // Get rid of anything we don't know about + // + + DesiredAccess = (DesiredAccess & + ( DELETE | + READ_CONTROL | + WRITE_OWNER | + WRITE_DAC | + SYNCHRONIZE | + ACCESS_SYSTEM_SECURITY | + FILE_WRITE_DATA | + FILE_READ_EA | + FILE_WRITE_EA | + FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES | + FILE_LIST_DIRECTORY | + FILE_TRAVERSE | + FILE_DELETE_CHILD | + FILE_APPEND_DATA)); + + // + // Our 'read only' access mask. These are the accesses we will + // allow for a read only file + // + + stAccessMask = DELETE | + READ_CONTROL | + WRITE_OWNER | + WRITE_DAC | + SYNCHRONIZE | + ACCESS_SYSTEM_SECURITY | + FILE_READ_DATA | + FILE_READ_EA | + FILE_WRITE_EA | + FILE_READ_ATTRIBUTES | + FILE_WRITE_ATTRIBUTES | + FILE_EXECUTE | + FILE_LIST_DIRECTORY | + FILE_TRAVERSE; + + // + // For a directory, add in the directory specific accesses + // + + if( DirectoryEntry) + { + + stAccessMask |= FILE_ADD_SUBDIRECTORY | + FILE_ADD_FILE | + FILE_DELETE_CHILD; + } + + if( FlagOn( DesiredAccess, ~stAccessMask)) + { + + // + // A write access is set ... + // + + bReturn = FALSE; + } + + return bReturn; +} + +NTSTATUS +AFSEvaluateNode( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirEntry) +{ + + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirEnumEntry *pDirEntry = NULL; + UNICODE_STRING uniTargetName; + + __Enter + { + + ntStatus = AFSEvaluateTargetByID( DirEntry->ObjectInformation, + AuthGroup, + FALSE, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + DirEntry->ObjectInformation->TargetFileId = pDirEntry->TargetFileId; + + DirEntry->ObjectInformation->Expiration = pDirEntry->Expiration; + + DirEntry->ObjectInformation->DataVersion = pDirEntry->DataVersion; + + DirEntry->ObjectInformation->FileType = pDirEntry->FileType; + + DirEntry->ObjectInformation->CreationTime = pDirEntry->CreationTime; + + DirEntry->ObjectInformation->LastAccessTime = pDirEntry->LastAccessTime; + + DirEntry->ObjectInformation->LastWriteTime = pDirEntry->LastWriteTime; + + DirEntry->ObjectInformation->ChangeTime = pDirEntry->ChangeTime; + + DirEntry->ObjectInformation->EndOfFile = pDirEntry->EndOfFile; + + DirEntry->ObjectInformation->AllocationSize = pDirEntry->AllocationSize; + + DirEntry->ObjectInformation->FileAttributes = pDirEntry->FileAttributes; + + DirEntry->ObjectInformation->EaSize = pDirEntry->EaSize; + + DirEntry->ObjectInformation->Links = pDirEntry->Links; + + // + // If we have a target name then see if it needs updating ... + // + + if( pDirEntry->TargetNameLength > 0) + { + + // + // Update the target name information if needed + // + + uniTargetName.Length = (USHORT)pDirEntry->TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset); + + AFSAcquireExcl( &DirEntry->NonPaged->Lock, + TRUE); + + if( DirEntry->NameInformation.TargetName.Length == 0 || + RtlCompareUnicodeString( &uniTargetName, + &DirEntry->NameInformation.TargetName, + TRUE) != 0) + { + + // + // Update the target name + // + + ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName, + &DirEntry->Flags, + uniTargetName.Buffer, + uniTargetName.Length); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + try_return( ntStatus); + } + } + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + } + +try_exit: + + if( pDirEntry != NULL) + { + + AFSExFreePool( pDirEntry); + } + } + + return ntStatus; +} + +NTSTATUS +AFSValidateSymLink( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirEntry) +{ + + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirEnumEntry *pDirEntry = NULL; + UNICODE_STRING uniTargetName; + + __Enter + { + + ntStatus = AFSEvaluateTargetByID( DirEntry->ObjectInformation, + AuthGroup, + FALSE, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + if( pDirEntry->FileType == AFS_FILE_TYPE_UNKNOWN || + pDirEntry->FileType == AFS_FILE_TYPE_INVALID) + { + + try_return( ntStatus = STATUS_OBJECT_NAME_NOT_FOUND); + } + + DirEntry->ObjectInformation->TargetFileId = pDirEntry->TargetFileId; + + DirEntry->ObjectInformation->Expiration = pDirEntry->Expiration; + + DirEntry->ObjectInformation->DataVersion = pDirEntry->DataVersion; + + // + // Update the target name information if needed + // + + uniTargetName.Length = (USHORT)pDirEntry->TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset); + + if( uniTargetName.Length > 0) + { + + AFSAcquireExcl( &DirEntry->NonPaged->Lock, + TRUE); + + if( DirEntry->NameInformation.TargetName.Length == 0 || + RtlCompareUnicodeString( &uniTargetName, + &DirEntry->NameInformation.TargetName, + TRUE) != 0) + { + + // + // Update the target name + // + + ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName, + &DirEntry->Flags, + uniTargetName.Buffer, + uniTargetName.Length); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + } + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + } + + // + // If the FileType is the same then nothing to do since it IS + // a SymLink + // + + if( pDirEntry->FileType == DirEntry->ObjectInformation->FileType) + { + + ASSERT( pDirEntry->FileType == AFS_FILE_TYPE_SYMLINK); + + try_return( ntStatus = STATUS_SUCCESS); + } + + DirEntry->ObjectInformation->FileType = pDirEntry->FileType; + + DirEntry->ObjectInformation->CreationTime = pDirEntry->CreationTime; + + DirEntry->ObjectInformation->LastAccessTime = pDirEntry->LastAccessTime; + + DirEntry->ObjectInformation->LastWriteTime = pDirEntry->LastWriteTime; + + DirEntry->ObjectInformation->ChangeTime = pDirEntry->ChangeTime; + + DirEntry->ObjectInformation->EndOfFile = pDirEntry->EndOfFile; + + DirEntry->ObjectInformation->AllocationSize = pDirEntry->AllocationSize; + + DirEntry->ObjectInformation->FileAttributes = pDirEntry->FileAttributes; + + DirEntry->ObjectInformation->EaSize = pDirEntry->EaSize; + + DirEntry->ObjectInformation->Links = pDirEntry->Links; + +try_exit: + + if( pDirEntry != NULL) + { + + AFSExFreePool( pDirEntry); + } + } + + return ntStatus; +} + +NTSTATUS +AFSInvalidateCache( IN AFSInvalidateCacheCB *InvalidateCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFcb *pDcb = NULL, *pFcb = NULL, *pNextFcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSFcb *pTargetDcb = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + AFSDirectoryCB *pCurrentDirEntry = NULL; + BOOLEAN bIsChild = FALSE; + ULONGLONG ullIndex = 0; + AFSObjectInfoCB *pObjectInfo = NULL; + IO_STATUS_BLOCK stIoStatus; + ULONG ulFilter = 0; + + __Enter + { + + // + // Need to locate the Fcb for the directory to purge + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n", + &pDevExt->Specific.RDR.VolumeTreeLock, + PsGetCurrentThread()); + + // + // Starve any exclusive waiters on this paticular call + // + + AFSAcquireSharedStarveExclusive( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE); + + // + // Locate the volume node + // + + ullIndex = AFSCreateHighIndex( &InvalidateCB->FileID); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( pVolumeCB != NULL) + { + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + } + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + if( !NT_SUCCESS( ntStatus) || + pVolumeCB == NULL) + { + try_return( ntStatus = STATUS_SUCCESS); + } + + // + // If this is a whole volume invalidation then go do it now + // + + if( InvalidateCB->WholeVolume || + AFSIsVolumeFID( &InvalidateCB->FileID)) + { + + ntStatus = AFSInvalidateVolume( pVolumeCB, + InvalidateCB->Reason); + + AFSFsRtlNotifyFullReportChange( &pVolumeCB->ObjectInformation, + NULL, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE, + FILE_ACTION_MODIFIED); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + try_return( ntStatus); + } + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Decrement count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + ullIndex = AFSCreateLowIndex( &InvalidateCB->FileID); + + ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfo); + + if( pObjectInfo != NULL) + { + + // + // Reference the node so it won't be torn down + // + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Increment count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( !NT_SUCCESS( ntStatus) || + pObjectInfo == NULL) + { + try_return( ntStatus = STATUS_SUCCESS); + } + + if( pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK || + pObjectInfo->FileType == AFS_FILE_TYPE_DFSLINK || + pObjectInfo->FileType == AFS_FILE_TYPE_MOUNTPOINT) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Invalidation on node type %d for fid %08lX-%08lX-%08lX-%08lX Reason %d\n", + pObjectInfo->FileType, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + InvalidateCB->Reason); + + // + // We only act on the mount point itself, not the target. If the + // node has been deleted then mark it as such otherwise indicate + // it requires verification + // + + if( InvalidateCB->Reason == AFS_INVALIDATE_DELETED) + { + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID); + } + else + { + + if( InvalidateCB->Reason == AFS_INVALIDATE_FLUSHED || + InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION) + { + pObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1; + } + + pObjectInfo->Expiration.QuadPart = 0; + + pObjectInfo->TargetFileId.Vnode = 0; + + pObjectInfo->TargetFileId.Unique = 0; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + } + + ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME; + + if( InvalidateCB->Reason == AFS_INVALIDATE_CREDS) + { + ulFilter |= FILE_NOTIFY_CHANGE_SECURITY; + } + + if( InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION) + { + ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; + } + else + { + ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + } + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + NULL, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES, + FILE_ACTION_MODIFIED); + + try_return( ntStatus); + } + + // + // Depending on the reason for invalidation then perform work on the node + // + + switch( InvalidateCB->Reason) + { + + case AFS_INVALIDATE_DELETED: + { + + // + // Mark this node as invalid + // + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DELETED); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Set DELETE flag on fid %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + if( pObjectInfo->ParentObjectInformation != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Set VERIFY flag on parent fid %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->ParentObjectInformation->FileId.Cell, + pObjectInfo->ParentObjectInformation->FileId.Volume, + pObjectInfo->ParentObjectInformation->FileId.Vnode, + pObjectInfo->ParentObjectInformation->FileId.Unique); + + SetFlag( pObjectInfo->ParentObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY); + pObjectInfo->ParentObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1; + pObjectInfo->ParentObjectInformation->Expiration.QuadPart = 0; + } + + if( pObjectInfo->FileType == AFS_FILE_TYPE_DIRECTORY) + { + ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME; + } + else + { + ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME; + } + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + NULL, + ulFilter, + FILE_ACTION_REMOVED); + + break; + } + + case AFS_INVALIDATE_FLUSHED: + { + + if( pObjectInfo->FileType == AFS_FILE_TYPE_FILE && + pObjectInfo->Fcb != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Flush/purge file fid %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Resource, + TRUE); + + __try + { + + CcFlushCache( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInvalidateCache CcFlushCache failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + + CcPurgeCacheSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + FALSE); + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + } + + AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Resource); + + // + // Clear out the extents + // Get rid of them (note this involves waiting + // for any writes or reads to the cache to complete) + // + + (VOID) AFSTearDownFcbExtents( pObjectInfo->Fcb); + } + + // Fall through to the default processing + } + + default: + { + + if( pObjectInfo->FileType == AFS_FILE_TYPE_DIRECTORY) + { + ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME; + } + else + { + ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME; + } + + if( InvalidateCB->Reason == AFS_INVALIDATE_CREDS) + { + ulFilter |= FILE_NOTIFY_CHANGE_SECURITY; + } + + if( InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION) + { + ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; + } + else + { + ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + } + + AFSFsRtlNotifyFullReportChange( pObjectInfo->ParentObjectInformation, + NULL, + ulFilter, + FILE_ACTION_MODIFIED); + + // + // Indicate this node requires re-evaluation for the remaining reasons + // + + pObjectInfo->Expiration.QuadPart = 0; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + + if( InvalidateCB->Reason == AFS_INVALIDATE_FLUSHED || + InvalidateCB->Reason == AFS_INVALIDATE_DATA_VERSION) + { + pObjectInfo->DataVersion.QuadPart = (ULONGLONG)-1; + + if( pObjectInfo->FileType == AFS_FILE_TYPE_FILE) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Setting VERIFY_DATA flag on fid %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA); + } + } + + break; + } + } + +try_exit: + + if( pObjectInfo != NULL) + { + + InterlockedDecrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateCache Decrement count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + } + + return ntStatus; +} + +BOOLEAN +AFSIsChildOfParent( IN AFSFcb *Dcb, + IN AFSFcb *Fcb) +{ + + BOOLEAN bIsChild = FALSE; + AFSFcb *pCurrentFcb = Fcb; + + while( pCurrentFcb != NULL) + { + + if( pCurrentFcb->ObjectInformation->ParentObjectInformation == Dcb->ObjectInformation) + { + + bIsChild = TRUE; + + break; + } + + pCurrentFcb = pCurrentFcb->ObjectInformation->ParentObjectInformation->Fcb; + } + + return bIsChild; +} + +inline +ULONGLONG +AFSCreateHighIndex( IN AFSFileID *FileID) +{ + + ULONGLONG ullIndex = 0; + + ullIndex = (((ULONGLONG)FileID->Cell << 32) | FileID->Volume); + + return ullIndex; +} + +inline +ULONGLONG +AFSCreateLowIndex( IN AFSFileID *FileID) +{ + + ULONGLONG ullIndex = 0; + + ullIndex = (((ULONGLONG)FileID->Vnode << 32) | FileID->Unique); + + return ullIndex; +} + +BOOLEAN +AFSCheckAccess( IN ACCESS_MASK DesiredAccess, + IN ACCESS_MASK GrantedAccess, + IN BOOLEAN DirectoryEntry) +{ + + BOOLEAN bAccessGranted = TRUE; + + // + // Check if we are asking for read/write and granted only read only + // NOTE: There will be more checks here + // + + if( !AFSCheckForReadOnlyAccess( DesiredAccess, + DirectoryEntry) && + AFSCheckForReadOnlyAccess( GrantedAccess, + DirectoryEntry)) + { + + bAccessGranted = FALSE; + } + + return bAccessGranted; +} + +NTSTATUS +AFSGetDriverStatus( IN AFSDriverStatusRespCB *DriverStatus) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + // + // Start with read + // + + DriverStatus->Status = AFS_DRIVER_STATUS_READY; + + if( AFSGlobalRoot == NULL) + { + + // + // We are not ready + // + + DriverStatus->Status = AFS_DRIVER_STATUS_NOT_READY; + } + + if( pControlDevExt->Specific.Control.CommServiceCB.IrpPoolControlFlag != POOL_ACTIVE) + { + + // + // No service yet + // + + DriverStatus->Status = AFS_DRIVER_STATUS_NO_SERVICE; + } + + return ntStatus; +} + +NTSTATUS +AFSSubstituteSysName( IN UNICODE_STRING *ComponentName, + IN UNICODE_STRING *SubstituteName, + IN ULONG StringIndex) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + AFSSysNameCB *pSysName = NULL; + ERESOURCE *pSysNameLock = NULL; + ULONG ulIndex = 1; + USHORT usIndex = 0; + UNICODE_STRING uniSysName; + + __Enter + { + +#if defined(_WIN64) + + if( IoIs32bitProcess( NULL)) + { + + pSysNameLock = &pControlDevExt->Specific.Control.SysName32ListLock; + + pSysName = pControlDevExt->Specific.Control.SysName32ListHead; + } + else + { + + pSysNameLock = &pControlDevExt->Specific.Control.SysName64ListLock; + + pSysName = pControlDevExt->Specific.Control.SysName64ListHead; + } +#else + + pSysNameLock = &pControlDevExt->Specific.Control.SysName32ListLock; + + pSysName = pControlDevExt->Specific.Control.SysName32ListHead; + +#endif + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSubstituteSysName Acquiring SysName lock %08lX SHARED %08lX\n", + pSysNameLock, + PsGetCurrentThread()); + + AFSAcquireShared( pSysNameLock, + TRUE); + + // + // Find where we are in the list + // + + while( pSysName != NULL && + ulIndex < StringIndex) + { + + pSysName = pSysName->fLink; + + ulIndex++; + } + + if( pSysName == NULL) + { + + try_return( ntStatus = STATUS_OBJECT_NAME_NOT_FOUND); + } + + RtlInitUnicodeString( &uniSysName, + L"@SYS"); + // + // If it is a full component of @SYS then just substitue the + // name in + // + + if( RtlCompareUnicodeString( &uniSysName, + ComponentName, + TRUE) == 0) + { + + SubstituteName->Length = pSysName->SysName.Length; + SubstituteName->MaximumLength = SubstituteName->Length; + + SubstituteName->Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + SubstituteName->Length, + AFS_SUBST_BUFFER_TAG); + + if( SubstituteName->Buffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( SubstituteName->Buffer, + pSysName->SysName.Buffer, + pSysName->SysName.Length); + } + else + { + + usIndex = 0; + + while( ComponentName->Buffer[ usIndex] != L'@') + { + + usIndex++; + } + + SubstituteName->Length = (usIndex * sizeof( WCHAR)) + pSysName->SysName.Length; + SubstituteName->MaximumLength = SubstituteName->Length; + + SubstituteName->Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + SubstituteName->Length, + AFS_SUBST_BUFFER_TAG); + + if( SubstituteName->Buffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( SubstituteName->Buffer, + ComponentName->Buffer, + usIndex * sizeof( WCHAR)); + + RtlCopyMemory( &SubstituteName->Buffer[ usIndex], + pSysName->SysName.Buffer, + pSysName->SysName.Length); + } + +try_exit: + + AFSReleaseResource( pSysNameLock); + } + + return ntStatus; +} + +NTSTATUS +AFSSubstituteNameInPath( IN OUT UNICODE_STRING *FullPathName, + IN OUT UNICODE_STRING *ComponentName, + IN UNICODE_STRING *SubstituteName, + IN OUT UNICODE_STRING *RemainingPath, + IN BOOLEAN FreePathName) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniPathName; + USHORT usPrefixNameLen = 0; + SHORT sNameLenDelta = 0; + + __Enter + { + + // + // If the passed in name can handle the additional length + // then just moves things around + // + + sNameLenDelta = SubstituteName->Length - ComponentName->Length; + + usPrefixNameLen = (USHORT)(ComponentName->Buffer - FullPathName->Buffer); + + if( FullPathName->MaximumLength > FullPathName->Length + sNameLenDelta) + { + + if( FullPathName->Length > usPrefixNameLen + ComponentName->Length) + { + + RtlMoveMemory( &FullPathName->Buffer[ ((usPrefixNameLen*sizeof( WCHAR) + SubstituteName->Length)/sizeof( WCHAR))], + &FullPathName->Buffer[ ((usPrefixNameLen*sizeof( WCHAR) + ComponentName->Length)/sizeof( WCHAR))], + FullPathName->Length - usPrefixNameLen*sizeof( WCHAR) - ComponentName->Length); + } + + RtlCopyMemory( &FullPathName->Buffer[ usPrefixNameLen], + SubstituteName->Buffer, + SubstituteName->Length); + + FullPathName->Length += sNameLenDelta; + + ComponentName->Length += sNameLenDelta; + + ComponentName->MaximumLength = ComponentName->Length; + + if ( RemainingPath->Buffer) + { + + RemainingPath->Buffer += sNameLenDelta/sizeof( WCHAR); + } + + try_return( ntStatus); + } + + // + // Need to re-allocate the buffer + // + + uniPathName.Length = FullPathName->Length - + ComponentName->Length + + SubstituteName->Length; + + uniPathName.MaximumLength = FullPathName->MaximumLength + PAGE_SIZE; + + uniPathName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniPathName.MaximumLength, + AFS_NAME_BUFFER_FOUR_TAG); + + if( uniPathName.Buffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + usPrefixNameLen = (USHORT)(ComponentName->Buffer - FullPathName->Buffer); + + usPrefixNameLen *= sizeof( WCHAR); + + RtlZeroMemory( uniPathName.Buffer, + uniPathName.MaximumLength); + + RtlCopyMemory( uniPathName.Buffer, + FullPathName->Buffer, + usPrefixNameLen); + + RtlCopyMemory( &uniPathName.Buffer[ (usPrefixNameLen/sizeof( WCHAR))], + SubstituteName->Buffer, + SubstituteName->Length); + + if( FullPathName->Length > usPrefixNameLen + ComponentName->Length) + { + + RtlCopyMemory( &uniPathName.Buffer[ (usPrefixNameLen + SubstituteName->Length)/sizeof( WCHAR)], + &FullPathName->Buffer[ (usPrefixNameLen + ComponentName->Length)/sizeof( WCHAR)], + FullPathName->Length - usPrefixNameLen - ComponentName->Length); + } + + ComponentName->Buffer = uniPathName.Buffer + (ComponentName->Buffer - FullPathName->Buffer); + + ComponentName->Length += sNameLenDelta; + + ComponentName->MaximumLength = ComponentName->Length; + + if ( RemainingPath->Buffer) + { + + RemainingPath->Buffer = uniPathName.Buffer + + (RemainingPath->Buffer - FullPathName->Buffer) + + sNameLenDelta/sizeof( WCHAR); + } + + if( FreePathName) + { + AFSExFreePool( FullPathName->Buffer); + } + + *FullPathName = uniPathName; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSInvalidateVolume( IN AFSVolumeCB *VolumeCB, + IN ULONG Reason) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFcb *pFcb = NULL; + AFSObjectInfoCB *pCurrentObject = NULL; + ULONG ulFilter = 0; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateVolume Invalidate volume fid %08lX-%08lX-%08lX-%08lX Reason %08lX\n", + VolumeCB->ObjectInformation.FileId.Cell, + VolumeCB->ObjectInformation.FileId.Volume, + VolumeCB->ObjectInformation.FileId.Vnode, + VolumeCB->ObjectInformation.FileId.Unique, + Reason); + + // + // Depending on the reason for invalidation then perform work on the node + // + + switch( Reason) + { + + case AFS_INVALIDATE_DELETED: + { + + // + // Mark this volume as invalid + // + + VolumeCB->ObjectInformation.Expiration.QuadPart = 0; + + SetFlag( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID); + + SetFlag( VolumeCB->Flags, AFS_VOLUME_FLAGS_OFFLINE); + + AFSFsRtlNotifyFullReportChange( &VolumeCB->ObjectInformation, + NULL, + FILE_NOTIFY_CHANGE_DIR_NAME, + FILE_ACTION_REMOVED); + + AFSAcquireShared( VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + pCurrentObject = VolumeCB->ObjectInfoListHead; + + while( pCurrentObject != NULL) + { + + if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY) + { + ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME; + } + else + { + ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME; + } + + AFSFsRtlNotifyFullReportChange( pCurrentObject, + NULL, + ulFilter, + FILE_ACTION_REMOVED); + + SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID); + + pFcb = pCurrentObject->Fcb; + + if( pFcb != NULL && + pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + + // + // Clear out the extents + // And get rid of them (note this involves waiting + // for any writes or reads to the cache to complete) + // + + (VOID) AFSTearDownFcbExtents( pFcb); + } + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + } + + AFSReleaseResource( VolumeCB->ObjectInfoTree.TreeLock); + + break; + } + + default: + { + + // + // Indicate this node requires re-evaluation for the remaining reasons + // + + VolumeCB->ObjectInformation.Expiration.QuadPart = 0; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateVolume Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n", + VolumeCB->ObjectInformation.FileId.Cell, + VolumeCB->ObjectInformation.FileId.Volume, + VolumeCB->ObjectInformation.FileId.Vnode, + VolumeCB->ObjectInformation.FileId.Unique); + + SetFlag( VolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_VERIFY); + + if( Reason == AFS_INVALIDATE_FLUSHED || + Reason == AFS_INVALIDATE_DATA_VERSION) + { + + VolumeCB->ObjectInformation.DataVersion.QuadPart = (ULONGLONG)-1; + } + + // + // Notify anyone that cares + // + + ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME; + + if( Reason == AFS_INVALIDATE_CREDS) + { + ulFilter |= FILE_NOTIFY_CHANGE_SECURITY; + } + + if( Reason == AFS_INVALIDATE_DATA_VERSION) + { + ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; + } + else + { + ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + } + + AFSFsRtlNotifyFullReportChange( &VolumeCB->ObjectInformation, + NULL, + ulFilter, + FILE_ACTION_MODIFIED); + + // + // Volume invalidations require all objects in the volume be re-verified + // + + AFSAcquireShared( VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + pCurrentObject = VolumeCB->ObjectInfoListHead; + + while( pCurrentObject != NULL) + { + + pCurrentObject->Expiration.QuadPart = 0; + + pCurrentObject->TargetFileId.Vnode = 0; + + pCurrentObject->TargetFileId.Unique = 0; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateVolume Setting VERIFY flag on fid %08lX-%08lX-%08lX-%08lX\n", + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY); + + if( Reason == AFS_INVALIDATE_FLUSHED || + Reason == AFS_INVALIDATE_DATA_VERSION) + { + + pCurrentObject->DataVersion.QuadPart = (ULONGLONG)-1; + + if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInvalidateVolume Setting VERIFY_DATA flag on fid %08lX-%08lX-%08lX-%08lX\n", + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA); + } + } + + if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY) + { + ulFilter = FILE_NOTIFY_CHANGE_DIR_NAME; + } + else + { + ulFilter = FILE_NOTIFY_CHANGE_FILE_NAME; + } + + if( Reason == AFS_INVALIDATE_CREDS) + { + ulFilter |= FILE_NOTIFY_CHANGE_SECURITY; + } + + if( Reason == AFS_INVALIDATE_DATA_VERSION) + { + ulFilter |= FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE; + } + else + { + ulFilter |= FILE_NOTIFY_CHANGE_ATTRIBUTES; + } + + AFSFsRtlNotifyFullReportChange( pCurrentObject, + NULL, + ulFilter, + FILE_ACTION_MODIFIED); + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + } + + AFSReleaseResource( VolumeCB->ObjectInfoTree.TreeLock); + + break; + } + } + } + + return ntStatus; +} + +NTSTATUS +AFSVerifyEntry( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirEnumEntry *pDirEnumEntry = NULL; + AFSObjectInfoCB *pObjectInfo = DirEntry->ObjectInformation; + IO_STATUS_BLOCK stIoStatus; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSVerifyEntry Verifying entry %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + ntStatus = AFSEvaluateTargetByID( pObjectInfo, + AuthGroup, + FALSE, + &pDirEnumEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateEntry Evaluate Target failed %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + // + // Check the data version of the file + // + + if( pObjectInfo->DataVersion.QuadPart == pDirEnumEntry->DataVersion.QuadPart && + !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyEntry No DV change %I64X for Fcb %wZ FID %08lX-%08lX-%08lX-%08lX\n", + pObjectInfo->DataVersion.QuadPart, + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + // + // We are ok, just get out + // + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + + try_return( ntStatus = STATUS_SUCCESS); + } + + // + // New data version so we will need to process the node based on the type + // + + switch( pDirEnumEntry->FileType) + { + + case AFS_FILE_TYPE_MOUNTPOINT: + { + + // + // For a mount point we need to ensure the target is the same + // + + if( !AFSIsEqualFID( &pObjectInfo->TargetFileId, + &pDirEnumEntry->TargetFileId)) + { + + } + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + } + + break; + } + + case AFS_FILE_TYPE_SYMLINK: + { + + ASSERT( pDirEnumEntry->TargetNameLength > 0); + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + } + + break; + } + + case AFS_FILE_TYPE_FILE: + { + FILE_OBJECT * pCCFileObject = NULL; + BOOLEAN bPurgeExtents = FALSE; + + if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA)) + { + bPurgeExtents = TRUE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyEntry Clearing VERIFY_DATA flag %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA); + } + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInvalidateCache Meta Data Update failed %wZ FID %08lX-%08lX-%08lX-%08lX ntStatus %08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + break; + } + + if( pObjectInfo->Fcb != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyEntry Flush/purge entry %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Resource, + TRUE); + + __try + { + + CcFlushCache( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSVerifyEntry CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + + if ( bPurgeExtents) + { + + CcPurgeCacheSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + FALSE); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSVerifyEntry CcFlushCache or CcPurgeCacheSection Exception %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + } + + AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Resource); + + if ( bPurgeExtents) + { + AFSFlushExtents( pObjectInfo->Fcb); + } + + // + // Reacquire the Fcb to purge the cache + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyEntry Acquiring Fcb lock %08lX EXCL %08lX\n", + &pObjectInfo->Fcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pObjectInfo->Fcb->NPFcb->Resource, + TRUE); + + // + // Update file sizes + // + + pObjectInfo->Fcb->Header.AllocationSize.QuadPart = pObjectInfo->AllocationSize.QuadPart; + pObjectInfo->Fcb->Header.FileSize.QuadPart = pObjectInfo->EndOfFile.QuadPart; + pObjectInfo->Fcb->Header.ValidDataLength.QuadPart = pObjectInfo->EndOfFile.QuadPart; + + pCCFileObject = CcGetFileObjectFromSectionPtrs( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers); + + if ( pCCFileObject != NULL) + { + CcSetFileSizes( pCCFileObject, + (PCC_FILE_SIZES)&pObjectInfo->Fcb->Header.AllocationSize); + } + + AFSReleaseResource( &pObjectInfo->Fcb->NPFcb->Resource); + } + else + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSValidateEntry Fcb NULL %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + } + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + + break; + } + + case AFS_FILE_TYPE_DIRECTORY: + { + + AFSFcb *pCurrentFcb = NULL; + AFSDirectoryCB *pCurrentDirEntry = NULL; + + // + // For a directory or root entry flush the content of + // the directory enumeration. + // + + if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSVerifyEntry Validating directory content for entry %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + AFSAcquireExcl( pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSValidateDirectoryCache( pObjectInfo, + AuthGroup); + + AFSReleaseResource( pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + } + + break; + } + + case AFS_FILE_TYPE_DFSLINK: + { + + UNICODE_STRING uniTargetName; + + // + // For a DFS link need to check the target name has not changed + // + + uniTargetName.Length = (USHORT)pDirEnumEntry->TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)pDirEnumEntry + pDirEnumEntry->TargetNameOffset); + + AFSAcquireExcl( &DirEntry->NonPaged->Lock, + TRUE); + + if( DirEntry->NameInformation.TargetName.Length == 0 || + RtlCompareUnicodeString( &uniTargetName, + &DirEntry->NameInformation.TargetName, + TRUE) != 0) + { + + // + // Update the target name + // + + ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName, + &DirEntry->Flags, + uniTargetName.Buffer, + uniTargetName.Length); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + break; + } + } + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY); + } + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSVerifyEntry Attempt to verify node of type %d\n", + pObjectInfo->FileType); + + break; + } + + try_exit: + + if( pDirEnumEntry != NULL) + { + + AFSExFreePool( pDirEnumEntry); + } + } + + return ntStatus; +} + +NTSTATUS +AFSSetVolumeState( IN AFSVolumeStatusCB *VolumeStatus) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + ULONGLONG ullIndex = 0; + AFSVolumeCB *pVolumeCB = NULL; + AFSFcb *pFcb = NULL; + AFSObjectInfoCB *pCurrentObject = NULL; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetVolumeState Marking volume state %d Volume Cell %08lX Volume %08lX\n", + VolumeStatus->Online, + VolumeStatus->FileID.Cell, + VolumeStatus->FileID.Volume); + + // + // Need to locate the Fcb for the directory to purge + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetVolumeState Acquiring RDR VolumeTreeLock lock %08lX SHARED %08lX\n", + &pDevExt->Specific.RDR.VolumeTreeLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE); + + // + // Locate the volume node + // + + ullIndex = AFSCreateHighIndex( &VolumeStatus->FileID); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( pVolumeCB != NULL) + { + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + // + // Set the volume state accordingly + // + + if( VolumeStatus->Online) + { + + InterlockedAnd( (LONG *)&(pVolumeCB->Flags), ~AFS_VOLUME_FLAGS_OFFLINE); + } + else + { + + InterlockedOr( (LONG *)&(pVolumeCB->Flags), AFS_VOLUME_FLAGS_OFFLINE); + } + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + pCurrentObject = pVolumeCB->ObjectInfoListHead;; + + while( pCurrentObject != NULL) + { + + if( VolumeStatus->Online) + { + + ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID); + + SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY); + + pCurrentObject->DataVersion.QuadPart = (ULONGLONG)-1; + } + else + { + + SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID); + } + + pFcb = pCurrentObject->Fcb; + + if( pFcb != NULL && + !(VolumeStatus->Online) && + pFcb->Header.NodeTypeCode == AFS_FILE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetVolumeState Marking volume offline and canceling extents Volume Cell %08lX Volume %08lX\n", + VolumeStatus->FileID.Cell, + VolumeStatus->FileID.Volume); + + // + // Clear out the extents + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetVolumeState Acquiring Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + + pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_CANCELLED; + + KeSetEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete, + 0, + FALSE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSSetVolumeState Releasing Fcb extents lock %08lX EXCL %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource); + + // + // And get rid of them (note this involves waiting + // for any writes or reads to the cache to complete) + // + + (VOID) AFSTearDownFcbExtents( pFcb); + } + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + } + else + { + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + } + } + + return ntStatus; +} + +NTSTATUS +AFSSetNetworkState( IN AFSNetworkStatusCB *NetworkStatus) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + if( AFSGlobalRoot == NULL) + { + + try_return( ntStatus); + } + + AFSAcquireExcl( AFSGlobalRoot->VolumeLock, + TRUE); + + // + // Set the network state according to the information + // + + if( NetworkStatus->Online) + { + + ClearFlag( AFSGlobalRoot->Flags, AFS_VOLUME_FLAGS_OFFLINE); + } + else + { + + SetFlag( AFSGlobalRoot->Flags, AFS_VOLUME_FLAGS_OFFLINE); + } + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSValidateDirectoryCache( IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + BOOLEAN bAcquiredLock = FALSE; + AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL; + AFSFcb *pFcb = NULL; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Validating content for FID %08lX-%08lX-%08lX-%08lX\n", + ObjectInfo->FileId.Cell, + ObjectInfo->FileId.Volume, + ObjectInfo->FileId.Vnode, + ObjectInfo->FileId.Unique); + + if( !ExIsResourceAcquiredLite( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Acquiring DirectoryNodeHdr.TreeLock lock %08lX EXCL %08lX\n", + ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + PsGetCurrentThread()); + + AFSAcquireExcl( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + bAcquiredLock = TRUE; + } + + // + // Check for inconsistency between DirectoryNodeList and DirectoryNodeCount + // + + if ( ObjectInfo->Specific.Directory.DirectoryNodeListHead == NULL && + ObjectInfo->Specific.Directory.DirectoryNodeCount > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateDirectoryCache Empty Node List but Non-Zero Node Count %08lX for dir FID %08lX-%08lX-%08lX-%08lX\n", + ObjectInfo->Specific.Directory.DirectoryNodeCount, + ObjectInfo->FileId.Cell, + ObjectInfo->FileId.Volume, + ObjectInfo->FileId.Vnode, + ObjectInfo->FileId.Unique); + } + + // + // Reset the directory list information by clearing all valid entries + // + + pCurrentDirEntry = ObjectInfo->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_FAKE)) + { + + ClearFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID); + } + + pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + } + + // + // Reget the directory contents + // + + AFSVerifyDirectoryContent( ObjectInfo, + AuthGroup); + + // + // Now start again and tear down any entries not valid + // + + pCurrentDirEntry = ObjectInfo->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + + if( BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_VALID)) + { + + pCurrentDirEntry = pNextDirEntry; + + continue; + } + + if( pCurrentDirEntry->OpenReferenceCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Deleting dir entry %wZ from parent FID %08lX-%08lX-%08lX-%08lX\n", + &pCurrentDirEntry->NameInformation.FileName, + ObjectInfo->FileId.Cell, + ObjectInfo->FileId.Volume, + ObjectInfo->FileId.Vnode, + ObjectInfo->FileId.Unique); + + AFSDeleteDirEntry( ObjectInfo, + pCurrentDirEntry); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateDirectoryCache Setting dir entry %p Name %wZ DELETED in parent FID %08lX-%08lX-%08lX-%08lX\n", + pCurrentDirEntry, + &pCurrentDirEntry->NameInformation.FileName, + ObjectInfo->FileId.Cell, + ObjectInfo->FileId.Volume, + ObjectInfo->FileId.Vnode, + ObjectInfo->FileId.Unique); + + SetFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_DELETED); + + AFSRemoveNameEntry( ObjectInfo, + pCurrentDirEntry); + } + + pCurrentDirEntry = pNextDirEntry; + } + +#if DBG + if( !AFSValidateDirList( ObjectInfo)) + { + + AFSPrint("AFSValidateDirectoryCache Invalid count ...\n"); + } +#endif + + if( bAcquiredLock) + { + + AFSReleaseResource( ObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + } + + return ntStatus; +} + +BOOLEAN +AFSIsVolumeFID( IN AFSFileID *FileID) +{ + + BOOLEAN bIsVolume = FALSE; + + if( FileID->Vnode == 1 && + FileID->Unique == 1) + { + + bIsVolume = TRUE; + } + + return bIsVolume; +} + +BOOLEAN +AFSIsFinalNode( IN AFSFcb *Fcb) +{ + + BOOLEAN bIsFinalNode = FALSE; + + if( Fcb->Header.NodeTypeCode == AFS_ROOT_FCB || + Fcb->Header.NodeTypeCode == AFS_DIRECTORY_FCB || + Fcb->Header.NodeTypeCode == AFS_FILE_FCB || + Fcb->Header.NodeTypeCode == AFS_DFS_LINK_FCB || + Fcb->Header.NodeTypeCode == AFS_INVALID_FCB ) + { + + bIsFinalNode = TRUE; + } + else + { + + ASSERT( Fcb->Header.NodeTypeCode == AFS_MOUNT_POINT_FCB || + Fcb->Header.NodeTypeCode == AFS_SYMBOLIC_LINK_FCB); + } + + return bIsFinalNode; +} + +NTSTATUS +AFSUpdateMetaData( IN AFSDirectoryCB *DirEntry, + IN AFSDirEnumEntry *DirEnumEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniTargetName; + AFSObjectInfoCB *pObjectInfo = DirEntry->ObjectInformation; + + __Enter + { + + pObjectInfo->TargetFileId = DirEnumEntry->TargetFileId; + + pObjectInfo->Expiration = DirEnumEntry->Expiration; + + pObjectInfo->DataVersion = DirEnumEntry->DataVersion; + + pObjectInfo->FileType = DirEnumEntry->FileType; + + pObjectInfo->CreationTime = DirEnumEntry->CreationTime; + + pObjectInfo->LastAccessTime = DirEnumEntry->LastAccessTime; + + pObjectInfo->LastWriteTime = DirEnumEntry->LastWriteTime; + + pObjectInfo->ChangeTime = DirEnumEntry->ChangeTime; + + pObjectInfo->EndOfFile = DirEnumEntry->EndOfFile; + + pObjectInfo->AllocationSize = DirEnumEntry->AllocationSize; + + pObjectInfo->FileAttributes = DirEnumEntry->FileAttributes; + + if( pObjectInfo->FileType == AFS_FILE_TYPE_MOUNTPOINT || + pObjectInfo->FileType == AFS_FILE_TYPE_SYMLINK || + pObjectInfo->FileType == AFS_FILE_TYPE_DFSLINK) + { + + pObjectInfo->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + } + + pObjectInfo->EaSize = DirEnumEntry->EaSize; + + pObjectInfo->Links = DirEnumEntry->Links; + + if( DirEnumEntry->TargetNameLength > 0) + { + + // + // Update the target name information if needed + // + + uniTargetName.Length = (USHORT)DirEnumEntry->TargetNameLength; + + uniTargetName.MaximumLength = uniTargetName.Length; + + uniTargetName.Buffer = (WCHAR *)((char *)DirEnumEntry + DirEnumEntry->TargetNameOffset); + + AFSAcquireExcl( &DirEntry->NonPaged->Lock, + TRUE); + + if( DirEntry->NameInformation.TargetName.Length == 0 || + RtlCompareUnicodeString( &uniTargetName, + &DirEntry->NameInformation.TargetName, + TRUE) != 0) + { + + // + // Update the target name + // + + ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName, + &DirEntry->Flags, + uniTargetName.Buffer, + uniTargetName.Length); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + try_return( ntStatus); + } + } + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + } + else if( DirEntry->NameInformation.TargetName.Length > 0) + { + + AFSAcquireExcl( &DirEntry->NonPaged->Lock, + TRUE); + + if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER) && + DirEntry->NameInformation.TargetName.Buffer != NULL) + { + AFSExFreePool( DirEntry->NameInformation.TargetName.Buffer); + } + + ClearFlag( DirEntry->Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER); + + DirEntry->NameInformation.TargetName.Length = 0; + DirEntry->NameInformation.TargetName.MaximumLength = 0; + DirEntry->NameInformation.TargetName.Buffer = NULL; + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSValidateEntry( IN AFSDirectoryCB *DirEntry, + IN GUID *AuthGroup, + IN BOOLEAN PurgeContent, + IN BOOLEAN FastCall) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + LARGE_INTEGER liSystemTime; + AFSDirEnumEntry *pDirEnumEntry = NULL; + AFSFcb *pCurrentFcb = NULL; + BOOLEAN bReleaseFcb = FALSE; + AFSObjectInfoCB *pObjectInfo = DirEntry->ObjectInformation; + + __Enter + { + + // + // If we have an Fcb hanging off the directory entry then be sure to acquire the locks in the + // correct order + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSValidateEntry Validating entry %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + // + // If this is a fake node then bail since the service knows nothing about it + // + + if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_FAKE)) + { + + try_return( ntStatus); + } + + if( PurgeContent && + pObjectInfo->Fcb != NULL) + { + + pCurrentFcb = pObjectInfo->Fcb; + + if( !ExIsResourceAcquiredLite( &pCurrentFcb->NPFcb->Resource)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateEntry Acquiring Fcb lock %08lX EXCL %08lX\n", + &pCurrentFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pCurrentFcb->NPFcb->Resource, + TRUE); + + bReleaseFcb = TRUE; + } + } + + // + // This routine ensures that the current entry is valid by: + // + // 1) Checking that the expiration time is non-zero and after where we + // currently are + // + + KeQuerySystemTime( &liSystemTime); + + if( !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED) && + !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY) && + !BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA) && + pObjectInfo->Expiration.QuadPart >= liSystemTime.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSValidateEntry Directory entry %wZ FID %08lX-%08lX-%08lX-%08lX VALID\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + try_return( ntStatus); + } + + // + // This node requires updating + // + + ntStatus = AFSEvaluateTargetByID( pObjectInfo, + AuthGroup, + FastCall, + &pDirEnumEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateEntry Failed to evaluate entry %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + // + // Failed validation of node so return access-denied + // + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateEntry Validating entry %wZ FID %08lX-%08lX-%08lX-%08lX DV %I64X returned DV %I64X FT %d\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + pObjectInfo->DataVersion.QuadPart, + pDirEnumEntry->DataVersion.QuadPart, + pDirEnumEntry->FileType); + + + // + // Based on the file type, process the node + // + + switch( pDirEnumEntry->FileType) + { + + case AFS_FILE_TYPE_MOUNTPOINT: + { + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY | AFS_OBJECT_FLAGS_NOT_EVALUATED); + } + + break; + } + + case AFS_FILE_TYPE_SYMLINK: + case AFS_FILE_TYPE_DFSLINK: + { + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY | AFS_OBJECT_FLAGS_NOT_EVALUATED); + } + + break; + } + + case AFS_FILE_TYPE_FILE: + { + + // + // For a file where the data version has become invalid we need to + // fail any current extent requests and purge the cache for the file + // Can't hold the Fcb resource while doing this + // + + if( pCurrentFcb != NULL && + (pObjectInfo->DataVersion.QuadPart != pDirEnumEntry->DataVersion.QuadPart || + BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA))) + { + + IO_STATUS_BLOCK stIoStatus; + BOOLEAN bPurgeExtents = FALSE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSValidateEntry Flush/purge entry %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + if ( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA)) + { + bPurgeExtents = TRUE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSVerifyEntry Clearing VERIFY_DATA flag %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY_DATA); + } + + __try + { + + CcFlushCache( &pCurrentFcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateEntry CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + + if ( bPurgeExtents) + { + + CcPurgeCacheSection( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + FALSE); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateEntry CcFlushCache or CcPurgeCacheSection exception %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + } + + AFSReleaseResource( &pCurrentFcb->NPFcb->Resource); + + if ( bPurgeExtents) + { + AFSFlushExtents( pCurrentFcb); + } + + // + // Reacquire the Fcb to purge the cache + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateEntry Acquiring Fcb lock %08lX EXCL %08lX\n", + &pCurrentFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pCurrentFcb->NPFcb->Resource, + TRUE); + } + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateEntry Meta Data Update failed %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + break; + } + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY | AFS_OBJECT_FLAGS_NOT_EVALUATED); + + // + // Update file sizes + // + + if( pObjectInfo->Fcb != NULL) + { + FILE_OBJECT *pCCFileObject = CcGetFileObjectFromSectionPtrs( &pObjectInfo->Fcb->NPFcb->SectionObjectPointers); + + pObjectInfo->Fcb->Header.AllocationSize.QuadPart = pObjectInfo->AllocationSize.QuadPart; + pObjectInfo->Fcb->Header.FileSize.QuadPart = pObjectInfo->EndOfFile.QuadPart; + pObjectInfo->Fcb->Header.ValidDataLength.QuadPart = pObjectInfo->EndOfFile.QuadPart; + + if ( pCCFileObject != NULL) + { + CcSetFileSizes( pCCFileObject, + (PCC_FILE_SIZES)&pObjectInfo->Fcb->Header.AllocationSize); + } + } + + break; + } + + case AFS_FILE_TYPE_DIRECTORY: + { + + AFSDirectoryCB *pCurrentDirEntry = NULL; + + if( pCurrentFcb != NULL && + pObjectInfo->DataVersion.QuadPart != pDirEnumEntry->DataVersion.QuadPart) + { + + // + // For a directory or root entry flush the content of + // the directory enumeration. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSValidateEntry Acquiring DirectoryNodeHdr.TreeLock lock %08lX EXCL %08lX\n", + pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + PsGetCurrentThread()); + + if( BooleanFlagOn( pObjectInfo->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSValidateEntry Validating directory content for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique); + + AFSAcquireExcl( pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSValidateDirectoryCache( pCurrentFcb->ObjectInformation, + AuthGroup); + + AFSReleaseResource( pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSValidateEntry Failed to re-enumerate %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &DirEntry->NameInformation.FileName, + pObjectInfo->FileId.Cell, + pObjectInfo->FileId.Volume, + pObjectInfo->FileId.Vnode, + pObjectInfo->FileId.Unique, + ntStatus); + + break; + } + } + + // + // Update the metadata for the entry + // + + ntStatus = AFSUpdateMetaData( DirEntry, + pDirEnumEntry); + + if( NT_SUCCESS( ntStatus)) + { + + ClearFlag( pObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY | AFS_OBJECT_FLAGS_NOT_EVALUATED); + } + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSValidateEntry Attempt to verify node of type %d\n", + pObjectInfo->FileType); + + break; + } + + try_exit: + + if( bReleaseFcb) + { + + AFSReleaseResource( &pCurrentFcb->NPFcb->Resource); + } + + if( pDirEnumEntry != NULL) + { + + AFSExFreePool( pDirEnumEntry); + } + } + + return ntStatus; +} + +NTSTATUS +AFSInitializeSpecialShareNameList() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pDirNode = NULL, *pLastDirNode = NULL; + AFSObjectInfoCB *pObjectInfoCB = NULL; + UNICODE_STRING uniShareName; + ULONG ulEntryLength = 0; + AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL; + + __Enter + { + + RtlInitUnicodeString( &uniShareName, + L"PIPE\\srvsvc"); + + pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation, + 0); + + if( pObjectInfoCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitializeSpecialShareNameList (srvsvc) Initializing count (1) on object %08lX\n", + pObjectInfoCB); + + pObjectInfoCB->ObjectReferenceCount = 1; + + pObjectInfoCB->FileType = AFS_FILE_TYPE_SPECIAL_SHARE_NAME; + + ulEntryLength = sizeof( AFSDirectoryCB) + + uniShareName.Length; + + pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + ExFreePool( pDirNode); + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID | AFS_DIR_ENTRY_SERVER_SERVICE); + + pDirNode->NameInformation.FileName.Length = uniShareName.Length; + + pDirNode->NameInformation.FileName.MaximumLength = uniShareName.Length; + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + RtlCopyMemory( pDirNode->NameInformation.FileName.Buffer, + uniShareName.Buffer, + pDirNode->NameInformation.FileName.Length); + + pDirNode->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName, + TRUE); + + AFSSpecialShareNames = pDirNode; + + pLastDirNode = pDirNode; + + RtlInitUnicodeString( &uniShareName, + L"PIPE\\wkssvc"); + + pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation, + 0); + + if( pObjectInfoCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitializeSpecialShareNameList (wkssvc) Initializing count (1) on object %08lX\n", + pObjectInfoCB); + + pObjectInfoCB->ObjectReferenceCount = 1; + + pObjectInfoCB->FileType = AFS_FILE_TYPE_SPECIAL_SHARE_NAME; + + ulEntryLength = sizeof( AFSDirectoryCB) + + uniShareName.Length; + + pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + ExFreePool( pDirNode); + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID | AFS_DIR_ENTRY_WORKSTATION_SERVICE); + + pDirNode->NameInformation.FileName.Length = uniShareName.Length; + + pDirNode->NameInformation.FileName.MaximumLength = uniShareName.Length; + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + RtlCopyMemory( pDirNode->NameInformation.FileName.Buffer, + uniShareName.Buffer, + pDirNode->NameInformation.FileName.Length); + + pDirNode->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName, + TRUE); + + pLastDirNode->ListEntry.fLink = pDirNode; + + pDirNode->ListEntry.bLink = pLastDirNode; + + pLastDirNode = pDirNode; + + RtlInitUnicodeString( &uniShareName, + L"IPC$"); + + pObjectInfoCB = AFSAllocateObjectInfo( &AFSGlobalRoot->ObjectInformation, + 0); + + if( pObjectInfoCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitializeSpecialShareNameList (ipc$) Initializing count (1) on object %08lX\n", + pObjectInfoCB); + + pObjectInfoCB->ObjectReferenceCount = 1; + + pObjectInfoCB->FileType = AFS_FILE_TYPE_SPECIAL_SHARE_NAME; + + ulEntryLength = sizeof( AFSDirectoryCB) + + uniShareName.Length; + + pDirNode = (AFSDirectoryCB *)AFSLibExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + ExFreePool( pDirNode); + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID | AFS_DIR_ENTRY_IPC); + + pDirNode->NameInformation.FileName.Length = uniShareName.Length; + + pDirNode->NameInformation.FileName.MaximumLength = uniShareName.Length; + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + RtlCopyMemory( pDirNode->NameInformation.FileName.Buffer, + uniShareName.Buffer, + pDirNode->NameInformation.FileName.Length); + + pDirNode->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName, + TRUE); + + pLastDirNode->ListEntry.fLink = pDirNode; + + pDirNode->ListEntry.bLink = pLastDirNode; + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( AFSSpecialShareNames != NULL) + { + + pDirNode = AFSSpecialShareNames; + + while( pDirNode != NULL) + { + + pLastDirNode = (AFSDirectoryCB *)pDirNode->ListEntry.fLink; + + AFSDeleteObjectInfo( pDirNode->ObjectInformation); + + ExDeleteResourceLite( &pDirNode->NonPaged->Lock); + + ExFreePool( pDirNode->NonPaged); + + ExFreePool( pDirNode); + + pDirNode = pLastDirNode; + } + + AFSSpecialShareNames = NULL; + } + } + } + + return ntStatus; +} + +AFSDirectoryCB * +AFSGetSpecialShareNameEntry( IN UNICODE_STRING *ShareName, + IN UNICODE_STRING *SecondaryName) +{ + + AFSDirectoryCB *pDirectoryCB = NULL; + ULONGLONG ullHash = 0; + UNICODE_STRING uniFullShareName; + + __Enter + { + + // + // Build up the entire name here. We are guaranteed that if there is a + // secondary name, it is pointing to a portion of the share name buffer + // + + if( SecondaryName->Length > 0 && + SecondaryName->Buffer != NULL) + { + + uniFullShareName = *SecondaryName; + + // + // The calling routine strips off the leading slash so add it back in + // + + uniFullShareName.Buffer--; + uniFullShareName.Length += sizeof( WCHAR); + uniFullShareName.MaximumLength += sizeof( WCHAR); + + // + // And the share name + // + + uniFullShareName.Buffer -= (ShareName->Length/sizeof( WCHAR)); + uniFullShareName.Length += ShareName->Length; + uniFullShareName.MaximumLength += ShareName->Length; + } + else + { + + uniFullShareName = *ShareName; + } + + // + // Generate our hash value + // + + ullHash = AFSGenerateCRC( &uniFullShareName, + TRUE); + + // + // Loop through our special share names to see if this is one of them + // + + pDirectoryCB = AFSSpecialShareNames; + + while( pDirectoryCB != NULL) + { + + if( ullHash == pDirectoryCB->CaseInsensitiveTreeEntry.HashIndex) + { + + break; + } + + pDirectoryCB = (AFSDirectoryCB *)pDirectoryCB->ListEntry.fLink; + } + } + + return pDirectoryCB; +} + +void +AFSWaitOnQueuedFlushes( IN AFSFcb *Fcb) +{ + + // + // Block on the queue flush event + // + + KeWaitForSingleObject( &Fcb->NPFcb->Specific.File.QueuedFlushEvent, + Executive, + KernelMode, + FALSE, + NULL); + + return; +} + +void +AFSWaitOnQueuedReleases() +{ + + AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + // + // Block on the queue flush event + // + + KeWaitForSingleObject( &pRDRDeviceExt->Specific.RDR.QueuedReleaseExtentEvent, + Executive, + KernelMode, + FALSE, + NULL); + + return; +} + +BOOLEAN +AFSIsEqualFID( IN AFSFileID *FileId1, + IN AFSFileID *FileId2) +{ + + BOOLEAN bIsEqual = FALSE; + + if( FileId1->Unique == FileId2->Unique && + FileId1->Vnode == FileId2->Vnode && + FileId1->Volume == FileId2->Volume && + FileId1->Cell == FileId2->Cell) + { + + bIsEqual = TRUE; + } + + return bIsEqual; +} + +NTSTATUS +AFSResetDirectoryContent( IN AFSObjectInfoCB *ObjectInfoCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL; + + __Enter + { + + ASSERT( ExIsResourceAcquiredExclusiveLite( ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.TreeLock)); + + // + // Reset the directory list information + // + + pCurrentDirEntry = ObjectInfoCB->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + + if( pCurrentDirEntry->OpenReferenceCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSResetDirectoryContent Deleting dir entry %p for %wZ\n", + pCurrentDirEntry, + &pCurrentDirEntry->NameInformation.FileName); + + AFSDeleteDirEntry( ObjectInfoCB, + pCurrentDirEntry); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSResetDirectoryContent Setting DELETE flag in dir entry %p for %wZ\n", + pCurrentDirEntry, + &pCurrentDirEntry->NameInformation.FileName); + + SetFlag( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_DELETED); + + AFSRemoveNameEntry( ObjectInfoCB, + pCurrentDirEntry); + } + + pCurrentDirEntry = pNextDirEntry; + } + + ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = NULL; + + ObjectInfoCB->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = NULL; + + ObjectInfoCB->Specific.Directory.ShortNameTree = NULL; + + ObjectInfoCB->Specific.Directory.DirectoryNodeListHead = NULL; + + ObjectInfoCB->Specific.Directory.DirectoryNodeListTail = NULL; + + ObjectInfoCB->Specific.Directory.DirectoryNodeCount = 0; + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSResetDirectoryContent Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n", + ObjectInfoCB->FileId.Cell, + ObjectInfoCB->FileId.Volume, + ObjectInfoCB->FileId.Vnode, + ObjectInfoCB->FileId.Unique); + } + + return ntStatus; +} + +NTSTATUS +AFSEnumerateGlobalRoot( IN GUID *AuthGroup) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pDirGlobalDirNode = NULL; + UNICODE_STRING uniFullName; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateGlobalRoot Acquiring GlobalRoot DirectoryNodeHdr.TreeLock lock %08lX EXCL %08lX\n", + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + PsGetCurrentThread()); + + AFSAcquireExcl( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + if( BooleanFlagOn( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + try_return( ntStatus); + } + + // + // Initialize the root information + // + + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.ContentIndex = 1; + + // + // Enumerate the shares in the volume + // + + ntStatus = AFSEnumerateDirectory( AuthGroup, + &AFSGlobalRoot->ObjectInformation, + TRUE); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + pDirGlobalDirNode = AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeListHead; + + // + // Indicate the node is initialized + // + + SetFlag( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED); + + uniFullName.MaximumLength = PAGE_SIZE; + uniFullName.Length = 0; + + uniFullName.Buffer = (WCHAR *)AFSLibExAllocatePoolWithTag( PagedPool, + uniFullName.MaximumLength, + AFS_GENERIC_MEMORY_12_TAG); + + if( uniFullName.Buffer == NULL) + { + + // + // Reset the directory content + // + + AFSResetDirectoryContent( &AFSGlobalRoot->ObjectInformation); + + ClearFlag( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Populate our list of entries in the NP enumeration list + // + + while( pDirGlobalDirNode != NULL) + { + + uniFullName.Buffer[ 0] = L'\\'; + uniFullName.Buffer[ 1] = L'\\'; + + uniFullName.Length = 2 * sizeof( WCHAR); + + RtlCopyMemory( &uniFullName.Buffer[ 2], + AFSServerName.Buffer, + AFSServerName.Length); + + uniFullName.Length += AFSServerName.Length; + + uniFullName.Buffer[ uniFullName.Length/sizeof( WCHAR)] = L'\\'; + + uniFullName.Length += sizeof( WCHAR); + + RtlCopyMemory( &uniFullName.Buffer[ uniFullName.Length/sizeof( WCHAR)], + pDirGlobalDirNode->NameInformation.FileName.Buffer, + pDirGlobalDirNode->NameInformation.FileName.Length); + + uniFullName.Length += pDirGlobalDirNode->NameInformation.FileName.Length; + + AFSAddConnectionEx( &uniFullName, + RESOURCEDISPLAYTYPE_SHARE, + 0); + + pDirGlobalDirNode = (AFSDirectoryCB *)pDirGlobalDirNode->ListEntry.fLink; + } + + AFSExFreePool( uniFullName.Buffer); + +try_exit: + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + return ntStatus; +} + +BOOLEAN +AFSIsRelativeName( IN UNICODE_STRING *Name) +{ + + BOOLEAN bIsRelative = FALSE; + + if( Name->Buffer[ 0] != L'\\') + { + + bIsRelative = TRUE; + } + + return bIsRelative; +} + +void +AFSUpdateName( IN UNICODE_STRING *Name) +{ + + USHORT usIndex = 0; + + while( usIndex < Name->Length/sizeof( WCHAR)) + { + + if( Name->Buffer[ usIndex] == L'/') + { + + Name->Buffer[ usIndex] = L'\\'; + } + + usIndex++; + } + + return; +} + +NTSTATUS +AFSUpdateTargetName( IN OUT UNICODE_STRING *TargetName, + IN OUT ULONG *Flags, + IN WCHAR *NameBuffer, + IN USHORT NameLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + WCHAR *pTmpBuffer = NULL; + + __Enter + { + + // + // If we have enough space then just move in the name otherwise + // allocate a new buffer + // + + if( TargetName->Length < NameLength) + { + + pTmpBuffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + NameLength, + AFS_NAME_BUFFER_FIVE_TAG); + + if( pTmpBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + if( BooleanFlagOn( *Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER)) + { + + AFSExFreePool( TargetName->Buffer); + } + + TargetName->MaximumLength = NameLength; + + TargetName->Buffer = pTmpBuffer; + + SetFlag( *Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER); + } + + TargetName->Length = NameLength; + + RtlCopyMemory( TargetName->Buffer, + NameBuffer, + TargetName->Length); + + // + // Update the name in the buffer + // + + AFSUpdateName( TargetName); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +AFSNameArrayHdr * +AFSInitNameArray( IN AFSDirectoryCB *DirectoryCB, + IN ULONG InitialElementCount) +{ + + AFSNameArrayHdr *pNameArray = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + if( InitialElementCount == 0) + { + + InitialElementCount = pDevExt->Specific.RDR.NameArrayLength; + } + + pNameArray = (AFSNameArrayHdr *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSNameArrayHdr) + + (InitialElementCount * sizeof( AFSNameArrayCB)), + AFS_NAME_ARRAY_TAG); + + if( pNameArray == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitNameArray Failed to allocate name array\n"); + + try_return( pNameArray); + } + + RtlZeroMemory( pNameArray, + sizeof( AFSNameArrayHdr) + + (InitialElementCount * sizeof( AFSNameArrayCB))); + + pNameArray->MaxElementCount = InitialElementCount; + + if( DirectoryCB != NULL) + { + + pNameArray->CurrentEntry = &pNameArray->ElementArray[ 0]; + + InterlockedIncrement( &pNameArray->Count); + + InterlockedIncrement( &DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitNameArray Increment count on %wZ DE %p Cnt %d\n", + &DirectoryCB->NameInformation.FileName, + DirectoryCB, + DirectoryCB->OpenReferenceCount); + + pNameArray->CurrentEntry->DirectoryCB = DirectoryCB; + + pNameArray->CurrentEntry->Component = DirectoryCB->NameInformation.FileName; + + pNameArray->CurrentEntry->FileId = DirectoryCB->ObjectInformation->FileId; + } + +try_exit: + + NOTHING; + } + + return pNameArray; +} + +NTSTATUS +AFSPopulateNameArray( IN AFSNameArrayHdr *NameArray, + IN UNICODE_STRING *Path, + IN AFSDirectoryCB *DirectoryCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSNameArrayCB *pCurrentElement = NULL; + UNICODE_STRING uniComponentName, uniRemainingPath; + AFSObjectInfoCB *pCurrentObject = NULL; + ULONG ulTotalCount = 0; + ULONG ulIndex = 0; + USHORT usLength = 0; + + __Enter + { + + // + // Init some info in the header + // + + pCurrentElement = &NameArray->ElementArray[ 0]; + + NameArray->CurrentEntry = pCurrentElement; + + // + // The first entry points at the root + // + + pCurrentElement->DirectoryCB = DirectoryCB->ObjectInformation->VolumeCB->DirectoryCB; + + InterlockedIncrement( &pCurrentElement->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPopulateNameArray Increment count on volume %wZ DE %p Cnt %d\n", + &pCurrentElement->DirectoryCB->NameInformation.FileName, + pCurrentElement->DirectoryCB, + pCurrentElement->DirectoryCB->OpenReferenceCount); + + pCurrentElement->Component = DirectoryCB->ObjectInformation->VolumeCB->DirectoryCB->NameInformation.FileName; + + pCurrentElement->FileId = DirectoryCB->ObjectInformation->VolumeCB->ObjectInformation.FileId; + + NameArray->Count = 1; + + NameArray->LinkCount = 0; + + // + // If the root is the parent then we are done ... + // + + if( &DirectoryCB->ObjectInformation->VolumeCB->ObjectInformation == DirectoryCB->ObjectInformation) + { + try_return( ntStatus); + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSPopulateNameArrayFromRelatedArray( IN AFSNameArrayHdr *NameArray, + IN AFSNameArrayHdr *RelatedNameArray, + IN AFSDirectoryCB *DirectoryCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSNameArrayCB *pCurrentElement = NULL, *pCurrentRelatedElement = NULL; + UNICODE_STRING uniComponentName, uniRemainingPath; + AFSObjectInfoCB *pObjectInfo = NULL; + ULONG ulTotalCount = 0; + ULONG ulIndex = 0; + USHORT usLength = 0; + + __Enter + { + + // + // Init some info in the header + // + + pCurrentElement = &NameArray->ElementArray[ 0]; + + pCurrentRelatedElement = &RelatedNameArray->ElementArray[ 0]; + + NameArray->Count = 0; + + NameArray->LinkCount = RelatedNameArray->LinkCount; + + // + // Populate the name array with the data from the related array + // + + while( TRUE) + { + + pCurrentElement->DirectoryCB = pCurrentRelatedElement->DirectoryCB; + + pCurrentElement->Component = pCurrentRelatedElement->DirectoryCB->NameInformation.FileName; + + pCurrentElement->FileId = pCurrentElement->DirectoryCB->ObjectInformation->FileId; + + InterlockedIncrement( &pCurrentElement->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPopulateNameArrayFromRelatedArray Increment count on %wZ DE %p Cnt %d\n", + &pCurrentElement->DirectoryCB->NameInformation.FileName, + pCurrentElement->DirectoryCB, + pCurrentElement->DirectoryCB->OpenReferenceCount); + + InterlockedIncrement( &NameArray->Count); + + if( pCurrentElement->DirectoryCB == DirectoryCB || + NameArray->Count == RelatedNameArray->Count) + { + + // + // Done ... + // + + break; + } + + pCurrentElement++; + + pCurrentRelatedElement++; + } + + if( NameArray->Count > 0) + { + NameArray->CurrentEntry = pCurrentElement; + } + } + + return ntStatus; +} + +NTSTATUS +AFSFreeNameArray( IN AFSNameArrayHdr *NameArray) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSNameArrayCB *pCurrentElement = NULL; + + __Enter + { + + pCurrentElement = &NameArray->ElementArray[ 0]; + + while( TRUE) + { + + if( pCurrentElement->DirectoryCB == NULL) + { + + break; + } + + InterlockedDecrement( &pCurrentElement->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSFreeNameArray Decrement count on %wZ DE %p Cnt %d\n", + &pCurrentElement->DirectoryCB->NameInformation.FileName, + pCurrentElement->DirectoryCB, + pCurrentElement->DirectoryCB->OpenReferenceCount); + + pCurrentElement++; + } + + AFSExFreePool( NameArray); + } + + return ntStatus; +} + +NTSTATUS +AFSInsertNextElement( IN AFSNameArrayHdr *NameArray, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + if( NameArray->Count == NameArray->MaxElementCount) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + if( NameArray->CurrentEntry != NULL && + NameArray->CurrentEntry->DirectoryCB == DirEntry) + { + + try_return( ntStatus); + } + + if( NameArray->Count > 0) + { + + NameArray->CurrentEntry++; + } + else + { + NameArray->CurrentEntry = &NameArray->ElementArray[ 0]; + } + + InterlockedIncrement( &NameArray->Count); + + InterlockedIncrement( &DirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertNextElement Increment count on %wZ DE %p Cnt %d\n", + &DirEntry->NameInformation.FileName, + DirEntry, + DirEntry->OpenReferenceCount); + + NameArray->CurrentEntry->DirectoryCB = DirEntry; + + NameArray->CurrentEntry->Component = DirEntry->NameInformation.FileName; + + NameArray->CurrentEntry->FileId = DirEntry->ObjectInformation->FileId; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +void +AFSReplaceCurrentElement( IN AFSNameArrayHdr *NameArray, + IN AFSDirectoryCB *DirectoryCB) +{ + + ASSERT( NameArray->CurrentEntry != NULL); + + InterlockedDecrement( &NameArray->CurrentEntry->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReplaceCurrentElement Decrement count on %wZ DE %p Cnt %d\n", + &NameArray->CurrentEntry->DirectoryCB->NameInformation.FileName, + NameArray->CurrentEntry->DirectoryCB, + NameArray->CurrentEntry->DirectoryCB->OpenReferenceCount); + + InterlockedIncrement( &DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSReplaceCurrentElement Increment count on %wZ DE %p Cnt %d\n", + &DirectoryCB->NameInformation.FileName, + DirectoryCB, + DirectoryCB->OpenReferenceCount); + + NameArray->CurrentEntry->DirectoryCB = DirectoryCB; + + NameArray->CurrentEntry->Component = DirectoryCB->NameInformation.FileName; + + NameArray->CurrentEntry->FileId = DirectoryCB->ObjectInformation->FileId; + + if( DirectoryCB->ObjectInformation->ParentObjectInformation == NULL) + { + + SetFlag( NameArray->CurrentEntry->Flags, AFS_NAME_ARRAY_FLAG_ROOT_ELEMENT); + } + + return; +} + +AFSDirectoryCB * +AFSBackupEntry( IN AFSNameArrayHdr *NameArray) +{ + + AFSDirectoryCB *pCurrentDirEntry = NULL; + + __Enter + { + + if( NameArray->Count == 0) + { + try_return( pCurrentDirEntry); + } + + InterlockedDecrement( &NameArray->CurrentEntry->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSBackupEntry Decrement count on %wZ DE %p Cnt %d\n", + &NameArray->CurrentEntry->DirectoryCB->NameInformation.FileName, + NameArray->CurrentEntry->DirectoryCB, + NameArray->CurrentEntry->DirectoryCB->OpenReferenceCount); + + NameArray->CurrentEntry->DirectoryCB = NULL; + + if( InterlockedDecrement( &NameArray->Count) == 0) + { + NameArray->CurrentEntry = NULL; + } + else + { + NameArray->CurrentEntry--; + pCurrentDirEntry = NameArray->CurrentEntry->DirectoryCB; + } + +try_exit: + + NOTHING; + } + + return pCurrentDirEntry; +} + +AFSDirectoryCB * +AFSGetParentEntry( IN AFSNameArrayHdr *NameArray) +{ + + AFSDirectoryCB *pDirEntry = NULL; + AFSNameArrayCB *pElement = NULL; + + __Enter + { + + if( NameArray->Count == 0 || + NameArray->Count == 1) + { + + try_return( pDirEntry = NULL); + } + + pElement = &NameArray->ElementArray[ NameArray->Count - 2]; + + pDirEntry = pElement->DirectoryCB; + +try_exit: + + NOTHING; + } + + return pDirEntry; +} + +void +AFSResetNameArray( IN AFSNameArrayHdr *NameArray, + IN AFSDirectoryCB *DirEntry) +{ + + AFSNameArrayCB *pCurrentElement = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + pCurrentElement = &NameArray->ElementArray[ 0]; + + while( TRUE) + { + + if( pCurrentElement->DirectoryCB == NULL) + { + + break; + } + + InterlockedDecrement( &pCurrentElement->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSResetNameArray Decrement count on %wZ DE %p Cnt %d\n", + &pCurrentElement->DirectoryCB->NameInformation.FileName, + pCurrentElement->DirectoryCB, + pCurrentElement->DirectoryCB->OpenReferenceCount); + + pCurrentElement++; + } + + RtlZeroMemory( NameArray, + sizeof( AFSNameArrayHdr) + + ((pDevExt->Specific.RDR.NameArrayLength - 1) * sizeof( AFSNameArrayCB))); + + NameArray->MaxElementCount = pDevExt->Specific.RDR.NameArrayLength; + + if( DirEntry != NULL) + { + + NameArray->CurrentEntry = &NameArray->ElementArray[ 0]; + + InterlockedIncrement( &NameArray->Count); + + InterlockedIncrement( &DirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSResetNameArray Increment count on %wZ DE %p Cnt %d\n", + &DirEntry->NameInformation.FileName, + DirEntry, + DirEntry->OpenReferenceCount); + + NameArray->CurrentEntry->DirectoryCB = DirEntry; + + NameArray->CurrentEntry->Component = DirEntry->NameInformation.FileName; + + NameArray->CurrentEntry->FileId = DirEntry->ObjectInformation->FileId; + } + } + + return; +} + +void +AFSDumpNameArray( IN AFSNameArrayHdr *NameArray) +{ + + AFSNameArrayCB *pCurrentElement = NULL; + + pCurrentElement = &NameArray->ElementArray[ 0]; + + AFSPrint("AFSDumpNameArray Start (%d)\n", NameArray->Count); + + while( pCurrentElement->DirectoryCB != NULL) + { + + AFSPrint("FID %08lX-%08lX-%08lX-%08lX %wZ\n", + pCurrentElement->FileId.Cell, + pCurrentElement->FileId.Volume, + pCurrentElement->FileId.Vnode, + pCurrentElement->FileId.Unique, + &pCurrentElement->DirectoryCB->NameInformation.FileName); + + pCurrentElement++; + } + + AFSPrint("AFSDumpNameArray End\n\n"); + + return; +} + +void +AFSSetEnumerationEvent( IN AFSFcb *Fcb) +{ + + // + // Depending on the type of node, set the event + // + + switch( Fcb->Header.NodeTypeCode) + { + + case AFS_DIRECTORY_FCB: + { + + KeSetEvent( &Fcb->NPFcb->Specific.Directory.DirectoryEnumEvent, + 0, + FALSE); + + InterlockedIncrement( &Fcb->NPFcb->Specific.Directory.DirectoryEnumCount); + + break; + } + + case AFS_ROOT_FCB: + case AFS_ROOT_ALL: + { + + KeSetEvent( &Fcb->NPFcb->Specific.Directory.DirectoryEnumEvent, + 0, + FALSE); + + InterlockedIncrement( &Fcb->NPFcb->Specific.Directory.DirectoryEnumCount); + + break; + } + } + + return; +} + +void +AFSClearEnumerationEvent( IN AFSFcb *Fcb) +{ + + // + // Depending on the type of node, set the event + // + + switch( Fcb->Header.NodeTypeCode) + { + + case AFS_DIRECTORY_FCB: + { + + ASSERT( Fcb->NPFcb->Specific.Directory.DirectoryEnumCount > 0); + + if( InterlockedDecrement( &Fcb->NPFcb->Specific.Directory.DirectoryEnumCount) == 0) + { + + KeClearEvent( &Fcb->NPFcb->Specific.Directory.DirectoryEnumEvent); + } + + break; + } + + case AFS_ROOT_FCB: + case AFS_ROOT_ALL: + { + + ASSERT( Fcb->NPFcb->Specific.Directory.DirectoryEnumCount > 0); + + if( InterlockedDecrement( &Fcb->NPFcb->Specific.Directory.DirectoryEnumCount) == 0) + { + + KeClearEvent( &Fcb->NPFcb->Specific.Directory.DirectoryEnumEvent); + } + + break; + } + } + + return; +} + +BOOLEAN +AFSIsEnumerationInProcess( IN AFSObjectInfoCB *ObjectInfo) +{ + + BOOLEAN bIsInProcess = FALSE; + + __Enter + { + + if( ObjectInfo->Fcb == NULL) + { + + try_return( bIsInProcess); + } + + // + // Depending on the type of node, set the event + // + + switch( ObjectInfo->Fcb->Header.NodeTypeCode) + { + + case AFS_DIRECTORY_FCB: + { + + if( KeReadStateEvent( &ObjectInfo->Fcb->NPFcb->Specific.Directory.DirectoryEnumEvent)) + { + + bIsInProcess = TRUE; + } + + break; + } + + case AFS_ROOT_FCB: + case AFS_ROOT_ALL: + { + + if( KeReadStateEvent( &ObjectInfo->Fcb->NPFcb->Specific.Directory.DirectoryEnumEvent)) + { + + bIsInProcess = TRUE; + } + + break; + } + } + +try_exit: + + NOTHING; + } + + return bIsInProcess; +} + +NTSTATUS +AFSVerifyVolume( IN ULONGLONG ProcessId, + IN AFSVolumeCB *VolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + + return ntStatus; +} + +NTSTATUS +AFSInitPIOCtlDirectoryCB( IN AFSObjectInfoCB *ObjectInfo) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSObjectInfoCB *pObjectInfoCB = NULL; + AFSDirectoryCB *pDirNode = NULL; + ULONG ulEntryLength = 0; + AFSNonPagedDirectoryCB *pNonPagedDirEntry = NULL; + + __Enter + { + + pObjectInfoCB = AFSAllocateObjectInfo( ObjectInfo, + 0); + + if( pObjectInfoCB == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInitPIOCtlDirectoryCB Initializing count (1) on object %08lX\n", + pObjectInfoCB); + + pObjectInfoCB->ObjectReferenceCount = 1; + + pObjectInfoCB->FileType = AFS_FILE_TYPE_PIOCTL; + + pObjectInfoCB->FileAttributes = FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM; + + ulEntryLength = sizeof( AFSDirectoryCB) + + AFSPIOCtlName.Length; + + pDirNode = (AFSDirectoryCB *)AFSExAllocatePoolWithTag( PagedPool, + ulEntryLength, + AFS_DIR_ENTRY_TAG); + + if( pDirNode == NULL) + { + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pNonPagedDirEntry = (AFSNonPagedDirectoryCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedDirectoryCB), + AFS_DIR_ENTRY_NP_TAG); + + if( pNonPagedDirEntry == NULL) + { + + AFSExFreePool( pDirNode); + + AFSDeleteObjectInfo( pObjectInfoCB); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pDirNode, + ulEntryLength); + + RtlZeroMemory( pNonPagedDirEntry, + sizeof( AFSNonPagedDirectoryCB)); + + ExInitializeResourceLite( &pNonPagedDirEntry->Lock); + + pDirNode->NonPaged = pNonPagedDirEntry; + + pDirNode->ObjectInformation = pObjectInfoCB; + + pDirNode->FileIndex = (ULONG)AFS_DIR_ENTRY_PIOCTL_INDEX; + + // + // Set valid entry + // + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_VALID | AFS_DIR_ENTRY_FAKE); + + pDirNode->NameInformation.FileName.Length = AFSPIOCtlName.Length; + + pDirNode->NameInformation.FileName.MaximumLength = AFSPIOCtlName.Length; + + pDirNode->NameInformation.FileName.Buffer = (WCHAR *)((char *)pDirNode + sizeof( AFSDirectoryCB)); + + RtlCopyMemory( pDirNode->NameInformation.FileName.Buffer, + AFSPIOCtlName.Buffer, + pDirNode->NameInformation.FileName.Length); + + pDirNode->CaseInsensitiveTreeEntry.HashIndex = AFSGenerateCRC( &pDirNode->NameInformation.FileName, + TRUE); + + ObjectInfo->Specific.Directory.PIOCtlDirectoryCB = pDirNode; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSRetrieveFileAttributes( IN AFSDirectoryCB *ParentDirectoryCB, + IN AFSDirectoryCB *DirectoryCB, + IN UNICODE_STRING *ParentPathName, + IN AFSNameArrayHdr *RelatedNameArray, + OUT AFSFileInfoCB *FileInfo) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirEnumEntry *pDirEntry = NULL, *pLastDirEntry = NULL; + UNICODE_STRING uniFullPathName; + AFSNameArrayHdr *pNameArray = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSDirectoryCB *pDirectoryEntry = NULL, *pParentDirEntry = NULL; + WCHAR *pwchBuffer = NULL; + UNICODE_STRING uniComponentName, uniRemainingPath, uniParsedName; + ULONG ulNameDifference = 0; + GUID *pAuthGroup = NULL; + + __Enter + { + + // + // Retrieve a target name for the entry + // + + AFSAcquireShared( &DirectoryCB->NonPaged->Lock, + TRUE); + + if( DirectoryCB->NameInformation.TargetName.Length == 0) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + if( ParentDirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &ParentDirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + else if( DirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &DirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + + ntStatus = AFSEvaluateTargetByID( DirectoryCB->ObjectInformation, + pAuthGroup, + FALSE, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus) || + pDirEntry->TargetNameLength == 0) + { + + if( pDirEntry != NULL) + { + + ntStatus = STATUS_ACCESS_DENIED; + } + + try_return( ntStatus); + } + + AFSAcquireExcl( &DirectoryCB->NonPaged->Lock, + TRUE); + + if( DirectoryCB->NameInformation.TargetName.Length == 0) + { + + // + // Update the target name + // + + ntStatus = AFSUpdateTargetName( &DirectoryCB->NameInformation.TargetName, + &DirectoryCB->Flags, + (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset), + (USHORT)pDirEntry->TargetNameLength); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + try_return( ntStatus); + } + } + + AFSConvertToShared( &DirectoryCB->NonPaged->Lock); + } + + // + // Need to pass the full path in for parsing. + // + + if( AFSIsRelativeName( &DirectoryCB->NameInformation.TargetName)) + { + + uniFullPathName.Length = 0; + uniFullPathName.MaximumLength = ParentPathName->Length + + sizeof( WCHAR) + + DirectoryCB->NameInformation.TargetName.Length; + + uniFullPathName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniFullPathName.MaximumLength, + AFS_NAME_BUFFER_SIX_TAG); + + if( uniFullPathName.Buffer == NULL) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pwchBuffer = uniFullPathName.Buffer; + + RtlZeroMemory( uniFullPathName.Buffer, + uniFullPathName.MaximumLength); + + RtlCopyMemory( uniFullPathName.Buffer, + ParentPathName->Buffer, + ParentPathName->Length); + + uniFullPathName.Length = ParentPathName->Length; + + if( uniFullPathName.Buffer[ (uniFullPathName.Length/sizeof( WCHAR)) - 1] != L'\\' && + DirectoryCB->NameInformation.TargetName.Buffer[ 0] != L'\\') + { + + uniFullPathName.Buffer[ uniFullPathName.Length/sizeof( WCHAR)] = L'\\'; + + uniFullPathName.Length += sizeof( WCHAR); + } + + RtlCopyMemory( &uniFullPathName.Buffer[ uniFullPathName.Length/sizeof( WCHAR)], + DirectoryCB->NameInformation.TargetName.Buffer, + DirectoryCB->NameInformation.TargetName.Length); + + uniFullPathName.Length += DirectoryCB->NameInformation.TargetName.Length; + + uniParsedName.Length = uniFullPathName.Length - ParentPathName->Length; + uniParsedName.MaximumLength = uniParsedName.Length; + + uniParsedName.Buffer = &uniFullPathName.Buffer[ ParentPathName->Length/sizeof( WCHAR)]; + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + // + // We populate up to the current parent + // + + if( RelatedNameArray != NULL) + { + + pNameArray = AFSInitNameArray( NULL, + RelatedNameArray->MaxElementCount); + + if( pNameArray == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ntStatus = AFSPopulateNameArrayFromRelatedArray( pNameArray, + RelatedNameArray, + ParentDirectoryCB); + } + else + { + + pNameArray = AFSInitNameArray( NULL, + 0); + + if( pNameArray == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ntStatus = AFSPopulateNameArray( pNameArray, + NULL, + ParentDirectoryCB); + } + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + pVolumeCB = ParentDirectoryCB->ObjectInformation->VolumeCB; + + AFSAcquireShared( pVolumeCB->VolumeLock, + TRUE); + + pParentDirEntry = ParentDirectoryCB; + } + else + { + + uniFullPathName.Length = 0; + uniFullPathName.MaximumLength = DirectoryCB->NameInformation.TargetName.Length; + + uniFullPathName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniFullPathName.MaximumLength, + AFS_NAME_BUFFER_SEVEN_TAG); + + if( uniFullPathName.Buffer == NULL) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pwchBuffer = uniFullPathName.Buffer; + + RtlZeroMemory( uniFullPathName.Buffer, + uniFullPathName.MaximumLength); + + RtlCopyMemory( uniFullPathName.Buffer, + DirectoryCB->NameInformation.TargetName.Buffer, + DirectoryCB->NameInformation.TargetName.Length); + + uniFullPathName.Length = DirectoryCB->NameInformation.TargetName.Length; + + // + // This name should begin with the \afs server so parse it off and check it + // + + FsRtlDissectName( uniFullPathName, + &uniComponentName, + &uniRemainingPath); + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSServerName, + TRUE) != 0) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSRetrieveFileAttributes Name %wZ contains invalid server name\n", + &uniFullPathName); + + try_return( ntStatus = STATUS_OBJECT_PATH_INVALID); + } + + uniFullPathName = uniRemainingPath; + + uniParsedName = uniFullPathName; + + ulNameDifference = (ULONG)(uniFullPathName.Length > 0 ? ((char *)uniFullPathName.Buffer - (char *)pwchBuffer) : 0); + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + // + // Our name array + // + + pNameArray = AFSInitNameArray( AFSGlobalRoot->DirectoryCB, + 0); + + if( pNameArray == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pVolumeCB = AFSGlobalRoot; + + AFSAcquireShared( pVolumeCB->VolumeLock, + TRUE); + + pParentDirEntry = AFSGlobalRoot->DirectoryCB; + } + + // + // Increment the ref count on the volume and dir entry for correct processing below + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + InterlockedIncrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Increment count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + + ntStatus = AFSLocateNameEntry( NULL, + NULL, + &uniFullPathName, + &uniParsedName, + pNameArray, + AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL, + &pVolumeCB, + &pParentDirEntry, + &pDirectoryEntry, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + // + // The volume lock was released on failure above + // Except for STATUS_OBJECT_NAME_NOT_FOUND + // + + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) + { + + if( pVolumeCB != NULL) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Decrement count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + if( pDirectoryEntry != NULL) + { + + InterlockedDecrement( &pDirectoryEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Decrement1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryEntry->NameInformation.FileName, + pDirectoryEntry, + NULL, + pDirectoryEntry->OpenReferenceCount); + } + else + { + + InterlockedDecrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + } + } + + pVolumeCB = NULL; + + try_return( ntStatus); + } + + // + // Store off the information + // + + FileInfo->FileAttributes = pDirectoryEntry->ObjectInformation->FileAttributes; + + // + // Check for the mount point being returned + // + + if( pDirectoryEntry->ObjectInformation->FileType == AFS_FILE_TYPE_MOUNTPOINT) + { + + FileInfo->FileAttributes |= (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); + } + else if( pDirectoryEntry->ObjectInformation->FileType == AFS_FILE_TYPE_SYMLINK || + pDirectoryEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DFSLINK) + { + + FileInfo->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT; + } + + FileInfo->AllocationSize = pDirectoryEntry->ObjectInformation->AllocationSize; + + FileInfo->EndOfFile = pDirectoryEntry->ObjectInformation->EndOfFile; + + FileInfo->CreationTime = pDirectoryEntry->ObjectInformation->CreationTime; + + FileInfo->LastAccessTime = pDirectoryEntry->ObjectInformation->LastAccessTime; + + FileInfo->LastWriteTime = pDirectoryEntry->ObjectInformation->LastWriteTime; + + FileInfo->ChangeTime = pDirectoryEntry->ObjectInformation->ChangeTime; + + // + // Remove the reference made above + // + + InterlockedDecrement( &pDirectoryEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Decrement3 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryEntry->NameInformation.FileName, + pDirectoryEntry, + NULL, + pDirectoryEntry->OpenReferenceCount); + +try_exit: + + if( pDirEntry != NULL) + { + + AFSExFreePool( pDirEntry); + } + + if( pVolumeCB != NULL) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Decrement2 count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + if( pNameArray != NULL) + { + + AFSFreeNameArray( pNameArray); + } + + if( pwchBuffer != NULL) + { + + // + // Always free the buffer that we allocated as AFSLocateNameEntry + // will not free it. If uniFullPathName.Buffer was allocated by + // AFSLocateNameEntry, then we must free that as well. + // Check that the uniFullPathName.Buffer in the string is not the same + // offset by the length of the server name + // + + AFSExFreePool( pwchBuffer); + + if( uniFullPathName.Length > 0 && + pwchBuffer != (WCHAR *)((char *)uniFullPathName.Buffer - ulNameDifference)) + { + + AFSExFreePool( uniFullPathName.Buffer); + } + } + } + + return ntStatus; +} + +AFSObjectInfoCB * +AFSAllocateObjectInfo( IN AFSObjectInfoCB *ParentObjectInfo, + IN ULONGLONG HashIndex) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSObjectInfoCB *pObjectInfo = NULL; + + __Enter + { + + pObjectInfo = (AFSObjectInfoCB *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSObjectInfoCB), + AFS_OBJECT_INFO_TAG); + + if( pObjectInfo == NULL) + { + + try_return( pObjectInfo); + } + + RtlZeroMemory( pObjectInfo, + sizeof( AFSObjectInfoCB)); + + pObjectInfo->NonPagedInfo = (AFSNonPagedObjectInfoCB *)AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSNonPagedObjectInfoCB), + AFS_NP_OBJECT_INFO_TAG); + + if( pObjectInfo->NonPagedInfo == NULL) + { + + AFSExFreePool( pObjectInfo); + + try_return( pObjectInfo = NULL); + } + + ExInitializeResourceLite( &pObjectInfo->NonPagedInfo->DirectoryNodeHdrLock); + + pObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock = &pObjectInfo->NonPagedInfo->DirectoryNodeHdrLock; + + pObjectInfo->VolumeCB = ParentObjectInfo->VolumeCB; + + pObjectInfo->ParentObjectInformation = ParentObjectInfo; + + if( ParentObjectInfo != NULL) + { + InterlockedIncrement( &ParentObjectInfo->ObjectReferenceCount); + } + + // + // Initialize the access time + // + + KeQueryTickCount( &pObjectInfo->LastAccessCount); + + if( HashIndex != 0) + { + + // + // Insert the entry into the object tree and list + // + + pObjectInfo->TreeEntry.HashIndex = HashIndex; + + if( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeHead == NULL) + { + + ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeHead = &pObjectInfo->TreeEntry; + } + else + { + + ntStatus = AFSInsertHashEntry( ParentObjectInfo->VolumeCB->ObjectInfoTree.TreeHead, + &pObjectInfo->TreeEntry); + + ASSERT( NT_SUCCESS( ntStatus)); + } + + // + // And the object list in the volume + // + + if( ParentObjectInfo->VolumeCB->ObjectInfoListHead == NULL) + { + + ParentObjectInfo->VolumeCB->ObjectInfoListHead = pObjectInfo; + } + else + { + + ParentObjectInfo->VolumeCB->ObjectInfoListTail->ListEntry.fLink = (void *)pObjectInfo; + + pObjectInfo->ListEntry.bLink = (void *)ParentObjectInfo->VolumeCB->ObjectInfoListTail; + } + + ParentObjectInfo->VolumeCB->ObjectInfoListTail = pObjectInfo; + + // + // Indicate the object is in the hash tree and linked list in the volume + // + + SetFlag( pObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE | AFS_OBJECT_INSERTED_VOLUME_LIST); + } + +try_exit: + + NOTHING; + } + + return pObjectInfo; +} + +void +AFSDeleteObjectInfo( IN AFSObjectInfoCB *ObjectInfo) +{ + + BOOLEAN bAcquiredTreeLock = FALSE; + + if( !ExIsResourceAcquiredExclusiveLite( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock)) + { + + ASSERT( !ExIsResourceAcquiredLite( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock)); + + AFSAcquireExcl( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + bAcquiredTreeLock = TRUE; + } + + // + // Remove it from the tree and list if it was inserted + // + + if( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_INSERTED_HASH_TREE)) + { + + AFSRemoveHashEntry( &ObjectInfo->VolumeCB->ObjectInfoTree.TreeHead, + &ObjectInfo->TreeEntry); + } + + if( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_INSERTED_VOLUME_LIST)) + { + + if( ObjectInfo->ListEntry.fLink == NULL) + { + + ObjectInfo->VolumeCB->ObjectInfoListTail = (AFSObjectInfoCB *)ObjectInfo->ListEntry.bLink; + + if( ObjectInfo->VolumeCB->ObjectInfoListTail != NULL) + { + + ObjectInfo->VolumeCB->ObjectInfoListTail->ListEntry.fLink = NULL; + } + } + else + { + + ((AFSObjectInfoCB *)(ObjectInfo->ListEntry.fLink))->ListEntry.bLink = ObjectInfo->ListEntry.bLink; + } + + if( ObjectInfo->ListEntry.bLink == NULL) + { + + ObjectInfo->VolumeCB->ObjectInfoListHead = (AFSObjectInfoCB *)ObjectInfo->ListEntry.fLink; + + if( ObjectInfo->VolumeCB->ObjectInfoListHead != NULL) + { + + ObjectInfo->VolumeCB->ObjectInfoListHead->ListEntry.bLink = NULL; + } + } + else + { + + ((AFSObjectInfoCB *)(ObjectInfo->ListEntry.bLink))->ListEntry.fLink = ObjectInfo->ListEntry.fLink; + } + } + + if( ObjectInfo->ParentObjectInformation != NULL) + { + InterlockedDecrement( &ObjectInfo->ParentObjectInformation->ObjectReferenceCount); + } + + if( bAcquiredTreeLock) + { + + AFSReleaseResource( ObjectInfo->VolumeCB->ObjectInfoTree.TreeLock); + } + + // + // Release the fid in the service + // + + if( BooleanFlagOn( ObjectInfo->Flags, AFS_OBJECT_HELD_IN_SERVICE)) + { + + AFSReleaseFid( &ObjectInfo->FileId); + } + + ExDeleteResourceLite( &ObjectInfo->NonPagedInfo->DirectoryNodeHdrLock); + + AFSExFreePool( ObjectInfo->NonPagedInfo); + + AFSExFreePool( ObjectInfo); + + return; +} + +NTSTATUS +AFSEvaluateRootEntry( IN AFSDirectoryCB *DirectoryCB, + OUT AFSDirectoryCB **TargetDirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirEnumEntry *pDirEntry = NULL, *pLastDirEntry = NULL; + UNICODE_STRING uniFullPathName; + AFSNameArrayHdr *pNameArray = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSDirectoryCB *pDirectoryEntry = NULL, *pParentDirEntry = NULL; + WCHAR *pwchBuffer = NULL; + UNICODE_STRING uniComponentName, uniRemainingPath, uniParsedName; + ULONG ulNameDifference = 0; + GUID *pAuthGroup = NULL; + + __Enter + { + + // + // Retrieve a target name for the entry + // + + AFSAcquireShared( &DirectoryCB->NonPaged->Lock, + TRUE); + + if( DirectoryCB->NameInformation.TargetName.Length == 0) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + if( DirectoryCB->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &DirectoryCB->ObjectInformation->Fcb->AuthGroup; + } + + ntStatus = AFSEvaluateTargetByID( DirectoryCB->ObjectInformation, + pAuthGroup, + FALSE, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus) || + pDirEntry->TargetNameLength == 0) + { + + if( pDirEntry != NULL) + { + + ntStatus = STATUS_ACCESS_DENIED; + } + + try_return( ntStatus); + } + + AFSAcquireExcl( &DirectoryCB->NonPaged->Lock, + TRUE); + + if( DirectoryCB->NameInformation.TargetName.Length == 0) + { + + // + // Update the target name + // + + ntStatus = AFSUpdateTargetName( &DirectoryCB->NameInformation.TargetName, + &DirectoryCB->Flags, + (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset), + (USHORT)pDirEntry->TargetNameLength); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + try_return( ntStatus); + } + } + + AFSConvertToShared( &DirectoryCB->NonPaged->Lock); + } + + // + // Need to pass the full path in for parsing. + // + + uniFullPathName.Length = 0; + uniFullPathName.MaximumLength = DirectoryCB->NameInformation.TargetName.Length; + + uniFullPathName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniFullPathName.MaximumLength, + AFS_NAME_BUFFER_EIGHT_TAG); + + if( uniFullPathName.Buffer == NULL) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pwchBuffer = uniFullPathName.Buffer; + + RtlZeroMemory( uniFullPathName.Buffer, + uniFullPathName.MaximumLength); + + RtlCopyMemory( uniFullPathName.Buffer, + DirectoryCB->NameInformation.TargetName.Buffer, + DirectoryCB->NameInformation.TargetName.Length); + + uniFullPathName.Length = DirectoryCB->NameInformation.TargetName.Length; + + // + // This name should begin with the \afs server so parse it off and chech it + // + + FsRtlDissectName( uniFullPathName, + &uniComponentName, + &uniRemainingPath); + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSServerName, + TRUE) != 0) + { + + // + // Try evaluating the full path + // + + uniFullPathName.Buffer = pwchBuffer; + + uniFullPathName.Length = DirectoryCB->NameInformation.TargetName.Length; + + uniFullPathName.MaximumLength = uniFullPathName.Length; + } + else + { + + uniFullPathName = uniRemainingPath; + } + + uniParsedName = uniFullPathName; + + ulNameDifference = (ULONG)(uniFullPathName.Length > 0 ? ((char *)uniFullPathName.Buffer - (char *)pwchBuffer) : 0); + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + // + // Our name array + // + + pNameArray = AFSInitNameArray( AFSGlobalRoot->DirectoryCB, + 0); + + if( pNameArray == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pVolumeCB = AFSGlobalRoot; + + AFSAcquireShared( pVolumeCB->VolumeLock, + TRUE); + + pParentDirEntry = AFSGlobalRoot->DirectoryCB; + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEvaluateRootEntry Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + InterlockedIncrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEvaluateRootEntry Increment count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + + ntStatus = AFSLocateNameEntry( NULL, + NULL, + &uniFullPathName, + &uniParsedName, + pNameArray, + 0, + &pVolumeCB, + &pParentDirEntry, + &pDirectoryEntry, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + // + // The volume lock was released on failure above + // Except for STATUS_OBJECT_NAME_NOT_FOUND + // + + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) + { + + if( pVolumeCB != NULL) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEvaluateRootEntry Decrement count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + if( pDirectoryEntry != NULL) + { + + InterlockedDecrement( &pDirectoryEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEvaluateRootEntry Decrement1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryEntry->NameInformation.FileName, + pDirectoryEntry, + NULL, + pDirectoryEntry->OpenReferenceCount); + } + else + { + + InterlockedDecrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEvaluateRootEntry Decrement1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + } + } + + pVolumeCB = NULL; + + try_return( ntStatus); + } + + // + // Pass back the target dir entry for this request + // + + *TargetDirEntry = pDirectoryEntry; + +try_exit: + + if( pDirEntry != NULL) + { + + AFSExFreePool( pDirEntry); + } + + if( pVolumeCB != NULL) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEvaluateRootEntry2 Decrement count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + if( pNameArray != NULL) + { + + AFSFreeNameArray( pNameArray); + } + + if( pwchBuffer != NULL) + { + + // + // Always free the buffer that we allocated as AFSLocateNameEntry + // will not free it. If uniFullPathName.Buffer was allocated by + // AFSLocateNameEntry, then we must free that as well. + // Check that the uniFullPathName.Buffer in the string is not the same + // offset by the length of the server name + // + + AFSExFreePool( pwchBuffer); + + if( uniFullPathName.Length > 0 && + pwchBuffer != (WCHAR *)((char *)uniFullPathName.Buffer - ulNameDifference)) + { + + AFSExFreePool( uniFullPathName.Buffer); + } + } + } + + return ntStatus; +} + +NTSTATUS +AFSCleanupFcb( IN AFSFcb *Fcb, + IN BOOLEAN ForceFlush) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pRDRDeviceExt = NULL, *pControlDeviceExt = NULL; + LARGE_INTEGER liTime; + IO_STATUS_BLOCK stIoStatus; + + __Enter + { + + pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + if( !BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID) && + !BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) + { + + AFSAcquireExcl( &Fcb->NPFcb->Resource, + TRUE); + + if( Fcb->OpenReferenceCount > 0) + { + + __try + { + + CcFlushCache( &Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCleanupFcb CcFlushCache [1] failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + + CcPurgeCacheSection( &Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + FALSE); + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + } + } + + AFSReleaseResource( &Fcb->NPFcb->Resource); + + // + // Wait for any currently running flush or release requests to complete + // + + AFSWaitOnQueuedFlushes( Fcb); + + // + // Now perform another flush on the file + // + + if( !NT_SUCCESS( AFSFlushExtents( Fcb))) + { + + AFSReleaseExtentsWithFlush( Fcb); + } + } + + if( Fcb->OpenReferenceCount == 0 || + BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID) || + BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) + { + + AFSTearDownFcbExtents( Fcb); + } + + try_return( ntStatus); + } + + KeQueryTickCount( &liTime); + + // + // First up are there dirty extents in the cache to flush? + // + + if( ForceFlush || + ( !BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID) && + !BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED) && + ( Fcb->Specific.File.ExtentsDirtyCount || + Fcb->Specific.File.ExtentCount) && + (liTime.QuadPart - Fcb->Specific.File.LastServerFlush.QuadPart) + >= pControlDeviceExt->Specific.Control.FcbFlushTimeCount.QuadPart)) + { + + if( !NT_SUCCESS( AFSFlushExtents( Fcb)) && + Fcb->OpenReferenceCount == 0) + { + + AFSReleaseExtentsWithFlush( Fcb); + } + } + else if( BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID) || + BooleanFlagOn( Fcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) + { + + // + // The file has been marked as invalid. Dump it + // + + AFSTearDownFcbExtents( Fcb); + } + + // + // If there are extents and they haven't been used recently *and* + // are not being used + // + + if( ( ForceFlush || + ( 0 != Fcb->Specific.File.ExtentCount && + 0 != Fcb->Specific.File.LastExtentAccess.QuadPart && + (liTime.QuadPart - Fcb->Specific.File.LastExtentAccess.QuadPart) >= + (AFS_SERVER_PURGE_SLEEP * pControlDeviceExt->Specific.Control.FcbPurgeTimeCount.QuadPart))) && + AFSAcquireExcl( &Fcb->NPFcb->Resource, + ForceFlush)) + { + + __try + { + + CcFlushCache( &Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCleanupFcb CcFlushCache [2] failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + + if( ForceFlush) + { + + CcPurgeCacheSection( &Fcb->NPFcb->SectionObjectPointers, + NULL, + 0, + FALSE); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + } + + AFSReleaseResource( &Fcb->NPFcb->Resource); + + if( Fcb->OpenReferenceCount == 0) + { + + // + // Tear em down we'll not be needing them again + // + + AFSTearDownFcbExtents( Fcb); + } + } + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSUpdateDirEntryName( IN AFSDirectoryCB *DirectoryCB, + IN UNICODE_STRING *NewFileName) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + WCHAR *pTmpBuffer = NULL; + + __Enter + { + + if( NewFileName->Length > DirectoryCB->NameInformation.FileName.Length) + { + + if( BooleanFlagOn( DirectoryCB->Flags, AFS_DIR_RELEASE_NAME_BUFFER)) + { + + AFSExFreePool( DirectoryCB->NameInformation.FileName.Buffer); + + ClearFlag( DirectoryCB->Flags, AFS_DIR_RELEASE_NAME_BUFFER); + + DirectoryCB->NameInformation.FileName.Buffer = NULL; + } + + // + // OK, we need to allocate a new name buffer + // + + pTmpBuffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + NewFileName->Length, + AFS_NAME_BUFFER_NINE_TAG); + + if( pTmpBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + DirectoryCB->NameInformation.FileName.Buffer = pTmpBuffer; + + DirectoryCB->NameInformation.FileName.MaximumLength = NewFileName->Length; + + SetFlag( DirectoryCB->Flags, AFS_DIR_RELEASE_NAME_BUFFER); + } + + DirectoryCB->NameInformation.FileName.Length = NewFileName->Length; + + RtlCopyMemory( DirectoryCB->NameInformation.FileName.Buffer, + NewFileName->Buffer, + NewFileName->Length); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSReadCacheFile( IN void *ReadBuffer, + IN LARGE_INTEGER *ReadOffset, + IN ULONG RequestedDataLength, + IN OUT PULONG BytesRead) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIRP pIrp = NULL; + KEVENT kEvent; + PIO_STACK_LOCATION pIoStackLocation = NULL; + AFSDeviceExt *pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + DEVICE_OBJECT *pTargetDeviceObject = NULL; + FILE_OBJECT *pCacheFileObject = NULL; + + __Enter + { + + pCacheFileObject = AFSReferenceCacheFileObject(); + + if( pCacheFileObject == NULL) + { + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + pTargetDeviceObject = IoGetRelatedDeviceObject( pCacheFileObject); + + // + // Initialize the event + // + + KeInitializeEvent( &kEvent, + SynchronizationEvent, + FALSE); + + // + // Allocate an irp for this request. This could also come from a + // private pool, for instance. + // + + pIrp = IoAllocateIrp( pTargetDeviceObject->StackSize, + FALSE); + + if( pIrp == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Build the IRP's main body + // + + pIrp->UserBuffer = ReadBuffer; + + pIrp->Tail.Overlay.Thread = PsGetCurrentThread(); + pIrp->RequestorMode = KernelMode; + pIrp->Flags |= IRP_READ_OPERATION; + + // + // Set up the I/O stack location. + // + + pIoStackLocation = IoGetNextIrpStackLocation( pIrp); + pIoStackLocation->MajorFunction = IRP_MJ_READ; + pIoStackLocation->DeviceObject = pTargetDeviceObject; + pIoStackLocation->FileObject = pCacheFileObject; + pIoStackLocation->Parameters.Read.Length = RequestedDataLength; + + pIoStackLocation->Parameters.Read.ByteOffset.QuadPart = ReadOffset->QuadPart; + + // + // Set the completion routine. + // + + IoSetCompletionRoutine( pIrp, + AFSIrpComplete, + &kEvent, + TRUE, + TRUE, + TRUE); + + // + // Send it to the FSD + // + + ntStatus = IoCallDriver( pTargetDeviceObject, + pIrp); + + if( NT_SUCCESS( ntStatus)) + { + + // + // Wait for the I/O + // + + ntStatus = KeWaitForSingleObject( &kEvent, + Executive, + KernelMode, + FALSE, + 0); + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = pIrp->IoStatus.Status; + + *BytesRead = (ULONG)pIrp->IoStatus.Information; + } + } + +try_exit: + + if( pCacheFileObject != NULL) + { + AFSReleaseCacheFileObject( pCacheFileObject); + } + + if( pIrp != NULL) + { + + if( pIrp->MdlAddress != NULL) + { + + if( FlagOn( pIrp->MdlAddress->MdlFlags, MDL_PAGES_LOCKED)) + { + + MmUnlockPages( pIrp->MdlAddress); + } + + IoFreeMdl( pIrp->MdlAddress); + } + + pIrp->MdlAddress = NULL; + + // + // Free the Irp + // + + IoFreeIrp( pIrp); + } + } + + return ntStatus; +} + +NTSTATUS +AFSIrpComplete( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context) +{ + + KEVENT *pEvent = (KEVENT *)Context; + + KeSetEvent( pEvent, + 0, + FALSE); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +BOOLEAN +AFSIsDirectoryEmptyForDelete( IN AFSFcb *Fcb) +{ + + BOOLEAN bIsEmpty = FALSE; + AFSDirectoryCB *pDirEntry = NULL; + + __Enter + { + + AFSAcquireShared( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + bIsEmpty = TRUE; + + if( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL) + { + + pDirEntry = Fcb->ObjectInformation->Specific.Directory.DirectoryNodeListHead; + + while( pDirEntry != NULL) + { + + if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_FAKE) && + !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED)) + { + + bIsEmpty = FALSE; + + break; + } + + pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink; + } + + } + + AFSReleaseResource( Fcb->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + return bIsEmpty; +} + +void +AFSRemoveNameEntry( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) + { + + try_return( ntStatus); + } + + ASSERT( ExIsResourceAcquiredExclusiveLite( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock)); + + // + // Remove the entry from the parent tree + // + + AFSRemoveCaseSensitiveDirEntry( &ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + DirEntry); + + AFSRemoveCaseInsensitiveDirEntry( &ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + DirEntry); + + if( ParentObjectInfo->Specific.Directory.ShortNameTree && + DirEntry->Type.Data.ShortNameTreeEntry.HashIndex != 0) + { + + // + // From the short name tree + // + + AFSRemoveShortNameDirEntry( &ParentObjectInfo->Specific.Directory.ShortNameTree, + DirEntry); + } + + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); + +try_exit: + + NOTHING; + } + + return; +} + +LARGE_INTEGER +AFSGetAuthenticationId() +{ + + LARGE_INTEGER liAuthId = {0,0}; + NTSTATUS ntStatus = STATUS_SUCCESS; + PACCESS_TOKEN hToken = NULL; + PTOKEN_STATISTICS pTokenInfo = NULL; + BOOLEAN bCopyOnOpen = FALSE; + BOOLEAN bEffectiveOnly = FALSE; + BOOLEAN bPrimaryToken = FALSE; + SECURITY_IMPERSONATION_LEVEL stImpersonationLevel; + + __Enter + { + + hToken = PsReferenceImpersonationToken( PsGetCurrentThread(), + &bCopyOnOpen, + &bEffectiveOnly, + &stImpersonationLevel); + + if( hToken == NULL) + { + + hToken = PsReferencePrimaryToken( PsGetCurrentProcess()); + + if( hToken == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_ERROR, + "AFSGetAuthenticationId Failed to retrieve impersonation or primary token\n"); + + try_return( ntStatus); + } + + bPrimaryToken = TRUE; + } + + ntStatus = SeQueryInformationToken( hToken, + TokenStatistics, + (PVOID *)&pTokenInfo); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_ERROR, + "AFSGetAuthenticationId Failed to retrieve information Status %08lX\n", ntStatus); + + try_return( ntStatus); + } + + liAuthId.HighPart = pTokenInfo->AuthenticationId.HighPart; + liAuthId.LowPart = pTokenInfo->AuthenticationId.LowPart; + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetAuthenticationId Successfully retrieved authentication ID %I64X\n", + liAuthId.QuadPart); + +try_exit: + + if( hToken != NULL) + { + + if( !bPrimaryToken) + { + + PsDereferenceImpersonationToken( hToken); + } + else + { + + PsDereferencePrimaryToken( hToken); + } + } + + if( pTokenInfo != NULL) + { + + AFSExFreePool( pTokenInfo); + } + } + + return liAuthId; +} + +void +AFSUnwindFileInfo( IN AFSFcb *Fcb, + IN AFSCcb *Ccb) +{ + + if( Ccb->FileUnwindInfo.FileAttributes != (ULONG)-1) + { + Ccb->DirectoryCB->ObjectInformation->FileAttributes = Ccb->FileUnwindInfo.FileAttributes; + } + + if( Ccb->FileUnwindInfo.CreationTime.QuadPart != (ULONGLONG)-1) + { + Ccb->DirectoryCB->ObjectInformation->CreationTime.QuadPart = Ccb->FileUnwindInfo.CreationTime.QuadPart; + } + + if( Ccb->FileUnwindInfo.LastAccessTime.QuadPart != (ULONGLONG)-1) + { + Ccb->DirectoryCB->ObjectInformation->LastAccessTime.QuadPart = Ccb->FileUnwindInfo.LastAccessTime.QuadPart; + } + + if( Ccb->FileUnwindInfo.LastWriteTime.QuadPart != (ULONGLONG)-1) + { + Ccb->DirectoryCB->ObjectInformation->LastWriteTime.QuadPart = Ccb->FileUnwindInfo.LastWriteTime.QuadPart; + } + + if( Ccb->FileUnwindInfo.ChangeTime.QuadPart != (ULONGLONG)-1) + { + Ccb->DirectoryCB->ObjectInformation->ChangeTime.QuadPart = Ccb->FileUnwindInfo.ChangeTime.QuadPart; + } + + return; +} + +BOOLEAN +AFSValidateDirList( IN AFSObjectInfoCB *ObjectInfo) +{ + + BOOLEAN bIsValid = TRUE; + ULONG ulCount = 0; + AFSDirectoryCB *pCurrentDirEntry = NULL; + + pCurrentDirEntry = ObjectInfo->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + if( !BooleanFlagOn( pCurrentDirEntry->Flags, AFS_DIR_ENTRY_FAKE)) + { + ulCount++; + } + + pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + } + + if( ulCount != ObjectInfo->Specific.Directory.DirectoryNodeCount) + { + + AFSPrint("AFSValidateDirList Count off Calc: %d Stored: %d\n", + ulCount, + ObjectInfo->Specific.Directory.DirectoryNodeCount); + + ObjectInfo->Specific.Directory.DirectoryNodeCount = ulCount; + + bIsValid = FALSE; + } + + return bIsValid; +} + +PFILE_OBJECT +AFSReferenceCacheFileObject() +{ + + AFSDeviceExt *pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + FILE_OBJECT *pCacheFileObject = NULL; + + AFSAcquireShared( &pRdrDevExt->Specific.RDR.CacheFileLock, + TRUE); + + pCacheFileObject = pRdrDevExt->Specific.RDR.CacheFileObject; + + if( pCacheFileObject != NULL) + { + ObReferenceObject( pCacheFileObject); + } + + AFSReleaseResource( &pRdrDevExt->Specific.RDR.CacheFileLock); + + return pCacheFileObject; +} + +void +AFSReleaseCacheFileObject( IN PFILE_OBJECT CacheFileObject) +{ + + ASSERT( CacheFileObject != NULL); + + ObDereferenceObject( CacheFileObject); + + return; +} + +NTSTATUS +AFSInitializeLibrary( IN AFSLibraryInitCB *LibraryInit) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pControlDevExt = NULL; + ULONG ulTimeIncrement = 0; + + __Enter + { + + AFSControlDeviceObject = LibraryInit->AFSControlDeviceObject; + + AFSRDRDeviceObject = LibraryInit->AFSRDRDeviceObject; + + AFSServerName = LibraryInit->AFSServerName; + + AFSDebugFlags = LibraryInit->AFSDebugFlags; + + // + // Callbacks in the framework + // + + AFSProcessRequest = LibraryInit->AFSProcessRequest; + + AFSDbgLogMsg = LibraryInit->AFSDbgLogMsg; + + AFSAddConnectionEx = LibraryInit->AFSAddConnectionEx; + + AFSExAllocatePoolWithTag = LibraryInit->AFSExAllocatePoolWithTag; + + AFSExFreePool = LibraryInit->AFSExFreePool; + + AFSDumpTraceFilesFnc = LibraryInit->AFSDumpTraceFiles; + + AFSRetrieveAuthGroupFnc = LibraryInit->AFSRetrieveAuthGroup; + + AFSLibCacheManagerCallbacks = LibraryInit->AFSCacheManagerCallbacks; + + if( LibraryInit->AFSCacheBaseAddress != NULL) + { + + SetFlag( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE); + + AFSLibCacheBaseAddress = LibraryInit->AFSCacheBaseAddress; + + AFSLibCacheLength = LibraryInit->AFSCacheLength; + } + + // + // Initialize some flush parameters + // + + pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + ulTimeIncrement = KeQueryTimeIncrement(); + + pControlDevExt->Specific.Control.ObjectLifeTimeCount.QuadPart = (ULONGLONG)((ULONGLONG)AFS_OBJECT_LIFETIME / (ULONGLONG)ulTimeIncrement); + pControlDevExt->Specific.Control.FcbPurgeTimeCount.QuadPart = AFS_ONE_SECOND; + pControlDevExt->Specific.Control.FcbPurgeTimeCount.QuadPart *= AFS_SERVER_PURGE_DELAY; + pControlDevExt->Specific.Control.FcbPurgeTimeCount.QuadPart /= ulTimeIncrement; + pControlDevExt->Specific.Control.FcbFlushTimeCount.QuadPart = (ULONGLONG)((ULONGLONG)(AFS_ONE_SECOND * AFS_SERVER_FLUSH_DELAY) / (ULONGLONG)ulTimeIncrement); + pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart = (ULONGLONG)((ULONGLONG)AFS_EXTENT_REQUEST_TIME/(ULONGLONG)ulTimeIncrement); + + // + // Initialize the global root entry + // + + ntStatus = AFSInitVolume( NULL, + &LibraryInit->GlobalRootFid, + &AFSGlobalRoot); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeLibrary AFSInitVolume failure %08lX\n", + ntStatus); + + try_return( ntStatus); + } + + ntStatus = AFSInitRootFcb( (ULONGLONG)PsGetCurrentProcessId(), + AFSGlobalRoot); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOAD_LIBRARY | AFS_SUBSYSTEM_INIT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeLibrary AFSInitRootFcb failure %08lX\n", + ntStatus); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + try_return( ntStatus); + } + + // + // Update the node type code to AFS_ROOT_ALL + // + + AFSGlobalRoot->ObjectInformation.Fcb->Header.NodeTypeCode = AFS_ROOT_ALL; + + SetFlag( AFSGlobalRoot->Flags, AFS_VOLUME_ACTIVE_GLOBAL_ROOT); + + // + // Drop the locks acquired above + // + + AFSInitVolumeWorker( AFSGlobalRoot); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Fcb->Header.Resource); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSCloseLibrary() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pDirNode = NULL, *pLastDirNode = NULL; + + __Enter + { + + if( AFSGlobalDotDirEntry != NULL) + { + + AFSDeleteObjectInfo( AFSGlobalDotDirEntry->ObjectInformation); + + ExDeleteResourceLite( &AFSGlobalDotDirEntry->NonPaged->Lock); + + ExFreePool( AFSGlobalDotDirEntry->NonPaged); + + ExFreePool( AFSGlobalDotDirEntry); + + AFSGlobalDotDirEntry = NULL; + } + + if( AFSGlobalDotDotDirEntry != NULL) + { + + AFSDeleteObjectInfo( AFSGlobalDotDotDirEntry->ObjectInformation); + + ExDeleteResourceLite( &AFSGlobalDotDotDirEntry->NonPaged->Lock); + + ExFreePool( AFSGlobalDotDotDirEntry->NonPaged); + + ExFreePool( AFSGlobalDotDotDirEntry); + + AFSGlobalDotDotDirEntry = NULL; + } + + if( AFSSpecialShareNames != NULL) + { + + pDirNode = AFSSpecialShareNames; + + while( pDirNode != NULL) + { + + pLastDirNode = (AFSDirectoryCB *)pDirNode->ListEntry.fLink; + + AFSDeleteObjectInfo( pDirNode->ObjectInformation); + + ExDeleteResourceLite( &pDirNode->NonPaged->Lock); + + ExFreePool( pDirNode->NonPaged); + + ExFreePool( pDirNode); + + pDirNode = pLastDirNode; + } + + AFSSpecialShareNames = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSDefaultLogMsg( IN ULONG Subsystem, + IN ULONG Level, + IN PCCH Format, + ...) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + va_list va_args; + char chDebugBuffer[ 256]; + + __Enter + { + + va_start( va_args, Format); + + ntStatus = RtlStringCbVPrintfA( chDebugBuffer, + 256, + Format, + va_args); + + if( NT_SUCCESS( ntStatus)) + { + DbgPrint( chDebugBuffer); + } + + va_end( va_args); + } + + return ntStatus; +} + +NTSTATUS +AFSGetObjectStatus( IN AFSGetStatusInfoCB *GetStatusInfo, + IN ULONG InputBufferLength, + IN AFSStatusInfoCB *StatusInfo, + OUT ULONG *ReturnLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSFcb *pFcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + AFSObjectInfoCB *pObjectInfo = NULL; + ULONGLONG ullIndex = 0; + UNICODE_STRING uniFullPathName, uniRemainingPath, uniComponentName, uniParsedName; + AFSNameArrayHdr *pNameArray = NULL; + AFSDirectoryCB *pDirectoryEntry = NULL, *pParentDirEntry = NULL; + + __Enter + { + + // + // If we are given a FID then look up the entry by that, otherwise + // do it by name + // + + if( GetStatusInfo->FileID.Cell != 0 && + GetStatusInfo->FileID.Volume != 0 && + GetStatusInfo->FileID.Vnode != 0 && + GetStatusInfo->FileID.Unique != 0) + { + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, TRUE); + + // + // Locate the volume node + // + + ullIndex = AFSCreateHighIndex( &GetStatusInfo->FileID); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + if( pVolumeCB != NULL) + { + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + } + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + if( !NT_SUCCESS( ntStatus) || + pVolumeCB == NULL) + { + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + if( AFSIsVolumeFID( &GetStatusInfo->FileID)) + { + + pObjectInfo = &pVolumeCB->ObjectInformation; + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + } + else + { + + AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Decrement count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + ullIndex = AFSCreateLowIndex( &GetStatusInfo->FileID); + + ntStatus = AFSLocateHashEntry( pVolumeCB->ObjectInfoTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pObjectInfo); + + if( pObjectInfo != NULL) + { + + // + // Reference the node so it won't be torn down + // + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Increment count on object %08lX Cnt %d\n", + pObjectInfo, + pObjectInfo->ObjectReferenceCount); + } + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( !NT_SUCCESS( ntStatus) || + pObjectInfo == NULL) + { + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + } + } + else + { + + if( GetStatusInfo->FileNameLength == 0 || + InputBufferLength < (ULONG)(FIELD_OFFSET( AFSGetStatusInfoCB, FileName) + GetStatusInfo->FileNameLength)) + { + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + uniFullPathName.Length = GetStatusInfo->FileNameLength; + uniFullPathName.MaximumLength = uniFullPathName.Length; + + uniFullPathName.Buffer = (WCHAR *)GetStatusInfo->FileName; + + // + // This name should begin with the \afs server so parse it off and check it + // + + FsRtlDissectName( uniFullPathName, + &uniComponentName, + &uniRemainingPath); + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSServerName, + TRUE) != 0) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSGetObjectStatus Name %wZ contains invalid server name\n", + &uniFullPathName); + + try_return( ntStatus = STATUS_OBJECT_PATH_INVALID); + } + + uniFullPathName = uniRemainingPath; + + uniParsedName = uniFullPathName; + + // + // Our name array + // + + pNameArray = AFSInitNameArray( AFSGlobalRoot->DirectoryCB, + 0); + + if( pNameArray == NULL) + { + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pVolumeCB = AFSGlobalRoot; + + AFSAcquireShared( pVolumeCB->VolumeLock, + TRUE); + + pParentDirEntry = AFSGlobalRoot->DirectoryCB; + + // + // Increment the ref count on the volume and dir entry for correct processing below + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + InterlockedIncrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Increment count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + + ntStatus = AFSLocateNameEntry( NULL, + NULL, + &uniFullPathName, + &uniParsedName, + pNameArray, + AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL | + AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL, + &pVolumeCB, + &pParentDirEntry, + &pDirectoryEntry, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + // + // The volume lock was released on failure above + // Except for STATUS_OBJECT_NAME_NOT_FOUND + // + + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) + { + + if( pVolumeCB != NULL) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Decrement count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + if( pDirectoryEntry != NULL) + { + + InterlockedDecrement( &pDirectoryEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Decrement1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirectoryEntry->NameInformation.FileName, + pDirectoryEntry, + NULL, + pDirectoryEntry->OpenReferenceCount); + } + else + { + + InterlockedDecrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetObjectStatus Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + } + } + + pVolumeCB = NULL; + + try_return( ntStatus); + } + + // + // Remove the reference made above + // + + InterlockedDecrement( &pDirectoryEntry->OpenReferenceCount); + + pObjectInfo = pDirectoryEntry->ObjectInformation; + + InterlockedIncrement( &pObjectInfo->ObjectReferenceCount); + + if( pVolumeCB != NULL) + { + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRetrieveFileAttributes Decrement2 count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + } + + // + // At this point we have an object info block, return the information + // + + StatusInfo->FileId = pObjectInfo->FileId; + + StatusInfo->TargetFileId = pObjectInfo->TargetFileId; + + StatusInfo->Expiration = pObjectInfo->Expiration; + + StatusInfo->DataVersion = pObjectInfo->DataVersion; + + StatusInfo->FileType = pObjectInfo->FileType; + + StatusInfo->ObjectFlags = pObjectInfo->Flags; + + StatusInfo->CreationTime = pObjectInfo->CreationTime; + + StatusInfo->LastAccessTime = pObjectInfo->LastAccessTime; + + StatusInfo->LastWriteTime = pObjectInfo->LastWriteTime; + + StatusInfo->ChangeTime = pObjectInfo->ChangeTime; + + StatusInfo->FileAttributes = pObjectInfo->FileAttributes; + + StatusInfo->EndOfFile = pObjectInfo->EndOfFile; + + StatusInfo->AllocationSize = pObjectInfo->AllocationSize; + + StatusInfo->EaSize = pObjectInfo->EaSize; + + StatusInfo->Links = pObjectInfo->Links; + + // + // Return the information length + // + + *ReturnLength = sizeof( AFSStatusInfoCB); + +try_exit: + + if( pObjectInfo != NULL) + { + + InterlockedDecrement( &pObjectInfo->ObjectReferenceCount); + } + + if( pNameArray != NULL) + { + + AFSFreeNameArray( pNameArray); + } + } + + return ntStatus; +} + +NTSTATUS +AFSCheckSymlinkAccess( IN AFSDirectoryCB *ParentDirectoryCB, + IN UNICODE_STRING *ComponentName) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pDirEntry = NULL; + ULONG ulCRC = 0; + + __Enter + { + + // + // Search for the entry in the parent + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCheckSymlinkAccess Searching for entry %wZ case sensitive\n", + ComponentName); + + ulCRC = AFSGenerateCRC( ComponentName, + FALSE); + + AFSAcquireShared( ParentDirectoryCB->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSLocateCaseSensitiveDirEntry( ParentDirectoryCB->ObjectInformation->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pDirEntry); + + if( pDirEntry == NULL) + { + + // + // Missed so perform a case insensitive lookup + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCheckSymlinkAccess Searching for entry %wZ case insensitive\n", + ComponentName); + + ulCRC = AFSGenerateCRC( ComponentName, + TRUE); + + AFSLocateCaseInsensitiveDirEntry( ParentDirectoryCB->ObjectInformation->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + ulCRC, + &pDirEntry); + + if( pDirEntry == NULL) + { + + // + // OK, if this component is a valid short name then try + // a lookup in the short name tree + // + + if( RtlIsNameLegalDOS8Dot3( ComponentName, + NULL, + NULL)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCheckSymlinkAccess Searching for entry %wZ short name\n", + ComponentName); + + AFSLocateShortNameDirEntry( ParentDirectoryCB->ObjectInformation->Specific.Directory.ShortNameTree, + ulCRC, + &pDirEntry); + } + } + } + + if( pDirEntry != NULL) + { + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + } + + AFSReleaseResource( ParentDirectoryCB->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + if( pDirEntry == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCheckSymlinkAccess Failed to locate entry %wZ\n", + ComponentName); + + try_return( ntStatus = STATUS_OBJECT_NAME_NOT_FOUND); + } + + // + // We have the symlink object but previously failed to process it so return access + // denied. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCheckSymlinkAccess Failing symlink access to entry %wZ ACCESS_DENIED\n", + ComponentName); + + ntStatus = STATUS_ACCESS_DENIED; + + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSRetrieveFinalComponent( IN UNICODE_STRING *FullPathName, + OUT UNICODE_STRING *ComponentName) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniFullPathName, uniRemainingPath, uniComponentName; + + uniFullPathName = *FullPathName; + + while( TRUE) + { + + FsRtlDissectName( uniFullPathName, + &uniComponentName, + &uniRemainingPath); + + if( uniRemainingPath.Length == 0) + { + break; + } + + uniFullPathName = uniRemainingPath; + } + + if( uniComponentName.Length > 0) + { + *ComponentName = uniComponentName; + } + + return ntStatus; +} + +void +AFSDumpTraceFiles_Default() +{ + return; +} + +BOOLEAN +AFSValidNameFormat( IN UNICODE_STRING *FileName) +{ + + BOOLEAN bIsValidName = TRUE; + USHORT usIndex = 0; + + __Enter + { + + while( usIndex < FileName->Length/sizeof( WCHAR)) + { + + if( FileName->Buffer[ usIndex] == L':' || + FileName->Buffer[ usIndex] == L'*' || + FileName->Buffer[ usIndex] == L'?' || + FileName->Buffer[ usIndex] == L'"' || + FileName->Buffer[ usIndex] == L'<' || + FileName->Buffer[ usIndex] == L'>') + { + bIsValidName = FALSE; + break; + } + + usIndex++; + } + } + + return bIsValidName; +} + +NTSTATUS +AFSCreateDefaultSecurityDescriptor() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PACL pSACL = NULL; + ULONG ulSACLSize = 0; + SYSTEM_MANDATORY_LABEL_ACE* pACE = NULL; + ULONG ulACESize = 0; + SECURITY_DESCRIPTOR *pSecurityDescr = NULL; + ULONG ulSDLength = 0; + SECURITY_DESCRIPTOR *pRelativeSecurityDescr = NULL; + + __Enter + { + + if( AFSRtlSetSaclSecurityDescriptor == NULL) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor AFSRtlSetSaclSecurityDescriptor == NULL\n"); + } + else + { + + ulACESize = sizeof( SYSTEM_MANDATORY_LABEL_ACE) + 128; + + pACE = (SYSTEM_MANDATORY_LABEL_ACE *)ExAllocatePoolWithTag( PagedPool, + ulACESize, + AFS_GENERIC_MEMORY_29_TAG); + + if( pACE == NULL) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor unable to allocate AFS_GENERIC_MEMORY_29_TAG\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pACE, + ulACESize); + + pACE->Header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE; + pACE->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE; + pACE->Header.AceSize = FIELD_OFFSET( SYSTEM_MANDATORY_LABEL_ACE, SidStart) + (USHORT)RtlLengthSid( SeExports->SeLowMandatorySid); + pACE->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP; + + RtlCopySid( RtlLengthSid( SeExports->SeLowMandatorySid), + &pACE->SidStart, + SeExports->SeLowMandatorySid); + + ulSACLSize = sizeof(ACL) + RtlLengthSid( SeExports->SeLowMandatorySid) + + FIELD_OFFSET( SYSTEM_MANDATORY_LABEL_ACE, SidStart) + ulACESize; + + pSACL = (PACL)ExAllocatePoolWithTag( PagedPool, + ulSACLSize, + AFS_GENERIC_MEMORY_29_TAG); + + if( pSACL == NULL) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor unable to allocate AFS_GENERIC_MEMORY_29_TAG\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ntStatus = RtlCreateAcl( pSACL, + ulSACLSize, + ACL_REVISION); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor RtlCreateAcl ntStatus %08lX\n", + ntStatus); + + try_return( ntStatus); + } + + ntStatus = RtlAddAce( pSACL, + ACL_REVISION, + 0, + pACE, + pACE->Header.AceSize); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor RtlAddAce ntStatus %08lX\n", + ntStatus); + + try_return( ntStatus); + } + } + + pSecurityDescr = (SECURITY_DESCRIPTOR *)ExAllocatePoolWithTag( NonPagedPool, + sizeof( SECURITY_DESCRIPTOR), + AFS_GENERIC_MEMORY_27_TAG); + + if( pSecurityDescr == NULL) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor unable to allocate AFS_GENERIC_MEMORY_27_TAG\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ntStatus = RtlCreateSecurityDescriptor( pSecurityDescr, + SECURITY_DESCRIPTOR_REVISION); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor RtlCreateSecurityDescriptor ntStatus %08lX\n", + ntStatus); + + try_return( ntStatus); + } + + if( AFSRtlSetSaclSecurityDescriptor != NULL) + { + ntStatus = AFSRtlSetSaclSecurityDescriptor( pSecurityDescr, + TRUE, + pSACL, + FALSE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor AFSRtlSetSaclSecurityDescriptor ntStatus %08lX\n", + ntStatus); + + try_return( ntStatus); + } + } + + if( !RtlValidSecurityDescriptor( pSecurityDescr)) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor RtlValidSecurityDescriptor NOT\n"); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + pRelativeSecurityDescr = (SECURITY_DESCRIPTOR *)ExAllocatePoolWithTag( NonPagedPool, + PAGE_SIZE, + AFS_GENERIC_MEMORY_27_TAG); + + if( pRelativeSecurityDescr == NULL) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor unable to allocate AFS_GENERIC_MEMORY_27_TAG\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ulSDLength = PAGE_SIZE; + + ntStatus = RtlAbsoluteToSelfRelativeSD( pSecurityDescr, + pRelativeSecurityDescr, + &ulSDLength); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint( "AFSCreateDefaultSecurityDescriptor RtlAbsoluteToSelfRelativeSD ntStatus %08lX\n", + ntStatus); + + try_return( ntStatus); + } + + AFSDefaultSD = pRelativeSecurityDescr; + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + if( pRelativeSecurityDescr != NULL) + { + ExFreePool( pRelativeSecurityDescr); + } + } + + if( pSecurityDescr != NULL) + { + ExFreePool( pSecurityDescr); + } + + if( pSACL != NULL) + { + ExFreePool( pSACL); + } + + if( pACE != NULL) + { + ExFreePool( pACE); + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSInit.cpp b/src/WINNT/afsrdr/kernel/lib/AFSInit.cpp new file mode 100644 index 0000000000..b2a1df0e66 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSInit.cpp @@ -0,0 +1,334 @@ +/* + * 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: AFSInit.cpp +// + +#include "AFSCommon.h" + +// +// DriverEntry +// +// This is the initial entry point for the driver. +// +// Inputs: +// DriverObject Pointer to Driver Object created by I/O manager +// RegistryPath Pointer to registry path representing this Driver +// +// Returns: +// Success To indicate Driver's inituaialization processing +// was successful +// NT ERROR STATUS Otherwise -- Driver does not remain loaded +// + +NTSTATUS +DriverEntry( PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt; + ULONG ulTimeIncrement = 0; + UNICODE_STRING uniDeviceName; + ULONG ulIndex = 0; + UNICODE_STRING uniRoutine; + RTL_OSVERSIONINFOW sysVersion; + + BOOLEAN bExit = FALSE; + + __try + { + + AFSPrint("AFSLibrary DriverEntry Initialization build %s:%s\n", __DATE__, __TIME__); + + // + // Our backdoor to not let the driver load + // + + if( bExit) + { + + // + // Return a failure so we can update the binary and manually start it without + // having to do a reboot + // + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Perform some initialization + // + + AFSLibraryDriverObject = DriverObject; + + // + // Setup the registry string + // + + AFSRegistryPath.MaximumLength = RegistryPath->MaximumLength; + AFSRegistryPath.Length = RegistryPath->Length; + + AFSRegistryPath.Buffer = (PWSTR)AFSLibExAllocatePoolWithTag( PagedPool, + AFSRegistryPath.Length, + AFS_GENERIC_MEMORY_13_TAG); + + if( AFSRegistryPath.Buffer == NULL) + { + + AFSPrint("AFS DriverEntry Failed to allocate registry path buffer\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( AFSRegistryPath.Buffer, + RegistryPath->Buffer, + RegistryPath->Length); + + RtlZeroMemory( &sysVersion, + sizeof( RTL_OSVERSIONINFOW)); + + sysVersion.dwOSVersionInfoSize = sizeof( RTL_OSVERSIONINFOW); + + RtlGetVersion( &sysVersion); + +#if 0 + // + // By not fetching the RtlSetSaclSecurityDescriptor function + // pointer it disables the additional of a mandatory label + // to the default acl which is returned by AFSRedir for all + // security information queries. The addition of the + // mandatory label appears to have a negative consequence + // for roaming profiles and redirected folders. All links + // become untrusted and IE9 is unable to open a new instance + // to a non-default home page. + // + // + // Only retrieve this function for Vista and above since + // Mandatory Labels only exist on those operating systems. + // + + if( sysVersion.dwMajorVersion >= 6) + { + RtlInitUnicodeString( &uniRoutine, + L"RtlSetSaclSecurityDescriptor"); + + AFSRtlSetSaclSecurityDescriptor = (PAFSRtlSetSaclSecurityDescriptor)MmGetSystemRoutineAddress( &uniRoutine); + } + + ntStatus = AFSCreateDefaultSecurityDescriptor(); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint("AFS DriverEntry AFSCreateDefaultSecurityDescriptor failed Status %08lX\n", ntStatus); + + ntStatus = STATUS_SUCCESS; + } +#endif + // + // Initilize the control device + // + + RtlInitUnicodeString( &uniDeviceName, + AFS_LIBRARY_CONTROL_DEVICE_NAME); + + ntStatus = IoCreateDevice( DriverObject, + sizeof( AFSDeviceExt), + &uniDeviceName, + FILE_DEVICE_DISK_FILE_SYSTEM, + 0, + FALSE, + &AFSLibraryDeviceObject); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint("AFS DriverEntry - Failed to allocate device control object Status %08lX\n", ntStatus); + + try_return( ntStatus); + } + + // + // Setup the device extension + // + + pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + // + // Now initialize the control device + // + + ntStatus = AFSInitializeLibraryDevice(); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + // + // Initialize the worker thread pool + // + + ntStatus = AFSInitializeWorkerPool(); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint("AFS DriverEntry Failed to initialize worker pool Status %08lX\n", ntStatus); + + try_return( ntStatus); + } + + // + // Fill in the dispatch table + // + + for( ulIndex = 0; ulIndex <= IRP_MJ_MAXIMUM_FUNCTION; ulIndex++) + { + + DriverObject->MajorFunction[ ulIndex] = AFSDefaultDispatch; + } + + DriverObject->MajorFunction[IRP_MJ_CREATE] = AFSCreate; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = AFSClose; + DriverObject->MajorFunction[IRP_MJ_READ] = AFSRead; + DriverObject->MajorFunction[IRP_MJ_WRITE] = AFSWrite; + DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = AFSQueryFileInfo; + DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = AFSSetFileInfo; + DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = AFSQueryEA; + DriverObject->MajorFunction[IRP_MJ_SET_EA] = AFSSetEA; + DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = AFSFlushBuffers; + DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = AFSQueryVolumeInfo; + DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = AFSSetVolumeInfo; + DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = AFSDirControl; + DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = AFSFSControl; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AFSDevControl; + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = AFSInternalDevControl; + DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = AFSShutdown; + DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = AFSLockControl; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = AFSCleanup; + DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY] = AFSQuerySecurity; + DriverObject->MajorFunction[IRP_MJ_SET_SECURITY] = AFSSetSecurity; + DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AFSSystemControl; + //DriverObject->MajorFunction[IRP_MJ_QUERY_QUOTA] = AFSQueryQuota; + //DriverObject->MajorFunction[IRP_MJ_SET_QUOTA] = AFSSetQuota; + + DriverObject->DriverUnload = AFSUnload; + + AFSSysProcess = PsGetCurrentProcessId(); + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + AFSPrint("AFSLibrary DriverEntry failed to initialize %08lX\n", ntStatus); + + if( AFSLibraryDeviceObject != NULL) + { + + AFSRemoveWorkerPool(); + } + + if( AFSRegistryPath.Buffer != NULL) + { + + ExFreePool( AFSRegistryPath.Buffer); + } + + if( AFSLibraryDeviceObject != NULL) + { + + AFSRemoveLibraryDevice(); + + IoDeleteDevice( AFSLibraryDeviceObject); + } + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSPrint( "EXCEPTION - AFS DriverEntry\n"); + } + + return ntStatus; +} + +void +AFSUnload( IN PDRIVER_OBJECT DriverObject) +{ + + if( AFSGlobalRoot != NULL) + { + + AFSInvalidateVolume( AFSGlobalRoot, + AFS_INVALIDATE_CALLBACK); + + ClearFlag( AFSGlobalRoot->Flags, AFS_VOLUME_ACTIVE_GLOBAL_ROOT); + + AFSShutdownVolumeWorker( AFSGlobalRoot); + } + + if( AFSLibraryDeviceObject != NULL) + { + + AFSRemoveWorkerPool(); + } + + if( AFSRegistryPath.Buffer != NULL) + { + + ExFreePool( AFSRegistryPath.Buffer); + } + + AFSCloseLibrary(); + + if( AFSDefaultSD != NULL) + { + ExFreePool( AFSDefaultSD); + } + + if( AFSLibraryDeviceObject != NULL) + { + + AFSRemoveLibraryDevice(); + + IoDeleteDevice( AFSLibraryDeviceObject); + } + + return; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSInternalDevControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSInternalDevControl.cpp new file mode 100644 index 0000000000..64e5e9c013 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSInternalDevControl.cpp @@ -0,0 +1,67 @@ +/* + * 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: AFSInternalDevControl.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSInternalDevControl( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_NOT_IMPLEMENTED; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSInternalDevControl\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSIoSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSIoSupport.cpp new file mode 100644 index 0000000000..d3d907abc4 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSIoSupport.cpp @@ -0,0 +1,527 @@ +/* + * 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: AFSIoSupport.cpp +// + +#include "AFSCommon.h" + +static AFSExtent *NextExtent(AFSExtent *Extent); + +// +// Called in the paging or non cached read and write paths to get the +// first and last extent in a span. We also the count of how many +// discontiguous extents the are in the cache file. +// + +NTSTATUS +AFSGetExtents( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Length, + OUT AFSExtent *From, + OUT ULONG *ExtentCount, + OUT ULONG *RunCount) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG extentsCount = 0, runCount = 0; + AFSExtent *pEndExtent = NULL; + LARGE_INTEGER liLastCacheOffset; + + *ExtentCount = 0; + + __Enter + { + ASSERT(AFSExtentContains(From, Offset)); + + pEndExtent = From; + extentsCount = 1; + runCount = 1; + liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size; + + while ((Offset->QuadPart + Length) > + pEndExtent->FileOffset.QuadPart + pEndExtent->Size) { + + pEndExtent = NextExtent(pEndExtent); + + if (liLastCacheOffset.QuadPart != pEndExtent->CacheOffset.QuadPart) { + // + // Discontiguous (in the cache) + // + runCount += 1; + + } + + extentsCount+= 1; + + liLastCacheOffset.QuadPart = pEndExtent->CacheOffset.QuadPart + pEndExtent->Size; + } + + *ExtentCount = extentsCount; + *RunCount = runCount; + ntStatus = STATUS_SUCCESS; + } + return ntStatus; +} + + +NTSTATUS +AFSSetupIoRun( IN PDEVICE_OBJECT CacheDevice, + IN PIRP MasterIrp, + IN PVOID SystemBuffer, + IN OUT AFSIoRun *IoRuns, + IN PLARGE_INTEGER Start, + IN ULONG Length, + IN AFSExtent *From, + IN OUT ULONG *RunCount) +{ + // + // Do all the work which we can prior to firing off the IRP + // (allocate them, calculate offsets and so on) + // + LARGE_INTEGER liCacheOffset; + LARGE_INTEGER liFileOffset = *Start; + ULONG ulCurrLength; + ULONG ulReadOffset; + ULONG ulCurrRun = 0; + AFSExtent *pExtent = From; + AFSExtent *pNextExtent; + PMDL *pMDL; + BOOLEAN done = FALSE; + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + while( !done) + { + ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart ); + + liCacheOffset = pExtent->CacheOffset; + liCacheOffset.QuadPart += (liFileOffset.QuadPart - + pExtent->FileOffset.QuadPart); + + ulCurrLength = 0; + + // + // While there is still data to process, loop + // + while ( (pExtent->FileOffset.QuadPart + pExtent->Size) < + (Start->QuadPart + Length) ) + { + // + // Collapse the read if we can + // + pNextExtent = NextExtent( pExtent ); + + if (pNextExtent->CacheOffset.QuadPart != + (pExtent->CacheOffset.QuadPart + pExtent->Size)) + { + // + // This extent and the next extent are not contiguous + // + break; + } + pExtent = pNextExtent; + } + + // + // So, this run goes from liCacheOffset to the end of pExtent + // + + if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length)) + { + // + // The last extent overruns the area we care + // about, so trim it back. + // + ulCurrLength = (ULONG) (Start->QuadPart + Length - + liFileOffset.QuadPart); + // + // But we are done + // + done = TRUE; + } + else + { + // + // Length is from the LiFileOffset to the end of this + // extent. + // + ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size - + liFileOffset.QuadPart); + done = FALSE; + } + + // + // Calculate the offset into the buffer + // + ulReadOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart); + + IoRuns[ulCurrRun].CacheOffset = liCacheOffset; + IoRuns[ulCurrRun].ByteCount = ulCurrLength; + + IoRuns[ulCurrRun].ChildIrp = IoAllocateIrp( CacheDevice->StackSize + 1, + FALSE); + + if (NULL == IoRuns[ulCurrRun].ChildIrp) + { + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + IoRuns[ulCurrRun].ChildIrp->UserBuffer = ((PCHAR) SystemBuffer) + ulReadOffset; + IoRuns[ulCurrRun].ChildIrp->Tail.Overlay.Thread = PsGetCurrentThread(); + IoRuns[ulCurrRun].ChildIrp->RequestorMode = KernelMode; + IoRuns[ulCurrRun].ChildIrp->MdlAddress = NULL; + + ulCurrRun ++; + if (!done) + { + ASSERT(pNextExtent != NULL && pNextExtent != pExtent); + // + // Move cursors forward + // + pExtent = pNextExtent; + liFileOffset = pExtent->FileOffset; + } + } + ASSERT(ulCurrRun <= *RunCount); +try_exit: + if (!NT_SUCCESS(ntStatus)) + { + for (ulCurrRun = 0 ; ulCurrRun < *RunCount; ulCurrRun++) + { + if (IoRuns[ulCurrRun].ChildIrp) { + IoFreeIrp( IoRuns[ulCurrRun].ChildIrp ); + IoRuns[ulCurrRun].ChildIrp = NULL; + } + } + } + else + { + *RunCount = ulCurrRun; + } + } + return ntStatus; +} + +// +// We manage our own scatter / gather. This completion +// function calls into our generic function. +// + +static +NTSTATUS +CompletionFunction(IN PDEVICE_OBJECT DeviceObject, + PIRP Irp, + PVOID Context) +{ + AFSGatherIo *pGather = (AFSGatherIo *) Context; + + AFSCompleteIo( pGather, Irp->IoStatus.Status); + + if (Irp->MdlAddress) { + if (Irp->MdlAddress->MdlFlags & MDL_PAGES_LOCKED) { + MmUnlockPages(Irp->MdlAddress); + } + IoFreeMdl(Irp->MdlAddress); + Irp->MdlAddress = NULL; + } + IoFreeIrp(Irp); + + // + // Tell io manager that we own the Irp + // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +NTSTATUS +AFSStartIos( IN PFILE_OBJECT CacheFileObject, + IN UCHAR FunctionCode, + IN ULONG IrpFlags, + IN AFSIoRun *IoRun, + IN ULONG Count, + IN OUT AFSGatherIo *Gather) +{ + + AFSDeviceExt *pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + PIO_STACK_LOCATION pIoStackLocation = NULL; + PIRP pIrp; + NTSTATUS ntStatus = STATUS_SUCCESS; + PDEVICE_OBJECT pDeviceObject = NULL; + + __Enter + { + + pDeviceObject = IoGetRelatedDeviceObject( CacheFileObject); + + for (ULONG i = 0; i < Count; i++) + { + + pIrp = IoRun[i].ChildIrp; + + pIoStackLocation = IoGetNextIrpStackLocation( pIrp); + + pIrp->Flags = IrpFlags; + pIoStackLocation->MajorFunction = FunctionCode; + pIoStackLocation->DeviceObject = pDeviceObject; + pIoStackLocation->FileObject = CacheFileObject; + pIoStackLocation->Parameters.Write.Length = IoRun[i].ByteCount; + pIoStackLocation->Parameters.Write.ByteOffset = IoRun[i].CacheOffset; + + // + // Bump the count *before* we start the IO, that way if it + // completes real fast it will still not set the event + // + InterlockedIncrement(&Gather->Count); + + // + // Set the completion routine. + // + + IoSetCompletionRoutine( pIrp, + CompletionFunction, + Gather, + TRUE, + TRUE, + TRUE); + + // + // Send it to the Cache + // + + ntStatus = IoCallDriver( pDeviceObject, + pIrp); + + if( !NT_SUCCESS( ntStatus)) + { + break; + } + } + } + + return ntStatus; +} + +VOID +AFSCompleteIo( IN AFSGatherIo *Gather, + IN NTSTATUS Status) +{ + if (!NT_SUCCESS(Status)) { + + Gather->Status = Status; + } + + if (0 == InterlockedDecrement( &Gather->Count )) { + // + // Last outstanding IO. Complete the parent and + // do whatever it takes to clean up + // + if (!NT_SUCCESS(Gather->Status)) + { + Gather->MasterIrp->IoStatus.Status = Gather->Status; + Gather->MasterIrp->IoStatus.Information = 0; + } + + if( Gather->CompleteMasterIrp) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCompleteIo Completing Irp %08lX Status %08lX\n", + Gather->MasterIrp, + Gather->Status); + + AFSCompleteRequest(Gather->MasterIrp, Gather->Status); + } + + if (Gather->Synchronous) + { + // + // Someone was waiting for us tell them. They also own + // the data structure so we don't free it + // + KeSetEvent( &Gather->Event, + 0, + FALSE); + } + else + { + + AFSExFreePool( Gather); + } + } +} + +static AFSExtent *ExtentFor(PLIST_ENTRY le) +{ + return CONTAINING_RECORD( le, AFSExtent, Lists[AFS_EXTENTS_LIST] ); +} + +static AFSExtent *NextExtent(AFSExtent *Extent) +{ + return ExtentFor(Extent->Lists[AFS_EXTENTS_LIST].Flink); +} + +NTSTATUS +AFSProcessExtentRun( IN PVOID SystemBuffer, + IN PLARGE_INTEGER Start, + IN ULONG Length, + IN AFSExtent *From, + IN BOOLEAN WriteRequest) +{ + + LARGE_INTEGER liCacheOffset; + LARGE_INTEGER liFileOffset = *Start; + ULONG ulCurrLength; + ULONG ulOffset = 0; + ULONG ulCurrRun = 0; + AFSExtent *pExtent = From; + AFSExtent *pNextExtent; + PMDL *pMDL; + BOOLEAN done = FALSE; + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + while( !done) + { + ASSERT( liFileOffset.QuadPart >= pExtent->FileOffset.QuadPart ); + + liCacheOffset = pExtent->CacheOffset; + liCacheOffset.QuadPart += (liFileOffset.QuadPart - + pExtent->FileOffset.QuadPart); + + ulCurrLength = 0; + + // + // While there is still data to process, loop + // + while ( (pExtent->FileOffset.QuadPart + pExtent->Size) < + (Start->QuadPart + Length) ) + { + // + // Collapse the read if we can + // + pNextExtent = NextExtent( pExtent ); + + if (pNextExtent->CacheOffset.QuadPart != + (pExtent->CacheOffset.QuadPart + pExtent->Size)) + { + // + // This extent and the next extent are not contiguous + // + break; + } + pExtent = pNextExtent; + } + + // + // So, this run goes from liCacheOffset to the end of pExtent + // + + if ((pExtent->FileOffset.QuadPart + pExtent->Size) >= (Start->QuadPart + Length)) + { + // + // The last extent overruns the area we care + // about, so trim it back. + // + ulCurrLength = (ULONG) (Start->QuadPart + Length - + liFileOffset.QuadPart); + // + // But we are done + // + done = TRUE; + } + else + { + // + // Length is from the LiFileOffset to the end of this + // extent. + // + ulCurrLength = (ULONG) (pExtent->FileOffset.QuadPart + pExtent->Size - + liFileOffset.QuadPart); + done = FALSE; + } + + // + // Calculate the offset into the buffer + // + ulOffset = (ULONG) (liFileOffset.QuadPart - Start->QuadPart); + + if( WriteRequest) + { + +#ifdef AMD64 + RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart), + ((char *)SystemBuffer + ulOffset), + ulCurrLength); +#else + ASSERT( liCacheOffset.HighPart == 0); + RtlCopyMemory( ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart), + ((char *)SystemBuffer + ulOffset), + ulCurrLength); +#endif + } + else + { + +#ifdef AMD64 + RtlCopyMemory( ((char *)SystemBuffer + ulOffset), + ((char *)AFSLibCacheBaseAddress + liCacheOffset.QuadPart), + ulCurrLength); +#else + ASSERT( liCacheOffset.HighPart == 0); + RtlCopyMemory( ((char *)SystemBuffer + ulOffset), + ((char *)AFSLibCacheBaseAddress + liCacheOffset.LowPart), + ulCurrLength); +#endif + } + + ulCurrRun ++; + if (!done) + { + ASSERT(pNextExtent != NULL && pNextExtent != pExtent); + // + // Move cursors forward + // + pExtent = pNextExtent; + liFileOffset = pExtent->FileOffset; + } + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSLockControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSLockControl.cpp new file mode 100644 index 0000000000..634cc606fe --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSLockControl.cpp @@ -0,0 +1,311 @@ +/* + * 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: AFSLockControl.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSLockControl( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG ulRequestType = 0; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + BOOLEAN bCompleteRequest = TRUE; + AFSByteRangeLockRequestCB stLockRequestCB; + AFSByteRangeLockResultCB stLockResultCB; + AFSByteRangeUnlockRequestCB stUnlockRequestCB; + AFSByteRangeUnlockResultCB stUnlockResultCB; + ULONG ulResultLen = 0; + BOOLEAN bReleaseResource = FALSE; + IO_STATUS_BLOCK stIoStatus; + + __try + { + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLockControl Attempted access (%08lX) when pFcb == NULL\n", + Irp); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + // + // Acquire the main shared for adding the lock control to the list + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLockControl Acquiring Fcb lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + bReleaseResource = TRUE; + + if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLockControl Failing request against PIOCtl Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLockControl Failing request against SpecialShare Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + // + // Post the request to the service for checks + // + + switch( pIrpSp->MinorFunction) + { + + case IRP_MN_LOCK: + { + + stLockRequestCB.Count = 1; + + stLockRequestCB.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + stLockRequestCB.Request[ 0].LockType = AFS_BYTE_RANGE_LOCK_TYPE_EXCL; + + stLockRequestCB.Request[ 0].Offset = pIrpSp->Parameters.LockControl.ByteOffset; + + stLockRequestCB.Request[ 0].Length.QuadPart = pIrpSp->Parameters.LockControl.Length->QuadPart; + + ulResultLen = sizeof( AFSByteRangeLockResultCB); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_BYTE_RANGE_LOCK, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pFcb->ObjectInformation->FileId, + &stLockRequestCB, + sizeof( AFSByteRangeLockRequestCB), + &stLockResultCB, + &ulResultLen); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + break; + } + + case IRP_MN_UNLOCK_ALL: + case IRP_MN_UNLOCK_ALL_BY_KEY: + { + + RtlZeroMemory( &stUnlockRequestCB, + sizeof( AFSByteRangeUnlockRequestCB)); + + stUnlockRequestCB.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_BYTE_RANGE_UNLOCK_ALL, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pFcb->ObjectInformation->FileId, + (void *)&stUnlockRequestCB, + sizeof( AFSByteRangeUnlockRequestCB), + NULL, + NULL); + + if( NT_SUCCESS( ntStatus)) + { + CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, + NULL, + 0, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLockControl CcFlushCache [1] failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + } + + // + // Even on a failure we need to notify the rtl package of the unlock + // + + break; + } + + case IRP_MN_UNLOCK_SINGLE: + { + + stUnlockRequestCB.Count = 1; + + stUnlockRequestCB.ProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + stUnlockRequestCB.Request[ 0].LockType = AFS_BYTE_RANGE_LOCK_TYPE_EXCL; + + stUnlockRequestCB.Request[ 0].Offset = pIrpSp->Parameters.LockControl.ByteOffset; + + stUnlockRequestCB.Request[ 0].Length.QuadPart = pIrpSp->Parameters.LockControl.Length->QuadPart; + + ulResultLen = sizeof( AFSByteRangeUnlockResultCB); + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_BYTE_RANGE_UNLOCK, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + &pFcb->ObjectInformation->FileId, + (void *)&stUnlockRequestCB, + sizeof( AFSByteRangeUnlockRequestCB), + (void *)&stUnlockResultCB, + &ulResultLen); + + if( NT_SUCCESS( ntStatus)) + { + CcFlushCache( &pFcb->NPFcb->SectionObjectPointers, + &pIrpSp->Parameters.LockControl.ByteOffset, + pIrpSp->Parameters.LockControl.Length->LowPart, + &stIoStatus); + + if( !NT_SUCCESS( stIoStatus.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLockControl CcFlushCache [2] failure FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + stIoStatus.Status, + stIoStatus.Information); + + ntStatus = stIoStatus.Status; + } + } + + break; + } + + default: + + break; + } + + // + // Below here we won't complete the request, it is handled by the lock package + // + + bCompleteRequest = FALSE; + + // + // Now call the system package for actually processing the lock request + // + + ntStatus = FsRtlProcessFileLock( &pFcb->Specific.File.FileLock, + Irp, + NULL); + +try_exit: + + if( bReleaseResource) + { + + // + // And drop it + // + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + + if( bCompleteRequest) + { + + AFSCompleteRequest( Irp, + ntStatus); + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation())) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSLockControl\n"); + + // + // Again, there is little point in failing this request but pass back some type of failure status + // + + ntStatus = STATUS_UNSUCCESSFUL; + + AFSCompleteRequest( Irp, + ntStatus); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSMD5Support.cpp b/src/WINNT/afsrdr/kernel/lib/AFSMD5Support.cpp new file mode 100644 index 0000000000..0e699b8f45 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSMD5Support.cpp @@ -0,0 +1,440 @@ +/* + * 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: AFSMD5Support.cpp +// + +#include "AFSCommon.h" + +// +// BEGIN Aladdin Enterprises MD5 SOURCES +// + +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +extern "C" +{ + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +} /* end extern "C" */ + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; + + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; + + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) + { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } + else + { + /* not aligned */ + RtlCopyMemory( xbuf, + data, + 64); + X = xbuf; + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) + { + + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + RtlCopyMemory( pms->buf + offset, + p, + copy); + + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + RtlCopyMemory( pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + + /* Append the length. */ + md5_append(pms, data, 8); + + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); + + return; +} + +// +// END Aladdin Enterprises MD5 SOURCES +// + +void +AFSGenerateMD5( IN char *DataBuffer, + IN ULONG Length, + OUT UCHAR *MD5Digest) +{ + + md5_state_t stMD5State; + + __Enter + { + + // + // Initialize the md5 context + // + + md5_init( &stMD5State); + + md5_append( &stMD5State, + (const md5_byte_t *)DataBuffer, + Length); + + md5_finish( &stMD5State, + (md5_byte_t *)MD5Digest); + } + + return; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp new file mode 100644 index 0000000000..3c93f8d2c7 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp @@ -0,0 +1,4365 @@ +/* + * 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: AFSNameSupport.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSLocateNameEntry( IN GUID *AuthGroup, + IN PFILE_OBJECT FileObject, + IN UNICODE_STRING *RootPathName, + IN UNICODE_STRING *ParsedPathName, + IN AFSNameArrayHdr *NameArray, + IN ULONG Flags, + OUT AFSVolumeCB **VolumeCB, + IN OUT AFSDirectoryCB **ParentDirectoryCB, + OUT AFSDirectoryCB **DirectoryCB, + OUT PUNICODE_STRING ComponentName) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniPathName, uniComponentName, uniRemainingPath, uniSearchName, uniFullPathName; + ULONG ulCRC = 0; + AFSDirectoryCB *pDirEntry = NULL, *pParentDirEntry = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + UNICODE_STRING uniSysName; + ULONG ulSubstituteIndex = 0; + BOOLEAN bSubstituteName = FALSE; + AFSNameArrayHdr *pNameArray = NameArray; + BOOLEAN bAllocatedSymLinkBuffer = FALSE; + UNICODE_STRING uniRelativeName, uniNoOpName; + AFSObjectInfoCB *pCurrentObject = NULL; + AFSVolumeCB *pCurrentVolume = *VolumeCB; + BOOLEAN bReleaseCurrentVolume = TRUE; + BOOLEAN bSubstitutedName = FALSE; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Processing full name %wZ\n", + FileObject, + RootPathName); + + RtlInitUnicodeString( &uniSysName, + L"*@SYS"); + + RtlInitUnicodeString( &uniRelativeName, + L".."); + + RtlInitUnicodeString( &uniNoOpName, + L"."); + + // + // Cleanup some parameters + // + + if( ComponentName != NULL) + { + + ComponentName->Length = 0; + ComponentName->MaximumLength = 0; + ComponentName->Buffer = NULL; + } + + // + // We will parse through the filename, locating the directory nodes until we encounter a cache miss + // Starting at the root node + // + + pParentDirEntry = NULL; + + pDirEntry = *ParentDirectoryCB; + + uniPathName = *ParsedPathName; + + uniFullPathName = *RootPathName; + + uniComponentName.Length = uniComponentName.MaximumLength = 0; + uniComponentName.Buffer = NULL; + + uniRemainingPath.Length = uniRemainingPath.MaximumLength = 0; + uniRemainingPath.Buffer = NULL; + + uniSearchName.Length = uniSearchName.MaximumLength = 0; + uniSearchName.Buffer = NULL; + + ASSERT( pCurrentVolume->VolumeReferenceCount > 1); + + while( TRUE) + { + + // + // Check our total link count for this name array + // + + if( pNameArray->LinkCount >= (LONG)pDevExt->Specific.RDR.MaxLinkCount) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + pCurrentObject = pDirEntry->ObjectInformation; + + KeQueryTickCount( &pCurrentObject->LastAccessCount); + + // + // Check that the directory entry is not deleted or pending delete + // + + if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Deleted parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + try_return( ntStatus = STATUS_FILE_DELETED); + } + + if( BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_PENDING_DELETE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Delete pending on %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + try_return( ntStatus = STATUS_DELETE_PENDING); + } + + // + // Check if the directory requires verification + // + + if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY) && + ( pCurrentObject->FileType != AFS_FILE_TYPE_DIRECTORY || + !AFSIsEnumerationInProcess( pCurrentObject))) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + ntStatus = AFSVerifyEntry( AuthGroup, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to verify parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Ensure the parent node has been evaluated, if not then go do it now + // + + if( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED) || + pCurrentObject->FileType == AFS_FILE_TYPE_UNKNOWN) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Evaluating parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + ntStatus = AFSEvaluateNode( AuthGroup, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to evaluate parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_NOT_EVALUATED); + } + + // + // If this is a mount point or symlink then go get the real directory node + // + + switch( pCurrentObject->FileType) + { + + case AFS_FILE_TYPE_SYMLINK: + { + + UNICODE_STRING uniTempName; + WCHAR *pTmpBuffer = NULL; + LONG lLinkCount = 0; + + // + // Check if the flag is set to NOT evaluate a symlink + // and we are done with the parsing + // + + if( BooleanFlagOn( Flags, AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL) && + uniRemainingPath.Length == 0) + { + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = pDirEntry; + + *VolumeCB = pCurrentVolume; + + *RootPathName = uniFullPathName; + + try_return( ntStatus); + } + + AFSAcquireExcl( &pDirEntry->NonPaged->Lock, + TRUE); + + if( pDirEntry->NameInformation.TargetName.Length == 0) + { + + // + // We'll reset the DV to ensure we validate the metadata content + // + + pCurrentObject->DataVersion.QuadPart = (ULONGLONG)-1; + + SetFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_VERIFY); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Verifying symlink parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + ntStatus = AFSVerifyEntry( AuthGroup, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to verify symlink parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + try_return( ntStatus); + } + + // + // If the type changed then reprocess this entry + // + + if( pCurrentObject->FileType != AFS_FILE_TYPE_SYMLINK) + { + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + continue; + } + } + + // + // If we were given a zero length target name then deny access to the entry + // + + if( pDirEntry->NameInformation.TargetName.Length == 0) + { + + ntStatus = STATUS_ACCESS_DENIED; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to retrieve target name for symlink %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + try_return( ntStatus); + } + + if( AFSIsRelativeName( &pDirEntry->NameInformation.TargetName)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Processing relative symlink target %wZ for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.TargetName, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // We'll substitute this name into the current process name + // starting at where we sit in the path + // + + uniTempName.Length = 0; + uniTempName.MaximumLength = (USHORT)((char *)uniComponentName.Buffer - (char *)uniFullPathName.Buffer) + + pDirEntry->NameInformation.TargetName.Length + + sizeof( WCHAR) + + uniRemainingPath.Length; + + uniTempName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniTempName.MaximumLength, + AFS_NAME_BUFFER_ONE_TAG); + + if( uniTempName.Buffer == NULL) + { + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // We have so first copy in the portion up to the component + // name + // + + RtlCopyMemory( uniTempName.Buffer, + uniFullPathName.Buffer, + (ULONG)((char *)uniComponentName.Buffer - (char *)uniFullPathName.Buffer)); + + uniTempName.Length = (USHORT)((char *)uniComponentName.Buffer - (char *)uniFullPathName.Buffer); + + if( bAllocatedSymLinkBuffer || + bSubstitutedName) + { + + pTmpBuffer = uniFullPathName.Buffer; + } + + bAllocatedSymLinkBuffer = TRUE; + + // + // Have we parsed this name yet? Better have at least once ... + // + + if( uniComponentName.Length == 0) + { + ASSERT( FALSE); + } + + // + // Copy in the target name ... + // + + RtlCopyMemory( &uniTempName.Buffer[ uniTempName.Length/sizeof( WCHAR)], + pDirEntry->NameInformation.TargetName.Buffer, + pDirEntry->NameInformation.TargetName.Length); + + uniPathName.Buffer = &uniTempName.Buffer[ uniTempName.Length/sizeof( WCHAR)]; + + uniPathName.Length += pDirEntry->NameInformation.TargetName.Length; + uniPathName.MaximumLength = uniTempName.MaximumLength; + + uniTempName.Length += pDirEntry->NameInformation.TargetName.Length; + + // + // And now any remaining portion of the name + // + + if( uniRemainingPath.Length > 0) + { + + if( uniRemainingPath.Buffer[ 0] != L'\\') + { + + uniRemainingPath.Buffer--; + uniRemainingPath.Length += sizeof( WCHAR); + + uniPathName.Length += sizeof( WCHAR); + } + + RtlCopyMemory( &uniTempName.Buffer[ uniTempName.Length/sizeof( WCHAR)], + uniRemainingPath.Buffer, + uniRemainingPath.Length); + + uniTempName.Length += uniRemainingPath.Length; + } + + uniFullPathName = uniTempName; + + if( pTmpBuffer != NULL) + { + + AFSExFreePool( pTmpBuffer); + } + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + // + // Dereference the current entry .. + // + + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + // + // OK, need to back up one entry for the correct parent since the current + // entry we are on is the symlink itself + // + + pDirEntry = AFSBackupEntry( pNameArray); + + // + // Increment our reference on this dir entry + // + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Increment1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + if( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_ROOT_VOLUME)) + { + + pParentDirEntry = NULL; + } + else + { + + pParentDirEntry = AFSGetParentEntry( pNameArray); + + ASSERT( pParentDirEntry != pDirEntry); + } + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Processing absolute symlink target %wZ for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.TargetName, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // We'll substitute this name into the current process name + // starting at where we sit in the path + // + + uniTempName.Length = 0; + uniTempName.MaximumLength = pDirEntry->NameInformation.TargetName.Length + + sizeof( WCHAR) + + uniRemainingPath.Length; + + uniTempName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniTempName.MaximumLength, + AFS_NAME_BUFFER_TWO_TAG); + + if( uniTempName.Buffer == NULL) + { + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + if( bAllocatedSymLinkBuffer || + bSubstitutedName) + { + + pTmpBuffer = uniFullPathName.Buffer; + } + + bAllocatedSymLinkBuffer = TRUE; + + // + // Have we parsed this name yet? Better have at least once ... + // + + if( uniComponentName.Length == 0) + { + ASSERT( FALSE); + } + + // + // Copy in the target name ... + // + + RtlCopyMemory( uniTempName.Buffer, + pDirEntry->NameInformation.TargetName.Buffer, + pDirEntry->NameInformation.TargetName.Length); + + uniTempName.Length = pDirEntry->NameInformation.TargetName.Length; + + // + // And now any remaining portion of the name + // + + if( uniRemainingPath.Length > 0) + { + + if( uniRemainingPath.Buffer[ 0] != L'\\') + { + + uniRemainingPath.Buffer--; + uniRemainingPath.Length += sizeof( WCHAR); + } + + RtlCopyMemory( &uniTempName.Buffer[ uniTempName.Length/sizeof( WCHAR)], + uniRemainingPath.Buffer, + uniRemainingPath.Length); + + uniTempName.Length += uniRemainingPath.Length; + } + + uniFullPathName = uniTempName; + + uniPathName = uniTempName; + + if( pTmpBuffer != NULL) + { + + AFSExFreePool( pTmpBuffer); + } + + AFSReleaseResource( &pDirEntry->NonPaged->Lock); + + // + // If our current volume is not the global root then make it so ... + // + + if( pCurrentVolume != AFSGlobalRoot) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Current volume not global, resetting for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + InterlockedDecrement( &pCurrentVolume->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement count on volume %08lX Cnt %d\n", + pCurrentVolume, + pCurrentVolume->VolumeReferenceCount); + + AFSReleaseResource( pCurrentVolume->VolumeLock); + + pCurrentVolume = AFSGlobalRoot; + + AFSAcquireShared( pCurrentVolume->VolumeLock, + TRUE); + + InterlockedIncrement( &pCurrentVolume->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Increment count on volume %08lX Cnt %d\n", + pCurrentVolume, + pCurrentVolume->VolumeReferenceCount); + } + + // + // Dereference our current dir entry + // + + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement2 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + pDirEntry = pCurrentVolume->DirectoryCB; + + // + // Reference the new dir entry + // + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Increment2 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + // + // Reset the name array + // Persist the link count in the name array + // + + lLinkCount = pNameArray->LinkCount; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Resetting name array for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + AFSResetNameArray( pNameArray, + pDirEntry); + + pNameArray->LinkCount = lLinkCount; + + // + // Process over the \\ portion of the name + // + + FsRtlDissectName( uniPathName, + &uniComponentName, + &uniRemainingPath); + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSServerName, + TRUE) != 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry Name %wZ contains invalid server name\n", + &uniPathName); + + // + // The correct response would be STATUS_OBJECT_PATH_INVALID + // but that prevents cmd.exe from performing a recursive + // directory enumeration when opening a directory entry + // that represents a symlink to an invalid path is discovered. + // + try_return( ntStatus = STATUS_OBJECT_PATH_NOT_FOUND); + } + + uniPathName = uniRemainingPath; + + pParentDirEntry = NULL; + } + + // + // Increment our link count + // + + InterlockedIncrement( &pNameArray->LinkCount); + + continue; + } + + case AFS_FILE_TYPE_MOUNTPOINT: + { + + // + // Check if the flag is set to NOT evaluate a mount point + // and we are done with the parsing + // + + if( BooleanFlagOn( Flags, AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL) && + uniRemainingPath.Length == 0) + { + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = pDirEntry; + + *VolumeCB = pCurrentVolume; + + *RootPathName = uniFullPathName; + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Building MP target for parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // Go retrieve the target entry for this node + // Release the current volume cb entry since we would + // have lock inversion in the following call + // Also decrement the ref count on the volume + // + + ASSERT( pCurrentVolume->VolumeReferenceCount > 1); + + InterlockedDecrement( &pCurrentVolume->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement2 count on volume %08lX Cnt %d\n", + pCurrentVolume, + pCurrentVolume->VolumeReferenceCount); + + AFSReleaseResource( pCurrentVolume->VolumeLock); + + ntStatus = AFSBuildMountPointTarget( AuthGroup, + pDirEntry, + &pCurrentVolume); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to build MP target for parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + // + // We already decremented the current volume above + // + + bReleaseCurrentVolume = FALSE; + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + ASSERT( pCurrentVolume->VolumeReferenceCount > 1); + + ASSERT( ExIsResourceAcquiredLite( pCurrentVolume->VolumeLock)); + + // + // Replace the current name for the mp with the volume root of the target + // + + AFSReplaceCurrentElement( pNameArray, + pCurrentVolume->DirectoryCB); + + // + // We want to restart processing here on the new parent ... + // Deref and ref count the entries + // + + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement3 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + pDirEntry = pCurrentVolume->DirectoryCB; + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Increment3 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + pParentDirEntry = NULL; + + // + // Increment our link count + // + + InterlockedIncrement( &pNameArray->LinkCount); + + continue; + } + + case AFS_FILE_TYPE_DFSLINK: + { + + if( BooleanFlagOn( Flags, AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL)) + { + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = pDirEntry; + + *VolumeCB = pCurrentVolume; + + *RootPathName = uniFullPathName; + + try_return( ntStatus); + } + + // + // This is a DFS link so we need to update the file name and return STATUS_REPARSE to the + // system for it to reevaluate it + // + + if( FileObject != NULL) + { + + ntStatus = AFSProcessDFSLink( pDirEntry, + FileObject, + &uniRemainingPath); + } + else + { + + // + // This is where we have been re-entered from an NP evaluation call via the BuildBranch() + // routine. + // + + ntStatus = STATUS_INVALID_PARAMETER; + } + + if( ntStatus != STATUS_SUCCESS && + ntStatus != STATUS_REPARSE) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to process DFSLink parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + } + + try_return( ntStatus); + } + + case AFS_FILE_TYPE_UNKNOWN: + case AFS_FILE_TYPE_INVALID: + { + + // + // Something was not processed ... + // + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + } /* end of switch */ + + // + // If the parent is not initialized then do it now + // + + if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY && + !BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Enumerating parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + if( !BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + ntStatus = AFSEnumerateDirectory( AuthGroup, + pCurrentObject, + TRUE); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to enumerate parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + SetFlag( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED); + } + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + else if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE) + { + + if( uniPathName.Length > 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Encountered file node %wZ FID %08lX-%08lX-%08lX-%08lX in path processing\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // The proper error code to return would be STATUS_OBJECT_PATH_INVALID because + // one of the components of the path is not a directory. However, returning + // that error prevents IIS 7 and 7.5 from being able to serve data out of AFS. + // Instead IIS insists on treating the target file as if it is a directory containing + // a potential web.config file. NTFS and LanMan return STATUS_OBJECT_PATH_NOT_FOUND. + // AFS will follow suit. + + ntStatus = STATUS_OBJECT_PATH_NOT_FOUND; + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Returning file %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = pDirEntry; + + *VolumeCB = pCurrentVolume; + + *RootPathName = uniFullPathName; + } + + try_return( ntStatus); + } + + // + // If we are at the end of the processing, set our returned information and get out + // + + if( uniPathName.Length == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Completed processing returning %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = pDirEntry; + + *VolumeCB = pCurrentVolume; + + *RootPathName = uniFullPathName; + + try_return( ntStatus); + } + + // + // We may have returned to the top of the while( TRUE) + // + if( bSubstituteName && + uniSearchName.Buffer != NULL) + { + + AFSExFreePool( uniSearchName.Buffer); + + bSubstituteName = FALSE; + + uniSearchName.Length = uniSearchName.MaximumLength = 0; + uniSearchName.Buffer = NULL; + } + + ulSubstituteIndex = 1; + + ntStatus = STATUS_SUCCESS; + + // + // Get the next component name + // + + FsRtlDissectName( uniPathName, + &uniComponentName, + &uniRemainingPath); + + // + // Check for the . and .. in the path + // + + if( RtlCompareUnicodeString( &uniComponentName, + &uniNoOpName, + TRUE) == 0) + { + + uniPathName = uniRemainingPath; + + continue; + } + + if( RtlCompareUnicodeString( &uniComponentName, + &uniRelativeName, + TRUE) == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Backing up entry from %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // Need to back up one entry in the name array + // + + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement4 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + pDirEntry = AFSBackupEntry( NameArray); + + if( pDirEntry == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry AFSBackupEntry failed\n"); + + try_return(ntStatus = STATUS_OBJECT_PATH_INVALID); + } + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + if( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_ROOT_VOLUME)) + { + + pParentDirEntry = NULL; + } + else + { + + pParentDirEntry = AFSGetParentEntry( pNameArray); + + ASSERT( pParentDirEntry != pDirEntry); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Increment4 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + uniPathName = uniRemainingPath; + + continue; + } + + // + // Update our pointers + // + + pParentDirEntry = pDirEntry; + + pDirEntry = NULL; + + uniSearchName = uniComponentName; + + while( pDirEntry == NULL) + { + + // + // If the SearchName contains @SYS then we perform the substitution. + // If there is no substitution we give up. + // + + if( !bSubstituteName && + FsRtlIsNameInExpression( &uniSysName, + &uniSearchName, + TRUE, + NULL)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Processing @SYS substitution for %wZ Index %08lX\n", + FileObject, + &uniComponentName, + ulSubstituteIndex); + + ntStatus = AFSSubstituteSysName( &uniComponentName, + &uniSearchName, + ulSubstituteIndex); + + if ( NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Located substitution %wZ for %wZ Index %08lX\n", + FileObject, + &uniSearchName, + &uniComponentName, + ulSubstituteIndex); + + // + // Go reparse the name again + // + + bSubstituteName = TRUE; + + ulSubstituteIndex++; // For the next entry, if needed + + continue; // while( pDirEntry == NULL) + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to locate substitute string for %wZ Index %08lX Status %08lX\n", + FileObject, + &uniComponentName, + ulSubstituteIndex, + ntStatus); + + if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) + { + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = NULL; + + *VolumeCB = pCurrentVolume; + + if( ComponentName != NULL) + { + + *ComponentName = uniComponentName; + } + + *RootPathName = uniFullPathName; + } + + // + // We can't possibly have a pDirEntry since the lookup failed + // + try_return( ntStatus); + } + } + + // + // Generate the CRC on the node and perform a case sensitive lookup + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Searching for entry %wZ case sensitive\n", + FileObject, + &uniSearchName); + + ulCRC = AFSGenerateCRC( &uniSearchName, + FALSE); + + AFSAcquireShared( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSLocateCaseSensitiveDirEntry( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pDirEntry); + + if( pDirEntry == NULL) + { + + // + // Missed so perform a case insensitive lookup + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Searching for entry %wZ case insensitive\n", + FileObject, + &uniSearchName); + + ulCRC = AFSGenerateCRC( &uniSearchName, + TRUE); + + AFSLocateCaseInsensitiveDirEntry( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + ulCRC, + &pDirEntry); + + if( pDirEntry == NULL) + { + + // + // OK, if this component is a valid short name then try + // a lookup in the short name tree + // + + if( RtlIsNameLegalDOS8Dot3( &uniSearchName, + NULL, + NULL)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Searching for entry %wZ short name\n", + FileObject, + &uniSearchName); + + AFSLocateShortNameDirEntry( pParentDirEntry->ObjectInformation->Specific.Directory.ShortNameTree, + ulCRC, + &pDirEntry); + } + + if( pDirEntry == NULL) + { + + // + // If we substituted a name then reset our search name and try again + // + + if( bSubstituteName) + { + + AFSExFreePool( uniSearchName.Buffer); + + uniSearchName = uniComponentName; + + bSubstituteName = FALSE; + + AFSReleaseResource( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + continue; // while( pDirEntry == NULL) + } + + if( uniRemainingPath.Length > 0) + { + + ntStatus = STATUS_OBJECT_PATH_NOT_FOUND; + } + else + { + + ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Returning name not found for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &uniSearchName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = NULL; + + *VolumeCB = pCurrentVolume; + + if( ComponentName != NULL) + { + + *ComponentName = uniComponentName; + } + + *RootPathName = uniFullPathName; + } + + AFSReleaseResource( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + // + // Node name not found so get out + // + + try_return( ntStatus); // while( pDirEntry == NULL) + } + } + else + { + + // + // Here we have a match on the case insensitive lookup for the name. If there + // Is more than one link entry for this node then fail the lookup request + // + + if( !BooleanFlagOn( pDirEntry->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD) || + pDirEntry->CaseInsensitiveList.fLink != NULL) + { + + AFSReleaseResource( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + try_return(ntStatus = STATUS_OBJECT_NAME_COLLISION); + } + } + } + + if( pDirEntry != NULL) + { + + // + // If the verify flag is set on the parent and the current entry is deleted + // revalidate the parent and search again. + // + + if( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED) && + BooleanFlagOn( pParentDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY)) + { + + AFSReleaseResource( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Verifying(2) parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry->ObjectInformation->FileId.Cell, + pParentDirEntry->ObjectInformation->FileId.Volume, + pParentDirEntry->ObjectInformation->FileId.Vnode, + pParentDirEntry->ObjectInformation->FileId.Unique); + + ntStatus = AFSVerifyEntry( AuthGroup, + pParentDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to verify(2) parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry->ObjectInformation->FileId.Cell, + pParentDirEntry->ObjectInformation->FileId.Volume, + pParentDirEntry->ObjectInformation->FileId.Vnode, + pParentDirEntry->ObjectInformation->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Reprocessing component %wZ in parent %wZ\n", + FileObject, + &uniSearchName, + &pParentDirEntry->NameInformation.FileName); + + + pDirEntry = NULL; + + continue; + } + + // + // Increment our dir entry ref count + // + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Increment5 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + } + + AFSReleaseResource( pParentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + } // End while( pDirEntry == NULL) + + // + // If we have a dirEntry for this component, perform some basic validation on it + // + + if( pDirEntry != NULL && + BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) + { + + pCurrentObject = pDirEntry->ObjectInformation; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Deleted parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // This entry was deleted through the invalidation call back so perform cleanup + // on the entry + // + + ASSERT( pCurrentObject->ParentObjectInformation != NULL); + + AFSAcquireExcl( pCurrentObject->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + AFSAcquireExcl( pCurrentObject->VolumeCB->ObjectInfoTree.TreeLock, + TRUE); + + if( InterlockedDecrement( &pDirEntry->OpenReferenceCount) == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Deleting dir entry %08lX (%08lX) for %wZ\n", + pDirEntry, + pCurrentObject, + &pDirEntry->NameInformation.FileName); + + // + // Remove and delete the directory entry from the parent list + // + + AFSDeleteDirEntry( pCurrentObject->ParentObjectInformation, + pDirEntry); + + if( pCurrentObject->ObjectReferenceCount == 0) + { + + if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_INSERTED_HASH_TREE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Removing object %08lX from volume tree\n", + pCurrentObject); + + AFSRemoveHashEntry( &pCurrentObject->VolumeCB->ObjectInfoTree.TreeHead, + &pCurrentObject->TreeEntry); + + ClearFlag( pCurrentObject->Flags, AFS_OBJECT_INSERTED_HASH_TREE); + } + } + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Setting DELETE flag in dir entry %p for %wZ\n", + pDirEntry, + &pDirEntry->NameInformation.FileName); + + SetFlag( pDirEntry->Flags, AFS_DIR_ENTRY_DELETED); + + AFSRemoveNameEntry( pCurrentObject->ParentObjectInformation, + pDirEntry); + } + + AFSReleaseResource( pCurrentObject->ParentObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSReleaseResource( pCurrentObject->VolumeCB->ObjectInfoTree.TreeLock); + + // + // We deleted the dir entry so check if there is any remaining portion + // of the name to process. + // + + if( uniRemainingPath.Length > 0) + { + ntStatus = STATUS_OBJECT_PATH_NOT_FOUND; + } + else + { + + ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Returning name not found(2) for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &uniComponentName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + // + // Pass back the directory entries + // + + *ParentDirectoryCB = pParentDirEntry; + + *DirectoryCB = NULL; + + *VolumeCB = pCurrentVolume; + + if( ComponentName != NULL) + { + + *ComponentName = uniComponentName; + } + + *RootPathName = uniFullPathName; + } + } + + if( ntStatus != STATUS_SUCCESS) + { + + try_return( ntStatus); + } + + // + // Decrement the previous parent + // + + InterlockedDecrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement5 count on Parent %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + + // + // If we ended up substituting a name in the component then update + // the full path and update the pointers + // + + if( bSubstituteName) + { + + BOOLEAN bRelativeOpen = FALSE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSLocateNameEntry (FO: %08lX) Substituting %wZ into %wZ Index %08lX\n", + FileObject, + &uniSearchName, + &uniComponentName, + ulSubstituteIndex); + + if( FileObject != NULL && + FileObject->RelatedFileObject != NULL) + { + + bRelativeOpen = TRUE; + } + + // + // AFSSubstituteNameInPath will replace the uniFullPathName.Buffer + // and free the prior Buffer contents but only if the fourth + // parameter is TRUE. + // + + ntStatus = AFSSubstituteNameInPath( &uniFullPathName, + &uniComponentName, + &uniSearchName, + &uniRemainingPath, + bRelativeOpen || + bAllocatedSymLinkBuffer || + bSubstitutedName); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failure to substitute %wZ into %wZ Index %08lX Status %08lX\n", + FileObject, + &uniSearchName, + &uniComponentName, + ulSubstituteIndex, + ntStatus); + + try_return( ntStatus); + } + + // + // We have substituted a name into the buffer so if we do this again for this + // path, we need to free up the buffer we allocated. + // + + bSubstitutedName = TRUE; + } + + // + // Update the search parameters + // + + uniPathName = uniRemainingPath; + + // + // Check if the is a SymLink entry but has no Target FileID or Name. In this + // case it might be a DFS Link so let's go and evaluate it to be sure + // + + if( pCurrentObject->FileType == AFS_FILE_TYPE_SYMLINK && + pCurrentObject->TargetFileId.Vnode == 0 && + pCurrentObject->TargetFileId.Unique == 0 && + pDirEntry->NameInformation.TargetName.Length == 0) + { + + ntStatus = AFSValidateSymLink( AuthGroup, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSLocateNameEntry (FO: %08lX) Failed to evaluate possible DFS Link %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique, + ntStatus); + + try_return( ntStatus); + } + } + + // + // Update the name array + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Inserting name array entry %wZ FID %08lX-%08lX-%08lX-%08lX\n", + FileObject, + &pDirEntry->NameInformation.FileName, + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + ntStatus = AFSInsertNextElement( pNameArray, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } // while (TRUE) + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry (FO: %08lX) Completed processing %wZ Status %08lX\n", + FileObject, + RootPathName, + ntStatus); + + if( ( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_OBJECT_NAME_NOT_FOUND) || + ntStatus == STATUS_REPARSE) + { + + if( pDirEntry != NULL) + { + + InterlockedDecrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement6 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + } + else if( pParentDirEntry != NULL) + { + + InterlockedDecrement( &pParentDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement7 count on %wZ DE %p Ccb %p Cnt %d\n", + &pParentDirEntry->NameInformation.FileName, + pParentDirEntry, + NULL, + pParentDirEntry->OpenReferenceCount); + } + + if( bReleaseCurrentVolume) + { + + ASSERT( pCurrentVolume->VolumeReferenceCount > 1); + + ASSERT( ExIsResourceAcquiredLite( pCurrentVolume->VolumeLock)); + + InterlockedDecrement( &pCurrentVolume->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Decrement3 count on volume %08lX Cnt %d\n", + pCurrentVolume, + pCurrentVolume->VolumeReferenceCount); + + AFSReleaseResource( pCurrentVolume->VolumeLock); + } + + if( RootPathName->Buffer != uniFullPathName.Buffer) + { + + AFSExFreePool( uniFullPathName.Buffer); + } + } + else + { + + if( *ParentDirectoryCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Count on Parent %wZ DE %p Ccb %p Cnt %d\n", + &(*ParentDirectoryCB)->NameInformation.FileName, + *ParentDirectoryCB, + NULL, + (*ParentDirectoryCB)->OpenReferenceCount); + } + + if( *DirectoryCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSLocateNameEntry Count on %wZ DE %p Ccb %p Cnt %d\n", + &(*DirectoryCB)->NameInformation.FileName, + *DirectoryCB, + NULL, + (*DirectoryCB)->OpenReferenceCount); + } + } + + if( bSubstituteName && + uniSearchName.Buffer != NULL) + { + + AFSExFreePool( uniSearchName.Buffer); + } + } + + return ntStatus; +} + +NTSTATUS +AFSCreateDirEntry( IN GUID *AuthGroup, + IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *ParentDirCB, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING ComponentName, + IN ULONG Attributes, + IN OUT AFSDirectoryCB **DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDirectoryCB *pDirNode = NULL; + UNICODE_STRING uniShortName; + LARGE_INTEGER liFileSize = {0,0}; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSCreateDirEntry Creating dir entry in parent %wZ FID %08lX-%08lX-%08lX-%08lX Component %wZ Attribs %08lX\n", + &ParentDirCB->NameInformation.FileName, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique, + ComponentName, + Attributes); + + // + // OK, before inserting the node into the parent tree, issue + // the request to the service for node creation + // We will need to drop the lock on the parent node since the create + // could cause a callback into the file system to invalidate it's cache + // + + ntStatus = AFSNotifyFileCreate( AuthGroup, + ParentObjectInfo, + &liFileSize, + Attributes, + ComponentName, + &pDirNode); + + // + // If the returned status is STATUS_REPARSE then the entry exists + // and we raced, get out. + + if( ntStatus == STATUS_REPARSE) + { + + *DirEntry = pDirNode; + + try_return( ntStatus = STATUS_SUCCESS); + } + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCreateDirEntry Failed to create dir entry in parent %wZ FID %08lX-%08lX-%08lX-%08lX Component %wZ Attribs %08lX Status %08lX\n", + &ParentDirCB->NameInformation.FileName, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique, + ComponentName, + Attributes, + ntStatus); + + try_return( ntStatus); + } + + 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", + &ParentDirCB->NameInformation.FileName, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique, + ComponentName); + + // + // Insert the directory node + // + + AFSInsertDirectoryNode( ParentObjectInfo, + pDirNode, + TRUE); + + // + // Pass back the dir entry + // + + *DirEntry = pDirNode; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +void +AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry, + IN BOOLEAN InsertInEnumList) +{ + + __Enter + { + + AFSAcquireExcl( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + // + // Insert the node into the directory node tree + // + + ClearFlag( DirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE); + + if( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead == NULL) + { + + ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = DirEntry; + } + else + { + + AFSInsertCaseSensitiveDirEntry( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + DirEntry); + } + + if( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead == NULL) + { + + ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = DirEntry; + + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + } + else + { + + AFSInsertCaseInsensitiveDirEntry( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + DirEntry); + } + + // + // Into the shortname tree + // + + if( DirEntry->Type.Data.ShortNameTreeEntry.HashIndex != 0) + { + + if( ParentObjectInfo->Specific.Directory.ShortNameTree == NULL) + { + + ParentObjectInfo->Specific.Directory.ShortNameTree = DirEntry; + } + else + { + + AFSInsertShortNameDirEntry( ParentObjectInfo->Specific.Directory.ShortNameTree, + DirEntry); + } + } + + if( InsertInEnumList) + { + + // + // And insert the node into the directory list + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertDirectoryNode Inserting entry %08lX %wZ FID %08lX-%08lX-%08lX-%08lXStatus %08lX\n", + DirEntry, + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique); + + if( ParentObjectInfo->Specific.Directory.DirectoryNodeListHead == NULL) + { + + ParentObjectInfo->Specific.Directory.DirectoryNodeListHead = DirEntry; + } + else + { + + ParentObjectInfo->Specific.Directory.DirectoryNodeListTail->ListEntry.fLink = (void *)DirEntry; + + DirEntry->ListEntry.bLink = (void *)ParentObjectInfo->Specific.Directory.DirectoryNodeListTail; + } + + ParentObjectInfo->Specific.Directory.DirectoryNodeListTail = DirEntry; + + SetFlag( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_ENUM_LIST); + + InterlockedIncrement( &ParentObjectInfo->Specific.Directory.DirectoryNodeCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertDirectoryNode Adding entry %wZ Inc Count %d to parent FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + ParentObjectInfo->Specific.Directory.DirectoryNodeCount, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique); + } + + AFSReleaseResource( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + return; +} + +NTSTATUS +AFSDeleteDirEntry( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSDeleteDirEntry Deleting dir entry in parent %08lX Entry %08lX %wZ FID %08lX-%08lX-%08lX-%08lX\n", + ParentObjectInfo, + DirEntry, + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique); + + AFSRemoveDirNodeFromParent( ParentObjectInfo, + DirEntry, + TRUE); + + // + // Free up the name buffer if it was reallocated + // + + if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_RELEASE_NAME_BUFFER)) + { + + AFSExFreePool( DirEntry->NameInformation.FileName.Buffer); + } + + if( BooleanFlagOn( DirEntry->Flags, AFS_DIR_RELEASE_TARGET_NAME_BUFFER)) + { + + AFSExFreePool( DirEntry->NameInformation.TargetName.Buffer); + } + + // + // Dereference the object for this dir entry + // + + ASSERT( DirEntry->ObjectInformation->ObjectReferenceCount > 0); + + InterlockedDecrement( &DirEntry->ObjectInformation->ObjectReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSDeleteDirEntry Decrement count on object %08lX Cnt %d\n", + DirEntry->ObjectInformation, + DirEntry->ObjectInformation->ObjectReferenceCount); + + ExDeleteResourceLite( &DirEntry->NonPaged->Lock); + + AFSExFreePool( DirEntry->NonPaged); + + // + // Free up the dir entry + // + + AFSExFreePool( DirEntry); + } + + return ntStatus; +} + +NTSTATUS +AFSRemoveDirNodeFromParent( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry, + IN BOOLEAN RemoveFromEnumList) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __Enter + { + + + ASSERT( ExIsResourceAcquiredExclusiveLite( ParentObjectInfo->Specific.Directory.DirectoryNodeHdr.TreeLock)); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveDirNodeFromParent Removing DirEntry %08lX %wZ FID %08lX-%08lX-%08lX-%08lX from Parent %08lX\n", + DirEntry, + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique, + ParentObjectInfo); + + if( !BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_NOT_IN_PARENT_TREE)) + { + + AFSRemoveNameEntry( ParentObjectInfo, + DirEntry); + } + + if( RemoveFromEnumList && + BooleanFlagOn( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_ENUM_LIST)) + { + + // + // And remove the entry from the enumeration list + // + + if( DirEntry->ListEntry.fLink == NULL) + { + + ParentObjectInfo->Specific.Directory.DirectoryNodeListTail = (AFSDirectoryCB *)DirEntry->ListEntry.bLink; + } + else + { + + ((AFSDirectoryCB *)DirEntry->ListEntry.fLink)->ListEntry.bLink = DirEntry->ListEntry.bLink; + } + + if( DirEntry->ListEntry.bLink == NULL) + { + + ParentObjectInfo->Specific.Directory.DirectoryNodeListHead = (AFSDirectoryCB *)DirEntry->ListEntry.fLink; + } + else + { + + ((AFSDirectoryCB *)DirEntry->ListEntry.bLink)->ListEntry.fLink = DirEntry->ListEntry.fLink; + } + + ASSERT( ParentObjectInfo->Specific.Directory.DirectoryNodeCount > 0); + + InterlockedDecrement( &ParentObjectInfo->Specific.Directory.DirectoryNodeCount); + + ClearFlag( DirEntry->Flags, AFS_DIR_ENTRY_INSERTED_ENUM_LIST); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveDirNodeFromParent Removing entry %wZ Dec Count %d to parent FID %08lX-%08lX-%08lX-%08lX\n", + &DirEntry->NameInformation.FileName, + ParentObjectInfo->Specific.Directory.DirectoryNodeCount, + ParentObjectInfo->FileId.Cell, + ParentObjectInfo->FileId.Volume, + ParentObjectInfo->FileId.Vnode, + ParentObjectInfo->FileId.Unique); + + DirEntry->ListEntry.fLink = NULL; + DirEntry->ListEntry.bLink = NULL; + } + } + + return ntStatus; +} + +NTSTATUS +AFSFixupTargetName( IN OUT PUNICODE_STRING FileName, + IN OUT PUNICODE_STRING TargetFileName) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniFileName; + + __Enter + { + + // + // We will process backwards from the end of the name looking + // for the first \ we encounter + // + + uniFileName.Length = FileName->Length; + uniFileName.MaximumLength = FileName->MaximumLength; + + uniFileName.Buffer = FileName->Buffer; + + while( TRUE) + { + + if( uniFileName.Buffer[ (uniFileName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + // + // Subtract one more character off of the filename if it is not the root + // + + if( uniFileName.Length > sizeof( WCHAR)) + { + + uniFileName.Length -= sizeof( WCHAR); + } + + // + // Now build up the target name + // + + TargetFileName->Length = FileName->Length - uniFileName.Length; + + // + // If we are not on the root then fixup the name + // + + if( uniFileName.Length > sizeof( WCHAR)) + { + + TargetFileName->Length -= sizeof( WCHAR); + + TargetFileName->Buffer = &uniFileName.Buffer[ (uniFileName.Length/sizeof( WCHAR)) + 1]; + } + else + { + + TargetFileName->Buffer = &uniFileName.Buffer[ uniFileName.Length/sizeof( WCHAR)]; + } + + // + // Fixup the passed back filename length + // + + FileName->Length = uniFileName.Length; + + TargetFileName->MaximumLength = TargetFileName->Length; + + break; + } + + uniFileName.Length -= sizeof( WCHAR); + } + } + + return ntStatus; +} + +NTSTATUS +AFSParseName( IN PIRP Irp, + IN GUID *AuthGroup, + OUT PUNICODE_STRING FileName, + OUT PUNICODE_STRING ParsedFileName, + OUT PUNICODE_STRING RootFileName, + OUT ULONG *ParseFlags, + OUT AFSVolumeCB **VolumeCB, + OUT AFSDirectoryCB **ParentDirectoryCB, + OUT AFSNameArrayHdr **NameArray) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + UNICODE_STRING uniFullName, uniComponentName, uniRemainingPath; + ULONG ulCRC = 0; + AFSDirectoryCB *pDirEntry = NULL, *pShareDirEntry = NULL, *pTargetDirEntry = NULL; + USHORT usIndex = 0, usDriveIndex = 0; + AFSCcb *pRelatedCcb = NULL; + AFSNameArrayHdr *pNameArray = NULL, *pRelatedNameArray = NULL; + USHORT usComponentIndex = 0; + USHORT usComponentLength = 0; + AFSVolumeCB *pVolumeCB = NULL; + AFSFcb *pRelatedFcb = NULL; + BOOLEAN bReleaseTreeLock = FALSE; + BOOLEAN bIsAllShare = FALSE; + + __Enter + { + + // + // Indicate we are opening a root ... + // + + *ParseFlags = AFS_PARSE_FLAG_ROOT_ACCESS; + + if( pIrpSp->FileObject->RelatedFileObject != NULL) + { + + pRelatedFcb = (AFSFcb *)pIrpSp->FileObject->RelatedFileObject->FsContext; + + pRelatedCcb = (AFSCcb *)pIrpSp->FileObject->RelatedFileObject->FsContext2; + + pRelatedNameArray = pRelatedCcb->NameArray; + + uniFullName = pIrpSp->FileObject->FileName; + + ASSERT( pRelatedFcb != NULL); + + // + // No wild cards in the name + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Relative open for %wZ FID %08lX-%08lX-%08lX-%08lX component %wZ\n", + Irp, + &pRelatedCcb->DirectoryCB->NameInformation.FileName, + pRelatedCcb->DirectoryCB->ObjectInformation->FileId.Cell, + pRelatedCcb->DirectoryCB->ObjectInformation->FileId.Volume, + pRelatedCcb->DirectoryCB->ObjectInformation->FileId.Vnode, + pRelatedCcb->DirectoryCB->ObjectInformation->FileId.Unique, + &uniFullName); + + if( FsRtlDoesNameContainWildCards( &uniFullName)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Component %wZ contains wild cards\n", + Irp, + &uniFullName); + + try_return( ntStatus = STATUS_OBJECT_NAME_INVALID); + } + + pVolumeCB = pRelatedFcb->ObjectInformation->VolumeCB; + + pDirEntry = pRelatedCcb->DirectoryCB; + + *FileName = pIrpSp->FileObject->FileName; + + // + // Grab the root node exclusive before returning + // + + AFSAcquireExcl( pVolumeCB->VolumeLock, + TRUE); + + if( BooleanFlagOn( pVolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID) || + BooleanFlagOn( pVolumeCB->Flags, AFS_VOLUME_FLAGS_OFFLINE)) + { + + // + // The volume has been taken off line so fail the access + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Volume %08lX:%08lX OFFLINE/INVALID\n", + Irp, + pVolumeCB->ObjectInformation.FileId.Cell, + pVolumeCB->ObjectInformation.FileId.Volume); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + if( BooleanFlagOn( pVolumeCB->ObjectInformation.Flags, AFS_OBJECT_FLAGS_VERIFY)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Verifying root of volume %08lX:%08lX\n", + Irp, + pVolumeCB->ObjectInformation.FileId.Cell, + pVolumeCB->ObjectInformation.FileId.Volume); + + ntStatus = AFSVerifyVolume( (ULONGLONG)PsGetCurrentProcessId(), + pVolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Failed verification of root Status %08lX\n", + Irp, + ntStatus); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus); + } + } + + AFSConvertToShared( pVolumeCB->VolumeLock); + + if( BooleanFlagOn( pDirEntry->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Verifying parent %wZ FID %08lX-%08lX-%08lX-%08lX\n", + Irp, + &pDirEntry->NameInformation.FileName, + pDirEntry->ObjectInformation->FileId.Cell, + pDirEntry->ObjectInformation->FileId.Volume, + pDirEntry->ObjectInformation->FileId.Vnode, + pDirEntry->ObjectInformation->FileId.Unique); + + ntStatus = AFSVerifyEntry( AuthGroup, + pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Failed verification of parent %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + Irp, + &pDirEntry->NameInformation.FileName, + pDirEntry->ObjectInformation->FileId.Cell, + pDirEntry->ObjectInformation->FileId.Volume, + pDirEntry->ObjectInformation->FileId.Vnode, + pDirEntry->ObjectInformation->FileId.Unique, + ntStatus); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus); + } + } + + // + // Create our full path name buffer + // + + uniFullName.MaximumLength = pRelatedCcb->FullFileName.Length + + sizeof( WCHAR) + + pIrpSp->FileObject->FileName.Length + + sizeof( WCHAR); + + uniFullName.Length = 0; + + uniFullName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniFullName.MaximumLength, + AFS_NAME_BUFFER_THREE_TAG); + + if( uniFullName.Buffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Failed to allocate full name buffer\n", + Irp); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( uniFullName.Buffer, + uniFullName.MaximumLength); + + RtlCopyMemory( uniFullName.Buffer, + pRelatedCcb->FullFileName.Buffer, + pRelatedCcb->FullFileName.Length); + + uniFullName.Length = pRelatedCcb->FullFileName.Length; + + usComponentIndex = (USHORT)(uniFullName.Length/sizeof( WCHAR)); + + usComponentLength = pIrpSp->FileObject->FileName.Length; + + if( uniFullName.Buffer[ (uniFullName.Length/sizeof( WCHAR)) - 1] != L'\\' && + pIrpSp->FileObject->FileName.Length > 0 && + pIrpSp->FileObject->FileName.Buffer[ 0] != L'\\' && + pIrpSp->FileObject->FileName.Buffer[ 0] != L':') + { + + uniFullName.Buffer[ (uniFullName.Length/sizeof( WCHAR))] = L'\\'; + + uniFullName.Length += sizeof( WCHAR); + + usComponentLength += sizeof( WCHAR); + } + + if( pIrpSp->FileObject->FileName.Length > 0) + { + + RtlCopyMemory( &uniFullName.Buffer[ uniFullName.Length/sizeof( WCHAR)], + pIrpSp->FileObject->FileName.Buffer, + pIrpSp->FileObject->FileName.Length); + + uniFullName.Length += pIrpSp->FileObject->FileName.Length; + } + + *RootFileName = uniFullName; + + // + // We populate up to the current parent + // + + if( pRelatedNameArray == NULL) + { + + // + // Init and populate our name array + // + + pNameArray = AFSInitNameArray( NULL, + 0); + + if( pNameArray == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Failed to initialize name array\n", + Irp); + + AFSExFreePool( uniFullName.Buffer); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ntStatus = AFSPopulateNameArray( pNameArray, + NULL, + pRelatedCcb->DirectoryCB); + } + else + { + + // + // Init and populate our name array + // + + pNameArray = AFSInitNameArray( NULL, + pRelatedNameArray->MaxElementCount); + + if( pNameArray == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Failed to initialize name array\n", + Irp); + + AFSExFreePool( uniFullName.Buffer); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ntStatus = AFSPopulateNameArrayFromRelatedArray( pNameArray, + pRelatedNameArray, + pRelatedCcb->DirectoryCB); + } + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Failed to populate name array\n", + Irp); + + AFSExFreePool( uniFullName.Buffer); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus); + } + + ParsedFileName->Length = usComponentLength; + ParsedFileName->MaximumLength = uniFullName.MaximumLength; + + ParsedFileName->Buffer = &uniFullName.Buffer[ usComponentIndex]; + + // + // Indicate to caller that RootFileName must be freed + // + + SetFlag( *ParseFlags, AFS_PARSE_FLAG_FREE_FILE_BUFFER); + + *NameArray = pNameArray; + + *VolumeCB = pVolumeCB; + + // + // Increment our volume reference count + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + *ParentDirectoryCB = pDirEntry; + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Returning full name %wZ\n", + Irp, + &uniFullName); + + try_return( ntStatus); + } + + // + // No wild cards in the name + // + + uniFullName = pIrpSp->FileObject->FileName; + + if( FsRtlDoesNameContainWildCards( &uniFullName) || + uniFullName.Length < AFSServerName.Length) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Name %wZ contains wild cards or too short\n", + Irp, + &uniFullName); + + try_return( ntStatus = STATUS_OBJECT_NAME_INVALID); + } + + // + // The name is a fully qualified name. Parse out the server/share names and + // point to the root qualified name + // First thing is to locate the server name + // + + FsRtlDissectName( uniFullName, + &uniComponentName, + &uniRemainingPath); + + uniFullName = uniRemainingPath; + + // + // This component is the server name we are serving + // + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSServerName, + TRUE) != 0) + { + + // + // Drive letter based name? + // + + uniFullName = pIrpSp->FileObject->FileName; + + while( usIndex < uniFullName.Length/sizeof( WCHAR)) + { + + if( uniFullName.Buffer[ usIndex] == L':') + { + + uniFullName.Buffer = &uniFullName.Buffer[ usIndex + 2]; + + uniFullName.Length -= (usIndex + 2) * sizeof( WCHAR); + + usDriveIndex = usIndex - 1; + + break; + } + + usIndex++; + } + + // + // Do we have the right server name now? + // + + FsRtlDissectName( uniFullName, + &uniComponentName, + &uniRemainingPath); + + uniFullName = uniRemainingPath; + + // + // This component is the server name we are serving + // + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSServerName, + TRUE) != 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Name %wZ does not have server name\n", + Irp, + &pIrpSp->FileObject->FileName); + + try_return( ntStatus = STATUS_BAD_NETWORK_NAME); + } + + // + // Validate this drive letter is actively mapped + // + + if( usDriveIndex > 0 && + !AFSIsDriveMapped( pIrpSp->FileObject->FileName.Buffer[ usDriveIndex])) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Name %wZ contains invalid drive mapping\n", + Irp, + &pIrpSp->FileObject->FileName); + + try_return( ntStatus = STATUS_BAD_NETWORK_NAME); + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Processing full name %wZ\n", + Irp, + &uniFullName); + + if( uniFullName.Length > 0 && + uniFullName.Buffer[ (uniFullName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + uniFullName.Length -= sizeof( WCHAR); + } + + // + // Be sure we are online and ready to go + // + + AFSAcquireExcl( AFSGlobalRoot->VolumeLock, + TRUE); + + if( BooleanFlagOn( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID) || + BooleanFlagOn( AFSGlobalRoot->Flags, AFS_VOLUME_FLAGS_OFFLINE)) + { + + // + // The volume has been taken off line so fail the access + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Volume %08lX:%08lX OFFLINE/INVALID\n", + Irp, + AFSGlobalRoot->ObjectInformation.FileId.Cell, + AFSGlobalRoot->ObjectInformation.FileId.Volume); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + if( BooleanFlagOn( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_VERIFY)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Verifying root of volume %08lX:%08lX\n", + Irp, + AFSGlobalRoot->ObjectInformation.FileId.Cell, + AFSGlobalRoot->ObjectInformation.FileId.Volume); + + ntStatus = AFSVerifyVolume( (ULONGLONG)PsGetCurrentProcessId(), + AFSGlobalRoot); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Failed verification of root Status %08lX\n", + Irp, + ntStatus); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + try_return( ntStatus); + } + } + + if( !BooleanFlagOn( AFSGlobalRoot->ObjectInformation.Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Enumerating global root of volume %08lX:%08lX\n", + Irp, + AFSGlobalRoot->ObjectInformation.FileId.Cell, + AFSGlobalRoot->ObjectInformation.FileId.Volume); + + ntStatus = AFSEnumerateGlobalRoot( AuthGroup); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSParseName (%08lX) Failed enumeraiton of root Status %08lX\n", + Irp, + ntStatus); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + try_return( ntStatus); + } + } + + // + // Check for the \\Server access and return it as though it where \\Server\Globalroot + // + + if( uniRemainingPath.Buffer == NULL || + ( uniRemainingPath.Length == sizeof( WCHAR) && + uniRemainingPath.Buffer[ 0] == L'\\')) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Returning global root access\n", + Irp); + + InterlockedIncrement( &AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment2 count on %wZ DE %p Ccb %p Cnt %d\n", + &AFSGlobalRoot->DirectoryCB->NameInformation.FileName, + AFSGlobalRoot->DirectoryCB, + NULL, + AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + *VolumeCB = NULL; + + FileName->Length = 0; + FileName->MaximumLength = 0; + FileName->Buffer = NULL; + + try_return( ntStatus = STATUS_SUCCESS); + } + + *RootFileName = uniFullName; + + // + // Include the starting \ in the root name + // + + if( RootFileName->Buffer[ 0] != L'\\') + { + RootFileName->Buffer--; + RootFileName->Length += sizeof( WCHAR); + RootFileName->MaximumLength += sizeof( WCHAR); + } + + // + // Get the 'share' name + // + + FsRtlDissectName( uniFullName, + &uniComponentName, + &uniRemainingPath); + + // + // If this is the ALL access then perform some additional processing + // + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSGlobalRootName, + TRUE) == 0) + { + + bIsAllShare = TRUE; + + // + // If there is nothing else then get out + // + + if( uniRemainingPath.Buffer == NULL || + uniRemainingPath.Length == 0 || + ( uniRemainingPath.Length == sizeof( WCHAR) && + uniRemainingPath.Buffer[ 0] == L'\\')) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Returning global root access\n", + Irp); + + InterlockedIncrement( &AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment3 count on %wZ DE %p Ccb %p Cnt %d\n", + &AFSGlobalRoot->DirectoryCB->NameInformation.FileName, + AFSGlobalRoot->DirectoryCB, + NULL, + AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + *VolumeCB = NULL; + + FileName->Length = 0; + FileName->MaximumLength = 0; + FileName->Buffer = NULL; + + try_return( ntStatus = STATUS_SUCCESS); + } + + // + // Process the name again to strip off the ALL portion + // + + uniFullName = uniRemainingPath; + + FsRtlDissectName( uniFullName, + &uniComponentName, + &uniRemainingPath); + + // + // Check for the PIOCtl name + // + + if( RtlCompareUnicodeString( &uniComponentName, + &AFSPIOCtlName, + TRUE) == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Returning root PIOCtl access\n", + Irp); + + InterlockedIncrement( &AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment4 count on %wZ DE %p Ccb %p Cnt %d\n", + &AFSGlobalRoot->DirectoryCB->NameInformation.FileName, + AFSGlobalRoot->DirectoryCB, + NULL, + AFSGlobalRoot->DirectoryCB->OpenReferenceCount); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + ClearFlag( *ParseFlags, AFS_PARSE_FLAG_ROOT_ACCESS); + + *VolumeCB = NULL; + + *FileName = AFSPIOCtlName; + + try_return( ntStatus = STATUS_SUCCESS); + } + } + else if( (pDirEntry = AFSGetSpecialShareNameEntry( &uniComponentName, + &uniRemainingPath)) != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSParseName (%08lX) Returning root share name %wZ access\n", + Irp, + &uniComponentName); + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + // + // Add in the full share name to pass back + // + + if( uniRemainingPath.Buffer != NULL) + { + + // + // This routine strips off the leading slash so add it back in + // + + uniRemainingPath.Buffer--; + uniRemainingPath.Length += sizeof( WCHAR); + uniRemainingPath.MaximumLength += sizeof( WCHAR); + + // + // And the cell name + // + + uniRemainingPath.Buffer -= (uniComponentName.Length/sizeof( WCHAR)); + uniRemainingPath.Length += uniComponentName.Length; + uniRemainingPath.MaximumLength += uniComponentName.Length; + + uniComponentName = uniRemainingPath; + } + + *VolumeCB = NULL; + + *FileName = uniComponentName; + + *ParentDirectoryCB = pDirEntry; + + ClearFlag( *ParseFlags, AFS_PARSE_FLAG_ROOT_ACCESS); + + InterlockedIncrement( &pDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment5 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirEntry->NameInformation.FileName, + pDirEntry, + NULL, + pDirEntry->OpenReferenceCount); + + try_return( ntStatus = STATUS_SUCCESS); + } + + // + // Determine the 'share' we are accessing + // + + ulCRC = AFSGenerateCRC( &uniComponentName, + FALSE); + + AFSAcquireShared( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + bReleaseTreeLock = TRUE; + + AFSLocateCaseSensitiveDirEntry( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pDirEntry); + + if( pDirEntry == NULL) + { + + ulCRC = AFSGenerateCRC( &uniComponentName, + TRUE); + + AFSLocateCaseInsensitiveDirEntry( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + ulCRC, + &pDirEntry); + + if( pDirEntry == NULL) + { + + // + // OK, if this component is a valid short name then try + // a lookup in the short name tree + // + + if( RtlIsNameLegalDOS8Dot3( &uniComponentName, + NULL, + NULL)) + { + + AFSLocateShortNameDirEntry( AFSGlobalRoot->ObjectInformation.Specific.Directory.ShortNameTree, + ulCRC, + &pDirEntry); + } + + if( pDirEntry == NULL) + { + + // + // Check with the service whether it is a valid cell name + // + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + bReleaseTreeLock = FALSE; + + ntStatus = AFSCheckCellName( AuthGroup, + &uniComponentName, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + if ( bIsAllShare && + uniRemainingPath.Length == 0 && + ntStatus == STATUS_OBJECT_PATH_NOT_FOUND) + { + + ntStatus = STATUS_OBJECT_NAME_NOT_FOUND; + } + + try_return( ntStatus); + } + } + } + } + + if( bReleaseTreeLock) + { + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + } + + // + // Be sure we are starting from the correct volume + // + + if( pDirEntry->ObjectInformation->VolumeCB != AFSGlobalRoot) + { + + // + // We dropped the global root in the CheckCellName routine which is the + // only way we can be here + // + + pVolumeCB = pDirEntry->ObjectInformation->VolumeCB; + + // + // In this case don't add back in the 'share' name since that is where we are + // starting. Just put the leading slash back in + // + + if( uniRemainingPath.Buffer != NULL) + { + + uniRemainingPath.Buffer--; + uniRemainingPath.Length += sizeof( WCHAR); + uniRemainingPath.MaximumLength += sizeof( WCHAR); + + if( uniRemainingPath.Length > sizeof( WCHAR)) + { + + ClearFlag( *ParseFlags, AFS_PARSE_FLAG_ROOT_ACCESS); + } + + // + // Pass back the parent being the root of the volume + // + + *ParentDirectoryCB = pVolumeCB->DirectoryCB; + } + else + { + + // + // Pass back a root slash + // + + uniRemainingPath = uniComponentName; + + uniRemainingPath.Buffer--; + uniRemainingPath.Length = sizeof( WCHAR); + uniRemainingPath.MaximumLength = sizeof( WCHAR); + + // + // This is a root open so pass back no parent + // + + *ParentDirectoryCB = NULL; + } + } + else + { + + pVolumeCB = AFSGlobalRoot; + + // + // Add back in the 'share' portion of the name since we will parse it out on return + // + + if( uniRemainingPath.Buffer != NULL) + { + + // + // This routine strips off the leading slash so add it back in + // + + uniRemainingPath.Buffer--; + uniRemainingPath.Length += sizeof( WCHAR); + uniRemainingPath.MaximumLength += sizeof( WCHAR); + + if( uniRemainingPath.Length > sizeof( WCHAR)) + { + + ClearFlag( *ParseFlags, AFS_PARSE_FLAG_ROOT_ACCESS); + } + + // + // And the cell name + // + + uniRemainingPath.Buffer -= (uniComponentName.Length/sizeof( WCHAR)); + uniRemainingPath.Length += uniComponentName.Length; + uniRemainingPath.MaximumLength += uniComponentName.Length; + } + else + { + + uniRemainingPath = uniComponentName; + } + + // + // And the leading slash again ... + // + + uniRemainingPath.Buffer--; + uniRemainingPath.Length += sizeof( WCHAR); + uniRemainingPath.MaximumLength += sizeof( WCHAR); + + InterlockedIncrement( &pVolumeCB->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment6 count on %wZ DE %p Ccb %p Cnt %d\n", + &pVolumeCB->DirectoryCB->NameInformation.FileName, + pVolumeCB->DirectoryCB, + NULL, + pVolumeCB->DirectoryCB->OpenReferenceCount); + + // + // Pass back the parent being the volume root + // + + *ParentDirectoryCB = pVolumeCB->DirectoryCB; + } + + // + // We only need the volume shared at this point + // + + AFSConvertToShared( pVolumeCB->VolumeLock); + + // + // Init our name array + // + + pNameArray = AFSInitNameArray( pVolumeCB->DirectoryCB, + 0); + + if( pNameArray == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName (%08lX) Failed to initialize name array\n", + Irp); + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Return the remaining portion as the file name + // + + *FileName = uniRemainingPath; + + *ParsedFileName = uniRemainingPath; + + *NameArray = pNameArray; + + *VolumeCB = pVolumeCB; + + // + // Increment our reference on the volume + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Increment2 count on global volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + +try_exit: + + if( NT_SUCCESS( ntStatus)) + { + + if( *ParentDirectoryCB != NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSParseName Count on %wZ DE %p Ccb %p Cnt %d\n", + &(*ParentDirectoryCB)->NameInformation.FileName, + *ParentDirectoryCB, + NULL, + (*ParentDirectoryCB)->OpenReferenceCount); + } + } + + if( *VolumeCB != NULL) + { + + ASSERT( (*VolumeCB)->VolumeReferenceCount > 1); + } + + if( ntStatus != STATUS_SUCCESS) + { + + if( pNameArray != NULL) + { + + AFSFreeNameArray( pNameArray); + } + } + } + + return ntStatus; +} + +NTSTATUS +AFSCheckCellName( IN GUID *AuthGroup, + IN UNICODE_STRING *CellName, + OUT AFSDirectoryCB **ShareDirEntry) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniName; + AFSFileID stFileID; + AFSDirEnumEntry *pDirEnumEntry = NULL; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSDirHdr *pDirHdr = &AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr; + AFSDirectoryCB *pDirNode = NULL; + UNICODE_STRING uniDirName, uniTargetName; + AFSVolumeCB *pVolumeCB = NULL; + + __Enter + { + + // + // Look for some default names we will not handle + // + + RtlInitUnicodeString( &uniName, + L"IPC$"); + + if( RtlCompareUnicodeString( &uniName, + CellName, + TRUE) == 0) + { + + try_return( ntStatus = STATUS_NO_SUCH_FILE); + } + + RtlInitUnicodeString( &uniName, + L"wkssvc"); + + if( RtlCompareUnicodeString( &uniName, + CellName, + TRUE) == 0) + { + + try_return( ntStatus = STATUS_NO_SUCH_FILE); + } + + RtlInitUnicodeString( &uniName, + L"srvsvc"); + + if( RtlCompareUnicodeString( &uniName, + CellName, + TRUE) == 0) + { + + try_return( ntStatus = STATUS_NO_SUCH_FILE); + } + + RtlInitUnicodeString( &uniName, + L"PIPE"); + + if( RtlCompareUnicodeString( &uniName, + CellName, + TRUE) == 0) + { + + try_return( ntStatus = STATUS_NO_SUCH_FILE); + } + + // + // OK, ask the CM about this component name + // + + stFileID = AFSGlobalRoot->ObjectInformation.FileId; + + ntStatus = AFSEvaluateTargetByName( AuthGroup, + &stFileID, + CellName, + &pDirEnumEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + // + // OK, we have a dir enum entry back so add it to the root node + // + + uniDirName = *CellName; + + uniTargetName.Length = (USHORT)pDirEnumEntry->TargetNameLength; + uniTargetName.MaximumLength = uniTargetName.Length; + uniTargetName.Buffer = (WCHAR *)((char *)pDirEnumEntry + pDirEnumEntry->TargetNameOffset); + + // + // Is this entry a root volume entry? + // + + if( pDirEnumEntry->FileId.Cell != AFSGlobalRoot->ObjectInformation.FileId.Cell || + pDirEnumEntry->FileId.Volume != AFSGlobalRoot->ObjectInformation.FileId.Volume) + { + + // + // We have the global root on entry so drop it now + // + + AFSReleaseResource( AFSGlobalRoot->VolumeLock); + + // + // Build the root volume entry + // + + ntStatus = AFSBuildRootVolume( AuthGroup, + &pDirEnumEntry->FileId, + &pVolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + // + // On failure this routine is expecting to hold the global root + // + + AFSAcquireShared( AFSGlobalRoot->VolumeLock, + TRUE); + + try_return( ntStatus); + } + + *ShareDirEntry = pVolumeCB->DirectoryCB; + + InterlockedIncrement( &pVolumeCB->DirectoryCB->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCheckCellName Increment1 count on %wZ DE %p Ccb %p Cnt %d\n", + &pVolumeCB->DirectoryCB->NameInformation.FileName, + pVolumeCB->DirectoryCB, + NULL, + pVolumeCB->DirectoryCB->OpenReferenceCount); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + } + else + { + + pDirNode = AFSInitDirEntry( &AFSGlobalRoot->ObjectInformation, + &uniDirName, + &uniTargetName, + pDirEnumEntry, + (ULONG)InterlockedIncrement( &pDirHdr->ContentIndex)); + + if( pDirNode == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Init the short name if we have one + // + + if( pDirEnumEntry->ShortNameLength > 0) + { + + pDirNode->NameInformation.ShortNameLength = pDirEnumEntry->ShortNameLength; + + RtlCopyMemory( pDirNode->NameInformation.ShortName, + pDirEnumEntry->ShortName, + pDirNode->NameInformation.ShortNameLength); + } + + AFSAcquireExcl( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + // + // Insert the node into the name tree + // + + ASSERT( ExIsResourceAcquiredExclusiveLite( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock)); + + if( pDirHdr->CaseSensitiveTreeHead == NULL) + { + + pDirHdr->CaseSensitiveTreeHead = pDirNode; + } + else + { + + AFSInsertCaseSensitiveDirEntry( pDirHdr->CaseSensitiveTreeHead, + pDirNode); + } + + if( pDirHdr->CaseInsensitiveTreeHead == NULL) + { + + pDirHdr->CaseInsensitiveTreeHead = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD); + } + else + { + + AFSInsertCaseInsensitiveDirEntry( pDirHdr->CaseInsensitiveTreeHead, + pDirNode); + } + + if( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeListHead == NULL) + { + + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeListHead = pDirNode; + } + else + { + + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeListTail->ListEntry.fLink = pDirNode; + + pDirNode->ListEntry.bLink = AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeListTail; + } + + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeListTail = pDirNode; + + SetFlag( pDirNode->Flags, AFS_DIR_ENTRY_INSERTED_ENUM_LIST); + + InterlockedIncrement( &AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCheckCellName Adding entry %wZ Inc Count %d to parent FID %08lX-%08lX-%08lX-%08lX\n", + &pDirNode->NameInformation.FileName, + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeCount, + AFSGlobalRoot->ObjectInformation.FileId.Cell, + AFSGlobalRoot->ObjectInformation.FileId.Volume, + AFSGlobalRoot->ObjectInformation.FileId.Vnode, + AFSGlobalRoot->ObjectInformation.FileId.Unique); + + InterlockedIncrement( &pDirNode->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCheckCellName Increment2 count on %wZ DE %p Ccb %p Cnt %d\n", + &pDirNode->NameInformation.FileName, + pDirNode, + NULL, + pDirNode->OpenReferenceCount); + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + // + // Pass back the dir node + // + + *ShareDirEntry = pDirNode; + } + +try_exit: + + if( pDirEnumEntry != NULL) + { + + AFSExFreePool( pDirEnumEntry); + } + } + + return ntStatus; +} + +NTSTATUS +AFSBuildMountPointTarget( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSVolumeCB **TargetVolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + AFSDirEnumEntry *pDirEntry = NULL; + AFSDirectoryCB *pDirNode = NULL; + UNICODE_STRING uniDirName, uniTargetName; + ULONGLONG ullIndex = 0; + AFSVolumeCB *pVolumeCB = NULL; + AFSFileID stTargetFileID; + + __Enter + { + + // + // Loop on each entry, building the chain until we encounter the final target + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildMountPointTarget Building target directory for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirectoryCB->NameInformation.FileName, + DirectoryCB->ObjectInformation->FileId.Cell, + DirectoryCB->ObjectInformation->FileId.Volume, + DirectoryCB->ObjectInformation->FileId.Vnode, + DirectoryCB->ObjectInformation->FileId.Unique); + + // + // Do we need to evaluate the node? + // + + //if( DirectoryCB->ObjectInformation->TargetFileId.Vnode == 0 && + // DirectoryCB->ObjectInformation->TargetFileId.Unique == 0) + { + + // + // Go evaluate the current target to get the target fid + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildMountPointTarget Evaluating target %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirectoryCB->NameInformation.FileName, + DirectoryCB->ObjectInformation->FileId.Cell, + DirectoryCB->ObjectInformation->FileId.Volume, + DirectoryCB->ObjectInformation->FileId.Vnode, + DirectoryCB->ObjectInformation->FileId.Unique); + + ntStatus = AFSEvaluateTargetByID( DirectoryCB->ObjectInformation, + AuthGroup, + FALSE, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSBuildMountPointTarget Failed to evaluate target %wZ Status %08lX\n", + &DirectoryCB->NameInformation.FileName, + ntStatus); + try_return( ntStatus); + } + + if( pDirEntry->TargetFileId.Vnode == 0 && + pDirEntry->TargetFileId.Unique == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSBuildMountPointTarget Target %wZ FID %08lX-%08lX-%08lX-%08lX service returned zero FID\n", + &DirectoryCB->NameInformation.FileName, + DirectoryCB->ObjectInformation->FileId.Cell, + DirectoryCB->ObjectInformation->FileId.Volume, + DirectoryCB->ObjectInformation->FileId.Vnode, + DirectoryCB->ObjectInformation->FileId.Unique); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + AFSAcquireExcl( &DirectoryCB->NonPaged->Lock, + TRUE); + + ntStatus = AFSUpdateTargetName( &DirectoryCB->NameInformation.TargetName, + &DirectoryCB->Flags, + (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset), + (USHORT)pDirEntry->TargetNameLength); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + try_return( ntStatus); + } + + AFSReleaseResource( &DirectoryCB->NonPaged->Lock); + + DirectoryCB->ObjectInformation->TargetFileId = pDirEntry->TargetFileId; + } + + stTargetFileID = DirectoryCB->ObjectInformation->TargetFileId; + + // + // Try to locate this FID. First the volume then the + // entry itself + // + + ullIndex = AFSCreateHighIndex( &stTargetFileID); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSBuildMountPointTarget Acquiring RDR VolumeTreeLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.RDR.VolumeTreeLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, + TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildMountPointTarget Locating volume for target %I64X\n", + ullIndex); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + // + // We can be processing a request for a target that is on a volume + // we have never seen before. + // + + if( pVolumeCB == NULL) + { + + // + // Locking is held correctly in init routine + // + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + // + // Go init the root of the volume + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildMountPointTarget Initializing root for %wZ FID %08lX-%08lX-%08lX-%08lX\n", + &DirectoryCB->NameInformation.FileName, + DirectoryCB->ObjectInformation->FileId.Cell, + DirectoryCB->ObjectInformation->FileId.Volume, + DirectoryCB->ObjectInformation->FileId.Vnode, + DirectoryCB->ObjectInformation->FileId.Unique); + + ntStatus = AFSInitVolume( AuthGroup, + &stTargetFileID, + &pVolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } + else + { + + // + // Check if this volume has been deleted or taken offline + // + + if( BooleanFlagOn( pVolumeCB->Flags, AFS_VOLUME_FLAGS_OFFLINE)) + { + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + try_return( ntStatus = STATUS_FILE_IS_OFFLINE); + } + + // + // Just to ensure that things don't get torn down AND we don't create a + // deadlock with invalidation + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + AFSAcquireExcl( pVolumeCB->VolumeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + } + + if( pVolumeCB->RootFcb == NULL) + { + + // + // Initialize the root fcb for this volume + // + + ntStatus = AFSInitRootFcb( (ULONGLONG)PsGetCurrentProcessId(), + pVolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus); + } + + // + // Drop the lock acquired above + // + + AFSReleaseResource( &pVolumeCB->RootFcb->NPFcb->Resource); + } + + AFSConvertToShared( pVolumeCB->VolumeLock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildMountPointTarget Evaluated target of %wZ FID %08lX-%08lX-%08lX-%08lX as root volume\n", + &pVolumeCB->DirectoryCB->NameInformation.FileName, + pVolumeCB->ObjectInformation.FileId.Cell, + pVolumeCB->ObjectInformation.FileId.Volume, + pVolumeCB->ObjectInformation.FileId.Vnode, + pVolumeCB->ObjectInformation.FileId.Unique); + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSBuildMountPointTarget Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + *TargetVolumeCB = pVolumeCB; + +try_exit: + + if( pDirEntry) + { + + AFSExFreePool( pDirEntry); + } + } + + return ntStatus; +} + +NTSTATUS +AFSBuildRootVolume( IN GUID *AuthGroup, + IN AFSFileID *FileId, + OUT AFSVolumeCB **TargetVolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = (AFSDeviceExt *) AFSRDRDeviceObject->DeviceExtension; + AFSDirectoryCB *pDirNode = NULL; + UNICODE_STRING uniDirName, uniTargetName; + ULONGLONG ullIndex = 0; + AFSVolumeCB *pVolumeCB = NULL; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildRootVolume Building target volume for FID %08lX-%08lX-%08lX-%08lX\n", + FileId->Cell, + FileId->Volume, + FileId->Vnode, + FileId->Unique); + + ullIndex = AFSCreateHighIndex( FileId); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSBuildRootVolume Acquiring RDR VolumeTreeLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.RDR.VolumeTreeLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pDevExt->Specific.RDR.VolumeTreeLock, + TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildRootVolume Locating volume for target %I64X\n", + ullIndex); + + ntStatus = AFSLocateHashEntry( pDevExt->Specific.RDR.VolumeTree.TreeHead, + ullIndex, + (AFSBTreeEntry **)&pVolumeCB); + + // + // We can be processing a request for a target that is on a volume + // we have never seen before. + // + + if( pVolumeCB == NULL) + { + + // + // Locking is held correctly in init routine + // + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + // + // Go init the root of the volume + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildRootVolume Initializing root for FID %08lX-%08lX-%08lX-%08lX\n", + FileId->Cell, + FileId->Volume, + FileId->Vnode, + FileId->Unique); + + ntStatus = AFSInitVolume( AuthGroup, + FileId, + &pVolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } + else + { + + // + // Just to ensure that things don't get torn down AND we don't create a + // deadlock with invalidation + // + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSReleaseResource( &pDevExt->Specific.RDR.VolumeTreeLock); + + AFSAcquireExcl( pVolumeCB->VolumeLock, + TRUE); + + InterlockedDecrement( &pVolumeCB->VolumeReferenceCount); + } + + + if( pVolumeCB->RootFcb == NULL) + { + + // + // Initialize the root fcb for this volume + // + + ntStatus = AFSInitRootFcb( (ULONGLONG)PsGetCurrentProcessId(), + pVolumeCB); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( pVolumeCB->VolumeLock); + + try_return( ntStatus); + } + + // + // Drop the lock acquired above + // + + AFSReleaseResource( &pVolumeCB->RootFcb->NPFcb->Resource); + } + + AFSConvertToShared( pVolumeCB->VolumeLock); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE_2, + "AFSBuildRootVolume Evaluated target of %wZ FID %08lX-%08lX-%08lX-%08lX as root volume\n", + &pVolumeCB->DirectoryCB->NameInformation.FileName, + pVolumeCB->ObjectInformation.FileId.Cell, + pVolumeCB->ObjectInformation.FileId.Volume, + pVolumeCB->ObjectInformation.FileId.Vnode, + pVolumeCB->ObjectInformation.FileId.Unique); + + InterlockedIncrement( &pVolumeCB->VolumeReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_VOLUME_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSBuildRootVolume Increment count on volume %08lX Cnt %d\n", + pVolumeCB, + pVolumeCB->VolumeReferenceCount); + + *TargetVolumeCB = pVolumeCB; + +try_exit: + + NOTHING; + } + + return ntStatus; +} + +NTSTATUS +AFSProcessDFSLink( IN AFSDirectoryCB *DirEntry, + IN PFILE_OBJECT FileObject, + IN UNICODE_STRING *RemainingPath) +{ + + NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST; + UNICODE_STRING uniReparseName; + UNICODE_STRING uniMUPDeviceName; + AFSDirEnumEntry *pDirEntry = NULL; + GUID *pAuthGroup = NULL; + + __Enter + { + + // + // Build up the name to reparse + // + + RtlInitUnicodeString( &uniMUPDeviceName, + L"\\Device\\MUP"); + + uniReparseName.Length = 0; + uniReparseName.Buffer = NULL; + + // + // Be sure we have a target name + // + + if( DirEntry->NameInformation.TargetName.Length == 0) + { + + if( DirEntry->ObjectInformation->Fcb != NULL) + { + pAuthGroup = &DirEntry->ObjectInformation->Fcb->AuthGroup; + } + + ntStatus = AFSEvaluateTargetByID( DirEntry->ObjectInformation, + pAuthGroup, + FALSE, + &pDirEntry); + + if( !NT_SUCCESS( ntStatus) || + pDirEntry->TargetNameLength == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessDFSLink EvaluateTargetByID failed for Fcb %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique, + ntStatus); + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_ACCESS_DENIED; + } + + try_return( ntStatus); + } + + // + // Update the target name + // + + AFSAcquireExcl( &DirEntry->NonPaged->Lock, + TRUE); + + ntStatus = AFSUpdateTargetName( &DirEntry->NameInformation.TargetName, + &DirEntry->Flags, + (WCHAR *)((char *)pDirEntry + pDirEntry->TargetNameOffset), + (USHORT)pDirEntry->TargetNameLength); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessDFSLink UpdateTargetName failed for Fcb %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique, + ntStatus); + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + try_return( ntStatus); + } + + AFSConvertToShared( &DirEntry->NonPaged->Lock); + } + else + { + AFSAcquireShared( &DirEntry->NonPaged->Lock, + TRUE); + } + + uniReparseName.MaximumLength = uniMUPDeviceName.Length + + sizeof( WCHAR) + + DirEntry->NameInformation.TargetName.Length + + sizeof( WCHAR); + + if( RemainingPath != NULL && + RemainingPath->Length > 0) + { + + uniReparseName.MaximumLength += RemainingPath->Length; + } + + // + // Allocate the reparse buffer + // + + uniReparseName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniReparseName.MaximumLength, + AFS_REPARSE_NAME_TAG); + + if( uniReparseName.Buffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSProcessDFSLink uniReparseName.Buffer == NULL Fcb %wZ FID %08lX-%08lX-%08lX-%08lX Status %08lX\n", + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique, + STATUS_INSUFFICIENT_RESOURCES); + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Start building the name + // + + RtlCopyMemory( uniReparseName.Buffer, + uniMUPDeviceName.Buffer, + uniMUPDeviceName.Length); + + uniReparseName.Length = uniMUPDeviceName.Length; + + if( DirEntry->NameInformation.TargetName.Buffer[ 0] != L'\\') + { + + uniReparseName.Buffer[ uniReparseName.Length/sizeof( WCHAR)] = L'\\'; + + uniReparseName.Length += sizeof( WCHAR); + } + + RtlCopyMemory( &uniReparseName.Buffer[ uniReparseName.Length/sizeof( WCHAR)], + DirEntry->NameInformation.TargetName.Buffer, + DirEntry->NameInformation.TargetName.Length); + + uniReparseName.Length += DirEntry->NameInformation.TargetName.Length; + + AFSReleaseResource( &DirEntry->NonPaged->Lock); + + if( RemainingPath != NULL && + RemainingPath->Length > 0) + { + + if( uniReparseName.Buffer[ (uniReparseName.Length/sizeof( WCHAR)) - 1] != L'\\' && + RemainingPath->Buffer[ 0] != L'\\') + { + + uniReparseName.Buffer[ uniReparseName.Length/sizeof( WCHAR)] = L'\\'; + + uniReparseName.Length += sizeof( WCHAR); + } + + RtlCopyMemory( &uniReparseName.Buffer[ uniReparseName.Length/sizeof( WCHAR)], + RemainingPath->Buffer, + RemainingPath->Length); + + uniReparseName.Length += RemainingPath->Length; + } + + // + // Update the name in the file object + // + + if( FileObject->FileName.Buffer != NULL) + { + + AFSExFreePool( FileObject->FileName.Buffer); + } + + FileObject->FileName = uniReparseName; + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSProcessDFSLink Reparsing access to Fcb %wZ FID %08lX-%08lX-%08lX-%08lX to %wZ\n", + &DirEntry->NameInformation.FileName, + DirEntry->ObjectInformation->FileId.Cell, + DirEntry->ObjectInformation->FileId.Volume, + DirEntry->ObjectInformation->FileId.Vnode, + DirEntry->ObjectInformation->FileId.Unique, + &uniReparseName); + + // + // Return status reparse ... + // + + ntStatus = STATUS_REPARSE; + +try_exit: + + if ( pDirEntry) + { + + AFSExFreePool( pDirEntry); + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSNetworkProviderSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSNetworkProviderSupport.cpp new file mode 100644 index 0000000000..26d3a6c923 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSNetworkProviderSupport.cpp @@ -0,0 +1,1930 @@ +/* + * 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: AFSNetworkProviderSupport.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSAddConnection( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN OUT PULONG ResultStatus, + IN OUT ULONG_PTR *ReturnOutputBufferLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSProviderConnectionCB *pConnection = NULL, *pLastConnection = NULL; + UNICODE_STRING uniRemoteName; + USHORT usIndex = 0; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection Acquiring AFSProviderListLock lock %08lX EXCL %08lX\n", + &pRDRDevExt->Specific.RDR.ProviderListLock, + PsGetCurrentThread()); + + if( ConnectCB->AuthenticationId.QuadPart == 0) + { + + ConnectCB->AuthenticationId = AFSGetAuthenticationId(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection Retrieved authentication id %I64X\n", + ConnectCB->AuthenticationId.QuadPart); + } + + AFSAcquireExcl( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + // + // Look for the connection + // + + uniRemoteName.Length = (USHORT)ConnectCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + + uniRemoteName.Buffer = ConnectCB->RemoteName; + + // + // Strip off any trailing slashes + // + + if( uniRemoteName.Buffer[ (uniRemoteName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + uniRemoteName.Length -= sizeof( WCHAR); + } + + pConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + + while( pConnection != NULL) + { + + if( pConnection->LocalName == ConnectCB->LocalName && + pConnection->AuthenticationId.QuadPart == ConnectCB->AuthenticationId.QuadPart && + RtlCompareUnicodeString( &uniRemoteName, + &pConnection->RemoteName, + TRUE) == 0) + { + + break; + } + + pConnection = pConnection->fLink; + } + + if( pConnection != NULL) + { + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection ALREADY_CONNECTED remote name %wZ Local %C authentication id %I64X\n", + &uniRemoteName, + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection ALREADY_CONNECTED remote name %wZ Local (NULL) authentication id %I64X\n", + &uniRemoteName, + ConnectCB->AuthenticationId.QuadPart); + } + + *ResultStatus = WN_ALREADY_CONNECTED; + + *ReturnOutputBufferLength = sizeof( ULONG); + + try_return( ntStatus); + } + + // + // Validate the remote name + // + + if( uniRemoteName.Length > 2 * sizeof( WCHAR) && + uniRemoteName.Buffer[ 0] == L'\\' && + uniRemoteName.Buffer[ 1] == L'\\') + { + + uniRemoteName.Buffer = &uniRemoteName.Buffer[ 2]; + + uniRemoteName.Length -= (2 * sizeof( WCHAR)); + } + + if( uniRemoteName.Length >= AFSServerName.Length) + { + + USHORT usLength = uniRemoteName.Length; + + if (uniRemoteName.Buffer[AFSServerName.Length/sizeof( WCHAR)] != L'\\') + { + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection BAD_NETNAME 1 remote name %wZ Local %C authentication id %I64X\n", + &uniRemoteName, + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection BAD_NETNAME 1 remote name %wZ Local (NULL) authentication id %I64X\n", + &uniRemoteName, + ConnectCB->AuthenticationId.QuadPart); + } + + *ResultStatus = WN_BAD_NETNAME; + + *ReturnOutputBufferLength = sizeof( ULONG); + + try_return( ntStatus = STATUS_SUCCESS); + } + + uniRemoteName.Length = AFSServerName.Length; + + if( RtlCompareUnicodeString( &AFSServerName, + &uniRemoteName, + TRUE) != 0) + { + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection BAD_NETNAME 2 remote name %wZ Local %C authentication id %I64X\n", + &uniRemoteName, + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection BAD_NETNAME 2 remote name %wZ Local (NULL) authentication id %I64X\n", + &uniRemoteName, + ConnectCB->AuthenticationId.QuadPart); + } + + *ResultStatus = WN_BAD_NETNAME; + + *ReturnOutputBufferLength = sizeof( ULONG); + + try_return( ntStatus = STATUS_SUCCESS); + } + + uniRemoteName.Length = usLength; + } + else + { + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection BAD_NETNAME 3 remote name %wZ Local %C authentication id %I64X\n", + &uniRemoteName, + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection BAD_NETNAME 3 remote name %wZ Local (NULL) authentication id %I64X\n", + &uniRemoteName, + ConnectCB->AuthenticationId.QuadPart); + } + + *ResultStatus = WN_BAD_NETNAME; + + *ReturnOutputBufferLength = sizeof( ULONG); + + try_return( ntStatus = STATUS_SUCCESS); + } + + uniRemoteName.Length = (USHORT)ConnectCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + + uniRemoteName.Buffer = ConnectCB->RemoteName; + + // + // Strip off any trailing slashes + // + + if( uniRemoteName.Buffer[ (uniRemoteName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + uniRemoteName.Length -= sizeof( WCHAR); + } + + // + // Allocate a new node and add it to our list + // + + pConnection = (AFSProviderConnectionCB *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSProviderConnectionCB) + + uniRemoteName.Length, + AFS_PROVIDER_CB); + + if( pConnection == NULL) + { + + *ResultStatus = WN_OUT_OF_MEMORY; + + *ReturnOutputBufferLength = sizeof( ULONG); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pConnection, + sizeof( AFSProviderConnectionCB) + uniRemoteName.Length); + + pConnection->LocalName = ConnectCB->LocalName; + + pConnection->RemoteName.Length = uniRemoteName.Length; + pConnection->RemoteName.MaximumLength = pConnection->RemoteName.Length; + + pConnection->RemoteName.Buffer = (WCHAR *)((char *)pConnection + sizeof( AFSProviderConnectionCB)); + + RtlCopyMemory( pConnection->RemoteName.Buffer, + uniRemoteName.Buffer, + pConnection->RemoteName.Length); + + pConnection->Type = ConnectCB->Type; + + pConnection->AuthenticationId = ConnectCB->AuthenticationId; + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection Adding connection remote name %wZ Local %C authentication id %I64X\n", + &uniRemoteName, + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSAddConnection Adding connection remote name %wZ Local (NULL) authentication id %I64X\n", + &uniRemoteName, + ConnectCB->AuthenticationId.QuadPart); + } + + // + // Point to the component portion of the name + // + + pConnection->ComponentName.Length = 0; + pConnection->ComponentName.MaximumLength = 0; + + pConnection->ComponentName.Buffer = &pConnection->RemoteName.Buffer[ (pConnection->RemoteName.Length/sizeof( WCHAR)) - 1]; + + while( pConnection->ComponentName.Length <= pConnection->RemoteName.Length) + { + + if( pConnection->ComponentName.Buffer[ 0] == L'\\') + { + + pConnection->ComponentName.Buffer++; + + break; + } + + pConnection->ComponentName.Length += sizeof( WCHAR); + pConnection->ComponentName.MaximumLength += sizeof( WCHAR); + + pConnection->ComponentName.Buffer--; + } + + // + // Go initialize the information about the connection + // + + AFSInitializeConnectionInfo( pConnection, + (ULONG)-1); + + // + // Insert the entry into our list + // + + if( pRDRDevExt->Specific.RDR.ProviderConnectionList == NULL) + { + + pRDRDevExt->Specific.RDR.ProviderConnectionList = pConnection; + } + else + { + + // + // Get the end of the list + // + + pLastConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + + while( pLastConnection->fLink != NULL) + { + + pLastConnection = pLastConnection->fLink; + } + + pLastConnection->fLink = pConnection; + } + + *ResultStatus = WN_SUCCESS; + + *ReturnOutputBufferLength = sizeof( ULONG); + +try_exit: + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + + } + + return ntStatus; +} + +NTSTATUS +AFSCancelConnection( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN OUT AFSCancelConnectionResultCB *ConnectionResult, + IN OUT ULONG_PTR *ReturnOutputBufferLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSProviderConnectionCB *pConnection = NULL, *pLastConnection = NULL; + UNICODE_STRING uniRemoteName; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + ConnectionResult->Version = AFS_NETWORKPROVIDER_INTERFACE_VERSION_1; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCancelConnection Acquiring AFSProviderListLock lock %08lX EXCL %08lX\n", + &pRDRDevExt->Specific.RDR.ProviderListLock, + PsGetCurrentThread()); + + if( ConnectCB->AuthenticationId.QuadPart == 0) + { + + ConnectCB->AuthenticationId = AFSGetAuthenticationId(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCancelConnection Retrieved authentication id %I64X\n", + ConnectCB->AuthenticationId.QuadPart); + } + + AFSAcquireExcl( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + // + // Look for the connection + // + + uniRemoteName.Length = (USHORT)ConnectCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length; + + uniRemoteName.Buffer = NULL; + + if( uniRemoteName.Length > 0) + { + + uniRemoteName.Buffer = ConnectCB->RemoteName; + } + + pConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + + while( pConnection != NULL) + { + + if( ( ConnectCB->LocalName != L'\0' && + pConnection->LocalName == ConnectCB->LocalName) + || + ( RtlCompareUnicodeString( &uniRemoteName, + &pConnection->RemoteName, + TRUE) == 0)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCancelConnection Checking remote name %wZ to stored %wZ authentication id %I64X - %I64X\n", + &uniRemoteName, + &pConnection->RemoteName, + ConnectCB->AuthenticationId.QuadPart, + pConnection->AuthenticationId.QuadPart); + + if( ConnectCB->AuthenticationId.QuadPart == pConnection->AuthenticationId.QuadPart && + ( ConnectCB->LocalName == L'\0' || + RtlCompareUnicodeString( &uniRemoteName, + &pConnection->RemoteName, + TRUE) == 0)) + { + + break; + } + } + + pLastConnection = pConnection; + + pConnection = pConnection->fLink; + } + + if( pConnection == NULL) + { + + ConnectionResult->Status = WN_NOT_CONNECTED; + + *ReturnOutputBufferLength = sizeof( AFSCancelConnectionResultCB); + + try_return( ntStatus); + } + + if( pLastConnection == NULL) + { + + pRDRDevExt->Specific.RDR.ProviderConnectionList = pConnection->fLink; + } + else + { + + pLastConnection->fLink = pConnection->fLink; + } + + if( pConnection->Comment.Buffer != NULL) + { + + AFSExFreePool( pConnection->Comment.Buffer); + } + + ConnectionResult->LocalName = pConnection->LocalName; + + AFSExFreePool( pConnection); + + ConnectionResult->Status = WN_SUCCESS; + + *ReturnOutputBufferLength = sizeof( AFSCancelConnectionResultCB); + +try_exit: + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + } + + return ntStatus; +} + +NTSTATUS +AFSGetConnection( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN OUT WCHAR *RemoteName, + IN ULONG RemoteNameBufferLength, + IN OUT ULONG_PTR *ReturnOutputBufferLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSProviderConnectionCB *pConnection = NULL; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection Local %C authentication id %I64X\n", + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection Local (NULL) authentication id %I64X\n", + ConnectCB->AuthenticationId.QuadPart); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection Acquiring AFSProviderListLock lock %08lX SHARED %08lX\n", + &pRDRDevExt->Specific.RDR.ProviderListLock, + PsGetCurrentThread()); + + if( ConnectCB->AuthenticationId.QuadPart == 0) + { + + ConnectCB->AuthenticationId = AFSGetAuthenticationId(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection Retrieved authentication id %I64X\n", + ConnectCB->AuthenticationId.QuadPart); + } + + AFSAcquireShared( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + // + // Look for the connection + // + + pConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + + while( pConnection != NULL) + { + + if( pConnection->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection Comparing passed in %C to %C authentication id %I64X - %I64X\n", + ConnectCB->LocalName, + pConnection->LocalName, + ConnectCB->AuthenticationId.QuadPart, + pConnection->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection Comparing passed in %C to (NULL) authentication id %I64X - %I64X\n", + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart, + pConnection->AuthenticationId.QuadPart); + } + + if( pConnection->LocalName == ConnectCB->LocalName && + pConnection->AuthenticationId.QuadPart == ConnectCB->AuthenticationId.QuadPart) + { + + break; + } + + pConnection = pConnection->fLink; + } + + if( pConnection == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection INVALID_PARAMETER\n"); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + if( RemoteNameBufferLength < pConnection->RemoteName.Length) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnection INSUFFICIENT_RESOURCES\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( RemoteName, + pConnection->RemoteName.Buffer, + pConnection->RemoteName.Length); + + *ReturnOutputBufferLength = pConnection->RemoteName.Length; + +try_exit: + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + } + + return ntStatus; +} + +NTSTATUS +AFSListConnections( IN OUT AFSNetworkProviderConnectionCB *ConnectCB, + IN ULONG ConnectionBufferLength, + IN OUT ULONG_PTR *ReturnOutputBufferLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSProviderConnectionCB *pConnection = NULL, *pRootConnection = NULL; + ULONG ulCopiedLength = 0, ulRemainingLength = ConnectionBufferLength; + ULONG ulScope, ulType; + UNICODE_STRING uniRemoteName, uniServerName, uniShareName, uniRemainingPath; + BOOLEAN bGlobalEnumeration = FALSE; + ULONG ulIndex = 0; + LARGE_INTEGER liAuthenticationID = {0,0}; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + // + // Save off some data before moving on + // + + ulScope = ConnectCB->Scope; + + ulType = ConnectCB->Type; + + if( ConnectCB->AuthenticationId.QuadPart == 0) + { + + ConnectCB->AuthenticationId = AFSGetAuthenticationId(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSListConnections Retrieved authentication id %I64X\n", + ConnectCB->AuthenticationId.QuadPart); + } + + liAuthenticationID.QuadPart = ConnectCB->AuthenticationId.QuadPart; + + uniRemoteName.Length = 0; + uniRemoteName.MaximumLength = 0; + uniRemoteName.Buffer = NULL; + + uniServerName.Length = 0; + uniServerName.MaximumLength = 0; + uniServerName.Buffer = NULL; + + uniShareName.Length = 0; + uniShareName.MaximumLength = 0; + uniShareName.Buffer = NULL; + + if( ConnectCB->RemoteNameLength > 0) + { + + uniRemoteName.Length = (USHORT)ConnectCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length + sizeof( WCHAR); + + uniRemoteName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniRemoteName.MaximumLength, + AFS_NETWORK_PROVIDER_1_TAG); + + if( uniRemoteName.Buffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( uniRemoteName.Buffer, + ConnectCB->RemoteName, + uniRemoteName.Length); + + if( uniRemoteName.Buffer[ 0] == L'\\' && + uniRemoteName.Buffer[ 1] == L'\\') + { + + uniRemoteName.Buffer = &uniRemoteName.Buffer[ 1]; + + uniRemoteName.Length -= sizeof( WCHAR); + } + + if( uniRemoteName.Buffer[ (uniRemoteName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + uniRemoteName.Length -= sizeof( WCHAR); + } + + FsRtlDissectName( uniRemoteName, + &uniServerName, + &uniRemainingPath); + + uniRemoteName = uniRemainingPath; + + if( uniRemoteName.Length > 0) + { + + FsRtlDissectName( uniRemoteName, + &uniShareName, + &uniRemainingPath); + } + + // + // If this is an enumeration of the global share name then + // adjust it to be the server name itself + // + + if( uniShareName.Length == 0 || + RtlCompareUnicodeString( &uniShareName, + &AFSGlobalRootName, + TRUE) == 0) + { + + bGlobalEnumeration = TRUE; + } + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSListConnections Acquiring AFSProviderListLock lock %08lX SHARED %08lX\n", + &pRDRDevExt->Specific.RDR.ProviderListLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + // + // If this is a globalnet enumeration with no name then enumerate the server list + // + + if( ulScope == RESOURCE_GLOBALNET) + { + + if( uniServerName.Buffer == NULL) + { + + pConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList; + } + else + { + + // + // Go locate the root entry for the name passed in + // + + if( bGlobalEnumeration) + { + + if( pRDRDevExt->Specific.RDR.ProviderEnumerationList == NULL) + { + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + + try_return( ntStatus); + } + + pConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList->EnumerationList; + } + else + { + + pRootConnection = AFSLocateEnumRootEntry( &uniShareName); + + if( pRootConnection == NULL) + { + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + + try_return( ntStatus); + } + + // + // Need to handle these enumerations from the directory listing + // + + ntStatus = AFSEnumerateConnection( ConnectCB, + pRootConnection, + ConnectionBufferLength, + &ulCopiedLength); + } + } + } + else + { + + pConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + } + + ulIndex = ConnectCB->CurrentIndex; + + while( pConnection != NULL) + { + + if( bGlobalEnumeration && + BooleanFlagOn( pConnection->Flags, AFS_CONNECTION_FLAG_GLOBAL_SHARE)) + { + + pConnection = pConnection->fLink; + + continue; + } + + if( ulScope != RESOURCE_GLOBALNET && + !BooleanFlagOn( pConnection->Usage, RESOURCEUSAGE_ATTACHED)) + { + + pConnection = pConnection->fLink; + + continue; + } + + if( pConnection->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSListConnections Processing entry %wZ %C authentication id %I64X - %I64X Scope %08lX\n", + &pConnection->RemoteName, + pConnection->LocalName, + liAuthenticationID.QuadPart, + pConnection->AuthenticationId.QuadPart, + pConnection->Scope); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSListConnections Processing entry %wZ NULL LocalName authentication id %I64X - %I64X Scope %08lX\n", + &pConnection->RemoteName, + liAuthenticationID.QuadPart, + pConnection->AuthenticationId.QuadPart, + pConnection->Scope); + } + + if( ulScope != RESOURCE_GLOBALNET && + pConnection->AuthenticationId.QuadPart != liAuthenticationID.QuadPart) + { + + pConnection = pConnection->fLink; + + continue; + } + + if( ulIndex > 0) + { + + ulIndex--; + + pConnection = pConnection->fLink; + + continue; + } + + if( ulRemainingLength < (ULONG)FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pConnection->RemoteName.Length + + pConnection->Comment.Length) + { + + break; + } + + ConnectCB->RemoteNameLength = pConnection->RemoteName.Length; + + RtlCopyMemory( ConnectCB->RemoteName, + pConnection->RemoteName.Buffer, + pConnection->RemoteName.Length); + + ConnectCB->LocalName = pConnection->LocalName; + + ConnectCB->Type = pConnection->Type; + + ConnectCB->Scope = pConnection->Scope; + + if( !bGlobalEnumeration) + { + + ConnectCB->Scope = RESOURCE_CONNECTED; + } + + ConnectCB->DisplayType = pConnection->DisplayType; + + ConnectCB->Usage = pConnection->Usage; + + ConnectCB->CommentLength = pConnection->Comment.Length; + + if( pConnection->Comment.Length > 0) + { + + ConnectCB->CommentOffset = (ULONG)(FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength); + + RtlCopyMemory( (void *)((char *)ConnectCB + ConnectCB->CommentOffset), + pConnection->Comment.Buffer, + ConnectCB->CommentLength); + } + + ulCopiedLength += FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength + + ConnectCB->CommentLength; + + ulRemainingLength -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength + + ConnectCB->CommentLength; + + ConnectCB = (AFSNetworkProviderConnectionCB *)((char *)ConnectCB + + FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength + + ConnectCB->CommentLength); + + pConnection = pConnection->fLink; + } + + if( NT_SUCCESS( ntStatus)) + { + + *ReturnOutputBufferLength = ulCopiedLength; + } + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + +try_exit: + + if( uniRemoteName.Buffer != NULL) + { + + AFSExFreePool( uniRemoteName.Buffer); + } + } + + return ntStatus; +} + +void +AFSInitializeConnectionInfo( IN AFSProviderConnectionCB *Connection, + IN ULONG DisplayType) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + UNICODE_STRING uniName, uniComponentName, uniRemainingName; + + __Enter + { + + uniName = Connection->RemoteName; + + // + // Strip of the double leading slash if there is one + // + + if( uniName.Buffer[ 0] == L'\\' && + uniName.Buffer[ 1] == L'\\') + { + + uniName.Buffer = &uniName.Buffer[ 1]; + + uniName.Length -= sizeof( WCHAR); + } + + + FsRtlDissectName( uniName, + &uniComponentName, + &uniRemainingName); + + // + // Initialize the information for the connection + // First, if this is the server only then mark it accordingly + // + + if( uniRemainingName.Length == 0 || + DisplayType == RESOURCEDISPLAYTYPE_SERVER) + { + + Connection->Type = RESOURCETYPE_DISK; + + Connection->Scope = 0; + + Connection->DisplayType = RESOURCEDISPLAYTYPE_SERVER; + + Connection->Usage = RESOURCEUSAGE_CONTAINER; + + Connection->Comment.Length = 20; + Connection->Comment.MaximumLength = 22; + + Connection->Comment.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + Connection->Comment.MaximumLength, + AFS_NETWORK_PROVIDER_2_TAG); + + if( Connection->Comment.Buffer != NULL) + { + + RtlZeroMemory( Connection->Comment.Buffer, + Connection->Comment.MaximumLength); + + RtlCopyMemory( Connection->Comment.Buffer, + L"AFS Root", + 16); + } + else + { + + Connection->Comment.Length = 0; + Connection->Comment.MaximumLength = 0; + } + + try_return( ntStatus); + } + + uniName = uniRemainingName; + + FsRtlDissectName( uniName, + &uniComponentName, + &uniRemainingName); + + if( uniRemainingName.Length == 0 || + uniRemainingName.Buffer == NULL || + DisplayType == RESOURCEDISPLAYTYPE_SHARE) + { + + Connection->Type = RESOURCETYPE_DISK; + + Connection->DisplayType = RESOURCEDISPLAYTYPE_SHARE; + + Connection->Usage = RESOURCEUSAGE_CONNECTABLE; + + if( Connection->LocalName != L'\0') + { + + Connection->Usage |= RESOURCEUSAGE_ATTACHED; + + Connection->Scope = RESOURCE_CONNECTED; + } + else + { + + Connection->Usage |= RESOURCEUSAGE_NOLOCALDEVICE; + + Connection->Scope = RESOURCE_GLOBALNET; + } + + Connection->Comment.Length = 18; + Connection->Comment.MaximumLength = 20; + + Connection->Comment.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + Connection->Comment.MaximumLength, + AFS_NETWORK_PROVIDER_3_TAG); + + if( Connection->Comment.Buffer != NULL) + { + + RtlZeroMemory( Connection->Comment.Buffer, + Connection->Comment.MaximumLength); + + RtlCopyMemory( Connection->Comment.Buffer, + L"AFS Share", + 18); + } + else + { + + Connection->Comment.Length = 0; + Connection->Comment.MaximumLength = 0; + } + + try_return( ntStatus); + } + + // + // This is a sub directory within a share + // + + Connection->Type = RESOURCETYPE_DISK; + + Connection->DisplayType = RESOURCEDISPLAYTYPE_DIRECTORY; + + Connection->Usage = RESOURCEUSAGE_CONNECTABLE; + + if( Connection->LocalName != L'\0') + { + + Connection->Usage |= RESOURCEUSAGE_ATTACHED; + } + else + { + + Connection->Usage |= RESOURCEUSAGE_NOLOCALDEVICE; + } + + Connection->Scope = RESOURCE_CONNECTED; + + Connection->Comment.Length = 26; + Connection->Comment.MaximumLength = 28; + + Connection->Comment.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + Connection->Comment.MaximumLength, + AFS_NETWORK_PROVIDER_4_TAG); + + if( Connection->Comment.Buffer != NULL) + { + + RtlZeroMemory( Connection->Comment.Buffer, + Connection->Comment.MaximumLength); + + RtlCopyMemory( Connection->Comment.Buffer, + L"AFS Directory", + 26); + } + else + { + + Connection->Comment.Length = 0; + Connection->Comment.MaximumLength = 0; + } + +try_exit: + + NOTHING; + } + + return; +} + +AFSProviderConnectionCB * +AFSLocateEnumRootEntry( IN UNICODE_STRING *RemoteName) +{ + + AFSProviderConnectionCB *pConnection = NULL; + UNICODE_STRING uniServerName, uniRemoteName = *RemoteName; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + if( pRDRDevExt->Specific.RDR.ProviderEnumerationList == NULL) + { + + try_return( pConnection); + } + + pConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList->EnumerationList; + + while( pConnection != NULL) + { + + if( RtlCompareUnicodeString( &uniRemoteName, + &pConnection->ComponentName, + TRUE) == 0) + { + + break; + } + + pConnection = pConnection->fLink; + } + +try_exit: + + NOTHING; + } + + return pConnection; +} + +NTSTATUS +AFSEnumerateConnection( IN OUT AFSNetworkProviderConnectionCB *ConnectCB, + IN AFSProviderConnectionCB *RootConnection, + IN ULONG BufferLength, + OUT PULONG CopiedLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + ULONG ulCRC = 0, ulCopiedLength = 0; + AFSDirectoryCB *pShareDirEntry = NULL; + AFSDirectoryCB *pDirEntry = NULL, *pTargetDirEntry = NULL; + ULONG ulIndex = 0; + BOOLEAN bContinueProcessing = TRUE; + AFSFileInfoCB stFileInformation; + + __Enter + { + + if( AFSGlobalRoot == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_ERROR, + "AFSEnumerateConnection Global root not yet initialized\n"); + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + ulCRC = AFSGenerateCRC( &RootConnection->ComponentName, + FALSE); + + // + // Grab our tree lock shared + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateConnection Acquiring GlobalRoot DirectoryNodeHdr.TreeLock lock %08lX SHARED %08lX\n", + AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + PsGetCurrentThread()); + + AFSAcquireShared( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + // + // Locate the dir entry for this node + // + + ntStatus = AFSLocateCaseSensitiveDirEntry( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead, + ulCRC, + &pShareDirEntry); + + if( pShareDirEntry == NULL || + !NT_SUCCESS( ntStatus)) + { + + // + // Perform a case insensitive search + // + + ulCRC = AFSGenerateCRC( &RootConnection->ComponentName, + TRUE); + + ntStatus = AFSLocateCaseInsensitiveDirEntry( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead, + ulCRC, + &pShareDirEntry); + + if( pShareDirEntry == NULL || + !NT_SUCCESS( ntStatus)) + { + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + try_return( ntStatus); + } + } + + InterlockedIncrement( &pShareDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateConnection1 Increment count on %wZ DE %p Ccb %p Cnt %d\n", + &pShareDirEntry->NameInformation.FileName, + pShareDirEntry, + NULL, + pShareDirEntry->OpenReferenceCount); + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + // + // Setup the request to evaluate the entry + // + + ntStatus = AFSEvaluateRootEntry( pShareDirEntry, + &pTargetDirEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + AFSAcquireShared( pTargetDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + // + // Enumerate the content + // + + pDirEntry = pTargetDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead; + + ulIndex = ConnectCB->CurrentIndex; + + while( pDirEntry != NULL) + { + + if( ulIndex > 0) + { + + ulIndex--; + + pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink; + + continue; + } + + if( BufferLength < (ULONG)FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pDirEntry->NameInformation.FileName.Length) + { + + break; + } + + ConnectCB->LocalName = L'\0'; + + ConnectCB->RemoteNameLength = pDirEntry->NameInformation.FileName.Length; + + RtlCopyMemory( ConnectCB->RemoteName, + pDirEntry->NameInformation.FileName.Buffer, + pDirEntry->NameInformation.FileName.Length); + + ConnectCB->Type = RESOURCETYPE_DISK; + + ConnectCB->Scope = RESOURCE_CONNECTED; + + if( BooleanFlagOn( pDirEntry->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_DIRECTORY)) + { + + ConnectCB->DisplayType = RESOURCEDISPLAYTYPE_DIRECTORY; + } + else + { + + ConnectCB->DisplayType = RESOURCEDISPLAYTYPE_FILE; + } + + ConnectCB->Usage = 0; + + ConnectCB->CommentLength = 0; + + ulCopiedLength += FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pDirEntry->NameInformation.FileName.Length; + + BufferLength -= FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pDirEntry->NameInformation.FileName.Length; + + ConnectCB = (AFSNetworkProviderConnectionCB *)((char *)ConnectCB + + FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength); + + pDirEntry = (AFSDirectoryCB *)pDirEntry->ListEntry.fLink; + } + + InterlockedDecrement( &pTargetDirEntry->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSEnumerateConnection Decrement count on %wZ DE %p Ccb %p Cnt %d\n", + &pTargetDirEntry->NameInformation.FileName, + pTargetDirEntry, + NULL, + pTargetDirEntry->OpenReferenceCount); + + *CopiedLength = ulCopiedLength; + + AFSReleaseResource( pTargetDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeHdr.TreeLock); + +try_exit: + + if( pShareDirEntry != NULL) + { + InterlockedDecrement( &pShareDirEntry->OpenReferenceCount); + } + } + + return ntStatus; +} + +NTSTATUS +AFSGetConnectionInfo( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN ULONG BufferLength, + IN OUT ULONG_PTR *ReturnOutputBufferLength) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSProviderConnectionCB *pConnection = NULL, *pBestMatch = NULL; + UNICODE_STRING uniRemoteName, uniServerName, uniShareName, uniRemainingPath, uniFullName, uniRemainingPathLocal; + USHORT usNameLen = 0, usMaxNameLen = 0; + BOOLEAN bEnumerationEntry = FALSE; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + uniServerName.Length = 0; + uniServerName.MaximumLength = 0; + uniServerName.Buffer = NULL; + + uniShareName.Length = 0; + uniShareName.MaximumLength = 0; + uniShareName.Buffer = NULL; + + uniRemainingPathLocal.Length = 0; + uniRemainingPathLocal.MaximumLength = 0; + uniRemainingPathLocal.Buffer = NULL; + + uniRemoteName.Length = (USHORT)ConnectCB->RemoteNameLength; + uniRemoteName.MaximumLength = uniRemoteName.Length + sizeof( WCHAR); + uniRemoteName.Buffer = (WCHAR *)ConnectCB->RemoteName; + + if( ConnectCB->LocalName != L'\0') + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo remote name %wZ Local %C authentication id %I64X\n", + &uniRemoteName, + ConnectCB->LocalName, + ConnectCB->AuthenticationId.QuadPart); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo remote name %wZ Local (NULL) authentication id %I64X\n", + &uniRemoteName, + ConnectCB->AuthenticationId.QuadPart); + } + + if( AFSGlobalRoot == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_ERROR, + "AFSGetConnectionInfo Global root not yet initialized\n"); + + try_return( ntStatus = STATUS_DEVICE_NOT_READY); + } + + uniFullName = uniRemoteName; + + if( uniRemoteName.Buffer[ 0] == L'\\' && + uniRemoteName.Buffer[ 1] == L'\\') + { + + uniRemoteName.Buffer = &uniRemoteName.Buffer[ 1]; + + uniRemoteName.Length -= sizeof( WCHAR); + } + + if( uniRemoteName.Buffer[ (uniRemoteName.Length/sizeof( WCHAR)) - 1] == L'\\') + { + + uniRemoteName.Length -= sizeof( WCHAR); + + uniFullName.Length -= sizeof( WCHAR); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Processing name %wZ\n", &uniFullName); + + FsRtlDissectName( uniRemoteName, + &uniServerName, + &uniRemainingPath); + + uniRemoteName = uniRemainingPath; + + if( uniRemoteName.Length > 0) + { + + FsRtlDissectName( uniRemoteName, + &uniShareName, + &uniRemainingPath); + } + + if( RtlCompareUnicodeString( &uniServerName, + &AFSServerName, + TRUE) != 0) + { + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + if ( uniRemainingPath.Length > 0 ) + { + + // + // Add back in the leading \ since it was stripped off above + // + + uniRemainingPath.Length += sizeof( WCHAR); + if( uniRemainingPath.Length > uniRemainingPath.MaximumLength) + { + uniRemainingPath.MaximumLength += sizeof( WCHAR); + } + + uniRemainingPath.Buffer--; + + uniRemainingPathLocal.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniRemainingPath.Length, + AFS_NETWORK_PROVIDER_5_TAG); + + if( uniRemainingPathLocal.Buffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo INSUFFICIENT_RESOURCES\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + uniRemainingPathLocal.MaximumLength = uniRemainingPath.Length; + uniRemainingPathLocal.Length = uniRemainingPath.Length; + + RtlCopyMemory( uniRemainingPathLocal.Buffer, + uniRemainingPath.Buffer, + uniRemainingPath.Length); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Acquiring AFSProviderListLock lock %08lX SHARED %08lX\n", + &pRDRDevExt->Specific.RDR.ProviderListLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + // + // If this is the server then return information about the + // server entry + // + + if( uniShareName.Length == 0 && + RtlCompareUnicodeString( &uniServerName, + &AFSServerName, + TRUE) == 0) + { + + pConnection = pRDRDevExt->Specific.RDR.ProviderEnumerationList; + } + else + { + + // + // See if we can locate it on our connection list + // + + pConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Searching for full name %wZ\n", &uniFullName); + + while( pConnection != NULL) + { + + if( usMaxNameLen < pConnection->RemoteName.Length && + pConnection->RemoteName.Length <= uniFullName.Length) + { + + usNameLen = uniFullName.Length; + + uniFullName.Length = pConnection->RemoteName.Length; + + if( pConnection->AuthenticationId.QuadPart == ConnectCB->AuthenticationId.QuadPart && + RtlCompareUnicodeString( &uniFullName, + &pConnection->RemoteName, + TRUE) == 0) + { + + usMaxNameLen = pConnection->RemoteName.Length; + + pBestMatch = pConnection; + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Found match for %wZ\n", &pConnection->RemoteName); + } + + uniFullName.Length = usNameLen; + } + + pConnection = pConnection->fLink; + } + + pConnection = pBestMatch; + + if( pConnection != NULL) + { + + bEnumerationEntry = TRUE; + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Using best match for %wZ\n", &pConnection->RemoteName); + } + + if( pConnection == NULL) + { + + // + // Locate the entry for the share + // + + pConnection = AFSLocateEnumRootEntry( &uniShareName); + } + } + + if( pConnection == NULL) + { + UNICODE_STRING uniFullName; + AFSFileID stFileID; + AFSDirEnumEntry *pDirEnumEntry = NULL; + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo No connection for full name %wZ\n", &uniFullName); + + // + // Drop the lock, we will pick it up again later + // + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + + // + // Perform a case insensitive search + // + + // + // OK, ask the CM about this component name + // + + stFileID = AFSGlobalRoot->ObjectInformation.FileId; + + ntStatus = AFSEvaluateTargetByName( NULL, + &stFileID, + &uniShareName, + &pDirEnumEntry); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Evaluation Failed share name %wZ\n", + uniShareName); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + + } + + // + // Don't need this + // + + AFSExFreePool( pDirEnumEntry); + + // + // The share name is valid + // Allocate a new node and add it to our list + // + uniFullName.MaximumLength = PAGE_SIZE; + uniFullName.Length = 0; + + uniFullName.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool, + uniFullName.MaximumLength, + AFS_NETWORK_PROVIDER_6_TAG); + + if( uniFullName.Buffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo INSUFFICIENT_RESOURCES\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + uniFullName.Buffer[ 0] = L'\\'; + uniFullName.Buffer[ 1] = L'\\'; + + uniFullName.Length = 2 * sizeof( WCHAR); + + RtlCopyMemory( &uniFullName.Buffer[ 2], + AFSServerName.Buffer, + AFSServerName.Length); + + uniFullName.Length += AFSServerName.Length; + + uniFullName.Buffer[ uniFullName.Length/sizeof( WCHAR)] = L'\\'; + + uniFullName.Length += sizeof( WCHAR); + + RtlCopyMemory( &uniFullName.Buffer[ uniFullName.Length/sizeof( WCHAR)], + uniShareName.Buffer, + uniShareName.Length); + + uniFullName.Length += uniShareName.Length; + + AFSAcquireExcl( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock, + TRUE); + + ntStatus = AFSAddConnectionEx( &uniFullName, + RESOURCEDISPLAYTYPE_SHARE, + 0); + + AFSReleaseResource( AFSGlobalRoot->ObjectInformation.Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSExFreePool( uniFullName.Buffer); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Acquiring AFSProviderListLock lock %08lX SHARED %08lX\n", + &pRDRDevExt->Specific.RDR.ProviderListLock, + PsGetCurrentThread()); + + AFSAcquireShared( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + if ( NT_SUCCESS( ntStatus) ) + { + // + // Once again, locate the entry for the share we just created + // + + pConnection = AFSLocateEnumRootEntry( &uniShareName); + } + + } + + if( pConnection == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_ERROR, + "AFSGetConnectionInfo Failed to locate entry for full name %wZ\n", &uniFullName); + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + + try_return( ntStatus = STATUS_INVALID_PARAMETER); + } + + // + // Fill in the returned connection info block + // + + if( BufferLength < (ULONG)FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + pConnection->RemoteName.Length + + pConnection->Comment.Length + + uniRemainingPath.Length) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Buffer too small for full name %wZ\n", + &uniFullName); + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + + try_return( ntStatus = STATUS_BUFFER_OVERFLOW); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Returning entry Scope %08lX partial name %wZ full name %wZ\n", + pConnection->Scope, &pConnection->RemoteName, &uniFullName); + + ConnectCB->RemoteNameLength = pConnection->RemoteName.Length; + + if( !bEnumerationEntry) + { + + RtlCopyMemory( ConnectCB->RemoteName, + uniFullName.Buffer, + pConnection->RemoteName.Length); + } + else + { + + RtlCopyMemory( ConnectCB->RemoteName, + pConnection->RemoteName.Buffer, + pConnection->RemoteName.Length); + } + + ConnectCB->LocalName = pConnection->LocalName; + + ConnectCB->Type = pConnection->Type; + + ConnectCB->Scope = pConnection->Scope; + + ConnectCB->DisplayType = pConnection->DisplayType; + + ConnectCB->Usage = pConnection->Usage; + + ConnectCB->CommentLength = pConnection->Comment.Length; + + ConnectCB->RemainingPathLength = uniRemainingPathLocal.Length; + + AFSDbgLogMsg( AFS_SUBSYSTEM_NETWORK_PROVIDER, + AFS_TRACE_LEVEL_VERBOSE, + "AFSGetConnectionInfo Returning lengths: remote %u comment %u remaining %u\n", + ConnectCB->RemoteNameLength, + ConnectCB->CommentLength, + ConnectCB->RemainingPathLength); + + if( ConnectCB->CommentLength > 0) + { + + ConnectCB->CommentOffset = (ULONG)(FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength); + + RtlCopyMemory( (void *)((char *)ConnectCB + ConnectCB->CommentOffset), + pConnection->Comment.Buffer, + ConnectCB->CommentLength); + } + + if ( ConnectCB->RemainingPathLength > 0 ) + { + + ConnectCB->RemainingPathOffset = (ULONG)(FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength + + ConnectCB->CommentLength); + + RtlCopyMemory( (void *)((char *)ConnectCB + ConnectCB->RemainingPathOffset), + uniRemainingPathLocal.Buffer, + uniRemainingPathLocal.Length); + } + + *ReturnOutputBufferLength = FIELD_OFFSET( AFSNetworkProviderConnectionCB, RemoteName) + + ConnectCB->RemoteNameLength + + ConnectCB->CommentLength + + ConnectCB->RemainingPathLength; + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + +try_exit: + + if ( uniRemainingPathLocal.Buffer ) + { + + AFSExFreePool( uniRemainingPathLocal.Buffer); + } + } + + return ntStatus; +} + +BOOLEAN +AFSIsDriveMapped( IN WCHAR DriveMapping) +{ + + BOOLEAN bDriveMapped = FALSE; + AFSProviderConnectionCB *pConnection = NULL; + AFSDeviceExt *pRDRDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + __Enter + { + + AFSAcquireShared( &pRDRDevExt->Specific.RDR.ProviderListLock, + TRUE); + + pConnection = pRDRDevExt->Specific.RDR.ProviderConnectionList; + + while( pConnection != NULL) + { + + if( pConnection->LocalName != L'\0' && + RtlUpcaseUnicodeChar( pConnection->LocalName) == RtlUpcaseUnicodeChar( DriveMapping)) + { + + bDriveMapped = TRUE; + + break; + } + + pConnection = pConnection->fLink; + } + + AFSReleaseResource( &pRDRDevExt->Specific.RDR.ProviderListLock); + } + + return bDriveMapped; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSQuota.cpp b/src/WINNT/afsrdr/kernel/lib/AFSQuota.cpp new file mode 100644 index 0000000000..ab8a0ddb47 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSQuota.cpp @@ -0,0 +1,104 @@ +/* + * 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: AFSQuota.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSQueryQuota( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryQuota Entry for FO %08lX\n", + pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueryQuota\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSSetQuota( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetQuota Entry for FO %08lX\n", + pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSSetQuota\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSRead.cpp b/src/WINNT/afsrdr/kernel/lib/AFSRead.cpp new file mode 100644 index 0000000000..2ef0f7c723 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSRead.cpp @@ -0,0 +1,1607 @@ +/* + * 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: AFSRead.cpp +// + +#include "AFSCommon.h" + +static +NTSTATUS +AFSCachedRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN LARGE_INTEGER StartingByte, + IN ULONG ByteCount) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = (AFSFcb *)pFileObject->FsContext; + AFSCcb *pCcb = (AFSCcb *)pFileObject->FsContext2; + BOOLEAN bSynchronousIo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO); + VOID *pSystemBuffer = NULL; + ULONG ulCurrentIO = 0, ulTotalLen = ByteCount; + PMDL pCurrentMdl = Irp->MdlAddress; + LARGE_INTEGER liCurrentOffset; + + __Enter + { + + Irp->IoStatus.Information = 0; + + liCurrentOffset.QuadPart = StartingByte.QuadPart; + + while( ulTotalLen > 0) + { + + ntStatus = STATUS_SUCCESS; + + if( pCurrentMdl != NULL) + { + + ASSERT( pCurrentMdl != NULL); + + pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl, + NormalPagePriority); + + ulCurrentIO = MmGetMdlByteCount( pCurrentMdl); + + if( ulCurrentIO > ulTotalLen) + { + ulCurrentIO = ulTotalLen; + } + } + else + { + + pSystemBuffer = AFSLockSystemBuffer( Irp, + ulTotalLen); + + ulCurrentIO = ulTotalLen; + } + + if( pSystemBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedRead (%08lX) Failed to lock system buffer\n", + Irp); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + __try + { + + if( !CcCopyRead( pFileObject, + &liCurrentOffset, + ulCurrentIO, + TRUE, + pSystemBuffer, + &Irp->IoStatus)) + { + + // + // Failed to process request. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedRead (%08lX) Failed CcCopyRead() %wZ @ %0I64X Status %08lX\n", + Irp, + &pFileObject->FileName, + liCurrentOffset.QuadPart, + Irp->IoStatus.Status); + + try_return( ntStatus = Irp->IoStatus.Status); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedRead (%08lX) CcCopyRead() Threw exception %wZ @ %0I64X Status %08lX\n", + Irp, + &pFileObject->FileName, + liCurrentOffset.QuadPart, + ntStatus); + } + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + if( ulTotalLen <= ulCurrentIO) + { + break; + } + + liCurrentOffset.QuadPart += ulCurrentIO; + + ulTotalLen -= ulCurrentIO; + + pCurrentMdl = pCurrentMdl->Next; + } + +try_exit: + + if( NT_SUCCESS( ntStatus)) + { + + Irp->IoStatus.Information = ByteCount; + + // + // Update the CBO if this is a sync read + // + + if( bSynchronousIo) + { + + pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount; + } + } + + AFSCompleteRequest( Irp, + ntStatus); + } + + return ntStatus; +} + +static +NTSTATUS +AFSNonCachedRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN LARGE_INTEGER StartingByte) +{ + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = (AFSFcb *)pFileObject->FsContext; + BOOLEAN bSynchronousIo = IoIsOperationSynchronous(Irp); + VOID *pSystemBuffer = NULL; + BOOLEAN bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO); + BOOLEAN bLocked = FALSE; + AFSGatherIo *pGatherIo = NULL; + AFSIoRun *pIoRuns = NULL; + AFSIoRun stIoRuns[AFS_MAX_STACK_IO_RUNS]; + ULONG extentsCount = 0, runCount = 0; + AFSExtent *pStartExtent = NULL; + AFSExtent *pIgnoreExtent = NULL; + BOOLEAN bExtentsMapped = FALSE; + BOOLEAN bCompleteIrp = TRUE; + ULONG ulReadByteCount; + ULONG ulByteCount; + AFSDeviceExt *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension; + ULONG ulRequestCount = 0; + LARGE_INTEGER liCurrentTime, liLastRequestTime; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + PFILE_OBJECT pCacheFileObject = NULL; + + __Enter + { + + ulByteCount = pIrpSp->Parameters.Read.Length; + + if (ulByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Request larger than MaxIO %I64X\n", + Irp, + pDevExt->Specific.RDR.MaxIo.QuadPart); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + pSystemBuffer = AFSLockSystemBuffer( Irp, + ulByteCount); + + if( pSystemBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to map system buffer\n", + Irp); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + if( StartingByte.QuadPart + ulByteCount > pFcb->Header.FileSize.QuadPart) + { + ULONG zeroCount = (ULONG) (StartingByte.QuadPart + ulByteCount - pFcb->Header.FileSize.QuadPart); + ulReadByteCount = (ULONG)(pFcb->Header.FileSize.QuadPart - StartingByte.QuadPart); + + // + // Clear up to EOF + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead (%08lX) Zeroing to EOF zero byte length %08lX\n", + Irp, + zeroCount); + + RtlZeroMemory( ((PCHAR)pSystemBuffer) + ulReadByteCount, zeroCount); + } + else + { + ulReadByteCount = ulByteCount; + } + + // + // Provoke a get of the extents - if we need to. + // + + pStartExtent = NULL; + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Requesting extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ulReadByteCount); + + ntStatus = AFSRequestExtentsAsync( pFcb, + &StartingByte, + ulReadByteCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to request extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + KeQueryTickCount( &liLastRequestTime); + + while (TRUE) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Acquiring Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, TRUE ); + bLocked = TRUE; + + pStartExtent = NULL; + pIgnoreExtent = NULL; + + if( AFSDoExtentsMapRegion( pFcb, + &StartingByte, + ulReadByteCount, + &pStartExtent, + &pIgnoreExtent )) + { + break; + } + + KeClearEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Releasing Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + bLocked= FALSE; + + // + // We will re-request the extents after 10 seconds of waiting for them + // + + KeQueryTickCount( &liCurrentTime); + + if( liCurrentTime.QuadPart - liLastRequestTime.QuadPart >= pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Requesting extents, again, for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ulReadByteCount); + + ntStatus = AFSRequestExtentsAsync( pFcb, + &StartingByte, + ulReadByteCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to request extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + KeQueryTickCount( &liLastRequestTime); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Waiting for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ulReadByteCount); + + ntStatus = AFSWaitForExtentMapping ( pFcb ); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead Failed wait for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ulReadByteCount, + ntStatus); + + try_return( ntStatus); + } + } + + // + // At this stage we know that the extents are fully mapped and + // that, because we took a reference they won't be unmapped. + // Thus the list will not move between the start and end. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Extents mapped for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ulReadByteCount); + + ntStatus = AFSGetExtents( pFcb, + &StartingByte, + ulReadByteCount, + pStartExtent, + &extentsCount, + &runCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to retrieve mapped extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead (%08lX) Successfully retrieved map extents count %08lX run count %08lX\n", + Irp, + extentsCount, + runCount); + + if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE)) + { + + Irp->IoStatus.Information = ulReadByteCount; + + ntStatus = AFSProcessExtentRun( pSystemBuffer, + &StartingByte, + ulReadByteCount, + pStartExtent, + FALSE); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to process extent run for non-persistent cache Status %08lX\n", + Irp, + ntStatus); + } + + try_return( ntStatus); + } + + // + // Retrieve the cache file object + // + + pCacheFileObject = AFSReferenceCacheFileObject(); + + if( pCacheFileObject == NULL) + { + + ntStatus = STATUS_DEVICE_NOT_READY; + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead Failed to retrieve cache fileobject for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ulReadByteCount, + ntStatus); + + try_return( ntStatus); + } + + if (runCount > AFS_MAX_STACK_IO_RUNS) + { + + pIoRuns = (AFSIoRun*) AFSExAllocatePoolWithTag( PagedPool, + runCount * sizeof( AFSIoRun ), + AFS_IO_RUN_TAG ); + if (NULL == pIoRuns) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to allocate IO run block\n", + Irp); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + } + else + { + + pIoRuns = stIoRuns; + } + + RtlZeroMemory( pIoRuns, runCount * sizeof( AFSIoRun )); + + ntStatus = AFSSetupIoRun( IoGetRelatedDeviceObject( pCacheFileObject), + Irp, + pSystemBuffer, + pIoRuns, + &StartingByte, + ulReadByteCount, + pStartExtent, + &runCount ); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to initialize IO run block Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + + AFSReferenceActiveExtents( pStartExtent, + extentsCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Releasing Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + bLocked = FALSE; + + pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSGatherIo ), + AFS_GATHER_TAG ); + + if (NULL == pGatherIo) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedRead (%08lX) Failed to allocate IO gather block\n", + Irp); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Acquiring(2) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + bLocked = TRUE; + + AFSDereferenceActiveExtents( pStartExtent, + extentsCount); + + try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo )); + + // + // Initialize count to 1, that was we won't get an early + // completion if the first irp completes before the second is + // queued. + // + pGatherIo->Count = 1; + pGatherIo->Status = STATUS_SUCCESS; + pGatherIo->MasterIrp = Irp; + pGatherIo->Synchronous = TRUE; + pGatherIo->Fcb = pFcb; + pGatherIo->CompleteMasterIrp = FALSE; + + bCompleteIrp = TRUE; + + if (pGatherIo->Synchronous) + { + KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE ); + } + else + { + IoMarkIrpPending( Irp); + } + + // + // Pre-emptively set up the count + // + + Irp->IoStatus.Information = ulByteCount; + + ntStatus = AFSQueueStartIos( pCacheFileObject, + IRP_MJ_READ, + IRP_READ_OPERATION | IRP_SYNCHRONOUS_API, + pIoRuns, + runCount, + pGatherIo); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead (%08lX) AFSStartIos completed Status %08lX\n", + Irp, + ntStatus); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Acquiring(3) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + bLocked = TRUE; + + AFSDereferenceActiveExtents( pStartExtent, + extentsCount); + + try_return( ntStatus); + } + + // + // Wait for completion of all IOs we started. + // + (VOID) KeWaitForSingleObject( &pGatherIo->Event, + Executive, + KernelMode, + FALSE, + NULL); + + ntStatus = pGatherIo->Status; + +#if 0 + // + // Setup the MD5 for each extent + // + + AFSSetupMD5Hash( pFcb, + pStartExtent, + extentsCount, + pSystemBuffer, + &StartingByte, + ulReadByteCount); +#endif + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead (%08lX) AFSStartIos wait completed Status %08lX\n", + Irp, + ntStatus); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Acquiring(4) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + bLocked = TRUE; + + AFSDereferenceActiveExtents( pStartExtent, + extentsCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Releasing Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + bLocked = FALSE; + + // + // The data is there now. Give back the extents now so the service + // has some in hand + // + (VOID) AFSReleaseExtentsWithFlush( pFcb); + +try_exit: + + if( pCacheFileObject != NULL) + { + AFSReleaseCacheFileObject( pCacheFileObject); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead (%08lX) Completed request Status %08lX\n", + Irp, + ntStatus); + + if (NT_SUCCESS(ntStatus) && + !bPagingIo && + BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO)) + { + // + // Update the CBO if this is a sync, nopaging read + // + pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ulByteCount; + } + + if (bLocked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Releasing Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + } + + if (pGatherIo) + { + AFSExFreePool(pGatherIo); + } + + if (NULL != pIoRuns && stIoRuns != pIoRuns) + { + AFSExFreePool(pIoRuns); + } + + if (bCompleteIrp) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedRead Completing irp %08lX Status %08lX Info %08lX\n", + Irp, + ntStatus, + Irp->IoStatus.Information); + + AFSCompleteRequest( Irp, ntStatus ); + } + } + return ntStatus; +} +// +// Function: AFSDispatch +// +// Description: +// +// A shim around AFSCommonRead (qv) +// +NTSTATUS +AFSRead( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __try + { + + ntStatus = AFSCommonRead( AFSRDRDeviceObject, Irp, NULL); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + + return ntStatus; +} +// +// Function: AFSRead +// +// Description: +// +// This function is a slightly widened Dispatch handler for the +// AFS Read function. The thrid parameter is FALSE if we were called +// at our dispatch point and TRUE if we have been posted. +// +// After doing the obvious (completing MDL writes and so forth) +// we then post, or not. +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSCommonRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE OnBehalfOf) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt; + IO_STACK_LOCATION *pIrpSp; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + BOOLEAN bReleaseMain = FALSE; + BOOLEAN bReleasePaging = FALSE; + BOOLEAN bPagingIo = FALSE; + BOOLEAN bNonCachedIo = FALSE; + BOOLEAN bCompleteIrp = TRUE; + BOOLEAN bMapped; + PFILE_OBJECT pFileObject = NULL; + LARGE_INTEGER liStartingByte; + ULONG ulByteCount; + VOID *pSystemBuffer = NULL; + HANDLE hCallingUser = NULL; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + pDeviceExt = (AFSDeviceExt *)DeviceObject->DeviceExtension; + + __Enter + { + // + // Decode the fileobject + // + pFileObject = pIrpSp->FileObject; + + // + // There is a risk (albeit infinitely small) that the Irp will + // complete before this function exits, then a cleanup and + // close will happen and the FCB will be torn down before we + // get to the try_exit. Pin the file Object which will pin the FCB + // + + ObReferenceObject( pFileObject); + + // + // If we are in shutdown mode then fail the request + // + + if( BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSCommonRead (%08lX) Open request after shutdown\n", + Irp); + + try_return( ntStatus = STATUS_TOO_LATE); + } + + pFcb = (AFSFcb *)pFileObject->FsContext; + + pCcb = (AFSCcb *)pFileObject->FsContext2; + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead Attempted read (%08lX) when pFcb == NULL\n", + Irp); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO); + bNonCachedIo = BooleanFlagOn( Irp->Flags,IRP_NOCACHE); + + liStartingByte = pIrpSp->Parameters.Read.ByteOffset; + ulByteCount = pIrpSp->Parameters.Read.Length; + + if( pFcb->Header.NodeTypeCode != AFS_IOCTL_FCB && + pFcb->Header.NodeTypeCode != AFS_FILE_FCB && + pFcb->Header.NodeTypeCode != AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead Attempted read (%08lX) on an invalid node type %08lX\n", + Irp, + pFcb->Header.NodeTypeCode); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + // + // If this is a read against an IOCtl node then handle it + // in a different pathway + // + + if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Processing file (PIOCTL) Offset %I64X Length %08lX Irp Flags %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount, + Irp->Flags); + + ntStatus = AFSIOCtlRead( DeviceObject, + Irp); + + try_return( ntStatus); + } + else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Processing file (SHARE) Offset %I64X Length %08lX Irp Flags %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount, + Irp->Flags); + + ntStatus = AFSShareRead( DeviceObject, + Irp); + + try_return( ntStatus); + } + + // + // No fileobject yet? Bail. + // + if( !BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE) && + NULL == pDeviceExt->Specific.RDR.CacheFileObject) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Request failed due to AFS cache closed\n", + Irp); + + try_return( ntStatus = STATUS_TOO_LATE ); + } + + if( pIrpSp->Parameters.Read.Length == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Request completed due to zero length\n", + Irp); + + try_return( ntStatus); + } + + if ( FlagOn(pIrpSp->MinorFunction, IRP_MN_COMPLETE) ) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) IRP_MN_COMPLETE being processed\n", + Irp); + + CcMdlReadComplete(pIrpSp->FileObject, Irp->MdlAddress); + + // + // Mdl is now Deallocated + // + + Irp->MdlAddress = NULL; + + try_return( ntStatus = STATUS_SUCCESS ); + } + + // + // If we get a non cached IO for a cached file we should do a purge. + // For now we will just promote to cached + // + if (NULL != pFileObject->SectionObjectPointer->DataSectionObject && !bPagingIo) + { + + bNonCachedIo = FALSE; + } + + // + // Setup the calling process + // + + if( NULL == OnBehalfOf) + { + + hCallingUser = PsGetCurrentProcessId(); + } + else + { + + hCallingUser = OnBehalfOf; + } + + // + // We acquire the main/paging resource first to synchronize + // against size checks. + // + + if( bPagingIo) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead Acquiring Fcb PagingIo lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->PagingResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->PagingResource, + TRUE); + + bReleasePaging = TRUE; + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead Acquiring Fcb lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + bReleaseMain = TRUE; + + // + // Check the BR locks + // + + if( !FsRtlCheckLockForReadAccess( &pFcb->Specific.File.FileLock, + Irp)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Request failed due to lock conflict\n", + Irp); + + try_return( ntStatus = STATUS_FILE_LOCK_CONFLICT); + } + } + + if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED) || + BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Request failed due to file deleted\n", + Irp); + + try_return( ntStatus = STATUS_FILE_DELETED); + } + + // + // If the read starts beyond End of File, return EOF. + // + + if( liStartingByte.QuadPart >= pFcb->Header.FileSize.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Request beyond EOF %I64X\n", + Irp, + pFcb->Header.FileSize.QuadPart); + + try_return( ntStatus = STATUS_END_OF_FILE); + } + + // + // + + if( liStartingByte.QuadPart + ulByteCount > pFcb->Header.FileSize.QuadPart) + { + + ulByteCount = (ULONG)(pFcb->Header.FileSize.QuadPart - liStartingByte.QuadPart); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Truncated read request to %08lX\n", + Irp, + ulByteCount); + } + + // + // Is this Fcb valid??? + // + + if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Failing request due to INVALID fcb\n", + Irp); + + Irp->IoStatus.Information = 0; + + try_return( ntStatus = STATUS_FILE_DELETED); + } + + // + // Save off the PID if this is not a paging IO + // +#if 0 + if( !bPagingIo && + ( pFcb->Specific.File.ExtentProcessId == 0 || + ( PsGetCurrentProcessId() != AFSSysProcess && + pFcb->Specific.File.ExtentProcessId != (ULONGLONG)PsGetCurrentProcessId()))) + { + + pFcb->Specific.File.ExtentProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + if( pFcb->Specific.File.ExtentProcessId == (ULONGLONG)AFSSysProcess) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "%s Setting ExtentProcessId to system process for Fcb %p\n", + __FUNCTION__, + pFcb); + } + + pFcb->Specific.File.ExtentThreadId = (ULONGLONG)PsGetCurrentThreadId(); + + pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } +#endif + + // + // If this is going to be posted OR this is a cached read, + // then ask for the extents before we post. + // + /* + if( !bPagingIo && !bNonCachedIo) + { + + ntStatus = AFSRequestExtentsAsync( pFcb, &liStartingByte, ulByteCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Failed to request extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + } + */ + + // + // If this is an cached IO + // + if( (!bPagingIo && !bNonCachedIo)) + { + // + // This is a top level irp. Init the caching if it has not yet + // been initialzed for this FO + // + + if( pFileObject->PrivateCacheMap == NULL) + { + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead Initialize caching on Fcb %08lX FO %08lX\n", + pFcb, + pFileObject); + + CcInitializeCacheMap( pFileObject, + (PCC_FILE_SIZES)&pFcb->Header.AllocationSize, + FALSE, + AFSLibCacheManagerCallbacks, + pFcb); + + CcSetReadAheadGranularity( pFileObject, + READ_AHEAD_GRANULARITY); + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Exception thrown while initializing cache map Status %08lX\n", + Irp, + ntStatus); + } + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } + + // + // And if this is MDL operation, deal with it now (yes we + // could post, but we are almost certainly posted + // already and we don't want to grow and SVA for it..) + // + + if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL)) + { + __try + { + + CcMdlRead( pFileObject, + &liStartingByte, + ulByteCount, + &Irp->MdlAddress, + &Irp->IoStatus); + ntStatus = Irp->IoStatus.Status; + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) Exception thrown during mdl read Status %08lX\n", + Irp, + ntStatus); + } + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonRead (%08lX) Failed to process MDL read Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + // + // Update the CBO if this is a sync read + // + + if( BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO)) + { + + pFileObject->CurrentByteOffset.QuadPart = liStartingByte.QuadPart + ulByteCount; + } + + try_return( ntStatus); + } + } + + // + // The called request completes the IRP for us. + // + + bCompleteIrp = FALSE; + + if( !bPagingIo && + !bNonCachedIo) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Processing CACHED request Offset %I64X Len %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount); + + ntStatus = AFSCachedRead( DeviceObject, Irp, liStartingByte, ulByteCount); + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Processing NON-CACHED request Offset %I64X Len %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount); + + ntStatus = AFSNonCachedRead( DeviceObject, Irp, liStartingByte); + } + + // + // We won't do this for now in read processing ... + +#if 0 + // + // Queue up a flush + // + + if( pFcb->Specific.File.ExtentsDirtyCount > 0 || + pFcb->Specific.File.ExtentLength > 1500) + { + + AFSQueueFlushExtents( pFcb); + } +#endif + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonRead (%08lX) Process complete Status %08lX\n", + Irp, + ntStatus); + + if( bReleasePaging) + { + + AFSReleaseResource( &pFcb->NPFcb->PagingResource); + } + + if( bReleaseMain) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + + if( bCompleteIrp) + { + + AFSCompleteRequest( Irp, ntStatus); + } + + ObDereferenceObject( pFileObject); + } + + return ntStatus; +} + +NTSTATUS +AFSIOCtlRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSPIOCtlIORequestCB stIORequestCB; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + AFSPIOCtlIOResultCB stIOResultCB; + ULONG ulBytesReturned = 0; + AFSFileID stParentFID; + + __Enter + { + + RtlZeroMemory( &stIORequestCB, + sizeof( AFSPIOCtlIORequestCB)); + + if( pIrpSp->Parameters.Read.Length == 0) + { + + // + // Nothing to do in this case + // + + try_return( ntStatus); + } + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSIOCtlRead Acquiring Fcb lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + // + // Get the parent fid to pass to the cm + // + + RtlZeroMemory( &stParentFID, + sizeof( AFSFileID)); + + if( pFcb->ObjectInformation->ParentObjectInformation != NULL) + { + + // + // The parent directory FID of the node + // + + ASSERT( pFcb->ObjectInformation->ParentObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY); + + stParentFID = pFcb->ObjectInformation->ParentObjectInformation->FileId; + } + + // + // Set the control block up + // + + stIORequestCB.RequestId = pCcb->RequestID; + + if( pFcb->ObjectInformation->VolumeCB != NULL) + { + stIORequestCB.RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId; + } + + // + // Lock down the buffer + // + + stIORequestCB.MappedBuffer = AFSMapToService( Irp, + pIrpSp->Parameters.Read.Length); + + if( stIORequestCB.MappedBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + stIORequestCB.BufferLength = pIrpSp->Parameters.Read.Length; + + stIOResultCB.BytesProcessed = 0; + + ulBytesReturned = sizeof( AFSPIOCtlIOResultCB); + + // + // Issue the request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_READ, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + NULL, + &stParentFID, + (void *)&stIORequestCB, + sizeof( AFSPIOCtlIORequestCB), + &stIOResultCB, + &ulBytesReturned); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + // + // Update the length read + // + + Irp->IoStatus.Information = stIOResultCB.BytesProcessed; + +try_exit: + + if( stIORequestCB.MappedBuffer != NULL) + { + + AFSUnmapServiceMappedBuffer( stIORequestCB.MappedBuffer, + Irp->MdlAddress); + } + + if( pFcb != NULL) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + } + + return ntStatus; +} + +NTSTATUS +AFSShareRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSPIOCtlIORequestCB stIORequestCB; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + ULONG ulBytesReturned = 0; + void *pBuffer = NULL; + AFSPipeIORequestCB stIoRequest; + + __Enter + { + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSShareRead On pipe %wZ Length %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pIrpSp->Parameters.Read.Length); + + if( pIrpSp->Parameters.Read.Length == 0) + { + + // + // Nothing to do in this case + // + + try_return( ntStatus); + } + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + // + // Retrieve the buffer for the read request + // + + pBuffer = AFSLockSystemBuffer( Irp, + pIrpSp->Parameters.Read.Length); + + if( pBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSShareRead Failed to map buffer on pipe %wZ\n", + &pCcb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( &stIoRequest, + sizeof( AFSPipeIORequestCB)); + + stIoRequest.RequestId = pCcb->RequestID; + + stIoRequest.RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId; + + stIoRequest.BufferLength = pIrpSp->Parameters.Read.Length; + + ulBytesReturned = pIrpSp->Parameters.Read.Length; + + // + // Issue the open request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_READ, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + NULL, + (void *)&stIoRequest, + sizeof( AFSPipeIORequestCB), + pBuffer, + &ulBytesReturned); + + if( !NT_SUCCESS( ntStatus) && + ntStatus != STATUS_BUFFER_OVERFLOW) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSShareRead (%08lX) Failed service read Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSShareRead Completed on pipe %wZ Length read %08lX Status %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + ulBytesReturned, + ntStatus); + + Irp->IoStatus.Information = ulBytesReturned; + +try_exit: + + if( pFcb != NULL) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSRedirLibInstall.inf b/src/WINNT/afsrdr/kernel/lib/AFSRedirLibInstall.inf new file mode 100644 index 0000000000..0e6dc43ac1 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSRedirLibInstall.inf @@ -0,0 +1,68 @@ +;;; +;;; AFS Redirector Installation file +;;; + +[Version] +signature = "$Windows NT$" +Class = "AFSRedirector" +ClassGuid = {63EA509E-71F9-42ec-9C5E-1ECC95E3A1A0} +Provider = %AFS% +DriverVer = 04/20/2006,1.0.0.0 + +[DestinationDirs] +DefaultDestDir = 12 +AFS.DriverFiles = 12 + +;; +;; Default install sections +;; + +[DefaultInstall] +CopyFiles = AFS.DriverFiles + +[SourceDisksNames] +1 = %Disk1% + +[SourceDisksFiles] +AFSRedirLib.sys = 1 + +[DefaultInstall.Services] +AddService = %AFSServiceName%,,AFS.Service + +;; +;; Default uninstall sections +;; + +[DefaultUninstall] +DelFiles = AFS.DriverFiles + +; +; Services Section +; + +[AFS.Service] +DisplayName = %AFSServiceName% +Description = %AFSServiceDesc% +ServiceBinary = %12%\AFSRedirLib.sys +ServiceType = 2 +StartType = 3 +ErrorControl = 1 +LoadOrderGroup = "Filesystem" + +; +; Copy Files +; + +[AFS.DriverFiles] +AFSRedirLib.sys + +;; +;; String Section +;; + +[Strings] +AFS = "OpenAFS" +AFSServiceDesc = "OpenAFS Redirector" +AFSServiceName = "AFSLibrary" +AFSRegistry = "system\currentcontrolset\services\AFSLibrary\Parameters" +Disk1 = "OpenAFS Media" diff --git a/src/WINNT/afsrdr/kernel/lib/AFSSecurity.cpp b/src/WINNT/afsrdr/kernel/lib/AFSSecurity.cpp new file mode 100644 index 0000000000..5b178b643b --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSSecurity.cpp @@ -0,0 +1,159 @@ +/* + * 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: AFSSecurity.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSSetSecurity( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSSetSecurity Entry for FO %08lX\n", + pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSSetSecurity\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSQuerySecurity( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + PIO_STACK_LOCATION pIrpSp; + PMDL pUserBufferMdl = NULL; + void *pLockedUserBuffer = NULL; + ULONG ulSDLength = 0; + + __try + { + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQuerySecurity Entry for FO %08lX\n", + pIrpSp->FileObject); + + if( AFSDefaultSD == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQuerySecurity No default SD allocated\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + ulSDLength = RtlLengthSecurityDescriptor( AFSDefaultSD); + + if( pIrpSp->Parameters.QuerySecurity.Length < ulSDLength || + Irp->UserBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQuerySecurity Buffer too small\n"); + + Irp->IoStatus.Information = (ULONG_PTR)ulSDLength; + + try_return( ntStatus = STATUS_BUFFER_OVERFLOW); + } + + pLockedUserBuffer = AFSLockUserBuffer( Irp->UserBuffer, + pIrpSp->Parameters.QuerySecurity.Length, + &pUserBufferMdl); + + if( pLockedUserBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQuerySecurity Failed to lock user buffer\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlCopyMemory( pLockedUserBuffer, + AFSDefaultSD, + ulSDLength); + + Irp->IoStatus.Information = (ULONG_PTR)ulSDLength; + +try_exit: + + if( pUserBufferMdl != NULL) + { + MmUnlockPages( pUserBufferMdl); + IoFreeMdl( pUserBufferMdl); + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQuerySecurity\n"); + } + + AFSCompleteRequest( Irp, + ntStatus); + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSShutdown.cpp b/src/WINNT/afsrdr/kernel/lib/AFSShutdown.cpp new file mode 100644 index 0000000000..9bf6f67f5c --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSShutdown.cpp @@ -0,0 +1,84 @@ +/* + * 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: AFSShutdown.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSShutdown( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + ntStatus = AFSShutdownFilesystem(); + + if( !NT_SUCCESS( ntStatus)) + { + + ntStatus = STATUS_SUCCESS; + } + + AFSCompleteRequest( Irp, + ntStatus); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSShutdown\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSShutdownFilesystem() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSSystemControl.cpp b/src/WINNT/afsrdr/kernel/lib/AFSSystemControl.cpp new file mode 100644 index 0000000000..109e065a4e --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSSystemControl.cpp @@ -0,0 +1,72 @@ +/* + * 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: AFSSystemControl.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSSystemControl( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSSystemControl Entry for FO %08lX\n", + pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSSystemControl\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp b/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp new file mode 100644 index 0000000000..16c455ed2f --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp @@ -0,0 +1,436 @@ +/* + * 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: AFSVolumeInfo.cpp +// + +#include "AFSCommon.h" + +NTSTATUS +AFSQueryVolumeInfo( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + IO_STACK_LOCATION *pIrpSp; + FS_INFORMATION_CLASS FsInformationClass; + void *pBuffer = NULL; + ULONG ulLength = 0; + BOOLEAN bReleaseResource = FALSE; + AFSFcb *pFcb = NULL; + AFSVolumeCB *pVolumeCB = NULL; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryVolumeInfo Failing request with NULL Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + pVolumeCB = pFcb->ObjectInformation->VolumeCB; + + ASSERT( pVolumeCB->ObjectInformation.FileType == AFS_FILE_TYPE_DIRECTORY && + pVolumeCB->ObjectInformation.FileId.Vnode == 1); + + ulLength = pIrpSp->Parameters.QueryVolume.Length; + FsInformationClass = pIrpSp->Parameters.QueryVolume.FsInformationClass; + pBuffer = Irp->AssociatedIrp.SystemBuffer; + + AFSAcquireExcl( pVolumeCB->VolumeLock, + TRUE); + + bReleaseResource = TRUE; + + // + // Don't allow requests against IOCtl nodes + // + + if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryVolumeInfo Failing request against PIOCtl Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueryVolumeInfo Failing request against SpecialShare Fcb\n"); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + // + // Process the request + // + + switch( FsInformationClass) + { + + case FileFsVolumeInformation: + { + + ntStatus = AFSQueryFsVolumeInfo( &pVolumeCB->VolumeInformation, + (PFILE_FS_VOLUME_INFORMATION)pBuffer, + &ulLength); + + break; + } + + case FileFsSizeInformation: + { + + ntStatus = AFSQueryFsSizeInfo( &pVolumeCB->VolumeInformation, + (PFILE_FS_SIZE_INFORMATION)pBuffer, + &ulLength); + + break; + } + + case FileFsDeviceInformation: + { + + ntStatus = AFSQueryFsDeviceInfo( &pVolumeCB->VolumeInformation, + (PFILE_FS_DEVICE_INFORMATION)pBuffer, + &ulLength); + + break; + } + + case FileFsAttributeInformation: + { + + ntStatus = AFSQueryFsAttributeInfo( &pVolumeCB->VolumeInformation, + (PFILE_FS_ATTRIBUTE_INFORMATION)pBuffer, + &ulLength); + + break; + } + + case FileFsFullSizeInformation: + { + + ntStatus = AFSQueryFsFullSizeInfo( &pVolumeCB->VolumeInformation, + (PFILE_FS_FULL_SIZE_INFORMATION)pBuffer, + &ulLength); + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSQueryVolumeInfo Invalid class %d\n", + FsInformationClass); + + ntStatus = STATUS_INVALID_PARAMETER; + + break; + } + +try_exit: + + // + // Setup the Irp's information field to what we actually copied in. + // + + Irp->IoStatus.Information = pIrpSp->Parameters.QueryVolume.Length - ulLength; + + if( bReleaseResource) + { + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueryVolumeInfo\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSSetVolumeInfo( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STACK_LOCATION *pIrpSp; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSSetVolumeInfo Entry for FO %08lX\n", pIrpSp->FileObject); + + AFSCompleteRequest( Irp, + ntStatus); + + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSSetVolumeInfo\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSQueryFsVolumeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_VOLUME_INFORMATION Buffer, + IN OUT PULONG Length) + +{ + + NTSTATUS ntStatus = STATUS_BUFFER_TOO_SMALL; + ULONG ulCopyLength; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= (ULONG)sizeof( FILE_FS_VOLUME_INFORMATION)) + { + + if( *Length >= (ULONG)(FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel) + (LONG)VolumeInfo->VolumeLabelLength)) + { + + ulCopyLength = (LONG)VolumeInfo->VolumeLabelLength; + + ntStatus = STATUS_SUCCESS; + } + else + { + + ulCopyLength = *Length - FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel); + + ntStatus = STATUS_BUFFER_OVERFLOW; + } + + Buffer->VolumeCreationTime.QuadPart = VolumeInfo->VolumeCreationTime.QuadPart; + + Buffer->VolumeSerialNumber = VolumeInfo->VolumeID; + + Buffer->VolumeLabelLength = VolumeInfo->VolumeLabelLength; + + Buffer->SupportsObjects = FALSE; + + *Length -= FIELD_OFFSET( FILE_FS_VOLUME_INFORMATION, VolumeLabel); + + if( ulCopyLength > 0) + { + + RtlCopyMemory( Buffer->VolumeLabel, + VolumeInfo->VolumeLabel, + ulCopyLength); + + *Length -= ulCopyLength; + } + } + + return ntStatus; +} + +NTSTATUS +AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_SIZE_INFORMATION Buffer, + IN OUT PULONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= sizeof( FILE_FS_SIZE_INFORMATION)) + { + + Buffer->TotalAllocationUnits.QuadPart = VolumeInfo->TotalAllocationUnits.QuadPart; + + Buffer->AvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart; + + Buffer->SectorsPerAllocationUnit = VolumeInfo->SectorsPerAllocationUnit; + + Buffer->BytesPerSector = VolumeInfo->BytesPerSector; + + *Length -= sizeof( FILE_FS_SIZE_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryFsDeviceInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_DEVICE_INFORMATION Buffer, + IN OUT PULONG Length) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= (LONG)sizeof( FILE_FS_DEVICE_INFORMATION)) + { + + Buffer->DeviceType = FILE_DEVICE_DISK; + + Buffer->Characteristics = VolumeInfo->Characteristics; + + *Length -= sizeof( FILE_FS_DEVICE_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryFsAttributeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, + IN OUT PULONG Length) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= (LONG)(sizeof( FILE_FS_ATTRIBUTE_INFORMATION))) + { + + Buffer->FileSystemAttributes = (FILE_CASE_PRESERVED_NAMES | + FILE_UNICODE_ON_DISK | + FILE_SUPPORTS_REPARSE_POINTS); + + Buffer->MaximumComponentNameLength = 255; + + Buffer->FileSystemNameLength = 18; + + *Length -= FIELD_OFFSET( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName); + + if( *Length >= 18) + { + + RtlCopyMemory( Buffer->FileSystemName, + L"AFSRDRFsd", + 18); + + *Length -= 18; + } + else + { + + ntStatus = STATUS_BUFFER_OVERFLOW; + } + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} + +NTSTATUS +AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, + IN OUT PULONG Length) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + RtlZeroMemory( Buffer, + *Length); + + if( *Length >= sizeof( FILE_FS_FULL_SIZE_INFORMATION)) + { + + Buffer->TotalAllocationUnits.QuadPart = VolumeInfo->TotalAllocationUnits.QuadPart; + + Buffer->CallerAvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart; + + Buffer->ActualAvailableAllocationUnits.QuadPart = VolumeInfo->AvailableAllocationUnits.QuadPart; + + Buffer->SectorsPerAllocationUnit = VolumeInfo->SectorsPerAllocationUnit; + + Buffer->BytesPerSector = VolumeInfo->BytesPerSector; + + *Length -= sizeof( FILE_FS_FULL_SIZE_INFORMATION); + } + else + { + + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp b/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp new file mode 100644 index 0000000000..721c26e642 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp @@ -0,0 +1,2433 @@ +/* + * 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: AFSWorker.cpp +// + +#include "AFSCommon.h" + +// +// Function: AFSInitializeWorkerPool +// +// Description: +// +// This function initializes the worker thread pool +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSInitializeWorkerPool() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkQueueContext *pCurrentWorker = NULL, *pLastWorker = NULL; + AFSDeviceExt *pDevExt = NULL; + + __Enter + { + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + // + // Initialize the worker threads. + // + + pDevExt->Specific.Library.WorkerCount = 0; + + KeInitializeEvent( &pDevExt->Specific.Library.WorkerQueueHasItems, + NotificationEvent, + FALSE); + + // + // Initialize the queue resource + // + + ExInitializeResourceLite( &pDevExt->Specific.Library.QueueLock); + + while( pDevExt->Specific.Library.WorkerCount < AFS_WORKER_COUNT) + { + + pCurrentWorker = (AFSWorkQueueContext *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSWorkQueueContext), + AFS_WORKER_CB_TAG); + + if( pCurrentWorker == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeWorkerPool Failed to allocate worker context\n"); + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + + break; + } + + RtlZeroMemory( pCurrentWorker, + sizeof( AFSWorkQueueContext)); + + ntStatus = AFSInitWorkerThread( pCurrentWorker, + (PKSTART_ROUTINE)AFSWorkerThread); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeWorkerPool Failed to initialize worker thread Status %08lX\n", ntStatus); + + ExFreePool( pCurrentWorker); + + break; + } + + if( pDevExt->Specific.Library.PoolHead == NULL) + { + + pDevExt->Specific.Library.PoolHead = pCurrentWorker; + } + else + { + + pLastWorker->fLink = pCurrentWorker; + } + + pLastWorker = pCurrentWorker; + + pDevExt->Specific.Library.WorkerCount++; + } + + // + // If there was a failure but there is at least one worker, then go with it. + // + + if( !NT_SUCCESS( ntStatus) && + pDevExt->Specific.Library.WorkerCount == 0) + { + + try_return( ntStatus); + } + + ntStatus = STATUS_SUCCESS; + + // + // Now our IO Worker queue + // + + pDevExt->Specific.Library.IOWorkerCount = 0; + + KeInitializeEvent( &pDevExt->Specific.Library.IOWorkerQueueHasItems, + NotificationEvent, + FALSE); + + // + // Initialize the queue resource + // + + ExInitializeResourceLite( &pDevExt->Specific.Library.IOQueueLock); + + while( pDevExt->Specific.Library.IOWorkerCount < AFS_IO_WORKER_COUNT) + { + + pCurrentWorker = (AFSWorkQueueContext *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSWorkQueueContext), + AFS_WORKER_CB_TAG); + + if( pCurrentWorker == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeWorkerPool Failed to allocate IO worker context\n"); + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + + break; + } + + RtlZeroMemory( pCurrentWorker, + sizeof( AFSWorkQueueContext)); + + ntStatus = AFSInitWorkerThread( pCurrentWorker, + (PKSTART_ROUTINE)AFSIOWorkerThread); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSInitializeWorkerPool Failed to initialize IO worker thread Status %08lX\n", ntStatus); + + ExFreePool( pCurrentWorker); + + break; + } + + if( pDevExt->Specific.Library.IOPoolHead == NULL) + { + + pDevExt->Specific.Library.IOPoolHead = pCurrentWorker; + } + else + { + + pLastWorker->fLink = pCurrentWorker; + } + + pLastWorker = pCurrentWorker; + + pDevExt->Specific.Library.IOWorkerCount++; + } + + // + // If there was a failure but there is at least one worker, then go with it. + // + + if( !NT_SUCCESS( ntStatus) && + pDevExt->Specific.Library.IOWorkerCount == 0) + { + + try_return( ntStatus); + } + +try_exit: + + if( !NT_SUCCESS( ntStatus)) + { + + // + // Failed to initialize the pool so tear it down + // + + AFSRemoveWorkerPool(); + } + } + + return ntStatus; +} + +// +// Function: AFSRemoveWorkerPool +// +// Description: +// +// This function tears down the worker thread pool +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSRemoveWorkerPool() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG index = 0; + AFSWorkQueueContext *pCurrentWorker = NULL, *pNextWorker = NULL; + AFSDeviceExt *pDevExt = NULL; + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + // + // Loop through the workers shutting them down + // + + pCurrentWorker = pDevExt->Specific.Library.PoolHead; + + while( index < pDevExt->Specific.Library.WorkerCount) + { + + ntStatus = AFSShutdownWorkerThread( pCurrentWorker); + + pNextWorker = pCurrentWorker->fLink; + + ExFreePool( pCurrentWorker); + + pCurrentWorker = pNextWorker; + + if( pCurrentWorker == NULL) + { + + break; + } + + index++; + } + + pDevExt->Specific.Library.PoolHead = NULL; + + ExDeleteResourceLite( &pDevExt->Specific.Library.QueueLock); + + // + // Loop through the IO workers shutting them down + // + + pCurrentWorker = pDevExt->Specific.Library.IOPoolHead; + + index = 0; + + while( index < pDevExt->Specific.Library.IOWorkerCount) + { + + ntStatus = AFSShutdownIOWorkerThread( pCurrentWorker); + + pNextWorker = pCurrentWorker->fLink; + + ExFreePool( pCurrentWorker); + + pCurrentWorker = pNextWorker; + + if( pCurrentWorker == NULL) + { + + break; + } + + index++; + } + + pDevExt->Specific.Library.IOPoolHead = NULL; + + ExDeleteResourceLite( &pDevExt->Specific.Library.IOQueueLock); + + return ntStatus; +} + +NTSTATUS +AFSInitVolumeWorker( IN AFSVolumeCB *VolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkQueueContext *pWorker = &VolumeCB->VolumeWorkerContext; + HANDLE hThread; + AFSDeviceExt *pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + PKSTART_ROUTINE pStartRoutine = NULL; + + __Enter + { + + if( VolumeCB == AFSGlobalRoot) + { + + pStartRoutine = AFSPrimaryVolumeWorkerThread; + } + else + { + + pStartRoutine = AFSVolumeWorkerThread; + } + + // + // Initialize the worker thread + // + + KeInitializeEvent( &pWorker->WorkerThreadReady, + NotificationEvent, + FALSE); + + // + // Set the worker to process requests + // + + pWorker->State = AFS_WORKER_PROCESS_REQUESTS; + + // + // Launch the thread + // + + ntStatus = PsCreateSystemThread( &hThread, + 0, + NULL, + NULL, + NULL, + pStartRoutine, + (void *)VolumeCB); + + if( NT_SUCCESS( ntStatus)) + { + + ObReferenceObjectByHandle( hThread, + GENERIC_READ | GENERIC_WRITE, + NULL, + KernelMode, + (PVOID *)&pWorker->WorkerThreadObject, + NULL); + + ntStatus = KeWaitForSingleObject( &pWorker->WorkerThreadReady, + Executive, + KernelMode, + FALSE, + NULL); + + if( InterlockedIncrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount) > 0) + { + + KeClearEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent); + } + + ZwClose( hThread); + } + } + + return ntStatus; +} + +// +// Function: AFSInitWorkerThread +// +// Description: +// +// This function initializes a worker thread in the pool +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSInitWorkerThread( IN AFSWorkQueueContext *PoolContext, + IN PKSTART_ROUTINE WorkerRoutine) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + HANDLE Handle; + + // + // INitialize the worker signal thread + // + + KeInitializeEvent( &PoolContext->WorkerThreadReady, + NotificationEvent, + FALSE); + + // + // Set the worker to process requests + // + + PoolContext->State = AFS_WORKER_PROCESS_REQUESTS; + + // + // Launch the thread + // + + ntStatus = PsCreateSystemThread( &Handle, + 0, + NULL, + NULL, + NULL, + WorkerRoutine, + (void *)PoolContext); + + if( NT_SUCCESS( ntStatus)) + { + + ObReferenceObjectByHandle( Handle, + GENERIC_READ | GENERIC_WRITE, + NULL, + KernelMode, + (PVOID *)&PoolContext->WorkerThreadObject, + NULL); + + ntStatus = KeWaitForSingleObject( &PoolContext->WorkerThreadReady, + Executive, + KernelMode, + FALSE, + NULL); + + ZwClose( Handle); + } + + return ntStatus; +} + +NTSTATUS +AFSShutdownVolumeWorker( IN AFSVolumeCB *VolumeCB) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkQueueContext *pWorker = &VolumeCB->VolumeWorkerContext; + + if( pWorker->WorkerThreadObject != NULL && + BooleanFlagOn( pWorker->State, AFS_WORKER_INITIALIZED)) + { + + // + // Clear the 'keep processing' flag + // + + ClearFlag( pWorker->State, AFS_WORKER_PROCESS_REQUESTS); + + ntStatus = KeWaitForSingleObject( pWorker->WorkerThreadObject, + Executive, + KernelMode, + FALSE, + NULL); + + ObDereferenceObject( pWorker->WorkerThreadObject); + + pWorker->WorkerThreadObject = NULL; + } + + return ntStatus; +} + +// +// Function: AFSShutdownWorkerThread +// +// Description: +// +// This function shusdown a worker thread in the pool +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSShutdownWorkerThread( IN AFSWorkQueueContext *PoolContext) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + if( PoolContext->WorkerThreadObject != NULL && + BooleanFlagOn( PoolContext->State, AFS_WORKER_INITIALIZED)) + { + + // + // Clear the 'keep processing' flag + // + + ClearFlag( PoolContext->State, AFS_WORKER_PROCESS_REQUESTS); + + // + // Wake up the thread if it is a sleep + // + + KeSetEvent( &pDeviceExt->Specific.Library.WorkerQueueHasItems, + 0, + FALSE); + + ntStatus = KeWaitForSingleObject( PoolContext->WorkerThreadObject, + Executive, + KernelMode, + FALSE, + NULL); + + ObDereferenceObject( PoolContext->WorkerThreadObject); + + PoolContext->WorkerThreadObject = NULL; + } + + return ntStatus; +} + +// +// Function: AFSShutdownIOWorkerThread +// +// Description: +// +// This function shutsdown an IO worker thread in the pool +// +// Return: +// +// A status is returned for the function +// + +NTSTATUS +AFSShutdownIOWorkerThread( IN AFSWorkQueueContext *PoolContext) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + if( PoolContext->WorkerThreadObject != NULL && + BooleanFlagOn( PoolContext->State, AFS_WORKER_INITIALIZED)) + { + + // + // Clear the 'keep processing' flag + // + + ClearFlag( PoolContext->State, AFS_WORKER_PROCESS_REQUESTS); + + // + // Wake up the thread if it is a sleep + // + + KeSetEvent( &pDeviceExt->Specific.Library.IOWorkerQueueHasItems, + 0, + FALSE); + + ntStatus = KeWaitForSingleObject( PoolContext->WorkerThreadObject, + Executive, + KernelMode, + FALSE, + NULL); + + ObDereferenceObject( PoolContext->WorkerThreadObject); + + PoolContext->WorkerThreadObject = NULL; + } + + return ntStatus; +} + +// +// Function: AFSWorkerThread +// +// Description: +// +// This is the worker thread entry point. +// +// Return: +// +// A status is returned for the function +// + +void +AFSWorkerThread( IN PVOID Context) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context; + AFSWorkItem *pWorkItem; + BOOLEAN freeWorkItem = TRUE; + BOOLEAN exitThread = FALSE; + AFSDeviceExt *pLibraryDevExt = NULL; + + pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + // + // Indicate that we are initialized and ready + // + + KeSetEvent( &pPoolContext->WorkerThreadReady, + 0, + FALSE); + + + // + // Indicate we are initialized + // + + SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED); + + while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS)) + { + + ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.WorkerQueueHasItems, + Executive, + KernelMode, + FALSE, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSWorkerThread Wait for queue items failed Status %08lX\n", ntStatus); + } + else + { + + pWorkItem = AFSRemoveWorkItem(); + + if( pWorkItem != NULL) + { + + freeWorkItem = TRUE; + + // + // Switch on the type of work item to process + // + + switch( pWorkItem->RequestType) + { + + case AFS_WORK_FLUSH_FCB: + { + + ntStatus = AFSFlushExtents( pWorkItem->Specific.Fcb.Fcb); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSReleaseExtentsWithFlush( pWorkItem->Specific.Fcb.Fcb); + } + + ASSERT( pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount != 0); + + InterlockedDecrement( &pWorkItem->Specific.Fcb.Fcb->OpenReferenceCount); + + break; + } + + case AFS_WORK_ASYNCH_READ: + { + + ASSERT( pWorkItem->Specific.AsynchIo.CallingProcess != NULL); + + (VOID) AFSCommonRead( pWorkItem->Specific.AsynchIo.Device, + pWorkItem->Specific.AsynchIo.Irp, + pWorkItem->Specific.AsynchIo.CallingProcess); + + break; + } + + case AFS_WORK_ASYNCH_WRITE: + { + + ASSERT( pWorkItem->Specific.AsynchIo.CallingProcess != NULL); + + (VOID) AFSCommonWrite( pWorkItem->Specific.AsynchIo.Device, + pWorkItem->Specific.AsynchIo.Irp, + pWorkItem->Specific.AsynchIo.CallingProcess); + break; + } + + case AFS_WORK_ENUMERATE_GLOBAL_ROOT: + { + + AFSEnumerateGlobalRoot( NULL); + + break; + } + + case AFS_WORK_START_IOS: + { + + freeWorkItem = TRUE; + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType); + + break; + } + + if( freeWorkItem) + { + + ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG); + } + } + } + } // worker thread loop + + PsTerminateSystemThread( 0); + + return; +} + +void +AFSIOWorkerThread( IN PVOID Context) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)Context; + AFSWorkItem *pWorkItem; + BOOLEAN freeWorkItem = TRUE; + BOOLEAN exitThread = FALSE; + AFSDeviceExt *pLibraryDevExt = NULL, *pRdrDevExt = NULL; + + pLibraryDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + // + // Indicate that we are initialized and ready + // + + KeSetEvent( &pPoolContext->WorkerThreadReady, + 0, + FALSE); + + + // + // Indicate we are initialized + // + + SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED); + + while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS)) + { + + ntStatus = KeWaitForSingleObject( &pLibraryDevExt->Specific.Library.IOWorkerQueueHasItems, + Executive, + KernelMode, + FALSE, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSIOWorkerThread Wait for queue items failed Status %08lX\n", ntStatus); + } + else + { + + pWorkItem = AFSRemoveIOWorkItem(); + + if( pWorkItem != NULL) + { + + freeWorkItem = TRUE; + + // + // Switch on the type of work item to process + // + + switch( pWorkItem->RequestType) + { + + case AFS_WORK_START_IOS: + { + + pRdrDevExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + // + // The final status is in the gather io + // + + ntStatus = AFSStartIos( pWorkItem->Specific.CacheAccess.CacheFileObject, + pWorkItem->Specific.CacheAccess.FunctionCode, + pWorkItem->Specific.CacheAccess.RequestFlags, + pWorkItem->Specific.CacheAccess.IoRuns, + pWorkItem->Specific.CacheAccess.RunCount, + pWorkItem->Specific.CacheAccess.GatherIo); + + // + // Regardless of the status we we do the complete - there may + // be IOs in flight + // Decrement the count - setting the event if we were told + // to. This may trigger completion. + // + + AFSCompleteIo( pWorkItem->Specific.CacheAccess.GatherIo, ntStatus ); + + freeWorkItem = TRUE; + + break; + } + + default: + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSWorkerThread Unknown request type %d\n", pWorkItem->RequestType); + + break; + } + + if( freeWorkItem) + { + + ExFreePoolWithTag( pWorkItem, AFS_WORK_ITEM_TAG); + } + } + } + } // worker thread loop + + PsTerminateSystemThread( 0); + + return; +} + +void +AFSPrimaryVolumeWorkerThread( IN PVOID Context) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&AFSGlobalRoot->VolumeWorkerContext; + AFSDeviceExt *pControlDeviceExt = NULL; + AFSDeviceExt *pRDRDeviceExt = NULL; + BOOLEAN exitThread = FALSE; + LARGE_INTEGER DueTime; + LONG TimeOut; + KTIMER Timer; + BOOLEAN bFoundOpenEntry = FALSE; + AFSObjectInfoCB *pCurrentObject = NULL, *pNextObject = NULL, *pCurrentChildObject = NULL; + AFSDirectoryCB *pCurrentDirEntry = NULL, *pNextDirEntry = NULL; + BOOLEAN bReleaseVolumeLock = FALSE; + AFSVolumeCB *pVolumeCB = NULL, *pNextVolume = NULL; + LARGE_INTEGER liCurrentTime; + BOOLEAN bVolumeObject = FALSE; + + pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPrimaryVolumeWorkerThread Initialized\n"); + + // + // Initialize the timer for the worker thread + // + + DueTime.QuadPart = -(5000); + + TimeOut = 5000; + + KeInitializeTimerEx( &Timer, + SynchronizationTimer); + + KeSetTimerEx( &Timer, + DueTime, + TimeOut, + NULL); + + // + // Indicate that we are initialized and ready + // + + KeSetEvent( &pPoolContext->WorkerThreadReady, + 0, + FALSE); + + // + // Indicate we are initialized + // + + SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED); + + while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS)) + { + + KeWaitForSingleObject( &Timer, + Executive, + KernelMode, + FALSE, + NULL); + + // + // This is the primary volume worker so it will traverse the volume list + // looking for cleanup or volumes requiring private workers + // + + AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock, + TRUE); + + pVolumeCB = pRDRDeviceExt->Specific.RDR.VolumeListHead; + + while( pVolumeCB != NULL) + { + + if( pVolumeCB == AFSGlobalRoot || + !AFSAcquireExcl( pVolumeCB->VolumeLock, + FALSE)) + { + + pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink; + + continue; + } + + if( pVolumeCB->ObjectInfoListHead == NULL && + pVolumeCB != AFSGlobalRoot) + { + + AFSReleaseResource( pVolumeCB->VolumeLock); + + AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + + AFSAcquireExcl( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock, + TRUE); + + AFSAcquireExcl( &pRDRDeviceExt->Specific.RDR.VolumeListLock, + TRUE); + + if( !AFSAcquireExcl( pVolumeCB->VolumeLock, + FALSE)) + { + + AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + + AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock); + + pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink; + + continue; + } + + KeQueryTickCount( &liCurrentTime); + + pNextVolume = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink; + + if( pVolumeCB->ObjectInfoListHead == NULL && + pVolumeCB->DirectoryCB->OpenReferenceCount == 0 && + pVolumeCB->VolumeReferenceCount == 1 && + ( pVolumeCB->RootFcb == NULL || + pVolumeCB->RootFcb->OpenReferenceCount == 0) && + pVolumeCB->ObjectInformation.ObjectReferenceCount == 0) + { + + if( pVolumeCB->RootFcb != NULL) + { + + AFSRemoveRootFcb( pVolumeCB->RootFcb); + } + + AFSRemoveVolume( pVolumeCB); + } + else + { + + AFSReleaseResource( pVolumeCB->VolumeLock); + } + + AFSConvertToShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + + AFSReleaseResource( pRDRDeviceExt->Specific.RDR.VolumeTree.TreeLock); + + pVolumeCB = pNextVolume; + + continue; + } + + // + // Don't need this lock anymore now that we have a volume cb to work with + // + + AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + + // + // For now we only need the volume lock shared + // + + AFSConvertToShared( pVolumeCB->VolumeLock); + + if( AFSAcquireShared( pVolumeCB->ObjectInfoTree.TreeLock, + FALSE)) + { + + pCurrentObject = pVolumeCB->ObjectInfoListHead; + + pNextObject = NULL; + + bReleaseVolumeLock = TRUE; + + while( pCurrentObject != NULL) + { + + if( pCurrentObject != &pVolumeCB->ObjectInformation) + { + + pNextObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + + if( pNextObject == NULL && + pVolumeCB != AFSGlobalRoot) // Don't free up the root of the global + { + + pNextObject = &pVolumeCB->ObjectInformation; + } + + bVolumeObject = FALSE; + } + else + { + + pNextObject = NULL; + + bVolumeObject = TRUE; + } + + if( pCurrentObject->FileType == AFS_FILE_TYPE_DIRECTORY && + !BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) // If we are in shutdown mode skip directories + { + + // + // If this object is deleted then remove it from the parent, if we can + // + + if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) && + pCurrentObject->ObjectReferenceCount == 0 && + ( pCurrentObject->Fcb == NULL || + pCurrentObject->Fcb->OpenReferenceCount == 0) && + pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL && + pCurrentObject->Specific.Directory.ChildOpenReferenceCount == 0) + { + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock, + FALSE)) + { + + if( pCurrentObject->Fcb != NULL) + { + + AFSRemoveFcb( pCurrentObject->Fcb); + } + + if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB != NULL) + { + + if( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb != NULL) + { + + AFSRemoveFcb( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb); + } + + AFSDeleteObjectInfo( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation); + + ExFreePool( pCurrentObject->Specific.Directory.PIOCtlDirectoryCB); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPrimaryWorker Deleting deleted object %08lX\n", + pCurrentObject); + + AFSDeleteObjectInfo( pCurrentObject); + + AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock); + + pCurrentObject = pNextObject; + + continue; + } + else + { + + bReleaseVolumeLock = FALSE; + + break; + } + } + + if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0 || + ( pCurrentObject->Fcb != NULL && + pCurrentObject->Fcb->OpenReferenceCount > 0) || + pCurrentObject->Specific.Directory.DirectoryNodeListHead == NULL) + { + + pCurrentObject = pNextObject; + + continue; + } + + if( !AFSAcquireShared( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock, + FALSE)) + { + + pCurrentObject = pNextObject; + + continue; + } + + KeQueryTickCount( &liCurrentTime); + + pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + if( pCurrentDirEntry->OpenReferenceCount > 0 || + ( pCurrentDirEntry->ObjectInformation->Fcb != NULL && + pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) || + liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart || + liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart < + pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart || + ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY && + ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL || + pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) || + ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE && + pCurrentDirEntry->ObjectInformation->Fcb != NULL && + pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)) + { + + break; + } + + pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + } + + if( pCurrentDirEntry != NULL) + { + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + pCurrentObject = pNextObject; + + continue; + } + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + // + // Now acquire the locks excl + // + + if( AFSAcquireExcl( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock, + FALSE)) + { + + if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock, + FALSE)) + { + + if( pCurrentObject->Specific.Directory.ChildOpenReferenceCount > 0) + { + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock); + + pCurrentObject = pNextObject; + + continue; + } + + KeQueryTickCount( &liCurrentTime); + + pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + if( pCurrentDirEntry->OpenReferenceCount > 0 || + ( pCurrentDirEntry->ObjectInformation->Fcb != NULL && + pCurrentDirEntry->ObjectInformation->Fcb->OpenReferenceCount > 0) || + liCurrentTime.QuadPart <= pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart || + liCurrentTime.QuadPart - pCurrentDirEntry->ObjectInformation->LastAccessCount.QuadPart < + pControlDeviceExt->Specific.Control.ObjectLifeTimeCount.QuadPart || + ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_DIRECTORY && + ( pCurrentDirEntry->ObjectInformation->Specific.Directory.DirectoryNodeListHead != NULL || + pCurrentDirEntry->ObjectInformation->Specific.Directory.ChildOpenReferenceCount > 0)) || + ( pCurrentDirEntry->ObjectInformation->FileType == AFS_FILE_TYPE_FILE && + pCurrentDirEntry->ObjectInformation->Fcb != NULL && + pCurrentDirEntry->ObjectInformation->Fcb->Specific.File.ExtentsDirtyCount > 0)) + { + + break; + } + + pCurrentDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + } + + if( pCurrentDirEntry != NULL) + { + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock); + + pCurrentObject = pNextObject; + + continue; + } + + pCurrentDirEntry = pCurrentObject->Specific.Directory.DirectoryNodeListHead; + + while( pCurrentDirEntry != NULL) + { + + pNextDirEntry = (AFSDirectoryCB *)pCurrentDirEntry->ListEntry.fLink; + + pCurrentChildObject = pCurrentDirEntry->ObjectInformation; + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPrimaryWorker Deleting DE %wZ Object %08lX\n", + &pCurrentDirEntry->NameInformation.FileName, + pCurrentChildObject); + + AFSDeleteDirEntry( pCurrentObject, + pCurrentDirEntry); + + if( pCurrentChildObject->ObjectReferenceCount == 0) + { + + if( pCurrentChildObject->Fcb != NULL) + { + + if( pCurrentChildObject->FileType == AFS_FILE_TYPE_FILE) + { + + AFSCleanupFcb( pCurrentChildObject->Fcb, + TRUE); + } + + AFSRemoveFcb( pCurrentChildObject->Fcb); + } + + if( pCurrentChildObject->FileType == AFS_FILE_TYPE_DIRECTORY && + pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB != NULL) + { + + if( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb != NULL) + { + + AFSRemoveFcb( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation->Fcb); + } + + AFSDeleteObjectInfo( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->ObjectInformation); + + ExDeleteResourceLite( &pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged->Lock); + + ExFreePool( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB->NonPaged); + + ExFreePool( pCurrentChildObject->Specific.Directory.PIOCtlDirectoryCB); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPrimaryWorker Deleting object %08lX\n", + pCurrentChildObject); + + AFSDeleteObjectInfo( pCurrentChildObject); + } + + pCurrentDirEntry = pNextDirEntry; + } + + pCurrentObject->Specific.Directory.DirectoryNodeListHead = NULL; + + pCurrentObject->Specific.Directory.DirectoryNodeListTail = NULL; + + pCurrentObject->Specific.Directory.ShortNameTree = NULL; + + pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseSensitiveTreeHead = NULL; + + pCurrentObject->Specific.Directory.DirectoryNodeHdr.CaseInsensitiveTreeHead = NULL; + + pCurrentObject->Specific.Directory.DirectoryNodeCount = 0; + + AFSDbgLogMsg( AFS_SUBSYSTEM_DIR_NODE_COUNT, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPrimaryWorker Reset count to 0 on parent FID %08lX-%08lX-%08lX-%08lX\n", + pCurrentObject->FileId.Cell, + pCurrentObject->FileId.Volume, + pCurrentObject->FileId.Vnode, + pCurrentObject->FileId.Unique); + + + // + // Clear our enumerated flag on this object so we retrieve info again on next access + // + + ClearFlag( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED); + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + } + else + { + + AFSReleaseResource( pCurrentObject->Specific.Directory.DirectoryNodeHdr.TreeLock); + + bReleaseVolumeLock = FALSE; + + break; + } + + AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock); + } + else + { + + // + // Try to grab the volume lock again ... no problem if we don't + // + + if( !AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock, + FALSE)) + { + + bReleaseVolumeLock = FALSE; + + break; + } + } + + if( pCurrentObject != &pVolumeCB->ObjectInformation) + { + + pCurrentObject = (AFSObjectInfoCB *)pCurrentObject->ListEntry.fLink; + + if( pCurrentObject == NULL && + pVolumeCB != AFSGlobalRoot) + { + + pCurrentObject = &pVolumeCB->ObjectInformation; + } + } + else + { + + pCurrentObject = NULL; + } + + continue; + } + else if( pCurrentObject->FileType == AFS_FILE_TYPE_FILE) + { + + if( BooleanFlagOn( pCurrentObject->Flags, AFS_OBJECT_FLAGS_DELETED) && + pCurrentObject->ObjectReferenceCount == 0 && + ( pCurrentObject->Fcb == NULL || + pCurrentObject->Fcb->OpenReferenceCount == 0)) + { + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock, + FALSE)) + { + + if( pCurrentObject->Fcb != NULL) + { + + AFSCleanupFcb( pCurrentObject->Fcb, + TRUE); + + AFSRemoveFcb( pCurrentObject->Fcb); + } + + AFSDeleteObjectInfo( pCurrentObject); + + AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock); + + pCurrentObject = pNextObject; + + continue; + } + else + { + + bReleaseVolumeLock = FALSE; + + break; + } + } + else if( pCurrentObject->Fcb != NULL) + { + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + + if( AFSAcquireExcl( pVolumeCB->ObjectInfoTree.TreeLock, + FALSE)) + { + + AFSCleanupFcb( pCurrentObject->Fcb, + FALSE); + + AFSConvertToShared( pVolumeCB->ObjectInfoTree.TreeLock); + + pCurrentObject = pNextObject; + + continue; + } + else + { + + bReleaseVolumeLock = FALSE; + + break; + } + } + } + + pCurrentObject = pNextObject; + } + + if( bReleaseVolumeLock) + { + + AFSReleaseResource( pVolumeCB->ObjectInfoTree.TreeLock); + } + } + + // + // Next volume cb + // + + AFSReleaseResource( pVolumeCB->VolumeLock); + + AFSAcquireShared( &pRDRDeviceExt->Specific.RDR.VolumeListLock, + TRUE); + + pVolumeCB = (AFSVolumeCB *)pVolumeCB->ListEntry.fLink; + } + + AFSReleaseResource( &pRDRDeviceExt->Specific.RDR.VolumeListLock); + + } // worker thread loop + + KeCancelTimer( &Timer); + + AFSDbgLogMsg( AFS_SUBSYSTEM_CLEANUP_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSPrimaryVolumeWorkerThread Exiting\n"); + + if( InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount) == 0) + { + + KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent, + 0, + FALSE); + } + + PsTerminateSystemThread( 0); + + return; +} + +void +AFSVolumeWorkerThread( IN PVOID Context) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSVolumeCB *pVolumeCB = (AFSVolumeCB * )Context; + AFSWorkQueueContext *pPoolContext = (AFSWorkQueueContext *)&pVolumeCB->VolumeWorkerContext; + AFSDeviceExt *pControlDeviceExt = NULL; + AFSDeviceExt *pRDRDeviceExt = NULL; + BOOLEAN exitThread = FALSE; + LARGE_INTEGER DueTime; + LONG TimeOut; + KTIMER Timer; + + pControlDeviceExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + + pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + + // + // Initialize the timer for the worker thread + // + + DueTime.QuadPart = -(5000); + + TimeOut = 5000; + + KeInitializeTimerEx( &Timer, + SynchronizationTimer); + + KeSetTimerEx( &Timer, + DueTime, + TimeOut, + NULL); + + // + // Indicate that we are initialized and ready + // + + KeSetEvent( &pPoolContext->WorkerThreadReady, + 0, + FALSE); + + // + // Indicate we are initialized + // + + SetFlag( pPoolContext->State, AFS_WORKER_INITIALIZED); + + while( BooleanFlagOn( pPoolContext->State, AFS_WORKER_PROCESS_REQUESTS)) + { + + ntStatus = KeWaitForSingleObject( &Timer, + Executive, + KernelMode, + FALSE, + NULL); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSVolumeWorkerThread Wait for queue items failed Status %08lX\n", ntStatus); + } + else + { + + // + // If we are in shutdown mode and the dirty flag is clear then get out now + // + + if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + break; + } + } + } // worker thread loop + + KeCancelTimer( &Timer); + + if( InterlockedDecrement( &pControlDeviceExt->Specific.Control.VolumeWorkerThreadCount) == 0) + { + + KeSetEvent( &pControlDeviceExt->Specific.Control.VolumeWorkerCloseEvent, + 0, + FALSE); + } + + PsTerminateSystemThread( 0); + + return; +} + +NTSTATUS +AFSInsertWorkitem( IN AFSWorkItem *WorkItem) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = NULL; + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertWorkitem Acquiring Control QueueLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.Library.QueueLock, + PsGetCurrentThread()); + + AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock, + TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertWorkitem Inserting work item %08lX Count %08lX\n", + WorkItem, + InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount)); + + if( pDevExt->Specific.Library.QueueTail != NULL) // queue already has nodes + { + + pDevExt->Specific.Library.QueueTail->next = WorkItem; + } + else // first node + { + + pDevExt->Specific.Library.QueueHead = WorkItem; + } + + WorkItem->next = NULL; + pDevExt->Specific.Library.QueueTail = WorkItem; + + // indicate that the queue has nodes + KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems), + 0, + FALSE); + + AFSReleaseResource( &pDevExt->Specific.Library.QueueLock); + + return ntStatus; +} + +NTSTATUS +AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = NULL; + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertIOWorkitem Acquiring Control QueueLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.Library.IOQueueLock, + PsGetCurrentThread()); + + AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock, + TRUE); + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertWorkitem Inserting IO work item %08lX Count %08lX\n", + WorkItem, + InterlockedIncrement( &pDevExt->Specific.Library.IOQueueItemCount)); + + if( pDevExt->Specific.Library.IOQueueTail != NULL) // queue already has nodes + { + + pDevExt->Specific.Library.IOQueueTail->next = WorkItem; + } + else // first node + { + + pDevExt->Specific.Library.IOQueueHead = WorkItem; + } + + WorkItem->next = NULL; + pDevExt->Specific.Library.IOQueueTail = WorkItem; + + // indicate that the queue has nodes + KeSetEvent( &(pDevExt->Specific.Library.IOWorkerQueueHasItems), + 0, + FALSE); + + AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock); + + return ntStatus; +} + +NTSTATUS +AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = NULL; + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertWorkitemAtHead Acquiring Control QueueLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.Library.QueueLock, + PsGetCurrentThread()); + + AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock, + TRUE); + + WorkItem->next = pDevExt->Specific.Library.QueueHead; + + pDevExt->Specific.Library.QueueHead = WorkItem; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSInsertWorkitemAtHead Inserting work item %08lX Count %08lX\n", + WorkItem, + InterlockedIncrement( &pDevExt->Specific.Library.QueueItemCount)); + + // + // indicate that the queue has nodes + // + + KeSetEvent( &(pDevExt->Specific.Library.WorkerQueueHasItems), + 0, + FALSE); + + AFSReleaseResource( &pDevExt->Specific.Library.QueueLock); + + return ntStatus; +} + +AFSWorkItem * +AFSRemoveWorkItem() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkItem *pWorkItem = NULL; + AFSDeviceExt *pDevExt = NULL; + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveWorkItem Acquiring Control QueueLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.Library.QueueLock, + PsGetCurrentThread()); + + AFSAcquireExcl( &pDevExt->Specific.Library.QueueLock, + TRUE); + + if( pDevExt->Specific.Library.QueueHead != NULL) // queue has nodes + { + + pWorkItem = pDevExt->Specific.Library.QueueHead; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveWorkItem Removing work item %08lX Count %08lX Thread %08lX\n", + pWorkItem, + InterlockedDecrement( &pDevExt->Specific.Library.QueueItemCount), + PsGetCurrentThreadId()); + + pDevExt->Specific.Library.QueueHead = pDevExt->Specific.Library.QueueHead->next; + + if( pDevExt->Specific.Library.QueueHead == NULL) // if queue just became empty + { + + pDevExt->Specific.Library.QueueTail = NULL; + + KeResetEvent(&(pDevExt->Specific.Library.WorkerQueueHasItems)); + } + } + else + { + KeResetEvent(&(pDevExt->Specific.Library.WorkerQueueHasItems)); + } + + AFSReleaseResource( &pDevExt->Specific.Library.QueueLock); + + return pWorkItem; +} + +AFSWorkItem * +AFSRemoveIOWorkItem() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkItem *pWorkItem = NULL; + AFSDeviceExt *pDevExt = NULL; + + pDevExt = (AFSDeviceExt *)AFSLibraryDeviceObject->DeviceExtension; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveIOWorkItem Acquiring Control QueueLock lock %08lX EXCL %08lX\n", + &pDevExt->Specific.Library.IOQueueLock, + PsGetCurrentThread()); + + AFSAcquireExcl( &pDevExt->Specific.Library.IOQueueLock, + TRUE); + + if( pDevExt->Specific.Library.IOQueueHead != NULL) // queue has nodes + { + + pWorkItem = pDevExt->Specific.Library.IOQueueHead; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSRemoveWorkItem Removing work item %08lX Count %08lX Thread %08lX\n", + pWorkItem, + InterlockedDecrement( &pDevExt->Specific.Library.IOQueueItemCount), + PsGetCurrentThreadId()); + + pDevExt->Specific.Library.IOQueueHead = pDevExt->Specific.Library.IOQueueHead->next; + + if( pDevExt->Specific.Library.IOQueueHead == NULL) // if queue just became empty + { + + pDevExt->Specific.Library.IOQueueTail = NULL; + + KeResetEvent(&(pDevExt->Specific.Library.IOWorkerQueueHasItems)); + } + } + else + { + KeResetEvent(&(pDevExt->Specific.Library.IOWorkerQueueHasItems)); + } + + AFSReleaseResource( &pDevExt->Specific.Library.IOQueueLock); + + return pWorkItem; +} + +NTSTATUS +AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = NULL; + BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST); + + // + // Submit the work item to the worker + // + + ntStatus = AFSInsertWorkitem( WorkItem); + + if( bWait) + { + + // + // Sync request so block on the work item event + // + + ntStatus = KeWaitForSingleObject( &WorkItem->Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = NULL; + BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST); + + // + // Submit the work item to the worker + // + + ntStatus = AFSInsertIOWorkitem( WorkItem); + + if( bWait) + { + + // + // Sync request so block on the work item event + // + + ntStatus = KeWaitForSingleObject( &WorkItem->Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDevExt = NULL; + BOOLEAN bWait = BooleanFlagOn( WorkItem->RequestFlags, AFS_SYNCHRONOUS_REQUEST); + + // + // Submit the work item to the worker + // + + ntStatus = AFSInsertWorkitemAtHead( WorkItem); + + if( bWait) + { + + // + // Sync request so block on the work item event + // + + ntStatus = KeWaitForSingleObject( &WorkItem->Event, + Executive, + KernelMode, + FALSE, + NULL); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueFlushExtents( IN AFSFcb *Fcb) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSWorkItem *pWorkItem = NULL; + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueFlushExtents Queuing request for FID %08lX-%08lX-%08lX-%08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique); + + // + // Increment our flush count here just to keep the number of items in the + // queue down. We'll decrement it just below. + // + + if( InterlockedIncrement( &Fcb->Specific.File.QueuedFlushCount) > 3) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueFlushExtents Max queued items for FID %08lX-%08lX-%08lX-%08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique); + + try_return( ntStatus); + } + + if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueFlushExtents Failing request, in shutdown\n"); + + try_return( ntStatus = STATUS_TOO_LATE); + } + + // + // Allocate our request structure and send it to the worker + // + + pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSWorkItem), + AFS_WORK_ITEM_TAG); + + if( pWorkItem == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueFlushExtents Failed to allocate work item\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pWorkItem, + sizeof( AFSWorkItem)); + + pWorkItem->Size = sizeof( AFSWorkItem); + + pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId(); + + pWorkItem->RequestType = AFS_WORK_FLUSH_FCB; + + pWorkItem->Specific.Fcb.Fcb = Fcb; + + InterlockedIncrement( &Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_FCB_REF_COUNTING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueFlushExtents Increment count on Fcb %08lX Cnt %d\n", + Fcb, + Fcb->OpenReferenceCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueFlushExtents Workitem %08lX for FID %08lX-%08lX-%08lX-%08lX\n", + pWorkItem, + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique); + + ntStatus = AFSQueueWorkerRequest( pWorkItem); + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueFlushExtents Request complete Status %08lX FID %08lX-%08lX-%08lX-%08lX\n", + Fcb->ObjectInformation->FileId.Cell, + Fcb->ObjectInformation->FileId.Volume, + Fcb->ObjectInformation->FileId.Vnode, + Fcb->ObjectInformation->FileId.Unique, + ntStatus); + + // + // Remove the count we added above + // + + if( InterlockedDecrement( &Fcb->Specific.File.QueuedFlushCount) == 0) + { + + KeSetEvent( &Fcb->NPFcb->Specific.File.QueuedFlushEvent, + 0, + FALSE); + } + + if( !NT_SUCCESS( ntStatus)) + { + + if( pWorkItem != NULL) + { + + InterlockedDecrement( &Fcb->OpenReferenceCount); + + ExFreePool( pWorkItem); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueFlushExtents Failed to queue request Status %08lX\n", ntStatus); + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueueFlushExtents\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueAsyncRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE CallerProcess) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkItem *pWorkItem = NULL; + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueAsyncRead Queuing request for Irp %08lX\n", + Irp); + + pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof(AFSWorkItem), + AFS_WORK_ITEM_TAG); + if (NULL == pWorkItem) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueAsyncRead Failed to allocate work item\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + RtlZeroMemory( pWorkItem, + sizeof(AFSWorkItem)); + + pWorkItem->Size = sizeof( AFSWorkItem); + + pWorkItem->RequestType = AFS_WORK_ASYNCH_READ; + + pWorkItem->Specific.AsynchIo.Device = DeviceObject; + + pWorkItem->Specific.AsynchIo.Irp = Irp; + + pWorkItem->Specific.AsynchIo.CallingProcess = CallerProcess; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueAsyncRead Workitem %08lX for Irp %08lX\n", + pWorkItem, + Irp); + + ntStatus = AFSQueueWorkerRequest( pWorkItem); + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueAsyncRead Request for Irp %08lX complete Status %08lX\n", + Irp, + ntStatus); + + if( !NT_SUCCESS( ntStatus)) + { + + if( pWorkItem != NULL) + { + + ExFreePool( pWorkItem); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueAsyncRead Failed to queue request Status %08lX\n", ntStatus); + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueueAsyncRead\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueAsyncWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE CallerProcess) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkItem *pWorkItem = NULL; + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueAsyncWrite Queuing request for Irp %08lX\n", + Irp); + + pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof(AFSWorkItem), + AFS_WORK_ITEM_TAG); + if (NULL == pWorkItem) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueAsyncWrite Failed to allocate work item\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + RtlZeroMemory( pWorkItem, + sizeof(AFSWorkItem)); + + pWorkItem->Size = sizeof( AFSWorkItem); + + pWorkItem->RequestType = AFS_WORK_ASYNCH_WRITE; + + pWorkItem->Specific.AsynchIo.Device = DeviceObject; + + pWorkItem->Specific.AsynchIo.Irp = Irp; + + pWorkItem->Specific.AsynchIo.CallingProcess = CallerProcess; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueAsyncWrite Workitem %08lX for Irp %08lX\n", + pWorkItem, + Irp); + + ntStatus = AFSQueueWorkerRequest( pWorkItem); + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueAsyncWrite Request for Irp %08lX complete Status %08lX\n", + Irp, + ntStatus); + + if( !NT_SUCCESS( ntStatus)) + { + + if( pWorkItem != NULL) + { + + ExFreePool( pWorkItem); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueAsyncWrite Failed to queue request Status %08lX\n", ntStatus); + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueueAsyncWrite\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueGlobalRootEnumeration() +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSWorkItem *pWorkItem = NULL; + + __try + { + + pWorkItem = (AFSWorkItem *) AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof(AFSWorkItem), + AFS_WORK_ITEM_TAG); + if (NULL == pWorkItem) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueGlobalRootEnumeration Failed to allocate work item\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + RtlZeroMemory( pWorkItem, + sizeof(AFSWorkItem)); + + pWorkItem->Size = sizeof( AFSWorkItem); + + pWorkItem->RequestType = AFS_WORK_ENUMERATE_GLOBAL_ROOT; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueGlobalRootEnumeration Workitem %08lX\n", + pWorkItem); + + ntStatus = AFSQueueWorkerRequest( pWorkItem); + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueGlobalRootEnumeration Request complete Status %08lX\n", + ntStatus); + + if( !NT_SUCCESS( ntStatus)) + { + + if( pWorkItem != NULL) + { + + ExFreePool( pWorkItem); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueGlobalRootEnumeration Failed to queue request Status %08lX\n", + ntStatus); + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueueGlobalRootEnumeration\n"); + } + + return ntStatus; +} + +NTSTATUS +AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject, + IN UCHAR FunctionCode, + IN ULONG RequestFlags, + IN AFSIoRun *IoRuns, + IN ULONG RunCount, + IN AFSGatherIo *GatherIo) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pRDRDeviceExt = (AFSDeviceExt *)AFSRDRDeviceObject->DeviceExtension; + AFSWorkItem *pWorkItem = NULL; + + __try + { + + if( BooleanFlagOn( pRDRDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueStartIos Failing request, in shutdown\n"); + + try_return( ntStatus = STATUS_TOO_LATE); + } + + // + // Allocate our request structure and send it to the worker + // + + pWorkItem = (AFSWorkItem *)AFSLibExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSWorkItem), + AFS_WORK_ITEM_TAG); + + if( pWorkItem == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSQueueStartIos Failed to allocate work item\n"); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pWorkItem, + sizeof( AFSWorkItem)); + + KeInitializeEvent( &pWorkItem->Event, + NotificationEvent, + FALSE); + + pWorkItem->Size = sizeof( AFSWorkItem); + + pWorkItem->ProcessID = (ULONGLONG)PsGetCurrentProcessId(); + + pWorkItem->RequestType = AFS_WORK_START_IOS; + + pWorkItem->Specific.CacheAccess.CacheFileObject = CacheFileObject; + + pWorkItem->Specific.CacheAccess.FunctionCode = FunctionCode; + + pWorkItem->Specific.CacheAccess.RequestFlags = RequestFlags; + + pWorkItem->Specific.CacheAccess.IoRuns = IoRuns; + + pWorkItem->Specific.CacheAccess.RunCount = RunCount; + + pWorkItem->Specific.CacheAccess.GatherIo = GatherIo; + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueStartIos Queuing IO Workitem %08lX\n", + pWorkItem); + + ntStatus = AFSQueueIOWorkerRequest( pWorkItem); + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_WORKER_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSQueueStartIos Request complete Status %08lX\n", + ntStatus); + + if( !NT_SUCCESS( ntStatus)) + { + + if( pWorkItem != NULL) + { + + ExFreePool( pWorkItem); + } + } + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + AFSDbgLogMsg( 0, + 0, + "EXCEPTION - AFSQueueStartIos\n"); + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp b/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp new file mode 100644 index 0000000000..12ff9e6f35 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp @@ -0,0 +1,1852 @@ +/* + * 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: AFSWrite.cpp +// + +#include "AFSCommon.h" + +static +NTSTATUS +AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN LARGE_INTEGER StartingByte, + IN ULONG ByteCount, + IN BOOLEAN ForceFlush); +static +NTSTATUS +AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN LARGE_INTEGER StartingByte, + IN ULONG ByteCount); + +static +NTSTATUS +AFSExtendingWrite( IN AFSFcb *Fcb, + IN PFILE_OBJECT FileObject, + IN LONGLONG NewLength); + +// +// Function: AFSWrite +// +// Description: +// +// This is the dispatch handler for the IRP_MJ_WRITE request +// +// Return: +// +// A status is returned for the function +// +NTSTATUS +AFSWrite( IN PDEVICE_OBJECT LibDeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + + __try + { + + ntStatus = AFSCommonWrite( AFSRDRDeviceObject, Irp, NULL); + } + __except( AFSExceptionFilter( GetExceptionCode(), GetExceptionInformation()) ) + { + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + + return ntStatus; +} + +NTSTATUS +AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE OnBehalfOf) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSDeviceExt *pDeviceExt = (AFSDeviceExt *)DeviceObject->DeviceExtension; + IO_STACK_LOCATION *pIrpSp; + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + AFSNonPagedFcb *pNPFcb = NULL; + ULONG ulByteCount = 0; + LARGE_INTEGER liStartingByte; + PFILE_OBJECT pFileObject; + BOOLEAN bPagingIo = FALSE; + BOOLEAN bNonCachedIo = FALSE; + BOOLEAN bReleaseMain = FALSE; + BOOLEAN bReleasePaging = FALSE; + BOOLEAN bExtendingWrite = FALSE; + BOOLEAN bCompleteIrp = TRUE; + BOOLEAN bForceFlush = FALSE; + BOOLEAN bLockOK; + BOOLEAN bMapped = TRUE; + HANDLE hCallingUser = OnBehalfOf; + ULONG ulExtensionLength = 0; + BOOLEAN bRetry = FALSE; + + pIrpSp = IoGetCurrentIrpStackLocation( Irp); + + __Enter + { + + pFileObject = pIrpSp->FileObject; + + // + // Extract the fileobject references + // + + pFcb = (AFSFcb *)pFileObject->FsContext; + pCcb = (AFSCcb *)pFileObject->FsContext2; + + ObReferenceObject( pFileObject); + + if( pFcb == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite Attempted write (%08lX) when pFcb == NULL\n", + Irp); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + pNPFcb = pFcb->NPFcb; + + // + // If we are in shutdown mode then fail the request + // + + if( BooleanFlagOn( pDeviceExt->DeviceFlags, AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "AFSCommonWrite (%08lX) Open request after shutdown\n", + Irp); + + try_return( ntStatus = STATUS_TOO_LATE); + } + + liStartingByte = pIrpSp->Parameters.Write.ByteOffset; + bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO); + bNonCachedIo = BooleanFlagOn( Irp->Flags, IRP_NOCACHE); + ulByteCount = pIrpSp->Parameters.Write.Length; + + if( pFcb->Header.NodeTypeCode != AFS_IOCTL_FCB && + pFcb->Header.NodeTypeCode != AFS_FILE_FCB && + pFcb->Header.NodeTypeCode != AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite Attempted write (%08lX) on an invalid node type %08lX\n", + Irp, + pFcb->Header.NodeTypeCode); + + try_return( ntStatus = STATUS_INVALID_DEVICE_REQUEST); + } + + // + // If this is a write against an IOCtl node then handle it + // in a different pathway + // + + if( pFcb->Header.NodeTypeCode == AFS_IOCTL_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Processing file (PIOCTL) Offset %I64X Length %08lX Irp Flags %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount, + Irp->Flags); + + ntStatus = AFSIOCtlWrite( DeviceObject, + Irp); + + try_return( ntStatus); + } + else if( pFcb->Header.NodeTypeCode == AFS_SPECIAL_SHARE_FCB) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Processing file (SHARE) Offset %I64X Length %08lX Irp Flags %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount, + Irp->Flags); + + ntStatus = AFSShareWrite( DeviceObject, + Irp); + + try_return( ntStatus); + } + + // + // Is the Cache not there yet? Exit. + // + if( !BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE) && + NULL == pDeviceExt->Specific.RDR.CacheFileObject) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Request failed due to AFS cache closed\n", + Irp); + + try_return( ntStatus = STATUS_TOO_LATE ); + } + + if( pFcb->ObjectInformation->VolumeCB != NULL && + BooleanFlagOn( pFcb->ObjectInformation->VolumeCB->VolumeInformation.Characteristics, FILE_READ_ONLY_DEVICE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Request failed due to read only volume\n", + Irp); + + try_return( ntStatus = STATUS_ACCESS_DENIED); + } + + // + // We need to know on whose behalf we have been called (which + // we will eventually tell to the server - for non paging + // writes). If we were posted then we were told. If this is + // the first time we saw the irp then we grab it now. + // + if( NULL == OnBehalfOf ) + { + + hCallingUser = PsGetCurrentProcessId(); + } + else + { + + hCallingUser = OnBehalfOf; + } + + // + // Check for zero length write + // + + if( ulByteCount == 0) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Request completed due to zero length\n", + Irp); + + try_return( ntStatus); + } + + // + // Is this Fcb valid??? + // + + if( BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_OBJECT_INVALID)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Failing request due to INVALID fcb\n", + Irp); + + Irp->IoStatus.Information = 0; + + try_return( ntStatus = STATUS_FILE_DELETED); + } + + if( BooleanFlagOn( pCcb->DirectoryCB->Flags, AFS_DIR_ENTRY_DELETED) || + BooleanFlagOn( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_DELETED)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Request failed due to file deleted\n", + Irp); + + try_return( ntStatus = STATUS_FILE_DELETED); + } + + if( FlagOn( pIrpSp->MinorFunction, IRP_MN_COMPLETE)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) IRP_MN_COMPLETE being processed\n", + Irp); + + CcMdlWriteComplete(pFileObject, &pIrpSp->Parameters.Write.ByteOffset, Irp->MdlAddress); + + // + // Mdl is now Deallocated + // + + Irp->MdlAddress = NULL; + + try_return( ntStatus = STATUS_SUCCESS ); + } + + // + // If we get a non cached IO for a cached file we should do a purge. + // For now we will just promote to cached + // + if( NULL != pFileObject->SectionObjectPointer->DataSectionObject && !bPagingIo && bNonCachedIo) + { + bNonCachedIo = FALSE; + bForceFlush = TRUE; + } + + if( (!bPagingIo && !bNonCachedIo)) + { + + if( pFileObject->PrivateCacheMap == NULL) + { + + __try + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite Initialize caching on Fcb %08lX FileObject %08lX\n", + pFcb, + pFileObject); + + CcInitializeCacheMap( pFileObject, + (PCC_FILE_SIZES)&pFcb->Header.AllocationSize, + FALSE, + AFSLibCacheManagerCallbacks, + pFcb); + + CcSetReadAheadGranularity( pFileObject, + READ_AHEAD_GRANULARITY); + + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Exception thrown while initializing cache map Status %08lX\n", + Irp, + ntStatus); + } + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + } + } + + while (!bNonCachedIo && !CcCanIWrite( pFileObject, + ulByteCount, + FALSE, + bRetry)) + { + static const LONGLONG llWriteDelay = (LONGLONG)-100000; + bRetry = TRUE; + KeDelayExecutionThread(KernelMode, FALSE, (PLARGE_INTEGER)&llWriteDelay); + } + + // + // Save off the PID if this is not a paging IO + // + + if( !bPagingIo && + ( pFcb->Specific.File.ExtentRequestProcessId == 0 || + ( PsGetCurrentProcessId() != AFSSysProcess && + pFcb->Specific.File.ExtentRequestProcessId != (ULONGLONG)PsGetCurrentProcessId()))) + { + + pFcb->Specific.File.ExtentRequestProcessId = (ULONGLONG)PsGetCurrentProcessId(); + + if( pFcb->Specific.File.ExtentRequestProcessId == (ULONGLONG)AFSSysProcess) + { + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_WARNING, + "%s Setting LastWriterExtentProcessId to system process for Fcb %p\n", + __FUNCTION__, + pFcb); + } + + pFcb->NPFcb->Specific.File.ExtentsRequestStatus = STATUS_SUCCESS; + } + + // + // We should be ready to go. So first of all ask for the extents + // Provoke a get of the extents - if we need to. + // + + /* + if( !bPagingIo && !bNonCachedIo) + { + + ntStatus = AFSRequestExtentsAsync( pFcb, &liStartingByte, ulByteCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Failed to request extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + } + */ + + // + // If they are not mapped and we are the Lazy Writer then just + // say "not now" + // + if (!bMapped && pFcb->Specific.File.LazyWriterThread == PsGetCurrentThread()) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Failing lazy writer for unmapped request\n", + Irp); + + try_return ( ntStatus = STATUS_FILE_LOCK_CONFLICT); + } + + // + // Take locks + // + // - if Paging then we need to nothing (the precalls will + // have acquired the paging resource), for clarity we will collect + // the paging resource + // - If extending Write then take the fileresource EX (EOF will change, Allocation will only move out) + // - Otherwise we collect the file shared, check against extending and + // + + bLockOK = FALSE; + + do + { + + if( !bPagingIo) + { + + bExtendingWrite = (((liStartingByte.QuadPart + ulByteCount) >= + pFcb->Header.FileSize.QuadPart) || + (liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE && + liStartingByte.HighPart == -1)) ; + } + + if( bPagingIo) + { + + //ASSERT( NULL != OnBehalfOf || ExIsResourceAcquiredLite( &pNPFcb->Resource )); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite Acquiring Fcb PagingIo lock %08lX SHARED %08lX\n", + &pNPFcb->PagingResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pNPFcb->PagingResource, + TRUE); + + bReleasePaging = TRUE; + + // + // We have the correct lock - we cannot have the wrong one + // + bLockOK = TRUE; + } + else if( bExtendingWrite) + { + // + // Check for lock inversion + // + + ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource )); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite Acquiring Fcb lock %08lX EXCL %08lX\n", + &pNPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireExcl( &pNPFcb->Resource, + TRUE); + + if (liStartingByte.LowPart == FILE_WRITE_TO_END_OF_FILE && + liStartingByte.HighPart == -1) + { + if (pFcb->Header.ValidDataLength.QuadPart > pFcb->Header.FileSize.QuadPart) + { + liStartingByte = pFcb->Header.ValidDataLength; + } + else + { + liStartingByte = pFcb->Header.FileSize; + } + } + bReleaseMain = TRUE; + + // + // We have the correct lock - even if we don't end up truncating + // + bLockOK = TRUE; + } + else + { + ASSERT( !ExIsResourceAcquiredLite( &pNPFcb->PagingResource )); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite Acquiring Fcb lock %08lX SHARED %08lX\n", + &pNPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireShared( &pNPFcb->Resource, + TRUE); + + bReleaseMain = TRUE; + + // + // Have things moved? Are we extending? If so, the the lock isn't OK + // + bLockOK = (liStartingByte.QuadPart + ulByteCount) < pFcb->Header.FileSize.QuadPart; + + if (!bLockOK) + { + AFSReleaseResource( &pNPFcb->Resource); + bReleaseMain = FALSE; + } + } + } + while (!bLockOK); + + // + // Check the BR locks on the file. + // + + if( !bPagingIo && + !FsRtlCheckLockForWriteAccess( &pFcb->Specific.File.FileLock, + Irp)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Request failed due to lock conflict\n", + Irp); + + try_return( ntStatus = STATUS_FILE_LOCK_CONFLICT); + } + + if( bExtendingWrite) + { + + ntStatus = AFSExtendingWrite( pFcb, pFileObject, (liStartingByte.QuadPart + ulByteCount)); + + if( !NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCommonWrite (%08lX) Failed extending write request Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + } + + // + // Fire off the request as appropriate + // + bCompleteIrp = FALSE; + + if( !bPagingIo && + !bNonCachedIo) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Processing CACHED request Offset %I64X Len %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount); + + ntStatus = AFSCachedWrite( DeviceObject, Irp, liStartingByte, ulByteCount, bForceFlush); + + } + else + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Processing NON-CACHED request Offset %I64X Len %08lX\n", + Irp, + liStartingByte.QuadPart, + ulByteCount); + + ntStatus = AFSNonCachedWrite( DeviceObject, Irp, liStartingByte, ulByteCount); + } + +try_exit: + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSCommonWrite (%08lX) Process complete Status %08lX\n", + Irp, + ntStatus); + + ObDereferenceObject(pFileObject); + + if( bReleaseMain) + { + + AFSReleaseResource( &pNPFcb->Resource); + } + + if( bReleasePaging) + { + + AFSReleaseResource( &pNPFcb->PagingResource); + } + + if( bCompleteIrp) + { + + AFSCompleteRequest( Irp, + ntStatus); + } + } + + return ntStatus; +} + +NTSTATUS +AFSIOCtlWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSPIOCtlIORequestCB stIORequestCB; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + AFSPIOCtlIOResultCB stIOResultCB; + ULONG ulBytesReturned = 0; + AFSFileID stParentFID; + + __Enter + { + + RtlZeroMemory( &stIORequestCB, + sizeof( AFSPIOCtlIORequestCB)); + + if( pIrpSp->Parameters.Write.Length == 0) + { + + // + // Nothing to do in this case + // + + try_return( ntStatus); + } + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSIOCtlWrite Acquiring Fcb lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Resource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + // + // Get the parent fid to pass to the cm + // + + RtlZeroMemory( &stParentFID, + sizeof( AFSFileID)); + + if( pFcb->ObjectInformation->ParentObjectInformation != NULL) + { + + // + // The parent directory FID of the node + // + + stParentFID = pFcb->ObjectInformation->ParentObjectInformation->FileId; + } + + // + // Set the control block up + // + + stIORequestCB.RequestId = pCcb->RequestID; + + if( pFcb->ObjectInformation->VolumeCB != NULL) + { + stIORequestCB.RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId; + } + + // + // Lock down the buffer + // + + stIORequestCB.MappedBuffer = AFSMapToService( Irp, + pIrpSp->Parameters.Write.Length); + + if( stIORequestCB.MappedBuffer == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + stIORequestCB.BufferLength = pIrpSp->Parameters.Write.Length; + + stIOResultCB.BytesProcessed = 0; + + ulBytesReturned = sizeof( AFSPIOCtlIOResultCB); + + // + // Issue the request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIOCTL_WRITE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + NULL, + &stParentFID, + (void *)&stIORequestCB, + sizeof( AFSPIOCtlIORequestCB), + &stIOResultCB, + &ulBytesReturned); + + if( !NT_SUCCESS( ntStatus)) + { + + try_return( ntStatus); + } + + // + // Update the length written + // + + Irp->IoStatus.Information = stIOResultCB.BytesProcessed; + +try_exit: + + if( stIORequestCB.MappedBuffer != NULL) + { + + AFSUnmapServiceMappedBuffer( stIORequestCB.MappedBuffer, + Irp->MdlAddress); + } + + if( pFcb != NULL) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + } + + return ntStatus; +} + +// +// This function is called when we know we have to read from the AFS Cache. +// +// It ensures that we have exents for the entirety of the write and +// then pins the extents into memory (meaning that although we may +// add we will not remove). Then it creates a scatter gather write +// and fires off the IRPs +// +static +NTSTATUS +AFSNonCachedWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN LARGE_INTEGER StartingByte, + IN ULONG ByteCount) +{ + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + VOID *pSystemBuffer = NULL; + BOOLEAN bPagingIo = BooleanFlagOn( Irp->Flags, IRP_PAGING_IO); + BOOLEAN bLocked = FALSE; + BOOLEAN bCompleteIrp = TRUE; + BOOLEAN bExtentsMapped = FALSE; + AFSGatherIo *pGatherIo = NULL; + AFSIoRun *pIoRuns = NULL; + AFSIoRun stIoRuns[AFS_MAX_STACK_IO_RUNS]; + ULONG extentsCount = 0, runCount = 0; + AFSExtent *pStartExtent = NULL; + AFSExtent *pIgnoreExtent = NULL; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = (AFSFcb *)pFileObject->FsContext; + AFSCcb *pCcb = (AFSCcb *)pFileObject->FsContext2; + BOOLEAN bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO); + AFSDeviceExt *pDevExt = (AFSDeviceExt *)DeviceObject->DeviceExtension; + ULONG ulRequestCount = 0; + LARGE_INTEGER liCurrentTime, liLastRequestTime; + AFSDeviceExt *pControlDevExt = (AFSDeviceExt *)AFSControlDeviceObject->DeviceExtension; + PFILE_OBJECT pCacheFileObject = NULL; + + __Enter + { + Irp->IoStatus.Information = 0; + + if (ByteCount > pDevExt->Specific.RDR.MaxIo.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Request %08lX Actual %08lX larger than MaxIO %I64X\n", + Irp, + ByteCount, + pIrpSp->Parameters.Write.Length, + pDevExt->Specific.RDR.MaxIo.QuadPart); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + + // + // Get the mapping for the buffer + // + pSystemBuffer = AFSLockSystemBuffer( Irp, + ByteCount); + + if( pSystemBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to map system buffer\n", + Irp); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + + // + // Provoke a get of the extents - if we need to. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Requesting extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ByteCount); + + ntStatus = AFSRequestExtentsAsync( pFcb, + &StartingByte, + ByteCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to request extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + KeQueryTickCount( &liLastRequestTime); + + while (TRUE) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Acquiring Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + ASSERT( !ExIsResourceAcquiredLite( &pFcb->NPFcb->Specific.File.ExtentsResource )); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, TRUE ); + bLocked = TRUE; + + pStartExtent = NULL; + pIgnoreExtent = NULL; + + if ( AFSDoExtentsMapRegion( pFcb, &StartingByte, ByteCount, &pStartExtent, &pIgnoreExtent )) + { + break; + } + + KeClearEvent( &pFcb->NPFcb->Specific.File.ExtentsRequestComplete ); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Releasing(1) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + bLocked= FALSE; + + // + // We will re-request the extents after 10 seconds of waiting for them + // + + KeQueryTickCount( &liCurrentTime); + + if( liCurrentTime.QuadPart - liLastRequestTime.QuadPart >= pControlDevExt->Specific.Control.ExtentRequestTimeCount.QuadPart) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Requesting extents, again, for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ByteCount); + + ntStatus = AFSRequestExtentsAsync( pFcb, + &StartingByte, + ByteCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to request extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + KeQueryTickCount( &liLastRequestTime); + } + + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Waiting for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ByteCount); + + // + // Wait for it + // + + ntStatus = AFSWaitForExtentMapping ( pFcb ); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite Failed wait for extents for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ByteCount, + ntStatus); + + try_return( ntStatus); + } + } + + // + // As per the read path - + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Extents located for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ByteCount); + + ntStatus = AFSGetExtents( pFcb, + &StartingByte, + ByteCount, + pStartExtent, + &extentsCount, + &runCount); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to retrieve mapped extents Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite (%08lX) Successfully retrieved map extents count %08lX run count %08lX\n", + Irp, + extentsCount, + runCount); + + if( BooleanFlagOn( AFSLibControlFlags, AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE)) + { + + Irp->IoStatus.Information = ByteCount; + +#if GEN_MD5 + // + // Setup the MD5 for each extent + // + + AFSSetupMD5Hash( pFcb, + pStartExtent, + extentsCount, + pSystemBuffer, + &StartingByte, + ByteCount); +#endif + + ntStatus = AFSProcessExtentRun( pSystemBuffer, + &StartingByte, + ByteCount, + pStartExtent, + TRUE); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to process extent run for non-persistent cache Status %08lX\n", + Irp, + ntStatus); + } + + try_return( ntStatus); + } + + // + // Retrieve the cache file object + // + + pCacheFileObject = AFSReferenceCacheFileObject(); + + if( pCacheFileObject == NULL) + { + + ntStatus = STATUS_DEVICE_NOT_READY; + + AFSDbgLogMsg( AFS_SUBSYSTEM_EXTENT_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite Failed to retrieve cache fileobject for fid %08lX-%08lX-%08lX-%08lX Offset %I64X Length %08lX Status %08lX\n", + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + StartingByte.QuadPart, + ByteCount, + ntStatus); + + try_return( ntStatus); + } + + if (runCount > AFS_MAX_STACK_IO_RUNS) + { + + pIoRuns = (AFSIoRun*) AFSExAllocatePoolWithTag( PagedPool, + runCount * sizeof( AFSIoRun ), + AFS_IO_RUN_TAG ); + if (NULL == pIoRuns) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to allocate IO run block\n", + Irp); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + } + else + { + + pIoRuns = stIoRuns; + } + + RtlZeroMemory( pIoRuns, runCount * sizeof( AFSIoRun )); + + ntStatus = AFSSetupIoRun( IoGetRelatedDeviceObject( pCacheFileObject), + Irp, + pSystemBuffer, + pIoRuns, + &StartingByte, + ByteCount, + pStartExtent, + &runCount ); + + if (!NT_SUCCESS(ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to initialize IO run block Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus ); + } + + AFSReferenceActiveExtents( pStartExtent, + extentsCount); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Releasing(2) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + bLocked = FALSE; + + pGatherIo = (AFSGatherIo*) AFSExAllocatePoolWithTag( NonPagedPool, + sizeof( AFSGatherIo), + AFS_GATHER_TAG); + + if (NULL == pGatherIo) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSNonCachedWrite (%08lX) Failed to allocate IO gather block\n", + Irp); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Acquiring(1) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + bLocked = TRUE; + + AFSDereferenceActiveExtents( pStartExtent, + extentsCount); + + try_return (ntStatus = STATUS_INSUFFICIENT_RESOURCES ); + } + + RtlZeroMemory( pGatherIo, sizeof( AFSGatherIo )); + + // + // Initialize count to 1, that was we won't get an early + // completion if the first irp completes before the second is + // queued. + // + pGatherIo->Count = 1; + pGatherIo->Status = STATUS_SUCCESS; + pGatherIo->MasterIrp = Irp; + pGatherIo->Synchronous = TRUE; + pGatherIo->CompleteMasterIrp = FALSE; + + bCompleteIrp = TRUE; + + if( pGatherIo->Synchronous) + { + KeInitializeEvent( &pGatherIo->Event, NotificationEvent, FALSE ); + } + +#if GEN_MD5 + // + // Setup the MD5 for each extent + // + + AFSSetupMD5Hash( pFcb, + pStartExtent, + extentsCount, + pSystemBuffer, + &StartingByte, + ByteCount); +#endif + + // + // Pre-emptively set up the count + // + + Irp->IoStatus.Information = ByteCount; + + ntStatus = AFSQueueStartIos( pCacheFileObject, + IRP_MJ_WRITE, + IRP_WRITE_OPERATION | IRP_SYNCHRONOUS_API, + pIoRuns, + runCount, + pGatherIo); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite (%08lX) AFSStartIos completed Status %08lX\n", + Irp, + ntStatus); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Acquiring(2) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + bLocked = TRUE; + + AFSDereferenceActiveExtents( pStartExtent, + extentsCount); + + try_return( ntStatus); + } + + // + // Wait for completion of All IOs we started. + // + + ntStatus = KeWaitForSingleObject( &pGatherIo->Event, + Executive, + KernelMode, + FALSE, + NULL); + + if( NT_SUCCESS( ntStatus)) + { + + ntStatus = pGatherIo->Status; + } + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Acquiring(3) Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSAcquireShared( &pFcb->NPFcb->Specific.File.ExtentsResource, + TRUE); + bLocked = TRUE; + + AFSDereferenceActiveExtents( pStartExtent, + extentsCount); + + try_return( ntStatus); + } + + // + // Since this is dirty we can mark the extents dirty now. + // AFSMarkDirty will dereference the extents. Do not call + // AFSDereferenceActiveExtents() in this code path. + // + + AFSMarkDirty( pFcb, + pStartExtent, + extentsCount, + &StartingByte); + + if (!bPagingIo) + { + // + // This was an uncached user write - tell the server to do + // the flush when the worker thread next wakes up + // + pFcb->Specific.File.LastServerFlush.QuadPart = 0; + } + + // + // All done + // + +try_exit: + + if( pCacheFileObject != NULL) + { + AFSReleaseCacheFileObject( pCacheFileObject); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite (%08lX) Completed request Status %08lX\n", + Irp, + ntStatus); + + if (NT_SUCCESS(ntStatus) && + !bPagingIo && + bSynchronousFo) + { + + pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount; + } + + if( bLocked) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Releasing Fcb extents lock %08lX SHARED %08lX\n", + &pFcb->NPFcb->Specific.File.ExtentsResource, + PsGetCurrentThread()); + + AFSReleaseResource( &pFcb->NPFcb->Specific.File.ExtentsResource ); + } + + if( pGatherIo) + { + AFSExFreePool(pGatherIo); + } + + if( NULL != pIoRuns && + stIoRuns != pIoRuns) + { + AFSExFreePool(pIoRuns); + } + + if( bCompleteIrp) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSNonCachedWrite Completing Irp %08lX Status %08lX Info %08lX\n", + Irp, + ntStatus, + Irp->IoStatus.Information); + + AFSCompleteRequest( Irp, ntStatus); + } + } + + return ntStatus; +} + +static +NTSTATUS +AFSCachedWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN LARGE_INTEGER StartingByte, + IN ULONG ByteCount, + IN BOOLEAN ForceFlush) +{ + PVOID pSystemBuffer = NULL; + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STATUS_BLOCK iosbFlush; + IO_STACK_LOCATION *pIrpSp = IoGetCurrentIrpStackLocation( Irp); + PFILE_OBJECT pFileObject = pIrpSp->FileObject; + AFSFcb *pFcb = (AFSFcb *)pFileObject->FsContext; + AFSCcb *pCcb = (AFSCcb *)pFileObject->FsContext2; + BOOLEAN bSynchronousFo = BooleanFlagOn( pFileObject->Flags, FO_SYNCHRONOUS_IO); + BOOLEAN bMapped = FALSE; + ULONG ulCurrentIO = 0, ulTotalLen = ByteCount; + PMDL pCurrentMdl = Irp->MdlAddress; + LARGE_INTEGER liCurrentOffset; + + __Enter + { + + Irp->IoStatus.Information = 0; + + if( BooleanFlagOn( pIrpSp->MinorFunction, IRP_MN_MDL)) + { + + __try + { + + CcPrepareMdlWrite( pFileObject, + &StartingByte, + ByteCount, + &Irp->MdlAddress, + &Irp->IoStatus); + + ntStatus = Irp->IoStatus.Status; + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) Exception thrown while preparing mdl write Status %08lX\n", + Irp, + ntStatus); + } + + if( !NT_SUCCESS( ntStatus)) + { + + // + // Free up any potentially allocated mdl's + // + + CcMdlWriteComplete( pFileObject, + &StartingByte, + Irp->MdlAddress); + + Irp->MdlAddress = NULL; + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) Failed to process MDL write Status %08lX\n", + Irp, + ntStatus); + } + + try_return( ntStatus); + } + + liCurrentOffset.QuadPart = StartingByte.QuadPart; + + while( ulTotalLen > 0) + { + + ntStatus = STATUS_SUCCESS; + + if( pCurrentMdl != NULL) + { + + pSystemBuffer = MmGetSystemAddressForMdlSafe( pCurrentMdl, + NormalPagePriority); + + ulCurrentIO = MmGetMdlByteCount( pCurrentMdl); + + if( ulCurrentIO > ulTotalLen) + { + ulCurrentIO = ulTotalLen; + } + } + else + { + + pSystemBuffer = AFSLockSystemBuffer( Irp, + ulTotalLen); + + ulCurrentIO = ulTotalLen; + } + + if( pSystemBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) Failed to lock system buffer\n", + Irp); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + __try + { + + if( !CcCopyWrite( pFileObject, + &liCurrentOffset, + ulCurrentIO, + TRUE, + pSystemBuffer)) + { + // + // Failed to process request. + // + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) Failed to issue CcCopyWrite %wZ @ %0I64X Status %08lX\n", + Irp, + &pFileObject->FileName, + liCurrentOffset.QuadPart, + Irp->IoStatus.Status); + + try_return( ntStatus = STATUS_UNSUCCESSFUL); + } + } + __except( EXCEPTION_EXECUTE_HANDLER) + { + + ntStatus = GetExceptionCode(); + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) CcCopyWrite Threw exception %wZ @ %0I64X Status %08lX\n", + Irp, + &pFileObject->FileName, + liCurrentOffset.QuadPart, + ntStatus); + } + + if( !NT_SUCCESS( ntStatus)) + { + try_return( ntStatus); + } + + if( ForceFlush) + { + + // + // We have detected a file we do a write through with. + // + + CcFlushCache(&pFcb->NPFcb->SectionObjectPointers, + &liCurrentOffset, + ulCurrentIO, + &iosbFlush); + + if( !NT_SUCCESS( iosbFlush.Status)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_IO_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSCachedWrite (%08lX) CcFlushCache failure %wZ FID %08lX-%08lX-%08lX-%08lX Status 0x%08lX Bytes 0x%08lX\n", + Irp, + &pFileObject->FileName, + pFcb->ObjectInformation->FileId.Cell, + pFcb->ObjectInformation->FileId.Volume, + pFcb->ObjectInformation->FileId.Vnode, + pFcb->ObjectInformation->FileId.Unique, + iosbFlush.Status, + iosbFlush.Information); + + try_return( ntStatus = iosbFlush.Status); + } + } + + if( ulTotalLen <= ulCurrentIO) + { + break; + } + + liCurrentOffset.QuadPart += ulCurrentIO; + + ulTotalLen -= ulCurrentIO; + + pCurrentMdl = pCurrentMdl->Next; + } + +try_exit: + + if( NT_SUCCESS( ntStatus)) + { + + Irp->IoStatus.Information = ByteCount; + + if( bSynchronousFo) + { + + pFileObject->CurrentByteOffset.QuadPart = StartingByte.QuadPart + ByteCount; + } + + // + // If this extended the Vdl, then update it accordingly + // + + if( StartingByte.QuadPart + ByteCount > pFcb->Header.ValidDataLength.QuadPart) + { + + pFcb->Header.ValidDataLength.QuadPart = StartingByte.QuadPart + ByteCount; + } + + if (BooleanFlagOn(pFileObject->Flags, (FO_NO_INTERMEDIATE_BUFFERING + FO_WRITE_THROUGH))) + { + // + // Write through asked for... Set things so that we get + // flush when the worker thread next wakes up + // + pFcb->Specific.File.LastServerFlush.QuadPart = 0; + } + + if( !BooleanFlagOn( pFcb->Flags, AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME)) + { + + SetFlag( pFcb->Flags, AFS_FCB_FLAG_UPDATE_WRITE_TIME); + + KeQuerySystemTime( &pFcb->ObjectInformation->LastWriteTime); + } + } + + AFSCompleteRequest( Irp, + ntStatus); + } + + return ntStatus; +} + +static +NTSTATUS +AFSExtendingWrite( IN AFSFcb *Fcb, + IN PFILE_OBJECT FileObject, + IN LONGLONG NewLength) +{ + LARGE_INTEGER liSaveFileSize = Fcb->Header.FileSize; + LARGE_INTEGER liSaveAllocation = Fcb->Header.AllocationSize; + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSCcb *pCcb = (AFSCcb *)FileObject->FsContext2; + + if( NewLength > Fcb->Header.AllocationSize.QuadPart) + { + + Fcb->Header.AllocationSize.QuadPart = NewLength; + + Fcb->ObjectInformation->AllocationSize = Fcb->Header.AllocationSize; + } + + if( NewLength > Fcb->Header.FileSize.QuadPart) + { + + Fcb->Header.FileSize.QuadPart = NewLength; + + Fcb->ObjectInformation->EndOfFile = Fcb->Header.FileSize; + } + + // + // Tell the server + // + + ntStatus = AFSUpdateFileInformation( &Fcb->ObjectInformation->ParentObjectInformation->FileId, + Fcb->ObjectInformation, + &Fcb->AuthGroup); + + AFSDbgLogMsg( AFS_SUBSYSTEM_LOCK_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSExtendingWrite Acquiring Fcb lock %08lX EXCL %08lX\n", + &Fcb->NPFcb->Resource, + PsGetCurrentThread()); + + if (NT_SUCCESS(ntStatus)) + { + + KeQuerySystemTime( &Fcb->ObjectInformation->ChangeTime); + + SetFlag( Fcb->Flags, AFS_FCB_FLAG_FILE_MODIFIED | AFS_FCB_FLAG_UPDATE_CHANGE_TIME); + + // + // If the file is currently cached, then let the MM know about the extension + // + + if( CcIsFileCached( FileObject)) + { + CcSetFileSizes( FileObject, + (PCC_FILE_SIZES)&Fcb->Header.AllocationSize); + } + } + else + { + Fcb->Header.FileSize = liSaveFileSize; + Fcb->Header.AllocationSize = liSaveAllocation; + } + + // + // DownConvert file resource to shared + // + ExConvertExclusiveToSharedLite( &Fcb->NPFcb->Resource); + + return ntStatus; +} + +NTSTATUS +AFSShareWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp) +{ + + NTSTATUS ntStatus = STATUS_SUCCESS; + AFSPIOCtlIORequestCB stIORequestCB; + PIO_STACK_LOCATION pIrpSp = IoGetCurrentIrpStackLocation( Irp); + AFSFcb *pFcb = NULL; + AFSCcb *pCcb = NULL; + AFSPipeIORequestCB *pIoRequest = NULL; + void *pBuffer = NULL; + AFSPipeIOResultCB stIoResult; + ULONG ulBytesReturned = 0; + + __Enter + { + + pFcb = (AFSFcb *)pIrpSp->FileObject->FsContext; + + pCcb = (AFSCcb *)pIrpSp->FileObject->FsContext2; + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSShareWrite On pipe %wZ Length %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + pIrpSp->Parameters.Write.Length); + + if( pIrpSp->Parameters.Write.Length == 0) + { + + // + // Nothing to do in this case + // + + try_return( ntStatus); + } + + // + // Retrieve the buffer for the read request + // + + pBuffer = AFSLockSystemBuffer( Irp, + pIrpSp->Parameters.Write.Length); + + if( pBuffer == NULL) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSShareWrite Failed to map buffer on pipe %wZ\n", + &pCcb->DirectoryCB->NameInformation.FileName); + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + AFSAcquireShared( &pFcb->NPFcb->Resource, + TRUE); + + pIoRequest = (AFSPipeIORequestCB *)AFSExAllocatePoolWithTag( PagedPool, + sizeof( AFSPipeIORequestCB) + + pIrpSp->Parameters.Write.Length, + AFS_GENERIC_MEMORY_14_TAG); + + if( pIoRequest == NULL) + { + + try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES); + } + + RtlZeroMemory( pIoRequest, + sizeof( AFSPipeIORequestCB) + pIrpSp->Parameters.Write.Length); + + pIoRequest->RequestId = pCcb->RequestID; + + pIoRequest->RootId = pFcb->ObjectInformation->VolumeCB->ObjectInformation.FileId; + + pIoRequest->BufferLength = pIrpSp->Parameters.Write.Length; + + RtlCopyMemory( (void *)((char *)pIoRequest + sizeof( AFSPipeIORequestCB)), + pBuffer, + pIrpSp->Parameters.Write.Length); + + stIoResult.BytesProcessed = 0; + + ulBytesReturned = sizeof( AFSPipeIOResultCB); + + // + // Issue the open request to the service + // + + ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_PIPE_WRITE, + AFS_REQUEST_FLAG_SYNCHRONOUS, + &pFcb->AuthGroup, + &pCcb->DirectoryCB->NameInformation.FileName, + NULL, + pIoRequest, + sizeof( AFSPipeIORequestCB) + + pIrpSp->Parameters.Write.Length, + &stIoResult, + &ulBytesReturned); + + if( !NT_SUCCESS( ntStatus)) + { + + AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING, + AFS_TRACE_LEVEL_ERROR, + "AFSShareWrite (%08lX) Failed service write Status %08lX\n", + Irp, + ntStatus); + + try_return( ntStatus); + } + + AFSDbgLogMsg( AFS_SUBSYSTEM_PIPE_PROCESSING, + AFS_TRACE_LEVEL_VERBOSE, + "AFSShareWrite Completed on pipe %wZ Length read %08lX\n", + &pCcb->DirectoryCB->NameInformation.FileName, + stIoResult.BytesProcessed); + + Irp->IoStatus.Information = stIoResult.BytesProcessed; + +try_exit: + + if( pFcb != NULL) + { + + AFSReleaseResource( &pFcb->NPFcb->Resource); + } + + if( pIoRequest != NULL) + { + + AFSExFreePool( pIoRequest); + } + } + + return ntStatus; +} diff --git a/src/WINNT/afsrdr/kernel/lib/Filesystem.rc b/src/WINNT/afsrdr/kernel/lib/Filesystem.rc new file mode 100644 index 0000000000..aca299616a --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/Filesystem.rc @@ -0,0 +1,15 @@ +/* + * Copyright 2010, Secure Endpoints Inc. + * All Rights Reserved. + * + * This software has been released under the terms of the MIT License. + */ + +/* Define VERSIONINFO resource */ + +#define AFS_VERINFO_FILE_DESCRIPTION "AFS Redirector Kernel Library" +#define AFS_VERINFO_NAME "AFSRedirLib" +#define AFS_VERINFO_FILENAME "AFSRedirLib.sys" + +#include "..\..\..\AFS_component_version_number.h" +#include "..\..\..\..\..\config\NTVersioninfo.rc" diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h new file mode 100644 index 0000000000..3bf182436d --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h @@ -0,0 +1,1450 @@ +/* + * 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. + */ + +#ifndef _AFS_COMMON_H +#define _AFS_COMMON_H + +// +// File: AFSCommon.h +// + +extern "C" +{ + +#define AFS_KERNEL_MODE + +#include +#include // for IoCreateDeviceSecure +#include + +#include "AFSDefines.h" + +#include "AFSUserDefines.h" + +#include "AFSUserIoctl.h" + +#include "AFSUserStructs.h" + +#include "AFSRedirCommonDefines.h" + +#include "AFSRedirCommonStructs.h" + +#include "AFSStructs.h" + +#include "AFSProvider.h" + +#ifndef NO_EXTERN +#include "AFSExtern.h" +#endif + +#define NTSTRSAFE_LIB +#include "ntstrsafe.h" + +NTSTATUS +ZwQueryInformationProcess( + __in HANDLE ProcessHandle, + __in PROCESSINFOCLASS ProcessInformationClass, + __out PVOID ProcessInformation, + __in ULONG ProcessInformationLength, + __out_opt PULONG ReturnLength +); + +NTSYSAPI +NTSTATUS +NTAPI +RtlAbsoluteToSelfRelativeSD( IN PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, + OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, + IN OUT PULONG BufferLength ); + +#ifndef FILE_OPEN_REPARSE_POINT +#define FILE_OPEN_REPARSE_POINT 0x00200000 +#endif +// +// AFSBTreeSupport.cpp Prototypes +// + +NTSTATUS +AFSLocateCaseSensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN ULONG Index, + IN OUT AFSDirectoryCB **DirEntry); + +NTSTATUS +AFSLocateCaseInsensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN ULONG Index, + IN OUT AFSDirectoryCB **DirEntry); + +NTSTATUS +AFSInsertCaseSensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSInsertCaseInsensitiveDirEntry( IN AFSDirectoryCB *RootNode, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSRemoveCaseSensitiveDirEntry( IN AFSDirectoryCB **RootNode, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSRemoveCaseInsensitiveDirEntry( IN AFSDirectoryCB **RootNode, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSLocateShortNameDirEntry( IN AFSDirectoryCB *RootNode, + IN ULONG Index, + IN OUT AFSDirectoryCB **DirEntry); + +NTSTATUS +AFSInsertShortNameDirEntry( IN AFSDirectoryCB *RootNode, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSRemoveShortNameDirEntry( IN AFSDirectoryCB **RootNode, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSLocateHashEntry( IN AFSBTreeEntry *TopNode, + IN ULONGLONG HashIndex, + IN OUT AFSBTreeEntry **TreeEntry); + +NTSTATUS +AFSInsertHashEntry( IN AFSBTreeEntry *TopNode, + IN AFSBTreeEntry *FileIDEntry); + +NTSTATUS +AFSRemoveHashEntry( IN AFSBTreeEntry **TopNode, + IN AFSBTreeEntry *FileIDEntry); + +// +// AFSInit.cpp Prototypes +// + +NTSTATUS +DriverEntry( IN PDRIVER_OBJECT DriverObj, + IN PUNICODE_STRING RegPath); + +void +AFSUnload( IN PDRIVER_OBJECT DriverObject); + +// +// AFSCommSupport.cpp Prototypes +// + +NTSTATUS +AFSEnumerateDirectory( IN GUID *AuthGroup, + IN AFSObjectInfoCB *ObjectInfoCB, + IN BOOLEAN FastQuery); + +NTSTATUS +AFSEnumerateDirectoryNoResponse( IN GUID *AuthGroup, + IN AFSFileID *FileId); + +NTSTATUS +AFSVerifyDirectoryContent( IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup); + +NTSTATUS +AFSNotifyFileCreate( IN GUID *AuthGroup, + IN AFSObjectInfoCB *ParentObjectInfo, + IN PLARGE_INTEGER FileSize, + IN ULONG FileAttributes, + IN UNICODE_STRING *FileName, + OUT AFSDirectoryCB **DirNode); + +NTSTATUS +AFSUpdateFileInformation( IN AFSFileID *ParentFid, + IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup); + +NTSTATUS +AFSNotifyDelete( IN AFSDirectoryCB *DirectoryCB, + IN BOOLEAN CheckOnly); + +NTSTATUS +AFSNotifyRename( IN AFSObjectInfoCB *ObjectInfo, + IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSObjectInfoCB *TargetParentObjectInfo, + IN AFSDirectoryCB *DirectoryCB, + IN UNICODE_STRING *TargetName, + OUT AFSFileID *UpdatedFID); + +NTSTATUS +AFSEvaluateTargetByID( IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup, + IN BOOLEAN FastCall, + OUT AFSDirEnumEntry **DirEnumEntry); + +NTSTATUS +AFSEvaluateTargetByName( IN GUID *AuthGroup, + IN AFSFileID *ParentFileId, + IN PUNICODE_STRING SourceName, + OUT AFSDirEnumEntry **DirEnumEntry); + +NTSTATUS +AFSRetrieveVolumeInformation( IN GUID *AuthGroup, + IN AFSFileID *FileID, + OUT AFSVolumeInfoCB *VolumeInformation); + +NTSTATUS +AFSNotifyPipeTransceive( IN AFSCcb *Ccb, + IN ULONG InputLength, + IN ULONG OutputLength, + IN void *InputDataBuffer, + OUT void *OutputDataBuffer, + OUT ULONG *BytesReturned); + +NTSTATUS +AFSNotifySetPipeInfo( IN AFSCcb *Ccb, + IN ULONG InformationClass, + IN ULONG InputLength, + IN void *DataBuffer); + +NTSTATUS +AFSNotifyQueryPipeInfo( IN AFSCcb *Ccb, + IN ULONG InformationClass, + IN ULONG OutputLength, + IN void *DataBuffer, + OUT ULONG *BytesReturned); + +NTSTATUS +AFSReleaseFid( IN AFSFileID *FileId); + +BOOLEAN +AFSIsExtentRequestQueued( IN AFSFileID *FileID, + IN LARGE_INTEGER *ExtentOffset, + IN ULONG Length); + +// +// AFSCreate.cpp Prototypes +// + +NTSTATUS +AFSCreate( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSCommonCreate( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSOpenRedirector( IN PIRP Irp, + IN AFSFcb **Fcb, + IN AFSCcb **Ccb); + +NTSTATUS +AFSOpenAFSRoot( IN PIRP Irp, + IN AFSFcb **Fcb, + IN AFSCcb **Ccb); + +NTSTATUS +AFSOpenRoot( IN PIRP Irp, + IN AFSVolumeCB *VolumeCB, + IN GUID *AuthGroup, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +NTSTATUS +AFSProcessCreate( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSVolumeCB *VolumeCB, + IN AFSDirectoryCB *ParentDirCB, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING ComponentName, + IN PUNICODE_STRING FullFileName, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +NTSTATUS +AFSOpenTargetDirectory( IN PIRP Irp, + IN AFSVolumeCB *VolumeCB, + IN AFSDirectoryCB *ParentDirectoryCB, + IN AFSDirectoryCB *TargetDirectoryCB, + IN UNICODE_STRING *TargetName, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +NTSTATUS +AFSProcessOpen( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSVolumeCB *VolumeCB, + IN AFSDirectoryCB *ParentDirCB, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +NTSTATUS +AFSProcessOverwriteSupersede( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN AFSVolumeCB *VolumeCB, + IN GUID *AuthGroup, + IN AFSDirectoryCB *ParentDirCB, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +NTSTATUS +AFSControlDeviceCreate( IN PIRP Irp); + +NTSTATUS +AFSOpenIOCtlFcb( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSDirectoryCB *ParentDirCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +NTSTATUS +AFSOpenSpecialShareFcb( IN PIRP Irp, + IN GUID *AuthGroup, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSFcb **Fcb, + OUT AFSCcb **Ccb); + +// +// AFSExtentsSupport.cpp Prototypes +// +VOID +AFSLockForExtentsTrim( IN AFSFcb *Fcb); + +PAFSExtent +AFSExtentForOffset( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN BOOLEAN ReturnPrevious); +BOOLEAN +AFSExtentContains( IN AFSExtent *Extent, IN PLARGE_INTEGER Offset); + + +NTSTATUS +AFSRequestExtents( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Size, + OUT BOOLEAN *FullyMApped); + +BOOLEAN AFSDoExtentsMapRegion(IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Size, + IN OUT AFSExtent **FirstExtent, + OUT AFSExtent **LastExtent); + +NTSTATUS +AFSRequestExtentsAsync( IN AFSFcb *Fcb, + IN PLARGE_INTEGER Offset, + IN ULONG Size); + +NTSTATUS +AFSWaitForExtentMapping ( IN AFSFcb *Fcb ); + +NTSTATUS +AFSProcessSetFileExtents( IN AFSSetFileExtentsCB *SetExtents ); + +NTSTATUS +AFSProcessReleaseFileExtents( IN PIRP Irp); + +NTSTATUS +AFSProcessExtentFailure( PIRP Irp); + +NTSTATUS +AFSProcessSetExtents( IN AFSFcb *pFcb, + IN ULONG Count, + IN AFSFileExtentCB *Result); + +NTSTATUS +AFSFlushExtents( IN AFSFcb *pFcb); + +NTSTATUS +AFSReleaseExtentsWithFlush( IN AFSFcb *Fcb); + +VOID +AFSMarkDirty( IN AFSFcb *pFcb, + IN AFSExtent *StartExtent, + IN ULONG ExtentsCount, + IN LARGE_INTEGER *StartingByte); + +BOOLEAN +AFSTearDownFcbExtents( IN AFSFcb *Fcb ) ; + +void +AFSTrimExtents( IN AFSFcb *Fcb, + IN PLARGE_INTEGER FileSize); + +void +AFSTrimSpecifiedExtents( IN AFSFcb *Fcb, + IN ULONG Count, + IN AFSFileExtentCB *Result); + +void +AFSReferenceActiveExtents( IN AFSExtent *StartExtent, + IN ULONG ExtentsCount); + +void +AFSDereferenceActiveExtents( IN AFSExtent *StartExtent, + IN ULONG ExtentsCount); + +void +AFSRemoveEntryDirtyList( IN AFSFcb *Fcb, + IN AFSExtent *Extent); + +#if GEN_MD5 +void +AFSSetupMD5Hash( IN AFSFcb *Fcb, + IN AFSExtent *StartExtent, + IN ULONG ExtentsCount, + IN void *SystemBuffer, + IN LARGE_INTEGER *ByteOffset, + IN ULONG ByteCount); +#endif + +// +// +// AFSIoSupp.cpp Prototypes +// +NTSTATUS +AFSGetExtents( IN AFSFcb *pFcb, + IN PLARGE_INTEGER Offset, + IN ULONG Length, + IN AFSExtent *From, + OUT ULONG *ExtentCount, + OUT ULONG *RunCount); + +NTSTATUS +AFSSetupIoRun( IN PDEVICE_OBJECT CacheDevice, + IN PIRP MasterIrp, + IN PVOID SystemBuffer, + IN OUT AFSIoRun *IoRun, + IN PLARGE_INTEGER Start, + IN ULONG Length, + IN AFSExtent *From, + IN OUT ULONG *RunCount); + +NTSTATUS +AFSStartIos( IN FILE_OBJECT *CacheFileObject, + IN UCHAR FunctionCode, + IN ULONG IrpFlags, + IN AFSIoRun *IoRun, + IN ULONG Count, + IN OUT AFSGatherIo *Gather); + +VOID +AFSCompleteIo( IN AFSGatherIo *Gather, + IN NTSTATUS Status); + +NTSTATUS +AFSProcessExtentRun( IN PVOID SystemBuffer, + IN PLARGE_INTEGER Start, + IN ULONG Length, + IN AFSExtent *From, + IN BOOLEAN WriteRequest); + +// +// AFSClose.cpp Prototypes +// + +NTSTATUS +AFSClose( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSFcbSupport.cpp Prototypes +// + +NTSTATUS +AFSInitFcb( IN AFSDirectoryCB *DirEntry, + IN OUT AFSFcb **Fcb); + +NTSTATUS +AFSInitVolume( IN GUID *AuthGroup, + IN AFSFileID *RootFid, + OUT AFSVolumeCB **VolumeCB); + +NTSTATUS +AFSRemoveVolume( IN AFSVolumeCB *VolumeCB); + +NTSTATUS +AFSInitRootFcb( IN ULONGLONG ProcessID, + IN AFSVolumeCB *VolumeCB); + +void +AFSRemoveRootFcb( IN AFSFcb *RootFcb); + +NTSTATUS +AFSInitCcb( IN OUT AFSCcb **Ccb); + +void +AFSRemoveFcb( IN AFSFcb *Fcb); + +NTSTATUS +AFSRemoveCcb( IN AFSCcb *Ccb); + +// +// AFSNameSupport.cpp Prototypes +// + +NTSTATUS +AFSLocateNameEntry( IN GUID *AuthGroup, + IN PFILE_OBJECT FileObject, + IN UNICODE_STRING *RootPathName, + IN UNICODE_STRING *ParsedPathName, + IN AFSNameArrayHdr *NameArray, + IN ULONG Flags, + OUT AFSVolumeCB **VolumeCB, + IN OUT AFSDirectoryCB **ParentDirectoryCB, + OUT AFSDirectoryCB **DirectoryCB, + OUT PUNICODE_STRING ComponentName); + +NTSTATUS +AFSCreateDirEntry( IN GUID *AuthGroup, + IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *ParentDirCB, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING ComponentName, + IN ULONG Attributes, + IN OUT AFSDirectoryCB **DirEntry); + +void +AFSInsertDirectoryNode( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry, + IN BOOLEAN InsertInEnumList); + +NTSTATUS +AFSDeleteDirEntry( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSRemoveDirNodeFromParent( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry, + IN BOOLEAN RemoveFromEnumList); + +NTSTATUS +AFSFixupTargetName( IN OUT PUNICODE_STRING FileName, + IN OUT PUNICODE_STRING TargetFileName); + +NTSTATUS +AFSParseName( IN PIRP Irp, + IN GUID *AuthGroup, + OUT PUNICODE_STRING FileName, + OUT PUNICODE_STRING ParsedFileName, + OUT PUNICODE_STRING RootFileName, + OUT ULONG *ParseFlags, + OUT AFSVolumeCB **VolumeCB, + OUT AFSDirectoryCB **ParentDirectoryCB, + OUT AFSNameArrayHdr **NameArray); + +NTSTATUS +AFSCheckCellName( IN GUID *AuthGroup, + IN UNICODE_STRING *CellName, + OUT AFSDirectoryCB **ShareDirEntry); + +NTSTATUS +AFSBuildMountPointTarget( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirectoryCB, + OUT AFSVolumeCB **VolumeCB); + +NTSTATUS +AFSBuildRootVolume( IN GUID *AuthGroup, + IN AFSFileID *FileId, + OUT AFSVolumeCB **TargetVolumeCB); + +NTSTATUS +AFSProcessDFSLink( IN AFSDirectoryCB *DirEntry, + IN PFILE_OBJECT FileObject, + IN UNICODE_STRING *RemainingPath); + +// +// AFSNetworkProviderSupport.cpp +// + +NTSTATUS +AFSAddConnection( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN OUT PULONG ResultStatus, + IN OUT ULONG_PTR *ReturnOutputBufferLength); + +NTSTATUS +AFSCancelConnection( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN OUT AFSCancelConnectionResultCB *ConnectionResult, + IN OUT ULONG_PTR *ReturnOutputBufferLength); + +NTSTATUS +AFSGetConnection( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN OUT WCHAR *RemoteName, + IN ULONG RemoteNameBufferLength, + IN OUT ULONG_PTR *ReturnOutputBufferLength); + +NTSTATUS +AFSListConnections( IN OUT AFSNetworkProviderConnectionCB *ConnectCB, + IN ULONG ConnectionBufferLength, + IN OUT ULONG_PTR *ReturnOutputBufferLength); + +void +AFSInitializeConnectionInfo( IN AFSProviderConnectionCB *Connection, + IN ULONG DisplayType); + +AFSProviderConnectionCB * +AFSLocateEnumRootEntry( IN UNICODE_STRING *RemoteName); + +NTSTATUS +AFSEnumerateConnection( IN OUT AFSNetworkProviderConnectionCB *ConnectCB, + IN AFSProviderConnectionCB *RootConnection, + IN ULONG BufferLength, + OUT PULONG CopiedLength); + +NTSTATUS +AFSGetConnectionInfo( IN AFSNetworkProviderConnectionCB *ConnectCB, + IN ULONG BufferLength, + IN OUT ULONG_PTR *ReturnOutputBufferLength); + +BOOLEAN +AFSIsDriveMapped( IN WCHAR DriveMapping); + +// +// AFSRead.cpp Prototypes +// + +NTSTATUS +AFSCommonRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE OnBehalfOf); + +NTSTATUS +AFSRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + + +NTSTATUS +AFSIOCtlRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSShareRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSWrite.cpp Prototypes +// + +NTSTATUS +AFSCommonWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE CallingUser); + +NTSTATUS +AFSWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSIOCtlWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSShareWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSFileInfo.cpp Prototypes +// + +NTSTATUS +AFSQueryFileInfo( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSQueryBasicInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_BASIC_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryStandardInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_STANDARD_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryInternalInfo( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_INTERNAL_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryEaInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_EA_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryPositionInfo( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_POSITION_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryNameInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_NAME_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryShortNameInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_NAME_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryNetworkInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT PFILE_NETWORK_OPEN_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryStreamInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT FILE_STREAM_INFORMATION *Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryAccess( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_ACCESS_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryMode( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_MODE_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryAlignment( IN PIRP Irp, + IN AFSFcb *Fcb, + IN OUT PFILE_ALIGNMENT_INFORMATION Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryAttribTagInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT FILE_ATTRIBUTE_TAG_INFORMATION *Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSQueryRemoteProtocolInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB, + IN OUT FILE_REMOTE_PROTOCOL_INFORMATION *Buffer, + IN OUT PLONG Length); + +NTSTATUS +AFSSetFileInfo( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSSetBasicInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSSetDispositionInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSSetRenameInfo( IN PIRP Irp); + +NTSTATUS +AFSSetPositionInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSSetAllocationInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSSetEndOfFileInfo( IN PIRP Irp, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSProcessShareSetInfo( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb); + +NTSTATUS +AFSProcessShareQueryInfo( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb); + +NTSTATUS +AFSProcessPIOCtlQueryInfo( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb, + IN OUT LONG *Length); + +// +// AFSEa.cpp Prototypes +// + +NTSTATUS +AFSQueryEA( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSSetEA( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSFlushBuffers.cpp Prototypes +// + +NTSTATUS +AFSFlushBuffers( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSVolumeInfo.cpp Prototypes +// + +NTSTATUS +AFSQueryVolumeInfo( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSSetVolumeInfo( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSQueryFsVolumeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_VOLUME_INFORMATION Buffer, + IN OUT PULONG Length); + +NTSTATUS +AFSQueryFsSizeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_SIZE_INFORMATION Buffer, + IN OUT PULONG Length); + +NTSTATUS +AFSQueryFsDeviceInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_DEVICE_INFORMATION Buffer, + IN OUT PULONG Length); + +NTSTATUS +AFSQueryFsAttributeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_ATTRIBUTE_INFORMATION Buffer, + IN OUT PULONG Length); + +NTSTATUS +AFSQueryFsFullSizeInfo( IN AFSVolumeInfoCB *VolumeInfo, + IN PFILE_FS_FULL_SIZE_INFORMATION Buffer, + IN OUT PULONG Length); + +// +// AFSDirControl.cpp Prototypes +// + +NTSTATUS +AFSDirControl( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSQueryDirectory( IN PIRP Irp); + +NTSTATUS +AFSNotifyChangeDirectory( IN PIRP Irp); + +AFSDirectoryCB * +AFSLocateNextDirEntry( IN AFSObjectInfoCB *ObjectInfo, + IN AFSCcb *Ccb); + +AFSDirectoryCB * +AFSLocateDirEntryByIndex( IN AFSObjectInfoCB *ObjectInfo, + IN AFSCcb *Ccb, + IN ULONG DirIndex); + +NTSTATUS +AFSSnapshotDirectory( IN AFSFcb *Fcb, + IN AFSCcb *Ccb); + +NTSTATUS +AFSFsRtlNotifyFullChangeDirectory( IN AFSObjectInfoCB *ObjectInfo, + IN AFSCcb *Context, + IN BOOLEAN WatchTree, + IN ULONG CompletionFilter, + IN PIRP NotifyIrp); + +void +AFSFsRtlNotifyFullReportChange( IN AFSObjectInfoCB *ObjectInfo, + IN AFSCcb *Ccb, + IN ULONG NotifyFilter, + IN ULONG NotificationAction); + +BOOLEAN +AFSNotifyReportChangeCallback( IN void *NotifyContext, + IN void *FilterContext); + +BOOLEAN +AFSIsNameInSnapshot( IN AFSSnapshotHdr *SnapshotHdr, + IN ULONG HashIndex); + +// +// AFSFSControl.cpp Prototypes +// + +NTSTATUS +AFSFSControl( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSProcessUserFsRequest( IN PIRP Irp); + +NTSTATUS +AFSProcessShareFsCtrl( IN IRP *Irp, + IN AFSFcb *Fcb, + IN AFSCcb *Ccb); + +// +// AFSDevControl.cpp Prototypes +// + +NTSTATUS +AFSDevControl( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSInternalDevControl.cpp Prototypes +// + +NTSTATUS +AFSInternalDevControl( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSShutdown.cpp Prototypes +// + +NTSTATUS +AFSShutdown( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + + +NTSTATUS +AFSShutdownFilesystem( void); + +// +// AFSLockControl.cpp Prototypes +// + +NTSTATUS +AFSLockControl( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSCleanup.cpp Prototypes +// + +NTSTATUS +AFSCleanup( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSSecurity.cpp Prototypes +// + +NTSTATUS +AFSQuerySecurity( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSSetSecurity( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSSystemControl.cpp Prototypes +// + +NTSTATUS +AFSSystemControl( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSQuota.cpp Prototypes +// + +NTSTATUS +AFSQueryQuota( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSSetQuota( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +// +// AFSGeneric.cpp Prototypes +// + +ULONG +AFSExceptionFilter( IN ULONG Code, + IN PEXCEPTION_POINTERS ExceptPtrs); + +BOOLEAN +AFSAcquireExcl( IN PERESOURCE Resource, + IN BOOLEAN wait); + +BOOLEAN +AFSAcquireSharedStarveExclusive( IN PERESOURCE Resource, + IN BOOLEAN Wait); + +BOOLEAN +AFSAcquireShared( IN PERESOURCE Resource, + IN BOOLEAN wait); + +void +AFSReleaseResource( IN PERESOURCE Resource); + +void +AFSConvertToShared( IN PERESOURCE Resource); + +void +AFSCompleteRequest( IN PIRP Irp, + IN ULONG Status); + +void +AFSBuildCRCTable( void); + +ULONG +AFSGenerateCRC( IN PUNICODE_STRING FileName, + IN BOOLEAN UpperCaseName); + +void * +AFSLockSystemBuffer( IN PIRP Irp, + IN ULONG Length); + +void * +AFSLockUserBuffer( IN void *UserBuffer, + IN ULONG BufferLength, + OUT MDL ** Mdl); + +void * +AFSMapToService( IN PIRP Irp, + IN ULONG ByteCount); + +NTSTATUS +AFSUnmapServiceMappedBuffer( IN void *MappedBuffer, + IN PMDL Mdl); + +NTSTATUS +AFSInitializeLibraryDevice( void); + +NTSTATUS +AFSRemoveLibraryDevice( void); + +NTSTATUS +AFSDefaultDispatch( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp); + +NTSTATUS +AFSInitializeGlobalDirectoryEntries( void); + +AFSDirectoryCB * +AFSInitDirEntry( IN AFSObjectInfoCB *ParentObjectInfo, + IN PUNICODE_STRING FileName, + IN PUNICODE_STRING TargetName, + IN AFSDirEnumEntry *DirEnumEntry, + IN ULONG FileIndex); + +BOOLEAN +AFSCheckForReadOnlyAccess( IN ACCESS_MASK DesiredAccess, + IN BOOLEAN DirectoryEntry); + +NTSTATUS +AFSEvaluateNode( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSValidateSymLink( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirEntry); + +NTSTATUS +AFSInvalidateCache( IN AFSInvalidateCacheCB *InvalidateCB); + +BOOLEAN +AFSIsChildOfParent( IN AFSFcb *Dcb, + IN AFSFcb *Fcb); + +inline +ULONGLONG +AFSCreateHighIndex( IN AFSFileID *FileID); + +inline +ULONGLONG +AFSCreateLowIndex( IN AFSFileID *FileID); + +BOOLEAN +AFSCheckAccess( IN ACCESS_MASK DesiredAccess, + IN ACCESS_MASK GrantedAccess, + IN BOOLEAN DirectoryEntry); + +NTSTATUS +AFSGetDriverStatus( IN AFSDriverStatusRespCB *DriverStatus); + +NTSTATUS +AFSSubstituteSysName( IN UNICODE_STRING *ComponentName, + IN UNICODE_STRING *SubstituteName, + IN ULONG StringIndex); + +NTSTATUS +AFSSubstituteNameInPath( IN OUT UNICODE_STRING *FullPathName, + IN OUT UNICODE_STRING *ComponentName, + IN UNICODE_STRING *SubstituteName, + IN OUT UNICODE_STRING *RemainingPath, + IN BOOLEAN FreePathName); + +NTSTATUS +AFSInvalidateVolume( IN AFSVolumeCB *VolumeCB, + IN ULONG Reason); + +NTSTATUS +AFSVerifyEntry( IN GUID *AuthGroup, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSSetVolumeState( IN AFSVolumeStatusCB *VolumeStatus); + +NTSTATUS +AFSSetNetworkState( IN AFSNetworkStatusCB *NetworkStatus); + +NTSTATUS +AFSValidateDirectoryCache( IN AFSObjectInfoCB *ObjectInfo, + IN GUID *AuthGroup); + +BOOLEAN +AFSIsVolumeFID( IN AFSFileID *FileID); + +BOOLEAN +AFSIsFinalNode( IN AFSFcb *Fcb); + +NTSTATUS +AFSUpdateMetaData( IN AFSDirectoryCB *DirEntry, + IN AFSDirEnumEntry *DirEnumEntry); + +NTSTATUS +AFSValidateEntry( IN AFSDirectoryCB *DirEntry, + IN GUID *AuthGroup, + IN BOOLEAN PurgeContent, + IN BOOLEAN FastCall); + +AFSDirectoryCB * +AFSGetSpecialShareNameEntry( IN UNICODE_STRING *ShareName, + IN UNICODE_STRING *SecondaryName); + +NTSTATUS +AFSInitializeSpecialShareNameList( void); + +void +AFSWaitOnQueuedFlushes( IN AFSFcb *Fcb); + +void +AFSWaitOnQueuedReleases( void); + +BOOLEAN +AFSIsEqualFID( IN AFSFileID *FileId1, + IN AFSFileID *FileId2); + +NTSTATUS +AFSResetDirectoryContent( IN AFSObjectInfoCB *ObjectInfoCB); + +NTSTATUS +AFSEnumerateGlobalRoot( IN GUID *AuthGroup); + +BOOLEAN +AFSIsRelativeName( IN UNICODE_STRING *Name); + +void +AFSUpdateName( IN UNICODE_STRING *Name); + +NTSTATUS +AFSUpdateTargetName( IN OUT UNICODE_STRING *TargetName, + IN OUT ULONG *Flags, + IN WCHAR *NameBuffer, + IN USHORT NameLength); + +AFSNameArrayHdr * +AFSInitNameArray( IN AFSDirectoryCB *DirectoryCB, + IN ULONG InitialElementCount); + +NTSTATUS +AFSPopulateNameArray( IN AFSNameArrayHdr *NameArray, + IN UNICODE_STRING *Path, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSPopulateNameArrayFromRelatedArray( IN AFSNameArrayHdr *NameArray, + IN AFSNameArrayHdr *RelatedNameArray, + IN AFSDirectoryCB *DirectoryCB); + +NTSTATUS +AFSFreeNameArray( IN AFSNameArrayHdr *NameArray); + +NTSTATUS +AFSInsertNextElement( IN AFSNameArrayHdr *NameArray, + IN AFSDirectoryCB *DirEntry); + +void +AFSReplaceCurrentElement( IN AFSNameArrayHdr *NameArray, + IN AFSDirectoryCB *DirectoryCB); + +AFSDirectoryCB * +AFSBackupEntry( IN AFSNameArrayHdr *NameArray); + +AFSDirectoryCB * +AFSGetParentEntry( IN AFSNameArrayHdr *NameArray); + +void +AFSResetNameArray( IN AFSNameArrayHdr *NameArray, + IN AFSDirectoryCB *DirEntry); + +void +AFSDumpNameArray( IN IN AFSNameArrayHdr *NameArray); + +void +AFSSetEnumerationEvent( IN AFSFcb *Fcb); + +void +AFSClearEnumerationEvent( IN AFSFcb *Fcb); + +BOOLEAN +AFSIsEnumerationInProcess( IN AFSObjectInfoCB *ObjectInfo); + +NTSTATUS +AFSVerifyVolume( IN ULONGLONG ProcessId, + IN AFSVolumeCB *VolumeCB); + +NTSTATUS +AFSInitPIOCtlDirectoryCB( IN AFSObjectInfoCB *ObjectInfo); + +NTSTATUS +AFSRetrieveFileAttributes( IN AFSDirectoryCB *ParentDirectoryCB, + IN AFSDirectoryCB *DirectoryCB, + IN UNICODE_STRING *ParentPathName, + IN AFSNameArrayHdr *RelatedNameArray, + OUT AFSFileInfoCB *FileInfo); + +AFSObjectInfoCB * +AFSAllocateObjectInfo( IN AFSObjectInfoCB *ParentObjectInfo, + IN ULONGLONG HashIndex); + +void +AFSDeleteObjectInfo( IN AFSObjectInfoCB *ObjectInfo); + +NTSTATUS +AFSEvaluateRootEntry( IN AFSDirectoryCB *DirectoryCB, + OUT AFSDirectoryCB **TargetDirEntry); + +NTSTATUS +AFSCleanupFcb( IN AFSFcb *Fcb, + IN BOOLEAN ForceFlush); + +NTSTATUS +AFSUpdateDirEntryName( IN AFSDirectoryCB *DirectoryCB, + IN UNICODE_STRING *NewFileName); + +NTSTATUS +AFSReadCacheFile( IN void *ReadBuffer, + IN LARGE_INTEGER *ReadOffset, + IN ULONG RequestedDataLength, + IN OUT PULONG BytesRead); + +NTSTATUS +AFSIrpComplete( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context); + +BOOLEAN +AFSIsDirectoryEmptyForDelete( IN AFSFcb *Fcb); + +void +AFSRemoveNameEntry( IN AFSObjectInfoCB *ParentObjectInfo, + IN AFSDirectoryCB *DirEntry); + +LARGE_INTEGER +AFSGetAuthenticationId( void); + +void +AFSUnwindFileInfo( IN AFSFcb *Fcb, + IN AFSCcb *Ccb); + +BOOLEAN +AFSValidateDirList( IN AFSObjectInfoCB *ObjectInfo); + +PFILE_OBJECT +AFSReferenceCacheFileObject( void); + +void +AFSReleaseCacheFileObject( IN PFILE_OBJECT CacheFileObject); + +NTSTATUS +AFSInitializeLibrary( IN AFSLibraryInitCB *LibraryInit); + +NTSTATUS +AFSCloseLibrary( void); + +NTSTATUS +AFSDefaultLogMsg( IN ULONG Subsystem, + IN ULONG Level, + IN PCCH Format, + ...); + +NTSTATUS +AFSGetObjectStatus( IN AFSGetStatusInfoCB *GetStatusInfo, + IN ULONG InputBufferLength, + IN AFSStatusInfoCB *StatusInfo, + OUT ULONG *ReturnLength); + +NTSTATUS +AFSCheckSymlinkAccess( IN AFSDirectoryCB *ParentDirectoryCB, + IN UNICODE_STRING *ComponentName); + +NTSTATUS +AFSRetrieveFinalComponent( IN UNICODE_STRING *FullPathName, + OUT UNICODE_STRING *ComponentName); + +void +AFSDumpTraceFiles_Default( void); + +void * +AFSLibExAllocatePoolWithTag( IN POOL_TYPE PoolType, + IN SIZE_T NumberOfBytes, + IN ULONG Tag); + +BOOLEAN +AFSValidNameFormat( IN UNICODE_STRING *FileName); + +NTSTATUS +AFSCreateDefaultSecurityDescriptor( void); + +// +// AFSWorker.cpp Prototypes +// + +NTSTATUS +AFSInitializeWorkerPool( void); + +NTSTATUS +AFSRemoveWorkerPool( void); + +NTSTATUS +AFSInitWorkerThread( IN AFSWorkQueueContext *PoolContext, + IN PKSTART_ROUTINE WorkerRoutine); + +NTSTATUS +AFSInitVolumeWorker( IN AFSVolumeCB *VolumeCB); + +NTSTATUS +AFSShutdownWorkerThread( IN AFSWorkQueueContext *PoolContext); + +NTSTATUS +AFSShutdownIOWorkerThread( IN AFSWorkQueueContext *PoolContext); + +NTSTATUS +AFSShutdownVolumeWorker( IN AFSVolumeCB *VolumeCB); + +void +AFSWorkerThread( IN PVOID Context); + +void +AFSIOWorkerThread( IN PVOID Context); + +void +AFSPrimaryVolumeWorkerThread( IN PVOID Context); + +void +AFSVolumeWorkerThread( IN PVOID Context); + +NTSTATUS +AFSInsertWorkitem( IN AFSWorkItem *WorkItem); + +NTSTATUS +AFSInsertIOWorkitem( IN AFSWorkItem *WorkItem); + +NTSTATUS +AFSInsertWorkitemAtHead( IN AFSWorkItem *WorkItem); + +AFSWorkItem * +AFSRemoveWorkItem( void); + +AFSWorkItem * +AFSRemoveIOWorkItem( void); + +NTSTATUS +AFSQueueWorkerRequest( IN AFSWorkItem *WorkItem); + +NTSTATUS +AFSQueueIOWorkerRequest( IN AFSWorkItem *WorkItem); + +NTSTATUS +AFSQueueWorkerRequestAtHead( IN AFSWorkItem *WorkItem); + +NTSTATUS +AFSShutdownVolumeWorker( IN AFSVolumeCB *VolumeCB); + +NTSTATUS +AFSQueueFlushExtents( IN AFSFcb *Fcb); + +NTSTATUS +AFSQueueAsyncRead( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE CallerProcess); + +NTSTATUS +AFSQueueAsyncWrite( IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN HANDLE CallerProcess); + +NTSTATUS +AFSQueueGlobalRootEnumeration( void); + +NTSTATUS +AFSQueuePurgeObject( IN AFSFcb *Fcb); + +NTSTATUS +AFSQueueStartIos( IN PFILE_OBJECT CacheFileObject, + IN UCHAR FunctionCode, + IN ULONG RequestFLags, + IN AFSIoRun *IoRuns, + IN ULONG RunCount, + IN AFSGatherIo *GatherIo); + +// +// AFSMD5Support.cpp Prototypes +// + +void +AFSGenerateMD5( IN char *DataBuffer, + IN ULONG Length, + OUT UCHAR *MD5Digest); + +}; + +#endif /* _AFS_COMMON_H */ diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h new file mode 100644 index 0000000000..0b88e0bc87 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h @@ -0,0 +1,446 @@ +/* + * 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. + */ + +#ifndef _AFS_DEFINES_H +#define _AFS_DEFINES_H +// +// File: AFSDefines.h +// + +// +// Conditional compiled code +// + +//#define AFS_FLUSH_PAGES_SYNCHRONOUSLY 1 // Flush pages as we mark them dirty + +// +// Debug information +// + +#if DBG + +//#define AFS_VALIDATE_EXTENTS 0 + +#define GEN_MD5 0 + +#else + +#endif + +// +// For 2K support +// + +#ifndef FsRtlSetupAdvancedHeader + +#define FSRTL_FLAG_ADVANCED_HEADER (0x40) +#define FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS (0x02) + +#define FsRtlSetupAdvancedHeader( _advhdr, _fmutx ) \ +{ \ + SetFlag( (_advhdr)->Flags, FSRTL_FLAG_ADVANCED_HEADER ); \ + SetFlag( (_advhdr)->Flags2, FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS ); \ + InitializeListHead( &(_advhdr)->FilterContexts ); \ + if ((_fmutx) != NULL) { \ + (_advhdr)->FastMutex = (_fmutx); \ + } \ +} + +#endif + +typedef +NTSTATUS +(*PAFSRtlSetSaclSecurityDescriptor)( PSECURITY_DESCRIPTOR SecurityDescriptor, + BOOLEAN SaclPresent, + PACL Sacl, + BOOLEAN SaclDefaulted); + +// +// Worker thread count +// + +#define AFS_WORKER_COUNT 5 +#define AFS_IO_WORKER_COUNT 5 + +// +// Worker thread states +// + +#define AFS_WORKER_INITIALIZED 0x0001 +#define AFS_WORKER_PROCESS_REQUESTS 0x0002 + +// +// Worker Thread codes +// + +#define AFS_WORK_UNUSED_1 0x0001 +#define AFS_WORK_FLUSH_FCB 0x0002 +#define AFS_WORK_ASYNCH_READ 0x0003 +#define AFS_WORK_ASYNCH_WRITE 0x0004 +#define AFS_WORK_UNUSED_5 0x0005 +#define AFS_WORK_ENUMERATE_GLOBAL_ROOT 0x0006 +#define AFS_WORK_UNUSED_7 0x0007 +#define AFS_WORK_START_IOS 0x0008 + +// +// Worker request flags +// + +#define AFS_SYNCHRONOUS_REQUEST 0x00000001 + +// +// Fcb flags +// + +#define AFS_FCB_FLAG_FILE_MODIFIED 0x00000001 +#define AFS_FCB_FILE_CLOSED 0x00000002 +#define AFS_FCB_FLAG_UPDATE_WRITE_TIME 0x00000004 +#define AFS_FCB_FLAG_UPDATE_CHANGE_TIME 0x00000008 +#define AFS_FCB_FLAG_UPDATE_ACCESS_TIME 0x00000010 +#define AFS_FCB_FLAG_UPDATE_CREATE_TIME 0x00000020 +#define AFS_FCB_FLAG_UPDATE_LAST_WRITE_TIME 0x00000040 + +// +// Object information flags +// + +#define AFS_OBJECT_FLAGS_OBJECT_INVALID 0x00000001 +#define AFS_OBJECT_FLAGS_VERIFY 0x00000002 +#define AFS_OBJECT_FLAGS_NOT_EVALUATED 0x00000004 +#define AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED 0x00000008 +#define AFS_OBJECT_FLAGS_DELETED 0x00000010 +#define AFS_OBJECT_INSERTED_HASH_TREE 0x00000020 +#define AFS_OBJECT_INSERTED_VOLUME_LIST 0x00000040 +#define AFS_OBJECT_HELD_IN_SERVICE 0x00000080 +#define AFS_OBJECT_ROOT_VOLUME 0x00000100 +#define AFS_OBJECT_FLAGS_VERIFY_DATA 0x00000200 + +// +// Fcb lifetime in seconds +// + +#define AFS_OBJECT_LIFETIME 300000000 + +#define AFS_EXTENT_REQUEST_TIME 100000000 + +// +// How big to make the runs +// +#define AFS_MAX_STACK_IO_RUNS 5 + +#ifndef FlagOn +#define FlagOn(_F,_SF) ((_F) & (_SF)) +#endif + +#ifndef BooleanFlagOn +#define BooleanFlagOn(F,SF) ((BOOLEAN)(((F) & (SF)) != 0)) +#endif + +#ifndef SetFlag +#define SetFlag(_F,_SF) ((_F) |= (_SF)) +#endif + +#ifndef ClearFlag +#define ClearFlag(_F,_SF) ((_F) &= ~(_SF)) +#endif + +#define QuadAlign(Ptr) ( \ + ((((ULONG)(Ptr)) + 7) & 0xfffffff8) \ + ) + +#define CRC32_POLYNOMIAL 0xEDB88320L; + +// +// Define one second in terms of 100 nS units +// + +#define AFS_ONE_SECOND 10000000 + +#define AFS_SERVER_FLUSH_DELAY 30 +#define AFS_SERVER_PURGE_DELAY 60 +// +// PURGE_SLEEP is the number of PURGE_DELAYS we wait before we will unilaterally +// give back extents. +// +// If the Service asks us, we will start at PURGE_SLEEP of delays and then work back +// +#define AFS_SERVER_PURGE_SLEEP 6 + +// +// Read ahead granularity +// + +#define READ_AHEAD_GRANULARITY 0x10000 // 64KB + +#define AFS_DIR_ENUM_BUFFER_LEN (16 * 1024) + +// +// IS_BYTE_OFFSET_WRITE_TO_EOF +// liOffset - should be from Irp.StackLocation.Parameters.Write.ByteOffset +// this macro checks to see if the Offset Large_Integer points to the +// special constant value which denotes to start the write at EndOfFile +// +#define IS_BYTE_OFFSET_WRITE_TO_EOF(liOffset) \ + (((liOffset).LowPart == FILE_WRITE_TO_END_OF_FILE) \ + && ((liOffset).HighPart == 0xFFFFFFFF)) + +// +// Ccb Directory enum flags +// + +#define CCB_FLAG_DIR_OF_DIRS_ONLY 0x00000001 +#define CCB_FLAG_FULL_DIRECTORY_QUERY 0x00000002 +#define CCB_FLAG_MASK_CONTAINS_WILD_CARDS 0x00000004 +#define CCB_FLAG_FREE_FULL_PATHNAME 0x00000008 +#define CCB_FLAG_RETURN_RELATIVE_ENTRIES 0x00000010 +#define CCB_FLAGS_DIRECTORY_QUERY_MAPPED 0x00000020 +#define CCB_FLAG_MASK_PIOCTL_QUERY 0x00000040 + +// +// DirEntry flags +// + +#define AFS_DIR_RELEASE_NAME_BUFFER 0x00000001 + +#define AFS_DIR_ENTRY_CASE_INSENSTIVE_LIST_HEAD 0x00000004 +#define AFS_DIR_ENTRY_NOT_IN_PARENT_TREE 0x00000008 +#define AFS_DIR_ENTRY_INSERTED_ENUM_LIST 0x00000010 +#define AFS_DIR_ENTRY_FAKE 0x00000020 +#define AFS_DIR_RELEASE_TARGET_NAME_BUFFER 0x00000040 +#define AFS_DIR_ENTRY_VALID 0x00000080 +#define AFS_DIR_ENTRY_PENDING_DELETE 0x00000100 +#define AFS_DIR_ENTRY_DELETED 0x00000200 +#define AFS_DIR_ENTRY_SERVER_SERVICE 0x00000400 +#define AFS_DIR_ENTRY_WORKSTATION_SERVICE 0x00000800 +#define AFS_DIR_ENTRY_IPC 0x00001000 + +// +// Network provider errors +// + +#define WN_SUCCESS 0L +#define WN_ALREADY_CONNECTED 85L +#define WN_OUT_OF_MEMORY 8L +#define WN_NOT_CONNECTED 2250L +#define WN_BAD_NETNAME 67L + +#define RESOURCE_CONNECTED 0x00000001 +#define RESOURCE_GLOBALNET 0x00000002 +#define RESOURCE_REMEMBERED 0x00000003 +#define RESOURCE_RECENT 0x00000004 +#define RESOURCE_CONTEXT 0x00000005 + +#define RESOURCETYPE_ANY 0x00000000 +#define RESOURCETYPE_DISK 0x00000001 +#define RESOURCETYPE_PRINT 0x00000002 +#define RESOURCETYPE_RESERVED 0x00000008 +#define RESOURCETYPE_UNKNOWN 0xFFFFFFFF + +#define RESOURCEUSAGE_CONNECTABLE 0x00000001 +#define RESOURCEUSAGE_CONTAINER 0x00000002 +#define RESOURCEUSAGE_NOLOCALDEVICE 0x00000004 +#define RESOURCEUSAGE_SIBLING 0x00000008 +#define RESOURCEUSAGE_ATTACHED 0x00000010 +#define RESOURCEUSAGE_ALL (RESOURCEUSAGE_CONNECTABLE | RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED) +#define RESOURCEUSAGE_RESERVED 0x80000000 + +#define RESOURCEDISPLAYTYPE_GENERIC 0x00000000 +#define RESOURCEDISPLAYTYPE_DOMAIN 0x00000001 +#define RESOURCEDISPLAYTYPE_SERVER 0x00000002 +#define RESOURCEDISPLAYTYPE_SHARE 0x00000003 +#define RESOURCEDISPLAYTYPE_FILE 0x00000004 +#define RESOURCEDISPLAYTYPE_GROUP 0x00000005 +#define RESOURCEDISPLAYTYPE_NETWORK 0x00000006 +#define RESOURCEDISPLAYTYPE_ROOT 0x00000007 +#define RESOURCEDISPLAYTYPE_SHAREADMIN 0x00000008 +#define RESOURCEDISPLAYTYPE_DIRECTORY 0x00000009 +#define RESOURCEDISPLAYTYPE_TREE 0x0000000A +#define RESOURCEDISPLAYTYPE_NDSCONTAINER 0x0000000B + +// +// Method for determining the different control device open requests +// + +#define AFS_CONTROL_INSTANCE 0x00000001 +#define AFS_REDIRECTOR_INSTANCE 0x00000002 + +// +// Extent flags +// + +#define AFS_EXTENT_DIRTY 0x00000001 + +// +// Extent skip list sizes +// +#define AFS_NUM_EXTENT_LISTS 3 + +// +// Extents skip lists +// +// We use constant sizes. +// +#define AFS_EXTENT_SIZE (4*1024) +#define AFS_EXTENTS_LIST 0 +// +// A max of 64 extents in ther first skip list +#define AFS_EXTENT_SKIP1_BITS 6 + +// +// Then 128 bits in the second skip list +#define AFS_EXTENT_SKIP2_BITS 7 + +// +// This means that the top list skips in steps of 2^25 (=12+6+7) which +// is 32 Mb. It is to be expected that files which are massively +// larger that this will not be fully mapped. +// +#define AFS_EXTENT_SKIP1_SIZE (AFS_EXTENT_SIZE << AFS_EXTENT_SKIP1_BITS) +#define AFS_EXTENT_SKIP2_SIZE (AFS_EXTENT_SKIP1_SIZE << AFS_EXTENT_SKIP2_BITS) + +#define AFS_EXTENTS_MASKS { (AFS_EXTENT_SIZE-1), \ + (AFS_EXTENT_SKIP1_SIZE-1), \ + (AFS_EXTENT_SKIP2_SIZE-1) } + +// +// Maximum count to release at a time +// + +#define AFS_MAXIMUM_EXTENT_RELEASE_COUNT 100 + +// {41966169-3FD7-4392-AFE4-E6A9D0A92C72} - generated using guidgen.exe +DEFINE_GUID (GUID_SD_AFS_REDIRECTOR_CONTROL_OBJECT, + 0x41966169, 0x3fd7, 0x4392, 0xaf, 0xe4, 0xe6, 0xa9, 0xd0, 0xa9, 0x2c, 0x72); + +// +// Debug log length +// + +#define AFS_DBG_LOG_LENGTH 256 + +// +// Debug log flags +// + +#define AFS_DBG_LOG_WRAPPED 0x00000001 + +// +// Connection flags +// + +#define AFS_CONNECTION_FLAG_GLOBAL_SHARE 0x00000001 + +// +// Process CB flags +// + +#define AFS_PROCESS_FLAG_IS_64BIT 0x00000001 + +// +// Maximum number of special share names +// + +#define AFS_SPECIAL_SHARE_NAME_COUNT_MAX 10 + +// +// Device flags +// + +#define AFS_DEVICE_FLAG_HIDE_DOT_NAMES 0x00000001 +#define AFS_DEVICE_FLAG_REDIRECTOR_SHUTDOWN 0x00000002 + +// +// Name Array flags +// + +#define AFS_NAME_ARRAY_FLAG_ROOT_ELEMENT 0x00000001 +#define AFS_NAME_ARRAY_FLAG_REDIRECTION_ELEMENT 0x00000002 + +// +// Maximum recursion depth +// + +#define AFS_MAX_RECURSION_COUNT 20 + +// +// LocateNameEntry flags +// + +#define AFS_LOCATE_FLAGS_SUBSTITUTE_NAME 0x00000001 +#define AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL 0x00000002 +#define AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL 0x00000004 +#define AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL 0x00000008 + +// +// Parse flags +// + +#define AFS_PARSE_FLAG_FREE_FILE_BUFFER 0x00000001 +#define AFS_PARSE_FLAG_ROOT_ACCESS 0x00000002 + +// +// Reparse tag information +// + +// +// Tag allocated to OpenAFS for DFS by Microsoft +// GUID: EF21A155-5C92-4470-AB3B-370403D96369 +// + +#ifndef IO_REPARSE_TAG_OPENAFS_DFS +#define IO_REPARSE_TAG_OPENAFS_DFS 0x00000037L +#endif + +// {EF21A155-5C92-4470-AB3B-370403D96369} +DEFINE_GUID (GUID_AFS_REPARSE_GUID, + 0xEF21A155, 0x5C92, 0x4470, 0xAB, 0x3B, 0x37, 0x04, 0x03, 0xD9, 0x63, 0x69); + +// +// Enumeration constants +// + +#define AFS_DIR_ENTRY_INITIAL_DIR_INDEX (ULONG)-3 +#define AFS_DIR_ENTRY_INITIAL_ROOT_INDEX (ULONG)-1 + +#define AFS_DIR_ENTRY_PIOCTL_INDEX (ULONG)-3 +#define AFS_DIR_ENTRY_DOT_INDEX (ULONG)-2 +#define AFS_DIR_ENTRY_DOT_DOT_INDEX (ULONG)-1 + +// +// Library state flags +// + +#define AFS_REDIR_LIB_FLAGS_NONPERSISTENT_CACHE 0x00000001 + +#endif /* _AFS_DEFINES_H */ diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSExtern.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSExtern.h new file mode 100644 index 0000000000..6596bd07fc --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSExtern.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +#ifndef _AFS_EXTERN_H +#define _AFS_EXTERN_H +// +// File: AFSExtern.h +// +// + +extern "C" { + +extern PDRIVER_OBJECT AFSLibraryDriverObject; + +extern PDEVICE_OBJECT AFSLibraryDeviceObject; + +extern PDEVICE_OBJECT AFSControlDeviceObject; + +extern PDEVICE_OBJECT AFSRDRDeviceObject; + +extern FAST_IO_DISPATCH AFSFastIoDispatch; + +extern unsigned long AFSCRCTable[]; + +extern UNICODE_STRING AFSRegistryPath; + +extern ULONG AFSDebugFlags; + +extern CACHE_MANAGER_CALLBACKS *AFSLibCacheManagerCallbacks; + +extern HANDLE AFSSysProcess; + +extern UNICODE_STRING AFSServerName; + +extern AFSVolumeCB *AFSGlobalRoot; + +extern AFSVolumeCB *AFSRedirectorRoot; + +extern UNICODE_STRING AFSPIOCtlName; + +extern UNICODE_STRING AFSGlobalRootName; + +extern AFSDirectoryCB *AFSSpecialShareNames; + +extern AFSDirectoryCB *AFSGlobalDotDirEntry; + +extern AFSDirectoryCB *AFSGlobalDotDotDirEntry; + +extern PAFSProcessRequest AFSProcessRequest; + +extern PAFSDbgLogMsg AFSDbgLogMsg; + +extern PAFSAddConnectionEx AFSAddConnectionEx; + +extern PAFSExAllocatePoolWithTag AFSExAllocatePoolWithTag; + +extern PAFSExFreePool AFSExFreePool; + +extern PAFSRetrieveAuthGroup AFSRetrieveAuthGroupFnc; + +extern ULONG AFSLibControlFlags; + +extern void *AFSLibCacheBaseAddress; + +extern LARGE_INTEGER AFSLibCacheLength; + +extern PAFSRtlSetSaclSecurityDescriptor AFSRtlSetSaclSecurityDescriptor; + +extern SECURITY_DESCRIPTOR *AFSDefaultSD; + +} + +#endif /* _AFS_EXTERN_H */ diff --git a/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h b/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h new file mode 100644 index 0000000000..ab05462992 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h @@ -0,0 +1,649 @@ +/* + * 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. + */ + +#ifndef _AFS_STRUCTS_H +#define _AFS_STRUCTS_H + +// +// File: AFSStructs.h +// + +typedef struct _AFS_DIR_HDR +{ + + struct _AFS_DIRECTORY_CB *CaseSensitiveTreeHead; + + struct _AFS_DIRECTORY_CB *CaseInsensitiveTreeHead; + + ERESOURCE *TreeLock; + + LONG ContentIndex; + +} AFSDirHdr; + +// +// Worker pool header +// + +typedef struct _AFS_WORKER_QUEUE_HDR +{ + + struct _AFS_WORKER_QUEUE_HDR *fLink; + + KEVENT WorkerThreadReady; + + void *WorkerThreadObject; + + ULONG State; + +} AFSWorkQueueContext, *PAFSWorkQueueContext; + +// +// These are the context control blocks for the open instance +// + +typedef struct _AFS_CCB +{ + + USHORT Size; + USHORT Type; + + ULONG Flags; + + // + // Directory enumeration informaiton + // + + UNICODE_STRING MaskName; + + struct _AFS_DIRECTORY_SS_HDR *DirectorySnapshot; + + ULONG CurrentDirIndex; + + // + // PIOCtl and share interface request id + // + + ULONG RequestID; + + // + // Full path of how the instance was opened + // + + UNICODE_STRING FullFileName; + + // + // Name array for this open + // + + struct _AFS_NAME_ARRAY_HEADER *NameArray; + + // + // Pointer to this entries meta data + // + + struct _AFS_DIRECTORY_CB *DirectoryCB; + + // + // Notification name + // + + UNICODE_STRING NotifyMask; + + // + // File unwind info + // + + struct + { + + ULONG FileAttributes; + + LARGE_INTEGER CreationTime; + + LARGE_INTEGER LastAccessTime; + + LARGE_INTEGER LastWriteTime; + + LARGE_INTEGER ChangeTime; + + } FileUnwindInfo; + +} AFSCcb; + +// +// Object information block +// + +typedef struct _AFS_NONPAGED_OBJECT_INFO_CB +{ + + ERESOURCE DirectoryNodeHdrLock; + +} AFSNonPagedObjectInfoCB; + +typedef struct _AFS_OBJECT_INFORMATION_CB +{ + + AFSBTreeEntry TreeEntry; + + AFSListEntry ListEntry; + + ULONG Flags; + + LONG ObjectReferenceCount; + + AFSNonPagedObjectInfoCB *NonPagedInfo; + + // + // The VolumeCB where this entry resides + // + + struct _AFS_VOLUME_CB *VolumeCB; + + // + // Parent object information + // + + struct _AFS_OBJECT_INFORMATION_CB *ParentObjectInformation; + + // + // Pointer to the current Fcb, if available + // + + AFSFcb *Fcb; + + // + // Last access time. + // + + LARGE_INTEGER LastAccessCount; + + // + // Per file metadata information + // + + AFSFileID FileId; + + AFSFileID TargetFileId; + + LARGE_INTEGER Expiration; /* FILETIME */ + + LARGE_INTEGER DataVersion; + + ULONG FileType; /* File, Dir, MountPoint, Symlink */ + + LARGE_INTEGER CreationTime; /* FILETIME */ + + LARGE_INTEGER LastAccessTime; /* FILETIME */ + + LARGE_INTEGER LastWriteTime; /* FILETIME */ + + LARGE_INTEGER ChangeTime; /* FILETIME */ + + ULONG FileAttributes; /* NTFS FILE_ATTRIBUTE_xxxx see below */ + + LARGE_INTEGER EndOfFile; + + LARGE_INTEGER AllocationSize; + + ULONG EaSize; + + ULONG Links; + + // + // Directory and file specific information + // + + union + { + + struct + { + + // + // The directory search and listing information for the node + // + + AFSDirHdr DirectoryNodeHdr; + + struct _AFS_DIRECTORY_CB *DirectoryNodeListHead; + + struct _AFS_DIRECTORY_CB *DirectoryNodeListTail; + + LONG DirectoryNodeCount; + + struct _AFS_DIRECTORY_CB *ShortNameTree; + + // + // PIOCtl directory cb entry + // + + struct _AFS_DIRECTORY_CB *PIOCtlDirectoryCB; + + // + // Open handle and reference count for this object + // + + LONG ChildOpenHandleCount; + + LONG ChildOpenReferenceCount; + + // + // Index for the PIOCtl and share open count + // + + LONG OpenRequestIndex; + + } Directory; + + struct + { + + ULONG Reserved; + + } File; + + } Specific; + +} AFSObjectInfoCB; + +// +// Volume control block structure +// + +typedef struct _AFS_NON_PAGED_VOLUME_CB +{ + + ERESOURCE VolumeLock; + + ERESOURCE ObjectInfoTreeLock; + + ERESOURCE DirectoryNodeHdrLock; + +}AFSNonPagedVolumeCB; + +typedef struct _AFS_VOLUME_CB +{ + + // + // Our tree entry. + // + + AFSBTreeEntry TreeEntry; + + // + // This is the linked list of nodes processed asynchronously by the respective worker thread + // + + AFSListEntry ListEntry; + + ULONG Flags; + + AFSNonPagedVolumeCB *NonPagedVcb; + + ERESOURCE *VolumeLock; + + // + // Reference count on the object + // + + LONG VolumeReferenceCount; + + // + // Object information tree + // + + AFSTreeHdr ObjectInfoTree; + + AFSObjectInfoCB *ObjectInfoListHead; + + AFSObjectInfoCB *ObjectInfoListTail; + + // + // Object information for the volume + // + + AFSObjectInfoCB ObjectInformation; + + // + // Root directory cb for this volume + // + + struct _AFS_DIRECTORY_CB *DirectoryCB; + + // + // The Fcb for this volume + // + + AFSFcb *RootFcb; + + // + // Volume worker thread + // + + AFSWorkQueueContext VolumeWorkerContext; + + // + // Volume information + // + + AFSVolumeInfoCB VolumeInformation; + +} AFSVolumeCB; + +typedef struct _AFS_NAME_INFORMATION_CB +{ + + CCHAR ShortNameLength; + + WCHAR ShortName[12]; + + UNICODE_STRING FileName; + + UNICODE_STRING TargetName; + +} AFSNameInfoCB; + +typedef struct _AFS_NON_PAGED_DIRECTORY_CB +{ + + ERESOURCE Lock; + +} AFSNonPagedDirectoryCB; + +typedef struct _AFS_DIRECTORY_CB +{ + + AFSBTreeEntry CaseSensitiveTreeEntry; // For entries in the NameEntry tree, the + // Index is a CRC on the name. For Volume, + // MP and SL nodes, the Index is the Cell, Volume + // For all others it is the vnode, uniqueid + + AFSBTreeEntry CaseInsensitiveTreeEntry; + + AFSListEntry CaseInsensitiveList; + + ULONG Flags; + + // + // Current open reference count on the directory entry. This count is used + // for tear down + // + + LONG OpenReferenceCount; + + // + // File index used in directory enumerations + // + + ULONG FileIndex; + + // + // Name information for this entry + // + + AFSNameInfoCB NameInformation; + + // + // List entry for the directory enumeration list in a parent node + // + + AFSListEntry ListEntry; + + // + // Back pointer to the ObjectInfo block for this entry + // + + AFSObjectInfoCB *ObjectInformation; + + // + // Non paged pointer + // + + AFSNonPagedDirectoryCB *NonPaged; + + // + // Type specific information + // + + union + { + + struct + { + + AFSBTreeEntry ShortNameTreeEntry; + + } Data; + + struct + { + + ULONG Reserved; + + } MountPoint; + + struct + { + + ULONG Reserved; + + } SymLink; + + } Type; + +} AFSDirectoryCB; + +// Read and writes can fan out and so they are syncrhonized via one of +// these structures +// + +typedef struct _AFS_GATHER_READWRITE +{ + KEVENT Event; + + LONG Count; + + NTSTATUS Status; + + PIRP MasterIrp; + + BOOLEAN Synchronous; + + BOOLEAN CompleteMasterIrp; + + AFSFcb *Fcb; + +} AFSGatherIo; + +typedef struct _AFS_IO_RUNS { + + LARGE_INTEGER CacheOffset; + PIRP ChildIrp; + ULONG ByteCount; +} AFSIoRun; + +// +// Name array element and header +// + +typedef struct _AFS_NAME_ARRAY_ELEMENT +{ + + UNICODE_STRING Component; + + AFSFileID FileId; + + AFSDirectoryCB *DirectoryCB; + + ULONG Flags; + +} AFSNameArrayCB; + +typedef struct _AFS_NAME_ARRAY_HEADER +{ + + AFSNameArrayCB *CurrentEntry; + + LONG Count; + + LONG LinkCount; + + ULONG Flags; + + ULONG MaxElementCount; + + AFSNameArrayCB ElementArray[ 1]; + +} AFSNameArrayHdr; + +typedef struct _AFS_FILE_INFO_CB +{ + + ULONG FileAttributes; + + LARGE_INTEGER AllocationSize; + + LARGE_INTEGER EndOfFile; + + LARGE_INTEGER CreationTime; + + LARGE_INTEGER LastAccessTime; + + LARGE_INTEGER LastWriteTime; + + LARGE_INTEGER ChangeTime; + +} AFSFileInfoCB; + +// +// Work item +// + +typedef struct _AFS_WORK_ITEM +{ + + struct _AFS_WORK_ITEM *next; + + ULONG RequestType; + + ULONG RequestFlags; + + NTSTATUS Status; + + KEVENT Event; + + ULONG Size; + + ULONGLONG ProcessID; + + union + { + struct + { + PIRP Irp; + + } ReleaseExtents; + + struct + { + AFSFcb *Fcb; + + AFSFcb **TargetFcb; + + AFSFileInfoCB FileInfo; + + struct _AFS_NAME_ARRAY_HEADER *NameArray; + + } Fcb; + + struct + { + PIRP Irp; + + PDEVICE_OBJECT Device; + + HANDLE CallingProcess; + + } AsynchIo; + + struct + { + + UCHAR FunctionCode; + + ULONG RequestFlags; + + struct _AFS_IO_RUNS *IoRuns; + + ULONG RunCount; + + struct _AFS_GATHER_READWRITE *GatherIo; + + FILE_OBJECT *CacheFileObject; + + } CacheAccess; + + struct + { + char Context[ 1]; + + } Other; + + } Specific; + +} AFSWorkItem, *PAFSWorkItem; + +// +// Directory snapshot structures +// + +typedef struct _AFS_DIRECTORY_SS_ENTRY +{ + + ULONG NameHash; + +} AFSSnapshotEntry; + +typedef struct _AFS_DIRECTORY_SS_HDR +{ + + ULONG EntryCount; + + AFSSnapshotEntry *TopEntry; + +} AFSSnapshotHdr; + +#endif /* _AFS_STRUCTS_H */ diff --git a/src/WINNT/afsrdr/kernel/lib/MAKEFILE b/src/WINNT/afsrdr/kernel/lib/MAKEFILE new file mode 100644 index 0000000000..6ee4f43fa4 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/MAKEFILE @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/src/WINNT/afsrdr/kernel/lib/sources b/src/WINNT/afsrdr/kernel/lib/sources new file mode 100644 index 0000000000..af67ae7158 --- /dev/null +++ b/src/WINNT/afsrdr/kernel/lib/sources @@ -0,0 +1,43 @@ + +TARGETNAME=AFSRedirLib +TARGETPATH=..\..\Build +TARGETTYPE=DRIVER + +DRIVERTYPE=FS + +INCLUDES=Include;..\..\Common; + +TARGETLIBS=$(DDK_LIB_PATH)\ntstrsafe.lib \ + $(DDK_LIB_PATH)\wdmsec.lib + +SOURCES= AFSInit.cpp \ + AFSBTreeSupport.cpp \ + AFSCleanup.cpp \ + AFSClose.cpp \ + AFSCommSupport.cpp \ + AFSCreate.cpp \ + AFSData.cpp \ + AFSDevControl.cpp \ + AFSDirControl.cpp \ + AFSEa.cpp \ + AFSExtentsSupport.cpp \ + AFSFcbSupport.cpp \ + AFSFileInfo.cpp \ + AFSFlushBuffers.cpp \ + AFSFSControl.cpp \ + AFSGeneric.cpp \ + AFSInternalDevControl.cpp \ + AFSIoSupport.cpp \ + AFSLockControl.cpp \ + AFSMD5Support.cpp \ + AFSNameSupport.cpp \ + AFSNetworkProviderSupport.cpp \ + AFSQuota.cpp \ + AFSRead.cpp \ + AFSSecurity.cpp \ + AFSShutdown.cpp \ + AFSSystemControl.cpp \ + AFSVolumeInfo.cpp \ + AFSWorker.cpp \ + AFSWrite.cpp \ + FileSystem.rc