Windows: CreateFile Reparse Point to File as File
authorJeffrey Altman <jaltman@your-file-system.com>
Mon, 4 Mar 2013 04:10:51 +0000 (23:10 -0500)
committerJeffrey Altman <jaltman@your-file-system.com>
Wed, 8 May 2013 00:39:36 +0000 (17:39 -0700)
Apply the Reparse Point to File as File Policy to CreateFile.  If the
FILE_OPEN_REPARSE_POINT flag is specified to the CreateFile operation
and AFSIgnoreReparsePointToFile() returns TRUE, evaluate the target
object (if possible) and if the object is a FILE, then ignore the
FILE_OPEN_REPARSE_POINT flag.  Otherwise, re-evaluate the request to
attempt to open a reparse point if it exists.

Change-Id: Ia1a3d5f4c4d638d7d94209c9b4a9dfc2e8aa2005
Reviewed-on: http://gerrit.openafs.org/9343
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Jeffrey Altman <jaltman@your-file-system.com>
Tested-by: Jeffrey Altman <jaltman@your-file-system.com>

src/WINNT/afsrdr/common/AFSRedirCommonDefines.h
src/WINNT/afsrdr/kernel/lib/AFSCreate.cpp

index 816331d..bdd1740 100644 (file)
@@ -91,6 +91,7 @@
 #define AFS_NAME_BUFFER_EIGHT_TAG    '8NFA'
 #define AFS_NAME_BUFFER_NINE_TAG     '9NFA'
 #define AFS_NAME_BUFFER_TEN_TAG      'ANFA'
+#define AFS_NAME_BUFFER_ELEVEN_TAG   'BNFA'
 #define AFS_SUBST_BUFFER_TAG         'SBFA'
 #define AFS_FILE_CREATE_BUFFER_TAG   'CFFA'
 #define AFS_RENAME_REQUEST_TAG       'RFFA'
index 81d9d8a..f12cc0c 100644 (file)
@@ -425,193 +425,590 @@ AFSCommonCreate( IN PDEVICE_OBJECT DeviceObject,
                 try_return( ntStatus);
             }
 
-            //
-            // Opening a reparse point directly?
-            //
 
