wslinux support: ATOMIC_CREATE_ECP_CONTEXT

This commit is contained in:
Bill Zissimopoulos 2019-04-27 15:30:57 -07:00
parent 195f3bf92d
commit c01402443d
12 changed files with 250 additions and 59 deletions

View File

@ -168,7 +168,8 @@ enum
/* additional kernel-mode flags */\ /* additional kernel-mode flags */\
UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\ UINT32 AllowOpenInKernelMode:1; /* allow kernel mode to open files when possible */\
UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\ UINT32 CasePreservedExtendedAttributes:1; /* preserve case of EA (default is UPPERCASE) */\
UINT32 KmReservedFlags:6;\ UINT32 WslFeatures:1; /* support features required for WSLinux */\
UINT32 KmReservedFlags:5;\
WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\ WCHAR Prefix[FSP_FSCTL_VOLUME_PREFIX_SIZE / sizeof(WCHAR)]; /* UNC prefix (\Server\Share) */\
WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)]; WCHAR FileSystemName[FSP_FSCTL_VOLUME_FSNAME_SIZE / sizeof(WCHAR)];
#define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\ #define FSP_FSCTL_VOLUME_PARAMS_V1_FIELD_DEFN\
@ -277,7 +278,7 @@ typedef struct
UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 DesiredAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */ UINT32 GrantedAccess; /* FILE_{READ_DATA,WRITE_DATA,etc.} */
UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */ UINT32 ShareAccess; /* FILE_SHARE_{READ,WRITE,DELETE} */
FSP_FSCTL_TRANSACT_BUF Ea; /* extended attributes buffer */ FSP_FSCTL_TRANSACT_BUF Ea; /* extended attributes or reparse point buffer */
UINT32 UserMode:1; /* request originated in user mode */ UINT32 UserMode:1; /* request originated in user mode */
UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */ UINT32 HasTraversePrivilege:1; /* requestor has TOKEN_HAS_TRAVERSE_PRIVILEGE */
UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */ UINT32 HasBackupPrivilege:1; /* requestor has TOKEN_HAS_BACKUP_PRIVILEGE */
@ -286,6 +287,7 @@ typedef struct
UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */ UINT32 CaseSensitive:1; /* FileName comparisons should be case-sensitive */
UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */ UINT32 HasTrailingBackslash:1; /* FileName had trailing backslash */
UINT32 AcceptsSecurityDescriptor:1; UINT32 AcceptsSecurityDescriptor:1;
UINT32 EaIsReparsePoint:1; /* Ea buffer is reparse point */
UINT32 ReservedFlags:24; UINT32 ReservedFlags:24;
UINT16 NamedStream; /* request targets named stream; colon offset in FileName */ UINT16 NamedStream; /* request targets named stream; colon offset in FileName */
} Create; } Create;

View File

