mirror of
https://github.com/winfsp/winfsp.git
synced 2025-06-15 00:02:46 -05:00
tst: memfs: extended attributes support
This commit is contained in:
@ -64,6 +64,11 @@ FSP_FSCTL_STATIC_ASSERT(MEMFS_MAX_PATH > MAX_PATH,
|
||||
*/
|
||||
#define MEMFS_CONTROL
|
||||
|
||||
/*
|
||||
* Define the MEMFS_EA macro to include extended attributes support.
|
||||
*/
|
||||
#define MEMFS_EA
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -237,6 +242,36 @@ BOOLEAN MemfsFileNameHasPrefix(PWSTR a, PWSTR b, BOOLEAN CaseInsensitive)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(MEMFS_EA)
|
||||
static inline
|
||||
int MemfsEaNameCompare(PSTR a, PSTR b)
|
||||
{
|
||||
/* EA names are always case-insensitive in MEMFS (to be inline with NTFS) */
|
||||
|
||||
int res;
|
||||
|
||||
res = CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, a, -1, b, -1);
|
||||
if (0 != res)
|
||||
res -= 2;
|
||||
else
|
||||
res = _stricmp(a, b);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct MEMFS_FILE_NODE_EA_LESS
|
||||
{
|
||||
MEMFS_FILE_NODE_EA_LESS()
|
||||
{
|
||||
}
|
||||
bool operator()(PSTR a, PSTR b) const
|
||||
{
|
||||
return 0 > MemfsEaNameCompare(a, b);
|
||||
}
|
||||
};
|
||||
typedef std::map<PSTR, FILE_FULL_EA_INFORMATION *, MEMFS_FILE_NODE_EA_LESS> MEMFS_FILE_NODE_EA_MAP;
|
||||
#endif
|
||||
|
||||
typedef struct _MEMFS_FILE_NODE
|
||||
{
|
||||
WCHAR FileName[MEMFS_MAX_PATH];
|
||||
@ -252,6 +287,9 @@ typedef struct _MEMFS_FILE_NODE
|
||||
#if defined(MEMFS_NAMED_STREAMS)
|
||||
struct _MEMFS_FILE_NODE *MainFileNode;
|
||||
#endif
|
||||
#if defined(MEMFS_EA)
|
||||
MEMFS_FILE_NODE_EA_MAP *EaMap;
|
||||
#endif
|
||||
} MEMFS_FILE_NODE;
|
||||
|
||||
struct MEMFS_FILE_NODE_LESS
|
||||
@ -311,6 +349,15 @@ NTSTATUS MemfsFileNodeCreate(PWSTR FileName, MEMFS_FILE_NODE **PFileNode)
|
||||
static inline
|
||||
VOID MemfsFileNodeDelete(MEMFS_FILE_NODE *FileNode)
|
||||
{
|
||||
#if defined(MEMFS_EA)
|
||||
if (0 != FileNode->EaMap)
|
||||
{
|
||||
for (MEMFS_FILE_NODE_EA_MAP::iterator p = FileNode->EaMap->begin(), q = FileNode->EaMap->end();
|
||||
p != q; ++p)
|
||||
free(p->second);
|
||||
delete FileNode->EaMap;
|
||||
}
|
||||
#endif
|
||||
#if defined(MEMFS_REPARSE_POINTS)
|
||||
free(FileNode->ReparseData);
|
||||
#endif
|
||||
@ -351,6 +398,120 @@ VOID MemfsFileNodeGetFileInfo(MEMFS_FILE_NODE *FileNode, FSP_FSCTL_FILE_INFO *Fi
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(MEMFS_EA)
|
||||
static inline
|
||||
NTSTATUS MemfsFileNodeGetEaMap(MEMFS_FILE_NODE *FileNode, MEMFS_FILE_NODE_EA_MAP **PEaMap)
|
||||
{
|
||||
#if defined(MEMFS_NAMED_STREAMS)
|
||||
if (0 != FileNode->MainFileNode)
|
||||
FileNode = FileNode->MainFileNode;
|
||||
#endif
|
||||
|
||||
*PEaMap = FileNode->EaMap;
|
||||
if (0 != *PEaMap)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
try
|
||||
{
|
||||
*PEaMap = FileNode->EaMap = new MEMFS_FILE_NODE_EA_MAP(MEMFS_FILE_NODE_EA_LESS());
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
*PEaMap = 0;
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
static inline
|
||||
NTSTATUS MemfsFileNodeSetEa(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PFILE_FULL_EA_INFORMATION Ea)
|
||||
{
|
||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)Context;
|
||||
MEMFS_FILE_NODE_EA_MAP *EaMap;
|
||||
FILE_FULL_EA_INFORMATION *FileNodeEa = 0;
|
||||
MEMFS_FILE_NODE_EA_MAP::iterator p;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = MemfsFileNodeGetEaMap(FileNode, &EaMap);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
|
||||
if (0 != Ea->EaValueLength)
|
||||
{
|
||||
FileNodeEa = (FILE_FULL_EA_INFORMATION *)malloc(
|
||||
sizeof *FileNodeEa + Ea->EaNameLength + Ea->EaValueLength);
|
||||
if (0 == FileNodeEa)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
memcpy(FileNodeEa, Ea, sizeof *FileNodeEa + Ea->EaNameLength + Ea->EaValueLength);
|
||||
FileNodeEa->NextEntryOffset = 0;
|
||||
}
|
||||
|
||||
p = EaMap->find(Ea->EaName);
|
||||
if (p != EaMap->end())
|
||||
{
|
||||
free(p->second);
|
||||
EaMap->erase(p);
|
||||
}
|
||||
|
||||
if (0 != Ea->EaValueLength)
|
||||
{
|
||||
try
|
||||
{
|
||||
EaMap->insert(MEMFS_FILE_NODE_EA_MAP::value_type(FileNodeEa->EaName, FileNodeEa));
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
free(FileNodeEa);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static inline
|
||||
BOOLEAN MemfsFileNodeNeedEa(MEMFS_FILE_NODE *FileNode)
|
||||
{
|
||||
#if defined(MEMFS_NAMED_STREAMS)
|
||||
if (0 != FileNode->MainFileNode)
|
||||
FileNode = FileNode->MainFileNode;
|
||||
#endif
|
||||
|
||||
if (0 != FileNode->EaMap)
|
||||
{
|
||||
for (MEMFS_FILE_NODE_EA_MAP::iterator p = FileNode->EaMap->begin(), q = FileNode->EaMap->end();
|
||||
p != q; ++p)
|
||||
if (0 != (p->second->Flags & FILE_NEED_EA))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static inline
|
||||
BOOLEAN MemfsFileNodeEnumerateEa(MEMFS_FILE_NODE *FileNode,
|
||||
BOOLEAN (*EnumFn)(PFILE_FULL_EA_INFORMATION Ea, PVOID), PVOID Context)
|
||||
{
|
||||
#if defined(MEMFS_NAMED_STREAMS)
|
||||
if (0 != FileNode->MainFileNode)
|
||||
FileNode = FileNode->MainFileNode;
|
||||
#endif
|
||||
|
||||
if (0 != FileNode->EaMap)
|
||||
{
|
||||
for (MEMFS_FILE_NODE_EA_MAP::iterator p = FileNode->EaMap->begin(), q = FileNode->EaMap->end();
|
||||
p != q; ++p)
|
||||
if (!EnumFn(p->second, Context))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline
|
||||
VOID MemfsFileNodeMapDump(MEMFS_FILE_NODE_MAP *FileNodeMap)
|
||||
{
|
||||
@ -869,6 +1030,9 @@ static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem,
|
||||
static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
||||
#if defined(MEMFS_EA)
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
|
||||
#endif
|
||||
PVOID *PFileNode, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
@ -948,6 +1112,18 @@ static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
memcpy(FileNode->FileSecurity, SecurityDescriptor, FileNode->FileSecuritySize);
|
||||
}
|
||||
|
||||
#if defined(MEMFS_EA)
|
||||
if (0 != Ea)
|
||||
{
|
||||
Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
MemfsFileNodeDelete(FileNode);
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
FileNode->FileInfo.AllocationSize = AllocationSize;
|
||||
if (0 != FileNode->FileInfo.AllocationSize)
|
||||
{
|
||||
@ -1005,6 +1181,22 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
return Result;
|
||||
}
|
||||
|
||||
#if defined(MEMFS_EA)
|
||||
/* if the OP specified no EA's check the need EA count, but only if accessing main stream */
|
||||
if (0 != (CreateOptions & FILE_NO_EA_KNOWLEDGE)
|
||||
#if defined(MEMFS_NAMED_STREAMS)
|
||||
&& (0 == FileNode->MainFileNode)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (MemfsFileNodeNeedEa(FileNode))
|
||||
{
|
||||
Result = STATUS_ACCESS_DENIED;
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
MemfsFileNodeReference(FileNode);
|
||||
*PFileNode = FileNode;
|
||||
MemfsFileNodeGetFileInfo(FileNode, FileInfo);
|
||||
@ -1025,6 +1217,9 @@ static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileNode0, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
|
||||
#if defined(MEMFS_EA)
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
|
||||
#endif
|
||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
MEMFS *Memfs = (MEMFS *)FileSystem->UserContext;
|
||||
@ -1047,6 +1242,15 @@ static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
MemfsFileNodeMapEnumerateFree(&Context);
|
||||
#endif
|
||||
|
||||
#if defined(MEMFS_EA)
|
||||
if (0 != Ea)
|
||||
{
|
||||
Result = FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
#endif
|
||||
|
||||
Result = SetFileSizeInternal(FileSystem, FileNode, AllocationSize, TRUE);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
@ -1881,7 +2085,7 @@ static NTSTATUS GetStreamInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
|
||||
#if defined(MEMFS_CONTROL)
|
||||
static NTSTATUS Control(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileContext, UINT32 ControlCode,
|
||||
PVOID FileNode, UINT32 ControlCode,
|
||||
PVOID InputBuffer, ULONG InputBufferLength,
|
||||
PVOID OutputBuffer, ULONG OutputBufferLength, PULONG PBytesTransferred)
|
||||
{
|
||||
@ -1911,14 +2115,63 @@ static NTSTATUS Control(FSP_FILE_SYSTEM *FileSystem,
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MEMFS_EA)
|
||||
typedef struct _MEMFS_GET_EA_CONTEXT
|
||||
{
|
||||
PFILE_FULL_EA_INFORMATION Ea;
|
||||
ULONG EaLength;
|
||||
PULONG PBytesTransferred;
|
||||
} MEMFS_GET_EA_CONTEXT;
|
||||
|
||||
static BOOLEAN GetEaEnumFn(PFILE_FULL_EA_INFORMATION Ea, PVOID Context0)
|
||||
{
|
||||
MEMFS_GET_EA_CONTEXT *Context = (MEMFS_GET_EA_CONTEXT *)Context0;
|
||||
|
||||
return FspFileSystemAddEa(Ea,
|
||||
Context->Ea, Context->EaLength, Context->PBytesTransferred);
|
||||
}
|
||||
|
||||
static NTSTATUS GetEa(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileNode0,
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength, PULONG PBytesTransferred)
|
||||
{
|
||||
MEMFS_FILE_NODE *FileNode = (MEMFS_FILE_NODE *)FileNode0;
|
||||
MEMFS_GET_EA_CONTEXT Context;
|
||||
|
||||
Context.Ea = Ea;
|
||||
Context.EaLength = EaLength;
|
||||
Context.PBytesTransferred = PBytesTransferred;
|
||||
|
||||
if (MemfsFileNodeEnumerateEa(FileNode, GetEaEnumFn, &Context))
|
||||
FspFileSystemAddEa(0, Ea, EaLength, PBytesTransferred);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS SetEa(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileNode,
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
|
||||
{
|
||||
return FspFileSystemEnumerateEa(FileSystem, MemfsFileNodeSetEa, FileNode, Ea, EaLength);
|
||||
}
|
||||
#endif
|
||||
|
||||
static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||
{
|
||||
GetVolumeInfo,
|
||||
SetVolumeLabel,
|
||||
GetSecurityByName,
|
||||
#if defined(MEMFS_EA)
|
||||
0,
|
||||
#else
|
||||
Create,
|
||||
#endif
|
||||
Open,
|
||||
#if defined(MEMFS_EA)
|
||||
0,
|
||||
#else
|
||||
Overwrite,
|
||||
#endif
|
||||
Cleanup,
|
||||
Close,
|
||||
Read,
|
||||
@ -1957,6 +2210,18 @@ static FSP_FILE_SYSTEM_INTERFACE MemfsInterface =
|
||||
Control,
|
||||
#else
|
||||
0,
|
||||
#endif
|
||||
0,
|
||||
#if defined(MEMFS_EA)
|
||||
Create,
|
||||
Overwrite,
|
||||
GetEa,
|
||||
SetEa
|
||||
#else
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user