-            ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME;
-
-            if( BooleanFlagOn( ulOptions, FILE_OPEN_REPARSE_POINT))
+           if ( !AFSIgnoreReparsePointToFile() ||
+                !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);
-            }
+               //
+               // If there is no ReparsePointPolicy then the FILE_OPEN_REPARSE_POINT
+               // flag is applied if it is set.
+               //
+               // If the FILE_OPEN_REPARSE_POINT flag is not set, then there is
+               // no extra work to be done in any case.  Use a single pass evaluation.
+               //
+
+               ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME;
+
+               //
+               // Opening a reparse point directly?
+               //
+
+               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,
+                                              &pNewVolumeCB,
+                                              &NewVolumeReferenceReason,
+                                              &pNewParentDirectoryCB,
+                                              &pDirectoryCB,
+                                              &uniComponentName);
+
+               if ( pNewVolumeCB != NULL)
+               {
+
+                   //
+                   // AFSLocateNameEntry returns pNewVolumeCB with a reference held
+                   // even if pVolumeCB == pNewVolumeCB.  It is always safe to release
+                   // the reference on pVolumeCB that was held prior to the call.
+                   // If pVolumeCB == pNewVolumeCB, the reference from AFSLocateNameEntry
+                   // will be released second.
+                   //
+
+                   lCount = AFSVolumeDecrement( pVolumeCB,
+                                                VolumeReferenceReason);
+
+                   AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
+                                 AFS_TRACE_LEVEL_VERBOSE,
+                                 "AFSCommonCreate Decrement count on volume %p Reason %u Cnt %d\n",
+                                 pVolumeCB,
+                                 VolumeReferenceReason,
+                                 lCount));
+
+                   pVolumeCB = pNewVolumeCB;
+
+                   pNewVolumeCB = NULL;
+
+                   VolumeReferenceReason = NewVolumeReferenceReason;
+
+                   NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID;
+
+                   bReleaseVolume = (pVolumeCB != NULL);
+               }
+
+               //
+               // AFSLocateNameEntry does not alter the reference count of
+               // pParentDirectoryCB and it returns pNewParentDirectoryCB with
+               // a reference held.
+               //
+
+               if ( bReleaseParentDir)
+               {
+
+                   lCount = InterlockedDecrement( &pParentDirectoryCB->DirOpenReferenceCount);
+
+                   AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
+                                 AFS_TRACE_LEVEL_VERBOSE,
+                                 "AFSCommonCreate DecrementX count on %wZ DE %p Ccb %p Cnt %d\n",
+                                 &pParentDirectoryCB->NameInformation.FileName,
+                                 pParentDirectoryCB,
+                                 pCcb,
+                                 lCount));
+               }
+
+               pParentDirectoryCB = pNewParentDirectoryCB;
+
+               pNewParentDirectoryCB = NULL;
+
+               bReleaseParentDir = (pParentDirectoryCB != NULL);
+
+               if ( pDirectoryCB)
+               {
+
+                   bReleaseDir = TRUE;
+               }
+
+               if( !NT_SUCCESS( ntStatus) &&
+                   ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
+               {
 
-            uniSubstitutedPathName = uniRootFileName;
+                   if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer)
+                   {
+                       uniSubstitutedPathName.Buffer = NULL;
+                   }
 
-            ntStatus = AFSLocateNameEntry( &stAuthGroup,
-                                           pFileObject,
-                                           &uniRootFileName,
-                                           &uniParsedFileName,
-                                           pNameArray,
-                                           ulNameProcessingFlags,
-                                           pVolumeCB,
-                                           pParentDirectoryCB,
-                                           &pNewVolumeCB,
-                                           &NewVolumeReferenceReason,
-                                           &pNewParentDirectoryCB,
-                                           &pDirectoryCB,
-                                           &uniComponentName);
+                   //
+                   // AFSLocateNameEntry released the Parent while walking the
+                   // branch
+                   //
 
-            if ( pNewVolumeCB != NULL)
-            {
+                   AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
+                                 AFS_TRACE_LEVEL_VERBOSE,
+                                 "AFSCommonCreate (%p) Failed to locate name entry for %wZ Status %08lX\n",
+                                 Irp,
+                                 &uniFileName,
+                                 ntStatus));
 
-                //
-                // AFSLocateNameEntry returns pNewVolumeCB with a reference held
-                // even if pVolumeCB == pNewVolumeCB.  It is always safe to release
-                // the reference on pVolumeCB that was held prior to the call.
-                // If pVolumeCB == pNewVolumeCB, the reference from AFSLocateNameEntry
-                // will be released second.
-                //
+                   try_return( ntStatus);
+               }
 
-                lCount = AFSVolumeDecrement( pVolumeCB,
-                                             VolumeReferenceReason);
+               //
+               // Check for STATUS_REPARSE
+               //
 
-                AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
-                              AFS_TRACE_LEVEL_VERBOSE,
-                              "AFSCommonCreate Decrement count on volume %p Reason %u Cnt %d\n",
-                              pVolumeCB,
-                              VolumeReferenceReason,
-                              lCount));
+               if( ntStatus == STATUS_REPARSE)
+               {
 
-                pVolumeCB = pNewVolumeCB;
+                   uniSubstitutedPathName.Buffer = NULL;
 
-                pNewVolumeCB = NULL;
+                   //
+                   // Update the information and return
+                   //
 
-                VolumeReferenceReason = NewVolumeReferenceReason;
+                   Irp->IoStatus.Information = IO_REPARSE;
 
-                NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID;
+                   try_return( ntStatus);
+               }
 
-                bReleaseVolume = (pVolumeCB != NULL);
-            }
+               //
+               // If we re-allocated the name, then update our substitute name
+               //
 
