예제 #1
0
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");

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_UNLOCK_VOLUME:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n");

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_DISMOUNT_VOLUME:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n");

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_MARK_VOLUME_DIRTY:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n");

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_IS_VOLUME_DIRTY:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n");

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_IS_VOLUME_MOUNTED:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n");

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_IS_PATHNAME_VALID:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n");

                ntStatus = STATUS_SUCCESS;

                break;
            }

#ifndef FSCTL_CSC_INTERNAL
#define FSCTL_CSC_INTERNAL                  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, FILE_ANY_ACCESS)
#endif
            case FSCTL_CSC_INTERNAL:
            {
                AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_CSC_INTERNAL request\n");

                ntStatus = STATUS_INVALID_DEVICE_REQUEST;

                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 %wZ Type 0x%x Attrib 0x%x\n",
                              &pCcb->DirectoryCB->NameInformation.FileName,
                              pCcb->DirectoryCB->ObjectInformation->FileType,
                              pCcb->DirectoryCB->ObjectInformation->FileAttributes);

                //
                // 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( 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);

                //
                // 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( &pCcb->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_REPARSE_POINT_NOT_RESOLVED;

                            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_REPARSE_POINT_NOT_RESOLVED;

                            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_REPARSE_POINT_NOT_RESOLVED;

                            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_SURROGATE|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 %wZ Type 0x%x Attrib 0x%x\n",
                              &pCcb->DirectoryCB->NameInformation.FileName,
                              pCcb->DirectoryCB->ObjectInformation->FileType,
                              pCcb->DirectoryCB->ObjectInformation->FileAttributes);

                //
                // 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( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
                {

                    ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                    break;
                }

                if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != 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_INVALID_PARAMETER;

                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 %wZ Type 0x%x Attrib 0x%x\n",
                              &pCcb->DirectoryCB->NameInformation.FileName,
                              pCcb->DirectoryCB->ObjectInformation->FileType,
                              pCcb->DirectoryCB->ObjectInformation->FileAttributes);

                //
                // 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( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
                {

                    ntStatus = STATUS_INVALID_PARAMETER;

                    break;
                }

                if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != 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_DEVICE_REQUEST;

                break;
        }

