grand EaSize patch; passes winfsp-tests and ifstest

This commit is contained in:
Bill Zissimopoulos 2019-03-21 18:14:15 -07:00
parent b619dbfe97
commit 732e6cc38c
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
13 changed files with 123 additions and 41 deletions

View File

@ -230,8 +230,6 @@ typedef struct
PWSTR NormalizedName; PWSTR NormalizedName;
UINT16 NormalizedNameSize; UINT16 NormalizedNameSize;
} FSP_FSCTL_OPEN_FILE_INFO; } FSP_FSCTL_OPEN_FILE_INFO;
FSP_FSCTL_STATIC_ASSERT(88 == sizeof(FSP_FSCTL_OPEN_FILE_INFO),
"sizeof(FSP_FSCTL_OPEN_FILE_INFO) must be exactly 88.");
typedef struct typedef struct
{ {
UINT16 Size; UINT16 Size;
@ -505,6 +503,7 @@ typedef struct
} QueryEa; } QueryEa;
struct struct
{ {
FSP_FSCTL_FILE_INFO FileInfo;
FSP_FSCTL_TRANSACT_BUF Ea; /* Size==0 means no extended atttributed returned */ FSP_FSCTL_TRANSACT_BUF Ea; /* Size==0 means no extended atttributed returned */
} SetEa; } SetEa;
struct struct

View File

