Windows: AFSRedirLib.sys file system library driver
authorPeter Scott <pscott@kerneldrivers.com>
Thu, 15 Sep 2011 05:48:59 +0000 (01:48 -0400)
committerJeffrey Altman <jaltman@openafs.org>
Thu, 15 Sep 2011 18:28:12 +0000 (11:28 -0700)
This patchset implements the AFS Redirector Library driver.
This driver contains all of the AFS specific implementation
details for service communication, network provider support,
directory management, extent management, metadata management,
callback invaldation, volume management, file locking, etc.

Rod Widdowson <rdw@steadingsoftware.com> and Jeffrey Altman
<jaltman@your-file-system.com> contributed to the development
of this driver.

Change-Id: Icc18c26b81b96a92096c20e01360007815ca1acb
Reviewed-on: http://gerrit.openafs.org/5438
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Rod Widdowson <rdw@steadingsoftware.com>
Tested-by: Rod Widdowson <rdw@steadingsoftware.com>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Tested-by: Jeffrey Altman <jaltman@openafs.org>

38 files changed:
src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSCleanup.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSClose.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSCommSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSData.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSDevControl.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSDirControl.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSEa.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSExtentsSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSFSControl.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSFcbSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSFileInfo.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSFlushBuffers.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSGeneric.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSInit.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSInternalDevControl.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSIoSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSLockControl.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSMD5Support.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSNameSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSNetworkProviderSupport.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSQuota.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSRead.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSRedirLibInstall.inf [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSSecurity.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSShutdown.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSSystemControl.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSVolumeInfo.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSWorker.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/AFSWrite.cpp [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/Filesystem.rc [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/Include/AFSCommon.h [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/Include/AFSDefines.h [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/Include/AFSExtern.h [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/Include/AFSStructs.h [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/MAKEFILE [new file with mode: 0644]
src/WINNT/afsrdr/kernel/lib/sources [new file with mode: 0644]

diff --git a/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp b/src/WINNT/afsrdr/kernel/lib/AFSBTreeSupport.cpp
new file mode 100644 (file)
index 0000000..107e53b
--- /dev/null
@@ -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 (file)
index 0000000..be8fedd
--- /dev/null
@@ -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 (file)
index 0000000..b97d64f
--- /dev/null
@@ -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 (file)
index 0000000..90e500e
--- /dev/null
@@ -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 (file)
index 0000000..72343c6
--- /dev/null
@@ -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 (file)
index 0000000..2a69e47
--- /dev/null
@@ -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 (file)
index 0000000..3464552
--- /dev/null
@@ -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 (file)
index 0000000..ca759ff
--- /dev/null
@@ -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 (file)
index 0000000..63100bd
--- /dev/null
@@ -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 (file)
index 0000000..7df7503
--- /dev/null
@@ -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 (file)
index 0000000..e9e2bd6
--- /dev/null
@@ -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>[<cell>:]<volume>
+
+    *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 (file)
index 0000000..cc61018
--- /dev/null
@@ -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 (file)
index 0000000..cad48b8
--- /dev/null
@@ -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 (file)
index 0000000..f480516
--- /dev/null
@@ -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 (file)
index 0000000..54b3b4f
--- /dev/null
@@ -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 (file)
index 0000000..b2a1df0
--- /dev/null
@@ -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 (file)
index 0000000..64e5e9c
--- /dev/null
@@ -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 (file)
index 0000000..d3d907a
--- /dev/null
@@ -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 (file)
index 0000000..634cc60
--- /dev/null
@@ -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 (file)
index 0000000..0e699b8
--- /dev/null
@@ -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
+  <ghost@aladdin.com>.  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 <purschke@bnl.gov>.
+  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 (file)
index 0000000..3c93f8d
--- /dev/null
@@ -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 \\<Global root> 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,
+                               pIr\epSp->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 (file)
index 0000000..26d3a6c
--- /dev/null
@@ -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 (file)
index 0000000..ab8a0dd
--- /dev/null
@@ -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 (file)
index 0000000..2ef0f7c
--- /dev/null
@@ -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 (file)
index 0000000..0e6dc43
--- /dev/null
@@ -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 (file)
index 0000000..5b178b6
--- /dev/null
@@ -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 (file)
index 0000000..9bf6f67
--- /dev/null
@@ -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 (file)
index 0000000..109e065
--- /dev/null
@@ -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 (file)
index 0000000..16c455e
--- /dev/null
@@ -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 (file)
index 0000000..721c26e
--- /dev/null
@@ -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 (file)
index 0000000..12ff9e6
--- /dev/null
@@ -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 (file)
index 0000000..aca2996
--- /dev/null
@@ -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 (file)
index 0000000..3bf1824
--- /dev/null
@@ -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 <ntifs.h>
+#include <wdmsec.h> // for IoCreateDeviceSecure
+#include <initguid.h>
+
+#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 (file)
index 0000000..0b88e0b
--- /dev/null
@@ -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 (file)
index 0000000..6596bd0
--- /dev/null
@@ -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 (file)
index 0000000..ab05462
--- /dev/null
@@ -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 (file)
index 0000000..6ee4f43
--- /dev/null
@@ -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 (file)
index 0000000..af67ae7
--- /dev/null
@@ -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