-            //
-            // AFSLocateNameEntry does not alter the reference count of
-            // pParentDirectoryCB and it returns pNewParentDirectoryCB with
-            // a reference held.
-            //
+               if( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer)
+                {
 
-            if ( bReleaseParentDir)
-            {
+                   uniSubstitutedPathName = uniRootFileName;
+               }
+               else
+               {
 
-                lCount = InterlockedDecrement( &pParentDirectoryCB->DirOpenReferenceCount);
+                    uniSubstitutedPathName.Buffer = NULL;
+                }
 
-                AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
-                              AFS_TRACE_LEVEL_VERBOSE,
-                              "AFSCommonCreate DecrementX count on %wZ DE %p Ccb %p Cnt %d\n",
-                              &pParentDirectoryCB->NameInformation.FileName,
-                              pParentDirectoryCB,
-                              pCcb,
-                              lCount));
-            }
+                //
+               // Check for a symlink access
+                //
 
-            pParentDirectoryCB = pNewParentDirectoryCB;
+               if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND &&
+                   pParentDirectoryCB != NULL)
+               {
 
-            pNewParentDirectoryCB = NULL;
+                   //
+                   // pParentDirectoryCB DirOpenReferenceCount is still held
+                   //
 
-            bReleaseParentDir = (pParentDirectoryCB != NULL);
+                   UNICODE_STRING uniFinalComponent;
 
-            if ( pDirectoryCB)
-            {
+                   uniFinalComponent.Length = 0;
+                   uniFinalComponent.MaximumLength = 0;
+                   uniFinalComponent.Buffer = NULL;
 
-                bReleaseDir = TRUE;
-            }
+                   AFSRetrieveFinalComponent( &uniFileName,
+                                              &uniFinalComponent);
+
+                   ntStatus = AFSCheckSymlinkAccess( pParentDirectoryCB,
+                                                     &uniFinalComponent);
+
+                   if( !NT_SUCCESS( ntStatus) &&
+                       ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
+                   {
+
+                       AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
+                                     AFS_TRACE_LEVEL_VERBOSE,
+                                     "AFSCommonCreate (%p) Failing access to symlink %wZ Status %08lX\n",
+                                     Irp,
+                                     &uniFileName,
+                                     ntStatus));
 
-            if( !NT_SUCCESS( ntStatus) &&
-                ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
+                       try_return( ntStatus);
+                   }
+               }
+           }
+           else
             {
+               AFSNameArrayHdr    *pNameArrayClone = NULL;
+               UNICODE_STRING      uniRootFileNameClone;
 
-                if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer)
-                {
-                    uniSubstitutedPathName.Buffer = NULL;
-                }
+               //
+               // The FILE_OPEN_REPARSE_POINT flag has been specified and a ReparsePointPolicy
+               // is in effect which conditionally applies depending on the type of the target
+               // object.  Therefore, two lookup passes must be performed.
+               //   1. Evaluate the path as if the FILE_OPEN_REPARSE_POINT flag had
+               //      not been specified.
+               //   2. If the target object type matches the policy, use it and ignore
+               //      the FILE_OPEN_REPARSE_POINT flag.
+               //   3. If the target object type does not match the policy, perform
+               //      a second pass that opens the reparse point.
+               //   4. If the target object cannot be evaluated, perform the second pass
+               //      that opens the reparse point.
+
+
+               ulNameProcessingFlags = AFS_LOCATE_FLAGS_SUBSTITUTE_NAME;
+
+               uniSubstitutedPathName = uniRootFileName;
 
                 //
-                // AFSLocateNameEntry released the Parent while walking the
-                // branch
+               // Since we may need to replay the call with different options
+               // the values that might be altered need to be cloned:
+               //   1. uniRootFileName
+               //   2. pNameArray
                 //
 
-                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
-                              AFS_TRACE_LEVEL_VERBOSE,
-                              "AFSCommonCreate (%p) Failed to locate name entry for %wZ Status %08lX\n",
-                              Irp,
-                              &uniFileName,
-                              ntStatus));
+               pNameArrayClone = AFSInitNameArray( NULL, 0);
 
-                try_return( ntStatus);
-            }
+               if ( pNameArrayClone == NULL)
+               {
 
-            //
-            // Check for STATUS_REPARSE
-            //
+                   AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
+                                 AFS_TRACE_LEVEL_VERBOSE,
+                                 "AFSCommonCreate (%p) Failed to initialize name array clone\n",
+                                 Irp));
 