@ -1023,6 +1023,9 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
* Extended attributes buffer. * Extended attributes buffer.
* @param EaLength * @param EaLength
* Extended attributes buffer length. * Extended attributes buffer length.
* @param FileInfo [out]
* Pointer to a structure that will receive the file information on successful return
* from this call. This information includes file attributes, file times, etc.
* @return * @return
* STATUS_SUCCESS or error code. * STATUS_SUCCESS or error code.
* @see * @see
@ -1030,7 +1033,8 @@ typedef struct _FSP_FILE_SYSTEM_INTERFACE
*/ */
NTSTATUS (*SetEa)(FSP_FILE_SYSTEM *FileSystem, NTSTATUS (*SetEa)(FSP_FILE_SYSTEM *FileSystem,
PVOID FileContext, PVOID FileContext,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength); PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
FSP_FSCTL_FILE_INFO *FileInfo);
/* /*
* This ensures that this interface will always contain 64 function pointers. * This ensures that this interface will always contain 64 function pointers.
@ -1624,6 +1628,20 @@ FSP_API NTSTATUS FspFileSystemEnumerateEa(FSP_FILE_SYSTEM *FileSystem,
*/ */
FSP_API BOOLEAN FspFileSystemAddEa(PFILE_FULL_EA_INFORMATION SingleEa, FSP_API BOOLEAN FspFileSystemAddEa(PFILE_FULL_EA_INFORMATION SingleEa,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PULONG PBytesTransferred); PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PULONG PBytesTransferred);
/**
* Get extended attribute "packed" size. This computation matches what NTFS reports.
*
* @param SingleEa
* The extended attribute to get the size for.
* @return
* The packed size of the extended attribute.
*/
static inline
UINT32 FspFileSystemGetEaPackedSize(PFILE_FULL_EA_INFORMATION SingleEa)
{
/* magic computations are courtesy of NTFS */
return 5 + SingleEa->EaNameLength + SingleEa->EaValueLength;
}
/* /*
* Directory buffering * Directory buffering

View File

@ -1208,12 +1208,22 @@ FSP_API NTSTATUS FspFileSystemOpQueryEa(FSP_FILE_SYSTEM *FileSystem,
FSP_API NTSTATUS FspFileSystemOpSetEa(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpSetEa(FSP_FILE_SYSTEM *FileSystem,
FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response) FSP_FSCTL_TRANSACT_REQ *Request, FSP_FSCTL_TRANSACT_RSP *Response)
{ {
NTSTATUS Result;
FSP_FSCTL_FILE_INFO FileInfo;
if (0 == FileSystem->Interface->SetEa) if (0 == FileSystem->Interface->SetEa)
return STATUS_INVALID_DEVICE_REQUEST; return STATUS_INVALID_DEVICE_REQUEST;
return FileSystem->Interface->SetEa(FileSystem, memset(&FileInfo, 0, sizeof FileInfo);
Result = FileSystem->Interface->SetEa(FileSystem,
(PVOID)ValOfFileContext(Request->Req.SetEa), (PVOID)ValOfFileContext(Request->Req.SetEa),
(PVOID)Request->Buffer, Request->Req.SetEa.Ea.Size); (PVOID)Request->Buffer, Request->Req.SetEa.Ea.Size,
&FileInfo);
if (!NT_SUCCESS(Result))
return Result;
memcpy(&Response->Rsp.SetEa.FileInfo, &FileInfo, sizeof FileInfo);
return STATUS_SUCCESS;
} }
FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSystem, FSP_API NTSTATUS FspFileSystemOpQueryVolumeInformation(FSP_FILE_SYSTEM *FileSystem,

View File

@ -2289,16 +2289,29 @@ static NTSTATUS fsp_fuse_intf_SetEaEntry(
static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem,
PVOID FileDesc, PVOID FileDesc,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength) PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
struct fsp_fuse_file_desc *filedesc = FileDesc; struct fsp_fuse_file_desc *filedesc = FileDesc;
UINT32 Uid, Gid, Mode;
struct fuse_file_info fi;
NTSTATUS Result;
if (0 == f->ops.setxattr || 0 == f->ops.removexattr) if (0 == f->ops.setxattr || 0 == f->ops.removexattr)
return STATUS_INVALID_DEVICE_REQUEST; return STATUS_INVALID_DEVICE_REQUEST;
return FspFileSystemEnumerateEa(FileSystem, Result = FspFileSystemEnumerateEa(FileSystem,
fsp_fuse_intf_SetEaEntry, filedesc->PosixPath, Ea, EaLength); fsp_fuse_intf_SetEaEntry, filedesc->PosixPath, Ea, EaLength);
if (!NT_SUCCESS(Result))
return Result;
memset(&fi, 0, sizeof fi);
fi.flags = filedesc->OpenFlags;
fi.fh = filedesc->FileHandle;
return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi,
&Uid, &Gid, &Mode, FileInfo);
} }
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf = FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =

View File

@ -1161,14 +1161,21 @@ namespace Fsp
Object FileNode, Object FileNode,
Object FileDesc, Object FileDesc,
IntPtr Ea, IntPtr Ea,
UInt32 EaLength) UInt32 EaLength,
out FileInfo FileInfo)
{ {
return Api.FspFileSystemEnumerateEa( Int32 Result;
Result = SetEaEntries(
FileNode, FileNode,
FileDesc, FileDesc,
this.SetEaEntry,
Ea, Ea,
EaLength); EaLength);
if (0 > Result)
{
FileInfo = default(FileInfo);
return Result;
}
return GetFileInfo(FileNode, FileDesc, out FileInfo);
} }
public virtual Int32 SetEaEntry( public virtual Int32 SetEaEntry(
Object FileNode, Object FileNode,
@ -1445,12 +1452,25 @@ namespace Fsp
return self.ExceptionHandler(ex); return self.ExceptionHandler(ex);
} }
} }
public Int32 SetEaEntries(
Object FileNode,
Object FileDesc,
IntPtr Ea,
UInt32 EaLength)
{
return Api.FspFileSystemEnumerateEa(
FileNode,
FileDesc,
this.SetEaEntry,
Ea,
EaLength);
}
public static UInt32 GetEaEntrySize( public static UInt32 GetEaEntrySize(
String EaName, String EaName,
Byte[] EaValue, Byte[] EaValue,
Boolean NeedEa) Boolean NeedEa)
{ {
return FullEaInformation.Size(EaName, EaValue, NeedEa); return FullEaInformation.PackedSize(EaName, EaValue, NeedEa);
} }
} }

View File

@ -1122,7 +1122,8 @@ namespace Fsp
IntPtr FileSystemPtr, IntPtr FileSystemPtr,
ref FullContext FullContext, ref FullContext FullContext,
IntPtr Ea, IntPtr Ea,
UInt32 EaLength) UInt32 EaLength,
out FileInfo FileInfo)
{ {
FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr); FileSystemBase FileSystem = (FileSystemBase)Api.GetUserContext(FileSystemPtr);
try try
@ -1133,10 +1134,12 @@ namespace Fsp
FileNode, FileNode,
FileDesc, FileDesc,
Ea, Ea,
EaLength); EaLength,
out FileInfo);
} }
catch (Exception ex) catch (Exception ex)
{ {
FileInfo = default(FileInfo);
return ExceptionHandler(FileSystem, ex); return ExceptionHandler(FileSystem, ex);
} }
} }

View File

@ -283,8 +283,6 @@ namespace Fsp.Interop
* This should really be: * This should really be:
* FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX - FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) * FSP_FSCTL_TRANSACT_RSP_BUFFER_SIZEMAX - FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName)
*/ */
internal static int EaNameOffset =
(int)Marshal.OffsetOf(typeof(FullEaInformation), "EaName");
internal UInt32 NextEntryOffset; internal UInt32 NextEntryOffset;
internal Byte Flags; internal Byte Flags;
@ -313,13 +311,14 @@ namespace Fsp.Interop
P[I + J] = Value[J]; P[I + J] = Value[J];
} }
} }
internal static UInt32 Size(String Name, Byte[] Value, Boolean NeedEa) internal static UInt32 PackedSize(String Name, Byte[] Value, Boolean NeedEa)
{ {
int NameLength = 254 < Name.Length ? 254 : Name.Length; int NameLength = 254 < Name.Length ? 254 : Name.Length;
int ValueLength = EaNameSize - Name.Length - 1 < Value.Length ? int ValueLength = EaNameSize - Name.Length - 1 < Value.Length ?
EaNameSize - Name.Length - 1 : Value.Length; EaNameSize - Name.Length - 1 : Value.Length;
return (UInt32)((EaNameOffset + NameLength + 1 + ValueLength + 3) & ~3); /* magic computations are courtesy of NTFS */
return (UInt32)(5 + NameLength + ValueLength);
} }
} }
@ -566,7 +565,8 @@ namespace Fsp.Interop
IntPtr FileSystem, IntPtr FileSystem,
ref FullContext FullContext, ref FullContext FullContext,
IntPtr Ea, IntPtr Ea,
UInt32 EaLength); UInt32 EaLength,
out FileInfo FileInfo);
} }
internal static int Size = IntPtr.Size * 64; internal static int Size = IntPtr.Size * 64;

