mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
dll: fuse: extended attributes support
This commit is contained in:
parent
c23aabe533
commit
8c6d037332
@ -67,11 +67,11 @@ struct fuse_operations
|
||||
/* S */ int (*flush)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*release)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*fsync)(const char *path, int datasync, struct fuse_file_info *fi);
|
||||
/* _ */ int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
/* S */ int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
int flags);
|
||||
/* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
/* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
/* _ */ int (*removexattr)(const char *path, const char *name);
|
||||
/* S */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
/* S */ int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
/* S */ int (*removexattr)(const char *path, const char *name);
|
||||
/* S */ int (*opendir)(const char *path, struct fuse_file_info *fi);
|
||||
/* S */ int (*readdir)(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
|
@ -106,11 +106,11 @@ struct fuse3_operations
|
||||
/* S */ int (*flush)(const char *path, struct fuse3_file_info *fi);
|
||||
/* S */ int (*release)(const char *path, struct fuse3_file_info *fi);
|
||||
/* S */ int (*fsync)(const char *path, int datasync, struct fuse3_file_info *fi);
|
||||
/* _ */ int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
/* S */ int (*setxattr)(const char *path, const char *name, const char *value, size_t size,
|
||||
int flags);
|
||||
/* _ */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
/* _ */ int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
/* _ */ int (*removexattr)(const char *path, const char *name);
|
||||
/* S */ int (*getxattr)(const char *path, const char *name, char *value, size_t size);
|
||||
/* S */ int (*listxattr)(const char *path, char *namebuf, size_t size);
|
||||
/* S */ int (*removexattr)(const char *path, const char *name);
|
||||
/* S */ int (*opendir)(const char *path, struct fuse3_file_info *fi);
|
||||
/* S */ int (*readdir)(const char *path, void *buf, fuse3_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse3_file_info *fi, enum fuse3_readdir_flags);
|
||||
|
@ -83,6 +83,8 @@ static struct fuse_opt fsp_fuse_core_opts[] =
|
||||
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("DirInfoTimeout=", set_DirInfoTimeout, 1),
|
||||
FSP_FUSE_CORE_OPT("DirInfoTimeout=%d", VolumeParams.DirInfoTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("EaTimeout=", set_EaTimeout, 1),
|
||||
FSP_FUSE_CORE_OPT("EaTimeout=%d", VolumeParams.EaTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("VolumeInfoTimeout=", set_VolumeInfoTimeout, 1),
|
||||
FSP_FUSE_CORE_OPT("VolumeInfoTimeout=%d", VolumeParams.VolumeInfoTimeout, 0),
|
||||
FSP_FUSE_CORE_OPT("KeepFileCache=", set_KeepFileCache, 1),
|
||||
@ -252,6 +254,7 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
FSP_FUSE_LIBRARY_NAME " advanced options:\n"
|
||||
" -o FileInfoTimeout=N metadata timeout (millis, -1 for data caching)\n"
|
||||
" -o DirInfoTimeout=N directory info timeout (millis)\n"
|
||||
" -o EaTimeout=N extended attribute timeout (millis)\n"
|
||||
" -o VolumeInfoTimeout=N volume info timeout (millis)\n"
|
||||
" -o KeepFileCache do not discard cache when files are closed\n"
|
||||
" -o ThreadCount number of file system dispatcher threads\n"
|
||||
@ -392,6 +395,8 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
opt_data.VolumeParams.FileInfoTimeout = opt_data.attr_timeout * 1000;
|
||||
if (opt_data.set_DirInfoTimeout)
|
||||
opt_data.VolumeParams.DirInfoTimeoutValid = 1;
|
||||
if (opt_data.set_EaTimeout)
|
||||
opt_data.VolumeParams.EaTimeoutValid = 1;
|
||||
if (opt_data.set_VolumeInfoTimeout)
|
||||
opt_data.VolumeParams.VolumeInfoTimeoutValid = 1;
|
||||
if (opt_data.set_KeepFileCache)
|
||||
|
@ -666,6 +666,9 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
|
||||
static NTSTATUS fsp_fuse_intf_GetReparsePointByName(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PWSTR FileName, BOOLEAN IsDirectory, PVOID Buffer, PSIZE_T PSize);
|
||||
static NTSTATUS fsp_fuse_intf_SetEaEntry(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PFILE_FULL_EA_INFORMATION SingleEa);
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem,
|
||||
FSP_FSCTL_VOLUME_INFO *VolumeInfo)
|
||||
@ -737,6 +740,7 @@ exit:
|
||||
static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess,
|
||||
UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize,
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
|
||||
PVOID *PFileDesc, FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
@ -750,6 +754,16 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
int err;
|
||||
NTSTATUS Result;
|
||||
|
||||
if (0 != Ea)
|
||||
{
|
||||
if (0 == f->ops.listxattr || 0 == f->ops.getxattr ||
|
||||
0 == f->ops.setxattr || 0 == f->ops.removexattr)
|
||||
{
|
||||
Result = STATUS_EAS_NOT_SUPPORTED;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
filedesc = MemAlloc(sizeof *filedesc);
|
||||
if (0 == filedesc)
|
||||
{
|
||||
@ -849,6 +863,13 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem,
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (0 != Ea)
|
||||
{
|
||||
Result = FspFileSystemEnumerateEa(FileSystem,
|
||||
fsp_fuse_intf_SetEaEntry, contexthdr->PosixPath, Ea, EaLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache.
|
||||
* NOTE: Originally WinFsp dit not support disabling the cache manager
|
||||
@ -1001,6 +1022,7 @@ exit:
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileDesc, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize,
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength,
|
||||
FSP_FSCTL_FILE_INFO *FileInfo)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
@ -1013,6 +1035,29 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem,
|
||||
if (filedesc->IsDirectory || filedesc->IsReparsePoint)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
if (0 != Ea)
|
||||
{
|
||||
char names[3 * 1024];
|
||||
int namesize;
|
||||
|
||||
if (0 == f->ops.listxattr || 0 == f->ops.getxattr ||
|
||||
0 == f->ops.setxattr || 0 == f->ops.removexattr)
|
||||
return STATUS_EAS_NOT_SUPPORTED;
|
||||
|
||||
namesize = f->ops.listxattr(filedesc->PosixPath, names, sizeof names);
|
||||
if (0 < namesize)
|
||||
for (char *p = names, *endp = p + namesize; endp > p; p += namesize)
|
||||
{
|
||||
namesize = lstrlenA(p) + 1;
|
||||
f->ops.removexattr(filedesc->PosixPath, p);
|
||||
}
|
||||
|
||||
Result = FspFileSystemEnumerateEa(FileSystem,
|
||||
fsp_fuse_intf_SetEaEntry, filedesc->PosixPath, Ea, EaLength);
|
||||
if (!NT_SUCCESS(Result))
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (0 != f->ops.ftruncate)
|
||||
{
|
||||
memset(&fi, 0, sizeof fi);
|
||||
@ -2173,14 +2218,97 @@ static NTSTATUS fsp_fuse_intf_Control(FSP_FILE_SYSTEM *FileSystem,
|
||||
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_GetEa(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileDesc,
|
||||
PFILE_FULL_EA_INFORMATION Ea0, ULONG EaLength, PULONG PBytesTransferred)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
struct fsp_fuse_file_desc *filedesc = FileDesc;
|
||||
char names[3 * 1024];
|
||||
int namesize, valuesize;
|
||||
PFILE_FULL_EA_INFORMATION Ea = Ea0, PrevEa = 0;
|
||||
PUINT8 EaEnd = (PUINT8)Ea + EaLength, EaValue;
|
||||
|
||||
if (0 == f->ops.listxattr || 0 == f->ops.getxattr)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
namesize = f->ops.listxattr(filedesc->PosixPath, names, sizeof names);
|
||||
if (0 >= namesize)
|
||||
{
|
||||
*PBytesTransferred = 0;
|
||||
return fsp_fuse_ntstatus_from_errno(f->env, namesize);
|
||||
}
|
||||
|
||||
for (char *p = names, *endp = p + namesize; endp > p; p += namesize)
|
||||
{
|
||||
namesize = lstrlenA(p) + 1;
|
||||
|
||||
EaValue = (PUINT8)Ea + FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + namesize;
|
||||
if (EaValue >= EaEnd)
|
||||
/* if there is no space (at least 1 byte) for a value bail out */
|
||||
break;
|
||||
|
||||
valuesize = f->ops.getxattr(filedesc->PosixPath, p, EaValue, EaEnd - EaValue);
|
||||
if (0 >= valuesize)
|
||||
continue;
|
||||
|
||||
Ea->NextEntryOffset = 0;
|
||||
Ea->Flags = 0;
|
||||
Ea->EaNameLength = namesize - 1;
|
||||
Ea->EaValueLength = valuesize;
|
||||
memcpy(Ea->EaName, p, namesize);
|
||||
|
||||
if (0 != PrevEa)
|
||||
PrevEa->NextEntryOffset = (ULONG)((PUINT8)Ea - (PUINT8)PrevEa);
|
||||
PrevEa = Ea;
|
||||
|
||||
*PBytesTransferred = (ULONG)((PUINT8)EaValue - (PUINT8)Ea0 + valuesize);
|
||||
Ea = (PVOID)((PUINT8)EaValue + FSP_FSCTL_ALIGN_UP(valuesize, sizeof(ULONG)));
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_SetEaEntry(
|
||||
FSP_FILE_SYSTEM *FileSystem, PVOID Context,
|
||||
PFILE_FULL_EA_INFORMATION SingleEa)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
const char *PosixPath = Context;
|
||||
int err;
|
||||
|
||||
if (0 != SingleEa->EaValueLength)
|
||||
err = f->ops.setxattr(PosixPath,
|
||||
SingleEa->EaName, SingleEa->EaName + SingleEa->EaNameLength + 1, SingleEa->EaValueLength, 0);
|
||||
else
|
||||
err = f->ops.removexattr(PosixPath,
|
||||
SingleEa->EaName);
|
||||
|
||||
return fsp_fuse_ntstatus_from_errno(f->env, err);
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_intf_SetEa(FSP_FILE_SYSTEM *FileSystem,
|
||||
PVOID FileDesc,
|
||||
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
|
||||
{
|
||||
struct fuse *f = FileSystem->UserContext;
|
||||
struct fsp_fuse_file_desc *filedesc = FileDesc;
|
||||
|
||||
if (0 == f->ops.setxattr || 0 == f->ops.removexattr)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
return FspFileSystemEnumerateEa(FileSystem,
|
||||
fsp_fuse_intf_SetEaEntry, filedesc->PosixPath, Ea, EaLength);
|
||||
}
|
||||
|
||||
FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||
{
|
||||
fsp_fuse_intf_GetVolumeInfo,
|
||||
fsp_fuse_intf_SetVolumeLabel,
|
||||
fsp_fuse_intf_GetSecurityByName,
|
||||
fsp_fuse_intf_Create,
|
||||
0,
|
||||
fsp_fuse_intf_Open,
|
||||
fsp_fuse_intf_Overwrite,
|
||||
0,
|
||||
fsp_fuse_intf_Cleanup,
|
||||
fsp_fuse_intf_Close,
|
||||
fsp_fuse_intf_Read,
|
||||
@ -2201,6 +2329,11 @@ FSP_FILE_SYSTEM_INTERFACE fsp_fuse_intf =
|
||||
0,
|
||||
fsp_fuse_intf_GetDirInfoByName,
|
||||
fsp_fuse_intf_Control,
|
||||
0,
|
||||
fsp_fuse_intf_Create,
|
||||
fsp_fuse_intf_Overwrite,
|
||||
fsp_fuse_intf_GetEa,
|
||||
fsp_fuse_intf_SetEa,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -160,6 +160,9 @@ static NTSTATUS fsp_fuse_loop_start(struct fuse *f)
|
||||
err = f->ops.readlink("/", buf, sizeof buf);
|
||||
f->has_symlinks = -ENOSYS_(f->env) != err;
|
||||
}
|
||||
if (0 != f->ops.listxattr && 0 != f->ops.getxattr &&
|
||||
0 != f->ops.setxattr && 0 != f->ops.removexattr)
|
||||
f->VolumeParams.ExtendedAttributes = 1;
|
||||
|
||||
/* the FSD does not currently limit these VolumeParams fields; do so here! */
|
||||
if (f->VolumeParams.SectorSize < FSP_FUSE_SECTORSIZE_MIN ||
|
||||
|
@ -143,6 +143,7 @@ struct fsp_fuse_core_opt_data
|
||||
rellinks;
|
||||
int set_FileInfoTimeout,
|
||||
set_DirInfoTimeout,
|
||||
set_EaTimeout,
|
||||
set_VolumeInfoTimeout,
|
||||
set_KeepFileCache;
|
||||
unsigned ThreadCount;
|
||||
|
Loading…
x
Reference in New Issue
Block a user