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);
+ }
+ }
}
}