/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
- * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Kernel Drivers, LLC.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Your File System, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
- * notice,
- * this list of conditions and the following disclaimer in the
- * documentation
- * and/or other materials provided with the distribution.
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
* - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
* nor the names of their contributors may be used to endorse or promote
* products derived from this software without specific prior written
return bRequestQueued;
}
+
+NTSTATUS
+AFSCreateSymlink( IN GUID *AuthGroup,
+ IN AFSObjectInfoCB *ParentObjectInfo,
+ IN UNICODE_STRING *FileName,
+ IN AFSObjectInfoCB *ObjectInfo,
+ IN UNICODE_STRING *TargetName)
+{
+
+ NTSTATUS ntStatus = STATUS_SUCCESS;
+ AFSCreateSymlinkCB *pSymlinkCreate = NULL;
+ ULONG ulResultLen = 0;
+ AFSCreateSymlinkResultCB *pSymlinkResult = NULL;
+
+ __Enter
+ {
+
+ //
+ // Allocate our request and result structures
+ //
+
+ pSymlinkCreate = (AFSCreateSymlinkCB *)ExAllocatePoolWithTag( PagedPool,
+ sizeof( AFSCreateSymlinkCB) +
+ TargetName->Length,
+ AFS_SYMLINK_REQUEST_TAG);
+
+ if( pSymlinkCreate == NULL)
+ {
+
+ try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlZeroMemory( pSymlinkCreate,
+ sizeof( AFSCreateSymlinkCB) +
+ TargetName->Length);
+
+ pSymlinkResult = (AFSCreateSymlinkResultCB *)ExAllocatePoolWithTag( PagedPool,
+ PAGE_SIZE,
+ AFS_SYMLINK_REQUEST_TAG);
+
+ if( pSymlinkResult == NULL)
+ {
+
+ try_return( ntStatus = STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ RtlZeroMemory( pSymlinkResult,
+ PAGE_SIZE);
+
+ //
+ // Populate the request buffer
+ //
+
+ RtlCopyMemory( &pSymlinkCreate->ParentId,
+ &ObjectInfo->ParentFileId,
+ sizeof( AFSFileID));
+
+ pSymlinkCreate->TargetNameLength = TargetName->Length;
+
+ RtlCopyMemory( pSymlinkCreate->TargetName,
+ TargetName->Buffer,
+ TargetName->Length);
+
+ ulResultLen = PAGE_SIZE;
+
+ //
+ // Call the service to create the symlink entry
+ //
+
+ ntStatus = AFSProcessRequest( AFS_REQUEST_TYPE_CREATE_SYMLINK,
+ AFS_REQUEST_FLAG_SYNCHRONOUS,
+ AuthGroup,
+ FileName,
+ &ObjectInfo->FileId,
+ ObjectInfo->VolumeCB->VolumeInformation.Cell,
+ ObjectInfo->VolumeCB->VolumeInformation.CellLength,
+ pSymlinkCreate,
+ sizeof( AFSCreateSymlinkCB) +
+ TargetName->Length,
+ pSymlinkResult,
+ &ulResultLen);
+
+ if ( ntStatus == STATUS_FILE_DELETED )
+ {
+
+ AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
+ AFS_TRACE_LEVEL_ERROR,
+ "AFSCreateSymlink failed FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
+ ObjectInfo->FileId.Cell,
+ ObjectInfo->FileId.Volume,
+ ObjectInfo->FileId.Vnode,
+ ObjectInfo->FileId.Unique,
+ ntStatus);
+
+ SetFlag( ParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
+
+ ClearFlag( ParentObjectInfo->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
+
+ SetFlag( ObjectInfo->Flags, AFS_OBJECT_FLAGS_DELETED);
+
+ try_return( ntStatus = STATUS_ACCESS_DENIED);
+ }
+ else if( ntStatus != STATUS_SUCCESS)
+ {
+
+ AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
+ AFS_TRACE_LEVEL_ERROR,
+ "AFSCreateSymlink failed FID %08lX-%08lX-%08lX-%08lX Status %08lX\n",
+ ObjectInfo->FileId.Cell,
+ ObjectInfo->FileId.Volume,
+ ObjectInfo->FileId.Vnode,
+ ObjectInfo->FileId.Unique,
+ ntStatus);
+
+ try_return( ntStatus);
+ }
+
+ //
+ // After successful creation the open object has been deleted and replaced by
+ // the actual symlink.
+ //
+
+ SetFlag( ParentObjectInfo->Flags, AFS_OBJECT_FLAGS_VERIFY);
+
+ ClearFlag( ParentObjectInfo->Flags, AFS_OBJECT_FLAGS_DIRECTORY_ENUMERATED);
+
+ SetFlag( ObjectInfo->Flags, AFS_OBJECT_FLAGS_DELETED);
+
+try_exit:
+
+ if( pSymlinkCreate != NULL)
+ {
+
+ AFSExFreePoolWithTag( pSymlinkCreate, AFS_SYMLINK_REQUEST_TAG);
+ }
+
+ if( pSymlinkResult != NULL)
+ {
+
+ AFSExFreePoolWithTag( pSymlinkResult, AFS_SYMLINK_REQUEST_TAG);
+ }
+ }
+
+ return ntStatus;
+}
/*
- * Copyright (c) 2008, 2009, 2010, 2011 Kernel Drivers, LLC.
- * Copyright (c) 2009, 2010, 2011 Your File System, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Kernel Drivers, LLC.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013 Your File System, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
- * notice,
- * this list of conditions and the following disclaimer in the
- * documentation
- * and/or other materials provided with the distribution.
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
* - Neither the names of Kernel Drivers, LLC and Your File System, Inc.
* nor the names of their contributors may be used to endorse or promote
* products derived from this software without specific prior written
case FSCTL_SET_REPARSE_POINT:
{
- REPARSE_GUID_DATA_BUFFER *pReparseBuffer = (REPARSE_GUID_DATA_BUFFER *)Irp->AssociatedIrp.SystemBuffer;
+ 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;
AFSDbgLogMsg( AFS_SUBSYSTEM_FILE_PROCESSING,
- AFS_TRACE_LEVEL_VERBOSE_2,
+ AFS_TRACE_LEVEL_VERBOSE,
"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))
+ if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
{
- ntStatus = STATUS_NOT_A_REPARSE_POINT;
+ ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
break;
}
- if( ulInputBufferLen < FIELD_OFFSET( REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer))
+ if( (pReparseGUIDBuffer->ReparseTag & 0x0000FFFF) == IO_REPARSE_TAG_OPENAFS_DFS)
{
- ntStatus = STATUS_IO_REPARSE_DATA_INVALID;
+ if( RtlCompareMemory( &pReparseGUIDBuffer->ReparseGuid,
+ &GUID_AFS_REPARSE_GUID,
+ sizeof( GUID)) != sizeof( GUID))
+ {
- break;
- }
+ ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
- if( (pReparseBuffer->ReparseTag & 0x0000FFFF) != IO_REPARSE_TAG_OPENAFS_DFS)
+ 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
+ //
- ntStatus = STATUS_IO_REPARSE_TAG_MISMATCH;
+ 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);
+
+ AFSDbgLogMsg( 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);
+
+ AFSDbgLogMsg( 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;
}
- if( RtlCompareMemory( &pReparseBuffer->ReparseGuid,
- &GUID_AFS_REPARSE_GUID,
- sizeof( GUID)) != sizeof( GUID))
+ //
+ // First thing is to locate/create our object information block
+ // for this entry
+ //
+
+ AFSAcquireExcl( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock,
+ TRUE);
+
+ ullIndex = AFSCreateLowIndex( &pCcb->DirectoryCB->ObjectInformation->ParentFileId);
+
+ ntStatus = AFSLocateHashEntry( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeHead,
+ ullIndex,
+ (AFSBTreeEntry **)&pParentObjectInfo);
+
+ if ( NT_SUCCESS( ntStatus) &&
+ pParentObjectInfo)
{
- ntStatus = STATUS_REPARSE_ATTRIBUTE_CONFLICT;
+ lCount = AFSObjectInfoIncrement( pParentObjectInfo,
+ AFS_OBJECT_REFERENCE_DIRENTRY);
- break;
+ AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+ AFS_TRACE_LEVEL_VERBOSE,
+ "AFSProcessUserFsRequest Increment count on object %p Cnt %d\n",
+ pParentObjectInfo,
+ lCount);
}
+ AFSReleaseResource( pCcb->DirectoryCB->ObjectInformation->VolumeCB->ObjectInfoTree.TreeLock);
+
//
- // For now deny access on this call
+ // Extract out the information to the call to the service
//
- ntStatus = STATUS_INVALID_PARAMETER;
+ ntStatus = AFSCreateSymlink( &pCcb->AuthGroup,
+ pParentObjectInfo,
+ &pCcb->DirectoryCB->NameInformation.FileName,
+ pCcb->DirectoryCB->ObjectInformation,
+ &uniTargetName);
+
+ AFSDbgLogMsg( 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,
+ pCcb->DirectoryCB->ObjectInformation->FileType,
+ pCcb->DirectoryCB->ObjectInformation->FileAttributes,
+ ntStatus);
+
+ lCount = AFSObjectInfoDecrement( pParentObjectInfo,
+ AFS_OBJECT_REFERENCE_DIRENTRY);
+
+ AFSDbgLogMsg( AFS_SUBSYSTEM_OBJECT_REF_COUNTING,
+ AFS_TRACE_LEVEL_VERBOSE,
+ "AFSProcessUserFsRequest Decrement count on object %p Cnt %d\n",
+ pParentObjectInfo,
+ lCount);
break;
}