View File

@ -1285,6 +1285,7 @@ typedef struct FSP_FILE_NODE
UINT64 LastAccessTime; UINT64 LastAccessTime;
UINT64 LastWriteTime; UINT64 LastWriteTime;
UINT64 ChangeTime; UINT64 ChangeTime;
UINT32 EaSize;
ULONG FileInfoChangeNumber; ULONG FileInfoChangeNumber;
UINT64 Security; UINT64 Security;
ULONG SecurityChangeNumber; ULONG SecurityChangeNumber;

View File

@ -578,9 +578,11 @@ NTSTATUS FspFsvolSetEaComplete(
PFILE_OBJECT FileObject = IrpSp->FileObject; PFILE_OBJECT FileObject = IrpSp->FileObject;
FSP_FILE_NODE *FileNode = FileObject->FsContext; FSP_FILE_NODE *FileNode = FileObject->FsContext;
FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp); FSP_FSCTL_TRANSACT_REQ *Request = FspIrpRequest(Irp);
BOOLEAN Valid; BOOLEAN EaValid;
Valid = FALSE; FspFileNodeSetFileInfo(FileNode, FileObject, &Response->Rsp.SetEa.FileInfo, FALSE);
EaValid = FALSE;
if (0 < Response->Rsp.SetEa.Ea.Size && if (0 < Response->Rsp.SetEa.Ea.Size &&
Response->Buffer + Response->Rsp.SetEa.Ea.Size <= Response->Buffer + Response->Rsp.SetEa.Ea.Size <=
(PUINT8)Response + Response->Size) (PUINT8)Response + Response->Size)
@ -589,19 +591,17 @@ NTSTATUS FspFsvolSetEaComplete(
(PVOID)Response->Buffer, /* FspEaBufferFromFileSystemValidate may alter the buffer! */ (PVOID)Response->Buffer, /* FspEaBufferFromFileSystemValidate may alter the buffer! */
Response->Rsp.SetEa.Ea.Size, Response->Rsp.SetEa.Ea.Size,
(PULONG)&Irp->IoStatus.Information); (PULONG)&Irp->IoStatus.Information);
Valid = NT_SUCCESS(Result); EaValid = NT_SUCCESS(Result);
} }
if (EaValid)
/* if the EA buffer that we got back is valid */
if (Valid)
{ {
/* update the cached EA */ /* if the EA buffer that we got back is valid, update the cached EA */
FspFileNodeSetEa(FileNode, FspFileNodeSetEa(FileNode,
Response->Buffer, Response->Rsp.SetEa.Ea.Size); Response->Buffer, Response->Rsp.SetEa.Ea.Size);
} }
else else
{ {
/* invalidate the cached EA */ /* if the EA buffer that we got back is not valid, invalidate the cached EA */
FspFileNodeSetEa(FileNode, 0, 0); FspFileNodeSetEa(FileNode, 0, 0);
} }