-            if( ntStatus == STATUS_REPARSE)
-            {
+                   try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
+               }
 
-                uniSubstitutedPathName.Buffer = NULL;
+               ntStatus = AFSPopulateNameArrayFromRelatedArray( pNameArrayClone,
+                                                                pNameArray,
+                                                                NULL);
 
-                //
-                // Update the information and return
-                //
+               if ( !NT_SUCCESS(ntStatus))
+               {
 
-                Irp->IoStatus.Information = IO_REPARSE;
+                   AFSFreeNameArray( pNameArrayClone);
 
-                try_return( ntStatus);
-            }
+                   try_return( ntStatus);
+               }
 
-            //
-            // If we re-allocated the name, then update our substitute name
-            //
+               uniRootFileNameClone = uniRootFileName;
 
-            if( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer)
-            {
+               uniRootFileNameClone.Buffer = (WCHAR *)AFSExAllocatePoolWithTag( PagedPool,
+                                                                                uniRootFileNameClone.MaximumLength,
+                                                                                AFS_NAME_BUFFER_ELEVEN_TAG);
 
-                uniSubstitutedPathName = uniRootFileName;
-            }
-            else
-            {
+               if( uniRootFileNameClone.Buffer == NULL)
+               {
 
-                uniSubstitutedPathName.Buffer = NULL;
-            }
+                   AFSFreeNameArray( pNameArrayClone);
 
-            //
-            // Check for a symlink access
-            //
+                   AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
+                                 AFS_TRACE_LEVEL_ERROR,
+                                 "AFSCommonCreate (%p) Failed to allocate uniRootFileNameClone\n",
+                                 Irp));
 
-            if( ntStatus == STATUS_OBJECT_NAME_NOT_FOUND &&
-                pParentDirectoryCB != NULL)
-            {
+                   try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
+               }
+
+               RtlCopyMemory( uniRootFileNameClone.Buffer,
+                              uniRootFileName.Buffer,
+                              uniRootFileNameClone.Length);
 
                 //
-                // pParentDirectoryCB DirOpenReferenceCount is still held
+               // Now that the data is saved perform the lookup to determine
+               // what the target resolves to.
                 //
 
