dotnet: extended attributes support

This commit is contained in:
Bill Zissimopoulos 2019-03-14 15:05:17 -07:00
parent 795caec679
commit 3553aec992
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
3 changed files with 319 additions and 5 deletions

View File

@ -1078,6 +1078,120 @@ namespace Fsp
else
return STATUS_SUCCESS;
}
public virtual Int32 CreateEx(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
UInt32 FileAttributes,
Byte[] SecurityDescriptor,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
out Object FileNode,
out Object FileDesc,
out FileInfo FileInfo,
out String NormalizedName)
{
Int32 Result;
Result = Create(
FileName,
CreateOptions,
GrantedAccess,
FileAttributes,
SecurityDescriptor,
AllocationSize,
out FileNode,
out FileDesc,
out FileInfo,
out NormalizedName);
if (0 > Result)
return Result;
if (IntPtr.Zero != Ea)
Result = SetEa(FileNode, FileDesc, Ea, EaLength); /* ignore Result */
return STATUS_SUCCESS;
}
public virtual Int32 OverwriteEx(
Object FileNode,
Object FileDesc,
UInt32 FileAttributes,
Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
out FileInfo FileInfo)
{
Int32 Result;
Result = Overwrite(
FileNode,
FileDesc,
FileAttributes,
ReplaceFileAttributes,
AllocationSize,
out FileInfo);
if (0 > Result)
return Result;
if (IntPtr.Zero != Ea)
Result = SetEa(FileNode, FileDesc, Ea, EaLength); /* ignore Result */
return STATUS_SUCCESS;
}
public virtual Int32 GetEa(
Object FileNode,
Object FileDesc,
IntPtr Ea,
UInt32 EaLength,
out UInt32 BytesTransferred)
{
Object Context = null;
String EaName;
Byte[] EaValue;
Boolean NeedEa;
FullEaInformation EaInfo = new FullEaInformation();
BytesTransferred = default(UInt32);
while (GetEaEntry(FileNode, FileDesc, ref Context, out EaName, out EaValue, out NeedEa))
{
EaInfo.Set(EaName, EaValue, NeedEa);
if (!Api.FspFileSystemAddEa(ref EaInfo, Ea, EaLength, out BytesTransferred))
return STATUS_SUCCESS;
}
Api.FspFileSystemEndEa(Ea, EaLength, out BytesTransferred);
return STATUS_SUCCESS;
}
public virtual Boolean GetEaEntry(
Object FileNode,
Object FileDesc,
ref Object Context,
out String EaName,
out Byte[] EaValue,
out Boolean NeedEa)
{
EaName = default(String);
EaValue = default(Byte[]);
NeedEa = default(Boolean);
return false;
}
public virtual Int32 SetEa(
Object FileNode,
Object FileDesc,
IntPtr Ea,
UInt32 EaLength)
{
return Api.FspFileSystemEnumerateEa(
FileNode,
FileDesc,
this.SetEaEntry,
Ea,
EaLength);
}
public virtual Int32 SetEaEntry(
Object FileNode,
Object FileDesc,
ref Object Context,
String EaName,
Byte[] EaValue,
Boolean NeedEa)
{
return STATUS_INVALID_DEVICE_REQUEST;
}
/* helpers */
/// <summary>

View File