@ -912,7 +912,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
/** /**
* Create new file or directory. * Create new file or directory.
* *
* This function works like Create, except that it also accepts EA (extended attributes). * This function works like Create, except that it also accepts an extra buffer that
* may contain extended attributes or a reparse point.
* *
* NOTE: If both Create and CreateEx are defined, CreateEx takes precedence. * NOTE: If both Create and CreateEx are defined, CreateEx takes precedence.
* *
@ -941,10 +942,12 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* Windows GetSecurityDescriptorLength API. Will be NULL for named streams. * Windows GetSecurityDescriptorLength API. Will be NULL for named streams.
* @param AllocationSize * @param AllocationSize
* Allocation size for the newly created file. * Allocation size for the newly created file.
* @param Ea * @param ExtraBuffer
* Extended attributes buffer. * Extended attributes or reparse point buffer.
* @param EaLength * @param ExtraLength
* Extended attributes buffer length. * Extended attributes or reparse point buffer length.
* @param ExtraBufferIsReparsePoint
* FALSE: extra buffer is extended attributes; TRUE: extra buffer is reparse point.
* @param PFileContext [out] * @param PFileContext [out]
* Pointer that will receive the file context on successful return from this call. * Pointer that will receive the file context on successful return from this call.
* @param FileInfo [out] * @param FileInfo [out]
@ -956,7 +959,7 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
NTSTATUS (*CreateEx)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*CreateEx)(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PVOID ExtraBuffer, ULONG ExtraLength, BOOLEAN ExtraBufferIsReparsePoint,
PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo); PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo);
/** /**
* Overwrite a file. * Overwrite a file.

View File

@ -443,6 +443,7 @@ static NTSTATUS FspFileSystemOpCreate_FileCreate(FSP_FILE_SYSTEM *FileSystem,
0 != Request->Req.Create.Ea.Size ? 0 != Request->Req.Create.Ea.Size ?
(PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0, (PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0,
Request->Req.Create.Ea.Size, Request->Req.Create.Ea.Size,
Request->Req.Create.EaIsReparsePoint,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo); AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
else else
Result = FileSystem->Interface->Create(FileSystem, Result = FileSystem->Interface->Create(FileSystem,
@ -590,6 +591,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOpenIf(FSP_FILE_SYSTEM *FileSystem,
0 != Request->Req.Create.Ea.Size ? 0 != Request->Req.Create.Ea.Size ?
(PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0, (PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0,
Request->Req.Create.Ea.Size, Request->Req.Create.Ea.Size,
Request->Req.Create.EaIsReparsePoint,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo); AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
else else
Result = FileSystem->Interface->Create(FileSystem, Result = FileSystem->Interface->Create(FileSystem,
@ -724,6 +726,7 @@ static NTSTATUS FspFileSystemOpCreate_FileOverwriteIf(FSP_FILE_SYSTEM *FileSyste
0 != Request->Req.Create.Ea.Size ? 0 != Request->Req.Create.Ea.Size ?
(PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0, (PVOID)(Request->Buffer + Request->Req.Create.Ea.Offset) : 0,
Request->Req.Create.Ea.Size, Request->Req.Create.Ea.Size,
Request->Req.Create.EaIsReparsePoint,
AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo); AddrOfFileContext(FullContext), &OpenFileInfo.FileInfo);
else else
Result = FileSystem->Interface->Create(FileSystem, Result = FileSystem->Interface->Create(FileSystem,

View File

@ -752,7 +752,7 @@ exit:
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PVOID ExtraBuffer, ULONG ExtraLength, BOOLEAN ExtraBufferIsReparsePoint,
PVOID *PFileDesc, FSP_FSCTL_FILE_INFO *FileInfo) PVOID *PFileDesc, FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
@ -766,7 +766,9 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
int err; int err;
NTSTATUS Result; NTSTATUS Result;
if (0 != Ea) if (0 != ExtraBuffer)
{
if (!ExtraBufferIsReparsePoint)
{ {
if (0 == f->ops.listxattr || 0 == f->ops.getxattr || if (0 == f->ops.listxattr || 0 == f->ops.getxattr ||
0 == f->ops.setxattr || 0 == f->ops.removexattr) 0 == f->ops.setxattr || 0 == f->ops.removexattr)
@ -775,6 +777,13 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
goto exit; goto exit;
} }
} }
else
{
/* !!!: revisit */
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
}
filedesc = MemAlloc(sizeof *filedesc); filedesc = MemAlloc(sizeof *filedesc);
if (0 == filedesc) if (0 == filedesc)
@ -889,13 +898,22 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
goto exit; goto exit;
} }
if (0 != Ea) if (0 != ExtraBuffer)
{
if (!ExtraBufferIsReparsePoint)
{ {
Result = FspFileSystemEnumerateEa(FileSystem, Result = FspFileSystemEnumerateEa(FileSystem,
fsp_fuse_intf_SetEaEntry, contexthdr->PosixPath, Ea, EaLength); fsp_fuse_intf_SetEaEntry, contexthdr->PosixPath, ExtraBuffer, ExtraLength);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
goto exit; goto exit;
} }
else
{
/* !!!: revisit: WslFeatures, GetFileInfoFunnel, GetReparsePointEx, SetReparsePoint */
Result = STATUS_INVALID_PARAMETER;
goto exit;
}
}
/* /*
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache. * Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
* NOTE: Originally WinFsp dit not support disabling the cache manager * NOTE: Originally WinFsp dit not support disabling the cache manager

View File

@ -1085,8 +1085,9 @@ namespace Fsp
UInt32 FileAttributes, UInt32 FileAttributes,
Byte[] SecurityDescriptor, Byte[] SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
out Object FileNode, out Object FileNode,
out Object FileDesc, out Object FileDesc,
out FileInfo FileInfo, out FileInfo FileInfo,
@ -1391,6 +1392,16 @@ namespace Fsp
} }
} }
/// <summary> /// <summary>
/// Makes a byte array that contains a reparse point.
/// </summary>
/// <returns>The reparse point byte array.</returns>
public static Byte[] MakeReparsePoint(
IntPtr Buffer,
UInt32 Size)
{
return Api.MakeReparsePoint(Buffer, (UIntPtr)Size);
}
/// <summary>
/// Gets the reparse tag from reparse data. /// Gets the reparse tag from reparse data.
/// </summary> /// </summary>
/// <param name="ReparseData"> /// <param name="ReparseData">

View File

@ -221,6 +221,11 @@ namespace Fsp
get { return 0 != (_VolumeParams.Flags & VolumeParams.AllowOpenInKernelMode); } get { return 0 != (_VolumeParams.Flags & VolumeParams.AllowOpenInKernelMode); }
set { _VolumeParams.Flags |= (value ? VolumeParams.AllowOpenInKernelMode : 0); } set { _VolumeParams.Flags |= (value ? VolumeParams.AllowOpenInKernelMode : 0); }
} }
public Boolean WslFeatures
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.WslFeatures); }
set { _VolumeParams.Flags |= (value ? VolumeParams.WslFeatures : 0); }
}
/// <summary> /// <summary>
/// Gets or sets the prefix for a network file system. /// Gets or sets the prefix for a network file system.
/// </summary> /// </summary>
@ -472,8 +477,9 @@ namespace Fsp
UInt32 FileAttributes, UInt32 FileAttributes,
IntPtr SecurityDescriptor, IntPtr SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
ref FullContext FullContext, ref FullContext FullContext,
ref OpenFileInfo OpenFileInfo) ref OpenFileInfo OpenFileInfo)
{ {
@ -490,8 +496,9 @@ namespace Fsp
FileAttributes, FileAttributes,
Api.MakeSecurityDescriptor(SecurityDescriptor), Api.MakeSecurityDescriptor(SecurityDescriptor),
AllocationSize, AllocationSize,
Ea, ExtraBuffer,
EaLength, ExtraLength,
ExtraBufferIsReparsePoint,
out FileNode, out FileNode,
out FileDesc, out FileDesc,
out OpenFileInfo.FileInfo, out OpenFileInfo.FileInfo,

View File

@ -53,6 +53,7 @@ namespace Fsp.Interop
internal const UInt32 UmFileContextIsFullContext = 0x00020000; internal const UInt32 UmFileContextIsFullContext = 0x00020000;
internal const UInt32 AllowOpenInKernelMode = 0x01000000; internal const UInt32 AllowOpenInKernelMode = 0x01000000;
internal const UInt32 CasePreservedExtendedAttributes = 0x02000000; internal const UInt32 CasePreservedExtendedAttributes = 0x02000000;
internal const UInt32 WslFeatures = 0x04000000;
internal const int PrefixSize = 192; internal const int PrefixSize = 192;
internal const int FileSystemNameSize = 16; internal const int FileSystemNameSize = 16;
@ -557,8 +558,9 @@ namespace Fsp.Interop
UInt32 FileAttributes, UInt32 FileAttributes,
IntPtr SecurityDescriptor, IntPtr SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
[MarshalAs(UnmanagedType.U1)] Boolean ExtraBufferIsReparsePoint,
ref FullContext FullContext, ref FullContext FullContext,
ref OpenFileInfo OpenFileInfo); ref OpenFileInfo OpenFileInfo);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] [UnmanagedFunctionPointer(CallingConvention.Cdecl)]

View File

@ -29,7 +29,7 @@ static NTSTATUS FspFsvolCreate(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp);
static NTSTATUS FspFsvolCreateNoLock( static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen); BOOLEAN MainFileOpen, PFSP_ATOMIC_CREATE_ECP_CONTEXT AtomicCreateEcp);
FSP_IOPREP_DISPATCH FspFsvolCreatePrepare; FSP_IOPREP_DISPATCH FspFsvolCreatePrepare;
FSP_IOCMPL_DISPATCH FspFsvolCreateComplete; FSP_IOCMPL_DISPATCH FspFsvolCreateComplete;
static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response, static NTSTATUS FspFsvolCreateTryOpen(PIRP Irp, const FSP_FSCTL_TRANSACT_RSP *Response,
@ -144,6 +144,7 @@ static NTSTATUS FspFsvolCreate(
PECP_LIST ExtraCreateParameters; PECP_LIST ExtraCreateParameters;
PVOID ExtraCreateParameter; PVOID ExtraCreateParameter;
BOOLEAN MainFileOpen = FALSE; BOOLEAN MainFileOpen = FALSE;
PFSP_ATOMIC_CREATE_ECP_CONTEXT AtomicCreateEcp = 0;
/* /*
* Check if the IRP has ECP's. * Check if the IRP has ECP's.
@ -219,6 +220,21 @@ static NTSTATUS FspFsvolCreate(
} }
} }
#endif #endif
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.WslFeatures)
{
// {4720bd83-52ac-4104-a130-d1ec6a8cc8e5}
static const GUID FspAtomicCreateEcpGuid =
{ 0x4720bd83, 0x52ac, 0x4104, { 0xa1, 0x30, 0xd1, 0xec, 0x6a, 0x8c, 0xc8, 0xe5 } };
ExtraCreateParameter = 0;
AtomicCreateEcp =
NT_SUCCESS(FsRtlFindExtraCreateParameter(ExtraCreateParameters,
&FspAtomicCreateEcpGuid, &ExtraCreateParameter, 0)) &&
0 != ExtraCreateParameter &&
!FsRtlIsEcpFromUserMode(ExtraCreateParameter) ?
ExtraCreateParameter : 0;
}
} }
if (!MainFileOpen) if (!MainFileOpen)
@ -226,7 +242,8 @@ static NTSTATUS FspFsvolCreate(
FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject); FspFsvolDeviceFileRenameAcquireShared(FsvolDeviceObject);
try try
{ {
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, FALSE); Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp,
MainFileOpen, AtomicCreateEcp);
} }
finally finally
{ {
@ -235,14 +252,15 @@ static NTSTATUS FspFsvolCreate(
} }
} }
else else
Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp, TRUE); Result = FspFsvolCreateNoLock(FsvolDeviceObject, Irp, IrpSp,
MainFileOpen, AtomicCreateEcp);
return Result; return Result;
} }
static NTSTATUS FspFsvolCreateNoLock( static NTSTATUS FspFsvolCreateNoLock(
PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp, PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
BOOLEAN MainFileOpen) BOOLEAN MainFileOpen, PFSP_ATOMIC_CREATE_ECP_CONTEXT AtomicCreateEcp)
{ {
PAGED_CODE(); PAGED_CODE();
@ -279,6 +297,8 @@ static NTSTATUS FspFsvolCreateNoLock(
USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess; USHORT ShareAccess = IrpSp->Parameters.Create.ShareAccess;
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer; PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
ULONG EaLength = IrpSp->Parameters.Create.EaLength; ULONG EaLength = IrpSp->Parameters.Create.EaLength;
PVOID ExtraBuffer = 0;
ULONG ExtraLength = 0;
ULONG Flags = IrpSp->Flags; ULONG Flags = IrpSp->Flags;
KPROCESSOR_MODE RequestorMode = KPROCESSOR_MODE RequestorMode =
FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode; FlagOn(Flags, SL_FORCE_ACCESS_CHECK) ? UserMode : Irp->RequestorMode;
@ -292,6 +312,7 @@ static NTSTATUS FspFsvolCreateNoLock(
BOOLEAN HasRestorePrivilege = BOOLEAN HasRestorePrivilege =
BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE); BooleanFlagOn(AccessState->Flags, TOKEN_HAS_RESTORE_PRIVILEGE);
BOOLEAN HasTrailingBackslash = FALSE; BOOLEAN HasTrailingBackslash = FALSE;
BOOLEAN EaIsReparsePoint = FALSE;
FSP_FILE_NODE *FileNode, *RelatedFileNode; FSP_FILE_NODE *FileNode, *RelatedFileNode;
FSP_FILE_DESC *FileDesc; FSP_FILE_DESC *FileDesc;
UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 }; UNICODE_STRING MainFileName = { 0 }, StreamPart = { 0 };
@ -302,6 +323,36 @@ static NTSTATUS FspFsvolCreateNoLock(
if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID)) if (FlagOn(CreateOptions, FILE_OPEN_BY_FILE_ID))
return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED;
/* is there an AtomicCreateEcp attached? */
if (0 != AtomicCreateEcp)
{
if ((FILE_CREATE != CreateDisposition && FILE_OPEN_IF != CreateDisposition) ||
0 != EaBuffer ||
RTL_SIZEOF_THROUGH_FIELD(FSP_ATOMIC_CREATE_ECP_CONTEXT, ReparseBuffer) >
AtomicCreateEcp->Size ||
/* !!!: revisit: FlagOn*/
!FlagOn(AtomicCreateEcp->InFlags,
ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT |
ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED))
return STATUS_INVALID_PARAMETER; /* docs do not say what to return on failure! */
if (FlagOn(AtomicCreateEcp->InFlags,
ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED))
{
Result = FsRtlValidateReparsePointBuffer(AtomicCreateEcp->ReparseBufferLength,
AtomicCreateEcp->ReparseBuffer);
if (!NT_SUCCESS(Result))
return Result;
/* mark that we satisfied the reparse point request, although we may fail it later! */
AtomicCreateEcp->OutFlags = ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET;
ExtraBuffer = AtomicCreateEcp->ReparseBuffer;
ExtraLength = AtomicCreateEcp->ReparseBufferLength;
EaIsReparsePoint = TRUE;
}
}
/* was an EA buffer specified? */ /* was an EA buffer specified? */
if (0 != EaBuffer) if (0 != EaBuffer)
{ {
@ -318,6 +369,9 @@ static NTSTATUS FspFsvolCreateNoLock(
EaBuffer, EaLength, (PULONG)&Irp->IoStatus.Information); EaBuffer, EaLength, (PULONG)&Irp->IoStatus.Information);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
ExtraBuffer = EaBuffer;
ExtraLength = EaLength;
} }
/* cannot open a paging file */ /* cannot open a paging file */
@ -555,9 +609,9 @@ static NTSTATUS FspFsvolCreateNoLock(
SecurityDescriptorSize = 0; SecurityDescriptorSize = 0;
FileAttributes = 0; FileAttributes = 0;
/* cannot set EA on named stream */ /* cannot set extra buffer on named stream */
EaBuffer = 0; ExtraBuffer = 0;
EaLength = 0; ExtraLength = 0;
/* remember the main file node */ /* remember the main file node */
ASSERT(0 == FileNode->MainFileNode); ASSERT(0 == FileNode->MainFileNode);
@ -577,8 +631,8 @@ static NTSTATUS FspFsvolCreateNoLock(
/* create the user-mode file system request */ /* create the user-mode file system request */
Result = FspIopCreateRequestEx(Irp, &FileNode->FileName, Result = FspIopCreateRequestEx(Irp, &FileNode->FileName,
0 != EaBuffer ? 0 != ExtraBuffer ?
FSP_FSCTL_DEFAULT_ALIGN_UP(SecurityDescriptorSize) + EaLength : SecurityDescriptorSize, FSP_FSCTL_DEFAULT_ALIGN_UP(SecurityDescriptorSize) + ExtraLength : SecurityDescriptorSize,
FspFsvolCreateRequestFini, &Request); FspFsvolCreateRequestFini, &Request);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
@ -616,10 +670,10 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.DesiredAccess = DesiredAccess; Request->Req.Create.DesiredAccess = DesiredAccess;
Request->Req.Create.GrantedAccess = GrantedAccess; Request->Req.Create.GrantedAccess = GrantedAccess;
Request->Req.Create.ShareAccess = ShareAccess; Request->Req.Create.ShareAccess = ShareAccess;
Request->Req.Create.Ea.Offset = 0 != EaBuffer ? Request->Req.Create.Ea.Offset = 0 != ExtraBuffer ?
(0 != Request->Req.Create.SecurityDescriptor.Offset ? (0 != Request->Req.Create.SecurityDescriptor.Offset ?
NEXTOFS(Request->Req.Create.SecurityDescriptor) : NEXTOFS(Request->FileName)) : 0; NEXTOFS(Request->Req.Create.SecurityDescriptor) : NEXTOFS(Request->FileName)) : 0;
Request->Req.Create.Ea.Size = 0 != EaBuffer ? (UINT16)EaLength : 0; Request->Req.Create.Ea.Size = 0 != ExtraBuffer ? (UINT16)ExtraLength : 0;
Request->Req.Create.UserMode = UserMode == RequestorMode; Request->Req.Create.UserMode = UserMode == RequestorMode;
Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege; Request->Req.Create.HasTraversePrivilege = HasTraversePrivilege;
Request->Req.Create.HasBackupPrivilege = HasBackupPrivilege; Request->Req.Create.HasBackupPrivilege = HasBackupPrivilege;
@ -628,10 +682,10 @@ static NTSTATUS FspFsvolCreateNoLock(
Request->Req.Create.CaseSensitive = CaseSensitive; Request->Req.Create.CaseSensitive = CaseSensitive;
Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash; Request->Req.Create.HasTrailingBackslash = HasTrailingBackslash;
Request->Req.Create.NamedStream = MainFileName.Length; Request->Req.Create.NamedStream = MainFileName.Length;
#undef NEXTOFS
Request->Req.Create.AcceptsSecurityDescriptor = 0 == Request->Req.Create.NamedStream && Request->Req.Create.AcceptsSecurityDescriptor = 0 == Request->Req.Create.NamedStream &&
!!FsvolDeviceExtension->VolumeParams.AllowOpenInKernelMode; !!FsvolDeviceExtension->VolumeParams.AllowOpenInKernelMode;
Request->Req.Create.EaIsReparsePoint = EaIsReparsePoint;
#undef NEXTOFS
ASSERT( ASSERT(
0 == StreamPart.Length && 0 == MainFileName.Length || 0 == StreamPart.Length && 0 == MainFileName.Length ||
@ -642,10 +696,10 @@ static NTSTATUS FspFsvolCreateNoLock(
RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset, RtlCopyMemory(Request->Buffer + Request->Req.Create.SecurityDescriptor.Offset,
SecurityDescriptor, SecurityDescriptorSize); SecurityDescriptor, SecurityDescriptorSize);
/* copy the EA buffer (if any) into the request */ /* copy the extra buffer (if any) into the request */
if (0 != EaBuffer) if (0 != ExtraBuffer)
RtlCopyMemory(Request->Buffer + Request->Req.Create.Ea.Offset, RtlCopyMemory(Request->Buffer + Request->Req.Create.Ea.Offset,
EaBuffer, EaLength); ExtraBuffer, ExtraLength);
/* fix FileNode->FileName if we are doing SL_OPEN_TARGET_DIRECTORY */ /* fix FileNode->FileName if we are doing SL_OPEN_TARGET_DIRECTORY */
if (Request->Req.Create.OpenTargetDirectory) if (Request->Req.Create.OpenTargetDirectory)

View File

@ -1678,4 +1678,39 @@ typedef struct
ULONG LxDeviceIdMajor; ULONG LxDeviceIdMajor;
ULONG LxDeviceIdMinor; ULONG LxDeviceIdMinor;
} FSP_FILE_STAT_LX_INFORMATION, *PFSP_FILE_STAT_LX_INFORMATION; } FSP_FILE_STAT_LX_INFORMATION, *PFSP_FILE_STAT_LX_INFORMATION;
/* ATOMIC_CREATE_ECP_CONTEXT is missing on some WDK's */
#define ATOMIC_CREATE_ECP_IN_FLAG_REPARSE_POINT_SPECIFIED 0x0002
#define ATOMIC_CREATE_ECP_OUT_FLAG_REPARSE_POINT_SET 0x0002
#define ATOMIC_CREATE_ECP_IN_FLAG_BEST_EFFORT 0x0100
typedef struct
{
LARGE_INTEGER CreationTime;
LARGE_INTEGER LastAccessTime;
LARGE_INTEGER LastWriteTime;
LARGE_INTEGER ChangeTime;
} FSP_FILE_TIMESTAMPS, *PFSP_FILE_TIMESTAMPS;
typedef struct
{
USHORT Size;
USHORT InFlags;
USHORT OutFlags;
USHORT ReparseBufferLength;
PREPARSE_DATA_BUFFER ReparseBuffer;
LONGLONG FileSize;
LONGLONG ValidDataLength;
PFSP_FILE_TIMESTAMPS FileTimestamps;
ULONG FileAttributes;
ULONG UsnSourceInfo;
USN Usn;
ULONG SuppressFileAttributeInheritanceMask;
ULONG InOpFlags;
ULONG OutOpFlags;
ULONG InGenFlags;
ULONG OutGenFlags;
ULONG CaseSensitiveFlagsMask;
ULONG InCaseSensitiveFlags;
ULONG OutCaseSensitiveFlags;
} FSP_ATOMIC_CREATE_ECP_CONTEXT, *PFSP_ATOMIC_CREATE_ECP_CONTEXT;
#endif #endif

View File

@ -981,10 +981,16 @@ static NTSTATUS FspFsvolQueryInformation(
Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0); Result = FspFsvolQueryStandardInformation(FileObject, &Buffer, BufferEnd, 0);
break; break;
case 68/*FileStatInformation*/: case 68/*FileStatInformation*/:
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.WslFeatures)
Result = FspFsvolQueryStatBaseInformation(FileObject, &Buffer, BufferEnd, 0); Result = FspFsvolQueryStatBaseInformation(FileObject, &Buffer, BufferEnd, 0);
else
Result = STATUS_INVALID_PARAMETER;
break; break;
case 70/*FileStatLxInformation*/: case 70/*FileStatLxInformation*/:
if (FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.WslFeatures)
Result = FspFsvolQueryStatLxBaseInformation(FileObject, &Buffer, BufferEnd, 0); Result = FspFsvolQueryStatLxBaseInformation(FileObject, &Buffer, BufferEnd, 0);
else
Result = STATUS_INVALID_PARAMETER;
break; break;
default: default:
Result = STATUS_INVALID_PARAMETER; Result = STATUS_INVALID_PARAMETER;

View File

@ -274,6 +274,7 @@ namespace memfs
Host.PostCleanupWhenModifiedOnly = true; Host.PostCleanupWhenModifiedOnly = true;
Host.PassQueryDirectoryFileName = true; Host.PassQueryDirectoryFileName = true;
Host.ExtendedAttributes = true; Host.ExtendedAttributes = true;
Host.WslFeatures = true;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -331,8 +332,9 @@ namespace memfs
UInt32 FileAttributes, UInt32 FileAttributes,
Byte[] SecurityDescriptor, Byte[] SecurityDescriptor,
UInt64 AllocationSize, UInt64 AllocationSize,
IntPtr Ea, IntPtr ExtraBuffer,
UInt32 EaLength, UInt32 ExtraLength,
Boolean ExtraBufferIsReparsePoint,
out Object FileNode0, out Object FileNode0,
out Object FileDesc, out Object FileDesc,
out FileInfo FileInfo, out FileInfo FileInfo,
@ -369,12 +371,22 @@ namespace memfs
FileNode.FileInfo.FileAttributes = 0 != (FileAttributes & (UInt32)System.IO.FileAttributes.Directory) ? FileNode.FileInfo.FileAttributes = 0 != (FileAttributes & (UInt32)System.IO.FileAttributes.Directory) ?
FileAttributes : FileAttributes | (UInt32)System.IO.FileAttributes.Archive; FileAttributes : FileAttributes | (UInt32)System.IO.FileAttributes.Archive;
FileNode.FileSecurity = SecurityDescriptor; FileNode.FileSecurity = SecurityDescriptor;
if (IntPtr.Zero != Ea) if (IntPtr.Zero != ExtraBuffer)
{ {
Result = SetEaEntries(FileNode, null, Ea, EaLength); if (!ExtraBufferIsReparsePoint)
{
Result = SetEaEntries(FileNode, null, ExtraBuffer, ExtraLength);
if (0 > Result) if (0 > Result)
return Result; return Result;
} }
else
{
Byte[] ReparseData = MakeReparsePoint(ExtraBuffer, ExtraLength);
FileNode.FileInfo.FileAttributes |= (UInt32)System.IO.FileAttributes.ReparsePoint;
FileNode.FileInfo.ReparseTag = GetReparseTag(ReparseData);
FileNode.ReparseData = ReparseData;
}
}
if (0 != AllocationSize) if (0 != AllocationSize)
{ {
Result = SetFileSizeInternal(FileNode, AllocationSize, true); Result = SetFileSizeInternal(FileNode, AllocationSize, true);

View File

@ -69,6 +69,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
*/ */
#define MEMFS_EA #define MEMFS_EA
/*
* Define the MEMFS_WSL macro to include WSLinux support.
*/
#define MEMFS_WSL
/* /*
* Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes * Define the DEBUG_BUFFER_CHECK macro on Windows 8 or above. This includes
* a check for the Write buffer to ensure that it is read-only. * a check for the Write buffer to ensure that it is read-only.
@ -1047,8 +1052,8 @@ static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PVOID ExtraBuffer, ULONG ExtraLength, BOOLEAN ExtraBufferIsReparsePoint,
#endif #endif
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo) PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
{ {
@ -1129,10 +1134,14 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize); memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize);
} }
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
if (0 != Ea) if (0 != ExtraBuffer)
{ {
Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength); #if defined(MEMFS_EA)
if (!ExtraBufferIsReparsePoint)
{
Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode,
(PFILE_FULL_EA_INFORMATION)ExtraBuffer, ExtraLength);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
{ {
MemfsFileNodeDelete(FileNode); MemfsFileNodeDelete(FileNode);
@ -1140,6 +1149,30 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
} }
} }
#endif #endif
#if defined(MEMFS_WSL)
if (ExtraBufferIsReparsePoint)
{
#if defined(MEMFS_REPARSE_POINTS)
FileNode->ReparseDataSize = ExtraLength;
FileNode->ReparseData = malloc(ExtraLength);
if (0 == FileNode->ReparseData && 0 != ExtraLength)
{
MemfsFileNodeDelete(FileNode);
return STATUS_INSUFFICIENT_RESOURCES;
}
FileNode->FileInfo.FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
FileNode->FileInfo.ReparseTag = *(PULONG)ExtraBuffer;
/* the first field in a reparse buffer is the reparse tag */
memcpy(FileNode->ReparseData, ExtraBuffer, ExtraLength);
#else
MemfsFileNodeDelete(FileNode);
return STATUS_INVALID_PARAMETER;
#endif
}
#endif
}
#endif
FileNode->FileInfo.AllocationSize = AllocationSize; FileNode->FileInfo.AllocationSize = AllocationSize;
if (0 != FileNode->FileInfo.AllocationSize) if (0 != FileNode->FileInfo.AllocationSize)
@ -2189,7 +2222,7 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
GetVolumeInfo, GetVolumeInfo,
SetVolumeLabel, SetVolumeLabel,
GetSecurityByName, GetSecurityByName,
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
0, 0,
#else #else
Create, Create,
@ -2240,8 +2273,10 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
0, 0,
#endif #endif
0, 0,
#if defined(MEMFS_EA) #if defined(MEMFS_EA) || defined(MEMFS_WSL)
Create, Create,
#endif
#if defined(MEMFS_EA)
Overwrite, Overwrite,
GetEa, GetEa,
SetEa SetEa
@ -2347,6 +2382,9 @@ NTSTATUS MemfsCreateFunnel(
#endif #endif
#if defined(MEMFS_EA) #if defined(MEMFS_EA)
VolumeParams.ExtendedAttributes = 1; VolumeParams.ExtendedAttributes = 1;
#endif
#if defined(MEMFS_WSL)
VolumeParams.WslFeatures = 1;
#endif #endif
VolumeParams.AllowOpenInKernelMode = 1; VolumeParams.AllowOpenInKernelMode = 1;
if (0 != VolumePrefix) if (0 != VolumePrefix)