-                UNICODE_STRING uniFinalComponent;
+               ntStatus = AFSLocateNameEntry( &stAuthGroup,
+                                              pFileObject,
+                                              &uniRootFileName,
+                                              &uniParsedFileName,
+                                              pNameArray,
+                                              ulNameProcessingFlags,
+                                              pVolumeCB,
+                                              pParentDirectoryCB,
+                                              &pNewVolumeCB,
+                                              &NewVolumeReferenceReason,
+                                              &pNewParentDirectoryCB,
+                                              &pDirectoryCB,
+                                              &uniComponentName);
+
+               if ( ntStatus == STATUS_SUCCESS ||
+                    ntStatus == STATUS_REPARSE ||
+                    ntStatus == STATUS_OBJECT_NAME_NOT_FOUND ||
+                    ntStatus == STATUS_ACCESS_DENIED)
+               {
+                   //
+                   // Decide what to do based upon the ReparsePointPolicy
+                   // and the type of the target object.
+                   //
+
+                   if ( ntStatus == STATUS_SUCCESS &&
+                        AFSIgnoreReparsePointToFile() &&
+                        pDirectoryCB->ObjectInformation->FileType == AFS_FILE_TYPE_FILE)
+                   {
+
+                       //
+                       // We found an entity that matches the policy.
+                       // Therefore, we are done.  Cleanup the cloned data
+                       // and clear the FILE_OPEN_REPARSE_FLAG so we do not
+                       // later mark the CCB with CCB_FLAG_MASK_OPENED_REPARSE_POINT.
+                       //
+
+                       AFSFreeNameArray( pNameArrayClone);
+
+                       pNameArrayClone = NULL;
+
+                       AFSExFreePoolWithTag( uniRootFileNameClone.Buffer,
+                                             AFS_NAME_BUFFER_ELEVEN_TAG);
+
+                       RtlZeroMemory( &uniRootFileNameClone,
+                                      sizeof( UNICODE_STRING));
+
+                       ClearFlag( ulOptions, FILE_OPEN_REPARSE_POINT);
+                   }
+                   else
+                   {
+                       //
+                       //  There is no matching policy, so we need to cleanup the
+                       //  output values from AFSLocateNameEntry(), restore the
+                       //  cloned information, and re-issue the request attempting
+                       //  to open the reparse point (if any).
+                       //
+
+                       if ( pNewVolumeCB != NULL)
+                       {
+
+                           lCount = AFSVolumeDecrement( pNewVolumeCB,
+                                                        NewVolumeReferenceReason);
+
+                           pNewVolumeCB = NULL;
+
+                           NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID;
+                       }
+
+                       if ( pNewParentDirectoryCB)
+                       {
+
+                           lCount = InterlockedDecrement( &pNewParentDirectoryCB->DirOpenReferenceCount);
+
+                           AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
+                                         AFS_TRACE_LEVEL_VERBOSE,
+                                         "AFSCommonCreate DecrementY count on %wZ DE %p Ccb %p Cnt %d\n",
+                                         &pNewParentDirectoryCB->NameInformation.FileName,
+                                         pNewParentDirectoryCB,
+                                         pCcb,
+                                         lCount));
+
+                           pNewParentDirectoryCB = NULL;
+                       }
+
+                       if ( pDirectoryCB)
+                       {
+
+                           lCount = InterlockedDecrement( &pDirectoryCB->DirOpenReferenceCount);
+
+                           AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
+                                         AFS_TRACE_LEVEL_VERBOSE,
+                                         "AFSCommonCreate DecrementZ count on %wZ DE %p Ccb %p Cnt %d\n",
+                                         &pDirectoryCB->NameInformation.FileName,
+                                         pDirectoryCB,
+                                         pCcb,
+                                         lCount));
+
+                           pDirectoryCB = NULL;
+                       }
+
+                       RtlZeroMemory( &uniComponentName,
+                                      sizeof( UNICODE_STRING));
+
+                       if ( uniSubstitutedPathName.Buffer != uniRootFileName.Buffer)
+                       {
+
+                           AFSExFreePoolWithTag( uniRootFileName.Buffer, 0);
 
-                uniFinalComponent.Length = 0;
-                uniFinalComponent.MaximumLength = 0;
-                uniFinalComponent.Buffer = NULL;
+                           uniRootFileName = uniSubstitutedPathName;
+                       }
 