@ -183,6 +183,14 @@ namespace Fsp
get { return 0 != (_VolumeParams.Flags & VolumeParams.NamedStreams); }
set { _VolumeParams.Flags |= (value ? VolumeParams.NamedStreams : 0); }
}
/// <summary>
/// Gets or sets a value that determines whether the file system supports extended attributes.
/// </summary>
public Boolean ExtendedAttributes
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.ExtendedAttributes); }
set { _VolumeParams.Flags |= (value ? VolumeParams.ExtendedAttributes : 0); }
}
public Boolean PostCleanupWhenModifiedOnly
{
get { return 0 != (_VolumeParams.Flags & VolumeParams.PostCleanupWhenModifiedOnly); }
@ -464,6 +472,8 @@ namespace Fsp
UInt32 FileAttributes,
IntPtr SecurityDescriptor,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
ref FullContext FullContext,
ref OpenFileInfo OpenFileInfo)
{
@ -473,13 +483,15 @@ namespace Fsp
Object FileNode, FileDesc;
String NormalizedName;
Int32 Result;
Result = FileSystem.Create(
Result = FileSystem.CreateEx(
FileName,
CreateOptions,
GrantedAccess,
FileAttributes,
Api.MakeSecurityDescriptor(SecurityDescriptor),
AllocationSize,
Ea,
EaLength,
out FileNode,
out FileDesc,
out OpenFileInfo.FileInfo,
@ -538,6 +550,8 @@ namespace Fsp
UInt32 FileAttributes,
Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
out FileInfo FileInfo)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
@ -545,12 +559,14 @@ namespace Fsp
{
Object FileNode, FileDesc;
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
return FileSystem.Overwrite(
return FileSystem.OverwriteEx(
FileNode,
FileDesc,
FileAttributes,
ReplaceFileAttributes,
AllocationSize,
Ea,
EaLength,
out FileInfo);
}
catch (Exception ex)
@ -1077,15 +1093,62 @@ namespace Fsp
return ExceptionHandler(FileSystem, ex);
}
}
private static Int32 GetEa(
IntPtr FileSystemPtr,
ref FullContext FullContext,
IntPtr Ea,
UInt32 EaLength,
out UInt32 PBytesTransferred)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
{
Object FileNode, FileDesc;
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
return FileSystem.GetEa(
FileNode,
FileDesc,
Ea,
EaLength,
out PBytesTransferred);
}
catch (Exception ex)
{
PBytesTransferred = default(UInt32);
return ExceptionHandler(FileSystem, ex);
}
}
private static Int32 SetEa(
IntPtr FileSystemPtr,
ref FullContext FullContext,
IntPtr Ea,
UInt32 EaLength)
{
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try
{
Object FileNode, FileDesc;
Api.GetFullContext(ref FullContext, out FileNode, out FileDesc);
return FileSystem.SetEa(
FileNode,
FileDesc,
Ea,
EaLength);
}
catch (Exception ex)
{
return ExceptionHandler(FileSystem, ex);
}
}
static FileSystemHost()
{
_FileSystemInterface.GetVolumeInfo = GetVolumeInfo;
_FileSystemInterface.SetVolumeLabel = SetVolumeLabel;
_FileSystemInterface.GetSecurityByName = GetSecurityByName;
_FileSystemInterface.Create = Create;
_FileSystemInterface.CreateEx = Create;
_FileSystemInterface.Open = Open;
_FileSystemInterface.Overwrite = Overwrite;
_FileSystemInterface.OverwriteEx = Overwrite;
_FileSystemInterface.Cleanup = Cleanup;
_FileSystemInterface.Close = Close;
_FileSystemInterface.Read = Read;
@ -1106,6 +1169,8 @@ namespace Fsp
_FileSystemInterface.GetDirInfoByName = GetDirInfoByName;
_FileSystemInterface.Control = Control;
_FileSystemInterface.SetDelete = SetDelete;
_FileSystemInterface.GetEa = GetEa;
_FileSystemInterface.SetEa = SetEa;
_FileSystemInterfacePtr = Marshal.AllocHGlobal(FileSystemInterface.Size);
Marshal.StructureToPtr(_FileSystemInterface, _FileSystemInterfacePtr, false);

View File

@ -52,6 +52,7 @@ namespace Fsp.Interop
internal const UInt32 UmFileContextIsUserContext2 = 0x00010000;
internal const UInt32 UmFileContextIsFullContext = 0x00020000;
internal const UInt32 AllowOpenInKernelMode = 0x01000000;
internal const UInt32 CasePreservedExtendedAttributes = 0x02000000;
internal const int PrefixSize = 192;
internal const int FileSystemNameSize = 16;
@ -270,6 +271,40 @@ namespace Fsp.Interop
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct FullEaInformation
{
internal const int EaNameSize = 16384 - 8;
internal UInt32 NextEntryOffset;
internal Byte Flags;
internal Byte EaNameLength;
internal UInt16 EaValueLength;
internal unsafe fixed Byte EaName[EaNameSize];
internal unsafe void Set(String Name, Byte[] Value, Boolean NeedEa)
{
int NameLength = 254 < Name.Length ? 254 : Name.Length;
int ValueLength = EaNameSize - Name.Length - 1 < Value.Length ?
EaNameSize - Name.Length - 1 : Value.Length;
NextEntryOffset = 0;
Flags = NeedEa ? (Byte)0x80/*FILE_NEED_EA*/ : (Byte)0;
EaNameLength = (Byte)NameLength;
EaValueLength = (UInt16)ValueLength;
fixed (Byte *P = EaName)
{
int I = 0;
for (; NameLength > I; I++)
P[I] = (Byte)Name[I];
P[I] = 0;
for (; ValueLength > I; I++)
P[I] = Value[I];
}
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct FullContext
{
@ -478,6 +513,42 @@ namespace Fsp.Interop
ref FullContext FullContext,
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
[MarshalAs(UnmanagedType.U1)] Boolean DeleteFile);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 CreateEx(
IntPtr FileSystem,
[MarshalAs(UnmanagedType.LPWStr)] String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
UInt32 FileAttributes,
IntPtr SecurityDescriptor,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
ref FullContext FullContext,
ref OpenFileInfo OpenFileInfo);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 OverwriteEx(
IntPtr FileSystem,
ref FullContext FullContext,
UInt32 FileAttributes,
[MarshalAs(UnmanagedType.U1)] Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
IntPtr Ea,
UInt32 EaLength,
out FileInfo FileInfo);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 GetEa(
IntPtr FileSystem,
ref FullContext FullContext,
IntPtr Ea,
UInt32 EaLength,
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
internal delegate Int32 SetEa(
IntPtr FileSystem,
ref FullContext FullContext,
IntPtr Ea,
UInt32 EaLength);
}
internal static int Size = IntPtr.Size * 64;
@ -509,7 +580,11 @@ namespace Fsp.Interop
internal Proto.GetDirInfoByName GetDirInfoByName;
internal Proto.Control Control;
internal Proto.SetDelete SetDelete;
/* NTSTATUS (*Reserved[37])(); */
internal Proto.CreateEx CreateEx;
internal Proto.OverwriteEx OverwriteEx;
internal Proto.GetEa GetEa;
internal Proto.SetEa SetEa;
/* NTSTATUS (*Reserved[33])(); */
}
[SuppressUnmanagedCodeSecurity]
@ -604,6 +679,13 @@ namespace Fsp.Interop
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAddEa(
IntPtr SingleEa,
IntPtr Ea,
UInt32 EaLength,
out UInt32 PBytesTransferred);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.U1)]
internal delegate Boolean FspFileSystemAcquireDirectoryBuffer(
ref IntPtr PDirBuffer,
[MarshalAs(UnmanagedType.U1)] Boolean Reset,
@ -737,6 +819,7 @@ namespace Fsp.Interop
internal static Proto.FspFileSystemResolveReparsePoints FspFileSystemResolveReparsePoints;
internal static Proto.FspFileSystemCanReplaceReparsePoint _FspFileSystemCanReplaceReparsePoint;
internal static Proto.FspFileSystemAddStreamInfo _FspFileSystemAddStreamInfo;
internal static Proto.FspFileSystemAddEa _FspFileSystemAddEa;
internal static Proto.FspFileSystemAcquireDirectoryBuffer FspFileSystemAcquireDirectoryBuffer;
internal static Proto.FspFileSystemFillDirectoryBuffer FspFileSystemFillDirectoryBuffer;
internal static Proto.FspFileSystemReleaseDirectoryBuffer FspFileSystemReleaseDirectoryBuffer;
@ -806,6 +889,57 @@ namespace Fsp.Interop
return _FspFileSystemAddStreamInfo(IntPtr.Zero, Buffer, Length, out PBytesTransferred);
}
internal delegate Int32 EnumerateEa(
Object FileNode,
Object FileDesc,
ref Object Context,
String EaName,
Byte[] EaValue,
Boolean NeedEa);
internal static unsafe Int32 FspFileSystemEnumerateEa(
Object FileNode,
Object FileDesc,
EnumerateEa EnumerateEa,
IntPtr Ea,
UInt32 EaLength)
{
Object Context = null;
FullEaInformation *P = (FullEaInformation *)Ea;
FullEaInformation *EndP = (FullEaInformation *)(Ea.ToInt64() + EaLength);
Int32 Result;
Result = 0/*STATUS_SUCCESS*/;
for (;
EndP > P && 0 != P->NextEntryOffset;
P = (FullEaInformation *)(((IntPtr)P).ToInt64() + P->NextEntryOffset))
{
String EaName = Marshal.PtrToStringAnsi((IntPtr)P->EaName, P->EaNameLength);
Byte[] EaValue = new Byte[P->EaValueLength];
Marshal.Copy((IntPtr)(((IntPtr)P->EaName).ToInt64() + P->EaNameLength + 1),
EaValue, 0, P->EaValueLength);
Boolean NeedEa = 0 != (0x80/*FILE_NEED_EA*/ & P->Flags);
Result = EnumerateEa(FileNode, FileDesc, ref Context, EaName, EaValue, NeedEa);
if (0 > Result)
break;
}
return Result;
}
internal static unsafe Boolean FspFileSystemAddEa(
ref FullEaInformation EaInfo,
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
fixed (FullEaInformation *P = &EaInfo)
return _FspFileSystemAddEa((IntPtr)P, Buffer, Length, out PBytesTransferred);
}
internal static unsafe Boolean FspFileSystemEndEa(
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
return _FspFileSystemAddEa(IntPtr.Zero, Buffer, Length, out PBytesTransferred);
}
internal unsafe static Object GetUserContext(
IntPtr NativePtr)
{
@ -1074,6 +1208,7 @@ namespace Fsp.Interop
FspFileSystemResolveReparsePoints = GetEntryPoint<Proto.FspFileSystemResolveReparsePoints>(Module);
_FspFileSystemCanReplaceReparsePoint = GetEntryPoint<Proto.FspFileSystemCanReplaceReparsePoint>(Module);
_FspFileSystemAddStreamInfo = GetEntryPoint<Proto.FspFileSystemAddStreamInfo>(Module);
_FspFileSystemAddEa = GetEntryPoint<Proto.FspFileSystemAddEa>(Module);
FspFileSystemAcquireDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemAcquireDirectoryBuffer>(Module);
FspFileSystemFillDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemFillDirectoryBuffer>(Module);
FspFileSystemReleaseDirectoryBuffer = GetEntryPoint<Proto.FspFileSystemReleaseDirectoryBuffer>(Module);