try_exit:

        NOTHING;
    }

    return ntStatus;
}
예제 #2
0
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 == NULL ||
            pCcb->DirectoryCB == NULL)
        {

            AFSDbgTrace(( 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:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_LOCK_VOLUME request\n"));

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_UNLOCK_VOLUME:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_UNLOCK_VOLUME request\n"));

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_DISMOUNT_VOLUME:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_DISMOUNT_VOLUME request\n"));

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_MARK_VOLUME_DIRTY:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_MARK_VOLUME_DIRTY request\n"));

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_IS_VOLUME_DIRTY:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_DIRTY request\n"));

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_IS_VOLUME_MOUNTED:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_IS_VOLUME_MOUNTED request\n"));

                ntStatus = STATUS_NOT_IMPLEMENTED;

                break;
            }

            case FSCTL_IS_PATHNAME_VALID:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_IS_PATHNAME_VALID request\n"));

                ntStatus = STATUS_SUCCESS;

                break;
            }

#ifndef FSCTL_CSC_INTERNAL
#define FSCTL_CSC_INTERNAL                  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 107, METHOD_NEITHER, FILE_ANY_ACCESS)
#endif
            case FSCTL_CSC_INTERNAL:
            {
                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_CSC_INTERNAL request\n"));

                ntStatus = STATUS_INVALID_DEVICE_REQUEST;

                break;
            }

            case FSCTL_GET_REPARSE_POINT:
            {

                REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
                REPARSE_DATA_BUFFER *pMSFTReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
                ULONG ulRemainingLen = ulOutputBufferLen;
                AFSReparseTagInfo *pReparseInfo = NULL;
                BOOLEAN bRelative = FALSE;
                BOOLEAN bDriveLetter = FALSE;
                WCHAR * PathBuffer = NULL;

                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_GET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
                              &pCcb->DirectoryCB->NameInformation.FileName,
                              pFcb->ObjectInformation->FileType,
                              pFcb->ObjectInformation->FileAttributes));

                //
                // Check if we have the reparse entry set on the entry
                //

                if( !BooleanFlagOn( pFcb->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
                {

                    ntStatus = STATUS_NOT_A_REPARSE_POINT;

                    break;
                }


                switch ( pFcb->ObjectInformation->FileType) {
                case AFS_FILE_TYPE_MOUNTPOINT:

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

                    break;

                default:

                    if( ulOutputBufferLen < FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
                    {

                        ntStatus = STATUS_BUFFER_TOO_SMALL;

                        Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer);

                        break;
                    }

                    ulRemainingLen -= FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer);

                    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
                    //

                    pFcb->ObjectInformation->DataVersion.QuadPart = (ULONGLONG)-1;

                    SetFlag( pFcb->ObjectInformation->Flags, AFS_OBJECT_FLAGS_VERIFY);

                    AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                                  AFS_TRACE_LEVEL_VERBOSE,
                                  "AFSProcessUserFsRequest Verifying symlink %wZ FID %08lX-%08lX-%08lX-%08lX\n",
                                  &pCcb->DirectoryCB->NameInformation.FileName,
                                  pFcb->ObjectInformation->FileId.Cell,
                                  pFcb->ObjectInformation->FileId.Volume,
                                  pFcb->ObjectInformation->FileId.Vnode,
                                  pFcb->ObjectInformation->FileId.Unique));

                    ntStatus = AFSVerifyEntry( &pCcb->AuthGroup,
					       pCcb->DirectoryCB,
					       FALSE);

                    if( !NT_SUCCESS( ntStatus))
                    {

                        AFSDbgTrace(( 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,
                                      pFcb->ObjectInformation->FileId.Cell,
                                      pFcb->ObjectInformation->FileId.Volume,
                                      pFcb->ObjectInformation->FileId.Vnode,
                                      pFcb->ObjectInformation->FileId.Unique,
                                      ntStatus));

                        AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);

                        break;
                    }
                }

                pReparseInfo = (AFSReparseTagInfo *)&pReparseBuffer->GenericReparseBuffer.DataBuffer[ 0];

                switch( pFcb->ObjectInformation->FileType)
                {

                    case AFS_FILE_TYPE_SYMLINK:
                    {

                        if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
                        {

                            ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;

                            break;
                        }

                        bRelative = AFSIsRelativeName( &pCcb->DirectoryCB->NameInformation.TargetName);

                        if ( bRelative)
                        {

                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                pCcb->DirectoryCB->NameInformation.TargetName.Length)
                            {

                                ntStatus = STATUS_BUFFER_TOO_SMALL;

                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length;

                                break;
                            }

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;

                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                        }
                        else
                        {

                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                /* Display Name */
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
                                /* Substitute Name */
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR))
                            {

                                ntStatus = STATUS_BUFFER_TOO_SMALL;

                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);

                                break;
                            }

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR);

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset =
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;

                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;

                            /* Display Name */
                            *PathBuffer++ = L'\\';

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR);

                            /* Substitute Name */
                            *PathBuffer++ = L'\\';
                            *PathBuffer++ = L'?';
                            *PathBuffer++ = L'?';
                            *PathBuffer++ = L'\\';
                            *PathBuffer++ = L'U';
                            *PathBuffer++ = L'N';
                            *PathBuffer++ = L'C';

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                        }

                        break;
                    }

                    case AFS_FILE_TYPE_MOUNTPOINT:
                    {
                        UNICODE_STRING Cell, Volume;
                        USHORT Type;

                        if( pCcb->DirectoryCB->NameInformation.TargetName.Length == 0)
                        {
                            ntStatus = STATUS_REPARSE_POINT_NOT_RESOLVED;

                            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_REPARSE_POINT_NOT_RESOLVED;

                            break;
                        }

                        bRelative = ( pCcb->DirectoryCB->NameInformation.TargetName.Buffer[0] == L'\\');

                        bDriveLetter = (bRelative == FALSE && pCcb->DirectoryCB->NameInformation.TargetName.Buffer[1] == L':');

                        if ( bRelative)
                        {

                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                pCcb->DirectoryCB->NameInformation.TargetName.Length)
                            {

                                ntStatus = STATUS_BUFFER_TOO_SMALL;

                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length;

                                break;
                            }

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;

                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                        }
                        else if ( bDriveLetter)
                        {

                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                /* Display Name */
                                pCcb->DirectoryCB->NameInformation.TargetName.Length +
                                /* Substitute Name */
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR))
                            {

                                ntStatus = STATUS_BUFFER_TOO_SMALL;

                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR);

                                break;
                            }

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 4 * sizeof( WCHAR);

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset =
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;

                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;

                            /* Display Name */
                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR);

                            /* Substitute Name */
                            *PathBuffer++ = L'\\';
                            *PathBuffer++ = L'?';
                            *PathBuffer++ = L'?';
                            *PathBuffer++ = L'\\';

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                        }
                        else
                        {

                            if( ulRemainingLen < (ULONG) FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                /* Display Name */
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
                                /* Substitute Name */
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR))
                            {

                                ntStatus = STATUS_BUFFER_TOO_SMALL;

                                Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR) +
                                    pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);

                                break;
                            }

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.Flags = 0;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 7 * sizeof( WCHAR);

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength =
                                pCcb->DirectoryCB->NameInformation.TargetName.Length + 1 * sizeof( WCHAR);

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset =
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength;

                            pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = 0;

                            PathBuffer = pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer;

                            /* Display Name */
                            *PathBuffer++ = L'\\';

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            PathBuffer += pCcb->DirectoryCB->NameInformation.TargetName.Length / sizeof( WCHAR);

                            /* Substitute Name */
                            *PathBuffer++ = L'\\';
                            *PathBuffer++ = L'?';
                            *PathBuffer++ = L'?';
                            *PathBuffer++ = L'\\';
                            *PathBuffer++ = L'U';
                            *PathBuffer++ = L'N';
                            *PathBuffer++ = L'C';

                            RtlCopyMemory( PathBuffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Buffer,
                                           pCcb->DirectoryCB->NameInformation.TargetName.Length);

                            pReparseBuffer->ReparseDataLength = FIELD_OFFSET( REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
                                FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
                                pMSFTReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                        }

                        break;
                    }

                    default:

                        ntStatus = STATUS_NOT_A_REPARSE_POINT;

                        break;
                }

                if ( ntStatus == STATUS_SUCCESS)
                {

                    ulRemainingLen -= pReparseBuffer->ReparseDataLength;

                    if ( pFcb->ObjectInformation->FileType == AFS_FILE_TYPE_MOUNTPOINT)
                    {

                        pReparseBuffer->ReparseTag = IO_REPARSE_TAG_SURROGATE|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;
                    }
                    else
                    {

                        pReparseBuffer->ReparseTag = IO_REPARSE_TAG_SYMLINK;

                        Irp->IoStatus.Information = FIELD_OFFSET( REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer)
                            + pReparseBuffer->ReparseDataLength;
                    }
                }

                AFSReleaseResource( &pCcb->DirectoryCB->NonPaged->Lock);

                break;
            }

            case FSCTL_SET_REPARSE_POINT:
            {

                REPARSE_GUID_DATA_BUFFER *pReparseGUIDBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
                REPARSE_DATA_BUFFER *pReparseBuffer = NULL;
                AFSReparseTagInfo *pReparseInfo = NULL;
                AFSObjectInfoCB *pParentObjectInfo = NULL;
                UNICODE_STRING uniTargetName;
                ULONGLONG ullIndex = 0;
                LONG lCount;

                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE,
                              "AFSProcessUserFsRequest Processing FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
                              &pCcb->DirectoryCB->NameInformation.FileName,
                              pFcb->ObjectInformation->FileType,
                              pFcb->ObjectInformation->FileAttributes));

                if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
                {

                    ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                    break;
                }

                if( (pReparseGUIDBuffer->ReparseTag & 0x0000FFFF) == IO_REPARSE_TAG_OPENAFS_DFS)
                {

                    if( RtlCompareMemory( &pReparseGUIDBuffer->ReparseGuid,
                                          &GUID_AFS_REPARSE_GUID,
                                          sizeof( GUID)) != sizeof( GUID))
                    {

                        ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;

                        break;
                    }

                    if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                                                        sizeof( AFSReparseTagInfo))
                    {

                        ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                        break;
                    }

                    pReparseInfo = (AFSReparseTagInfo *)pReparseGUIDBuffer->GenericReparseBuffer.DataBuffer;

                    switch( pReparseInfo->SubTag)
                    {

                        case OPENAFS_SUBTAG_SYMLINK:
                        {

                            if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                                           FIELD_OFFSET( AFSReparseTagInfo, AFSSymLink.Buffer) +
                                                           pReparseInfo->AFSSymLink.SymLinkTargetLength))
                            {

                                ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                                break;
                            }

                            uniTargetName.Length = pReparseInfo->AFSSymLink.SymLinkTargetLength;
                            uniTargetName.MaximumLength = uniTargetName.Length;

                            uniTargetName.Buffer = (WCHAR *)pReparseInfo->AFSSymLink.Buffer;

                            break;
                        }

                        case OPENAFS_SUBTAG_UNC:
                        {

                            if( ulInputBufferLen < (ULONG)(FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
                                                           FIELD_OFFSET( AFSReparseTagInfo, UNCReferral.Buffer) +
                                                           pReparseInfo->UNCReferral.UNCTargetLength))
                            {

                                ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                                break;
                            }

                            uniTargetName.Length = pReparseInfo->UNCReferral.UNCTargetLength;
                            uniTargetName.MaximumLength = uniTargetName.Length;

                            uniTargetName.Buffer = (WCHAR *)pReparseInfo->UNCReferral.Buffer;

                            break;
                        }

                        case OPENAFS_SUBTAG_MOUNTPOINT:
                            //
                            // Not yet handled
                            //
                        default:
                        {

                            ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                            break;
                        }
                    }
                }
                else
                {
                    //
                    // Handle Microsoft Reparse Tags
                    //

                    switch( pReparseGUIDBuffer->ReparseTag)
                    {

                        case IO_REPARSE_TAG_MOUNT_POINT:
                        {

                            pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;

                            uniTargetName.Length = pReparseBuffer->MountPointReparseBuffer.PrintNameLength;
                            uniTargetName.MaximumLength = uniTargetName.Length;

                            uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->MountPointReparseBuffer.PathBuffer +
                                                              pReparseBuffer->MountPointReparseBuffer.PrintNameOffset);

                            AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                                          AFS_TRACE_LEVEL_VERBOSE_2,
                                          "AFSProcessUserFsRequest IO_REPARSE_TAG_MOUNT_POINT request %wZ\n",
                                          &uniTargetName));

                            ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                            break;
                        }

                        case IO_REPARSE_TAG_SYMLINK:
                        {

                            pReparseBuffer = (REPARSE_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;

                            uniTargetName.Length = pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
                            uniTargetName.MaximumLength = uniTargetName.Length;

                            uniTargetName.Buffer = (WCHAR *)((char *)pReparseBuffer->SymbolicLinkReparseBuffer.PathBuffer +
                                                              pReparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameOffset);

                            AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                                          AFS_TRACE_LEVEL_VERBOSE_2,
                                          "AFSProcessUserFsRequest IO_REPARSE_TAG_SYMLINK request %wZ\n",
                                          &uniTargetName));
                            break;
                        }

                        default:
                        {

                            ntStatus = STATUS_IO_REPARSE_DATA_INVALID;

                            break;
                        }
                    }
                }

                if( !NT_SUCCESS( ntStatus))
                {

                    break;
                }

                //
                // First thing is to locate/create our object information block
                // for this entry
                //

                AFSAcquireExcl( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock,
                                TRUE);

                if ( AFSIsVolumeFID( &pFcb->ObjectInformation->ParentFileId))
                {

                    pParentObjectInfo = &pFcb->ObjectInformation->VolumeCB->ObjectInformation;
                }
                else
                {
                    ullIndex = AFSCreateLowIndex( &pFcb->ObjectInformation->ParentFileId);

                    ntStatus = AFSLocateHashEntry( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead,
                                                   ullIndex,
                                                   (AFSBTreeEntry **)&pParentObjectInfo);
                }

                if ( NT_SUCCESS( ntStatus))
                {

                    lCount = AFSObjectInfoIncrement( pParentObjectInfo,
                                                     AFS_OBJECT_REFERENCE_FS_REQ);

                    AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
                                  AFS_TRACE_LEVEL_VERBOSE,
                                  "AFSProcessUserFsRequest Increment count on object %p Cnt %d\n",
                                  pParentObjectInfo,
                                  lCount));

                    KeQueryTickCount( &pParentObjectInfo->LastAccessCount);
                }

                AFSReleaseResource( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock);

                if ( NT_SUCCESS( ntStatus))
                {

                    //
                    // Extract out the information to the call to the service
                    //

                    ntStatus = AFSCreateSymlink( &pCcb->AuthGroup,
                                                 pParentObjectInfo,
                                                 &pCcb->DirectoryCB->NameInformation.FileName,
                                                 pFcb->ObjectInformation,
                                                 &uniTargetName);

                    AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                                  AFS_TRACE_LEVEL_VERBOSE_2,
                                  "AFSProcessUserFsRequest Processed FSCTL_SET_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x Status %08lX\n",
                                  &pCcb->DirectoryCB->NameInformation.FileName,
                                  pFcb->ObjectInformation->FileType,
                                  pFcb->ObjectInformation->FileAttributes,
                                  ntStatus));

                    AFSAcquireShared( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock,
                                      TRUE);

                    lCount = AFSObjectInfoDecrement( pParentObjectInfo,
                                                     AFS_OBJECT_REFERENCE_FS_REQ);

                    AFSDbgTrace(( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
                                  AFS_TRACE_LEVEL_VERBOSE,
                                  "AFSProcessUserFsRequest Decrement count on object %p Cnt %d\n",
                                  pParentObjectInfo,
                                  lCount));

                    AFSReleaseResource( pFcb->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock);
                }

                break;
            }

            case FSCTL_DELETE_REPARSE_POINT:
            {

                REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;

                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing FSCTL_DELETE_REPARSE_POINT request %wZ Type 0x%x Attrib 0x%x\n",
                              &pCcb->DirectoryCB->NameInformation.FileName,
                              pFcb->ObjectInformation->FileType,
                              pFcb->ObjectInformation->FileAttributes));

                //
                // Check if we have the reparse entry set on the entry
                //

                if( !BooleanFlagOn( pFcb->ObjectInformation->FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT))
                {

                    ntStatus = STATUS_NOT_A_REPARSE_POINT;

                    break;
                }

                if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
                {

                    ntStatus = STATUS_INVALID_PARAMETER;

                    break;
                }

                if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != 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;
                }

                //
                // Claim success.  The typical usage is setting delete on close
                // as the next operation on the reparse point before closing
                // the handle.
                //

                ntStatus = STATUS_SUCCESS;

                break;
            }

#ifndef FSCTL_SET_PURGE_FAILURE_MODE
#define FSCTL_SET_PURGE_FAILURE_MODE        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 156, METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif

            case FSCTL_SET_PURGE_FAILURE_MODE:
            {

                //
                // For the time being just succeed this call
                //

                ntStatus = STATUS_SUCCESS;

                break;
            }

            default :
            {

                AFSDbgTrace(( AFS_SUBSYSTEM_FILE_PROCESSING,
                              AFS_TRACE_LEVEL_VERBOSE_2,
                              "AFSProcessUserFsRequest Processing default (%08lX) request\n",
                              ulFsControlCode));

                ntStatus = STATUS_INVALID_DEVICE_REQUEST;

                break;
            }
        }

try_exit:

        NOTHING;
    }

    return ntStatus;
}