-                AFSRetrieveFinalComponent( &uniFileName,
-                                           &uniFinalComponent);
+                       AFSFreeNameArray( pNameArray);
+
+                       pNameArray = pNameArrayClone;
+
+                       pNameArrayClone = NULL;
+
+                       //
+                       // Retry the lookup
+                       //
+
+                       ulNameProcessingFlags |= (AFS_LOCATE_FLAGS_NO_MP_TARGET_EVAL |
+                                                  AFS_LOCATE_FLAGS_NO_SL_TARGET_EVAL |
+                                                  AFS_LOCATE_FLAGS_NO_DFS_LINK_EVAL);
+
+                       ntStatus = AFSLocateNameEntry( &stAuthGroup,
+                                                      pFileObject,
+                                                      &uniRootFileName,
+                                                      &uniParsedFileName,
+                                                      pNameArray,
+                                                      ulNameProcessingFlags,
+                                                      pVolumeCB,
+                                                      pParentDirectoryCB,
+                                                      &pNewVolumeCB,
+                                                      &NewVolumeReferenceReason,
+                                                      &pNewParentDirectoryCB,
+                                                      &pDirectoryCB,
+                                                      &uniComponentName);
+                   }
+               }
+
+               if ( pNewVolumeCB != NULL)
+               {
+
+                   //
+                   // AFSLocateNameEntry returns pNewVolumeCB with a reference held
+                   // even if pVolumeCB == pNewVolumeCB.  It is always safe to release
+                   // the reference on pVolumeCB that was held prior to the call.
+                   // If pVolumeCB == pNewVolumeCB, the reference from AFSLocateNameEntry
+                   // will be released second.
+                   //
+
+                   lCount = AFSVolumeDecrement( pVolumeCB,
+                                                VolumeReferenceReason);
+
+                   AFSDbgTrace(( AFS_SUBSYSTEM_VOLUME_REF_COUNTING,
+                                 AFS_TRACE_LEVEL_VERBOSE,
+                                 "AFSCommonCreate Decrement count on volume %p Reason %u Cnt %d\n",
+                                 pVolumeCB,
+                                 VolumeReferenceReason,
+                                 lCount));
+
+                   pVolumeCB = pNewVolumeCB;
+
+                   pNewVolumeCB = NULL;
+
+                   VolumeReferenceReason = NewVolumeReferenceReason;
+
+                   NewVolumeReferenceReason = AFS_VOLUME_REFERENCE_INVALID;
+
+                   bReleaseVolume = (pVolumeCB != NULL);
+               }
+
+               //
+               // AFSLocateNameEntry does not alter the reference count of
+               // pParentDirectoryCB and it returns pNewParentDirectoryCB with
+               // a reference held.
+               //
+
+               if ( bReleaseParentDir)
+               {
+
+                   lCount = InterlockedDecrement( &pParentDirectoryCB->DirOpenReferenceCount);
+
+                   AFSDbgTrace(( AFS_SUBSYSTEM_DIRENTRY_REF_COUNTING,
+                                 AFS_TRACE_LEVEL_VERBOSE,
+                                 "AFSCommonCreate DecrementX count on %wZ DE %p Ccb %p Cnt %d\n",
+                                 &pParentDirectoryCB->NameInformation.FileName,
+                                 pParentDirectoryCB,
+                                 pCcb,
+                                 lCount));
+               }
 
-                ntStatus = AFSCheckSymlinkAccess( pParentDirectoryCB,
-                                                  &uniFinalComponent);
+               pParentDirectoryCB = pNewParentDirectoryCB;
+
+               pNewParentDirectoryCB = NULL;
+
+               bReleaseParentDir = (pParentDirectoryCB != NULL);
+
+               if ( pDirectoryCB)
+               {
+
+                   bReleaseDir = TRUE;
+               }
 
                 if( !NT_SUCCESS( ntStatus) &&
                     ntStatus != STATUS_OBJECT_NAME_NOT_FOUND)
                 {
 
+                   if ( uniSubstitutedPathName.Buffer == uniRootFileName.Buffer)
+                   {
+                       uniSubstitutedPathName.Buffer = NULL;
+                   }
+
+                   //
+                   // AFSLocateNameEntry released the Parent while walking the
+                   // branch
+                   //
+
                     AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                                   AFS_TRACE_LEVEL_VERBOSE,
-                                  "AFSCommonCreate (%p) Failing access to symlink %wZ Status %08lX\n",
+                                 "AFSCommonCreate (%p) Failed to locate name entry for %wZ Status %08lX\n",
                                   Irp,
                                   &uniFileName,
                                   ntStatus));
 
                     try_return( ntStatus);
                 }
+
+               //
+               // Check for STATUS_REPARSE
+               //
+
+               if( ntStatus == STATUS_REPARSE)
+               {
+
+                   uniSubstitutedPathName.Buffer = NULL;
+
+                   //
+                   // Update the information and return
+                   //
+
+                   Irp->IoStatus.Information = IO_REPARSE;
+
+                   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)
+               {
+
+                   //
+                   // pParentDirectoryCB DirOpenReferenceCount is still held
+                   //
+
+                   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)
+                   {
+
+                       AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
+                                     AFS_TRACE_LEVEL_VERBOSE,
+                                     "AFSCommonCreate (%p) Failing access to symlink %wZ Status %08lX\n",
+                                     Irp,
+                                     &uniFileName,
+                                     ntStatus));
+
+                       try_return( ntStatus);
+                   }
+               }
             }
         }