View File

@ -1631,6 +1631,7 @@ VOID FspFileNodeGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileIn
FileInfo->LastAccessTime = FileNode->LastAccessTime; FileInfo->LastAccessTime = FileNode->LastAccessTime;
FileInfo->LastWriteTime = FileNode->LastWriteTime; FileInfo->LastWriteTime = FileNode->LastWriteTime;
FileInfo->ChangeTime = FileNode->ChangeTime; FileInfo->ChangeTime = FileNode->ChangeTime;
FileInfo->EaSize = FileNode->EaSize;
} }
BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo) BOOLEAN FspFileNodeTryGetFileInfo(FSP_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *FileInfo)
@ -1778,6 +1779,7 @@ VOID FspFileNodeSetFileInfo(FSP_FILE_NODE *FileNode, PFILE_OBJECT CcFileObject,
MainFileNode->LastAccessTime = FileInfo->LastAccessTime; MainFileNode->LastAccessTime = FileInfo->LastAccessTime;
MainFileNode->LastWriteTime = FileInfo->LastWriteTime; MainFileNode->LastWriteTime = FileInfo->LastWriteTime;
MainFileNode->ChangeTime = FileInfo->ChangeTime; MainFileNode->ChangeTime = FileInfo->ChangeTime;
MainFileNode->EaSize = FileInfo->EaSize;
if (0 != CcFileObject) if (0 != CcFileObject)
{ {

View File

@ -179,6 +179,9 @@ static NTSTATUS FspFsvolQueryAllInformation(PFILE_OBJECT FileObject,
Info->EaInformation.EaSize = Info->EaInformation.EaSize =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes ? FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes ?
FileInfo->EaSize : 0; FileInfo->EaSize : 0;
/* magic computations are courtesy of NTFS */
if (0 != Info->EaInformation.EaSize)
Info->EaInformation.EaSize += 4;
Info->PositionInformation.CurrentByteOffset = FileObject->CurrentByteOffset; Info->PositionInformation.CurrentByteOffset = FileObject->CurrentByteOffset;
@ -258,6 +261,9 @@ static NTSTATUS FspFsvolQueryEaInformation(PFILE_OBJECT FileObject,
Info->EaSize = Info->EaSize =
FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes ? FspFsvolDeviceExtension(FileNode->FsvolDeviceObject)->VolumeParams.ExtendedAttributes ?
FileInfo->EaSize : 0; FileInfo->EaSize : 0;
/* magic computations are courtesy of NTFS */
if (0 != Info->EaSize)
Info->EaSize += 4;
*PBuffer = (PVOID)(Info + 1); *PBuffer = (PVOID)(Info + 1);

View File

@ -371,7 +371,7 @@ namespace memfs
FileNode.FileSecurity = SecurityDescriptor; FileNode.FileSecurity = SecurityDescriptor;
if (IntPtr.Zero != Ea) if (IntPtr.Zero != Ea)
{ {
Result = SetEa(FileNode, null, Ea, EaLength); Result = SetEaEntries(FileNode, null, Ea, EaLength);
if (0 > Result) if (0 > Result)
return Result; return Result;
} }
@ -469,7 +469,7 @@ namespace memfs
} }
if (IntPtr.Zero != Ea) if (IntPtr.Zero != Ea)
{ {
Result = SetEa(FileNode, null, Ea, EaLength); Result = SetEaEntries(FileNode, null, Ea, EaLength);
if (0 > Result) if (0 > Result)
return Result; return Result;
} }
@ -1121,6 +1121,11 @@ namespace memfs
SortedDictionary<String, EaValueData> EaMap = FileNode.GetEaMap(true); SortedDictionary<String, EaValueData> EaMap = FileNode.GetEaMap(true);
EaValueData Data; EaValueData Data;
UInt32 EaSizePlus = 0, EaSizeMinus = 0; UInt32 EaSizePlus = 0, EaSizeMinus = 0;
if (EaMap.TryGetValue(EaName, out Data))
{
EaSizeMinus = GetEaEntrySize(EaName, Data.EaValue, Data.NeedEa);
EaMap.Remove(EaName);
}
if (null != EaValue) if (null != EaValue)
{ {
Data.EaValue = EaValue; Data.EaValue = EaValue;
@ -1128,11 +1133,6 @@ namespace memfs
EaMap[EaName] = Data; EaMap[EaName] = Data;
EaSizePlus = GetEaEntrySize(EaName, EaValue, NeedEa); EaSizePlus = GetEaEntrySize(EaName, EaValue, NeedEa);
} }
else if (EaMap.TryGetValue(EaName, out Data))
{
EaSizeMinus = GetEaEntrySize(EaName, Data.EaValue, Data.NeedEa);
EaMap.Remove(EaName);
}
FileNode.FileInfo.EaSize = FileNode.FileInfo.EaSize + EaSizePlus - EaSizeMinus; FileNode.FileInfo.EaSize = FileNode.FileInfo.EaSize + EaSizePlus - EaSizeMinus;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View File

@ -458,13 +458,15 @@ NTSTATUS MemfsFileNodeSetEa(
return STATUS_INSUFFICIENT_RESOURCES; return STATUS_INSUFFICIENT_RESOURCES;
memcpy(FileNodeEa, Ea, EaSizePlus); memcpy(FileNodeEa, Ea, EaSizePlus);
FileNodeEa->NextEntryOffset = 0; FileNodeEa->NextEntryOffset = 0;
EaSizePlus = FspFileSystemGetEaPackedSize(Ea);
} }
p = EaMap->find(Ea->EaName); p = EaMap->find(Ea->EaName);
if (p != EaMap->end()) if (p != EaMap->end())
{ {
EaSizeMinus = FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + EaSizeMinus = FspFileSystemGetEaPackedSize(Ea);
p->second->EaNameLength + 1 + p->second->EaValueLength;
free(p->second); free(p->second);
EaMap->erase(p); EaMap->erase(p);
} }
@ -482,9 +484,7 @@ NTSTATUS MemfsFileNodeSetEa(
} }
} }
FileNode->FileInfo.EaSize = FileNode->FileInfo.EaSize FileNode->FileInfo.EaSize = FileNode->FileInfo.EaSize + EaSizePlus - EaSizeMinus;
+ FSP_FSCTL_ALIGN_UP(EaSizePlus, sizeof(ULONG))
- FSP_FSCTL_ALIGN_UP(EaSizeMinus, sizeof(ULONG));
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -2167,10 +2167,20 @@ static NTSTATUS GetEa(FSP_FILE_SYSTEM *FileSystem,
} }
static NTSTATUS SetEa(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS SetEa(FSP_FILE_SYSTEM *FileSystem,
PVOID FileNode, PVOID FileNode0,
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength) PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
FSP_FSCTL_FILE_INFO *FileInfo)
{ {
return FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength); MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
NTSTATUS Result;
Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength);
if (!NT_SUCCESS(Result))
return Result;
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
return STATUS_SUCCESS;
} }
#endif #endif