mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
tst: passthrough-fuse: xattr
This commit is contained in:
parent
574efe3f72
commit
4e7d2fd204
@ -438,6 +438,9 @@ static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim, &FileInfo->ChangeTime);
|
FspPosixUnixTimeToFileTime((void *)&stbuf.st_ctim, &FileInfo->ChangeTime);
|
||||||
FileInfo->IndexNumber = stbuf.st_ino;
|
FileInfo->IndexNumber = stbuf.st_ino;
|
||||||
|
|
||||||
|
FileInfo->HardLinks = 0;
|
||||||
|
FileInfo->EaSize = 0;
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2263,7 +2266,10 @@ static NTSTATUS fsp_fuse_intf_GetEa(FSP_FILE_SYSTEM *FileSystem,
|
|||||||
PrevEa = Ea;
|
PrevEa = Ea;
|
||||||
|
|
||||||
*PBytesTransferred = (ULONG)((PUINT8)EaValue - (PUINT8)Ea0 + valuesize);
|
*PBytesTransferred = (ULONG)((PUINT8)EaValue - (PUINT8)Ea0 + valuesize);
|
||||||
Ea = (PVOID)((PUINT8)EaValue + FSP_FSCTL_ALIGN_UP(valuesize, sizeof(ULONG)));
|
Ea = (PVOID)((PUINT8)Ea +
|
||||||
|
FSP_FSCTL_ALIGN_UP(
|
||||||
|
FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + namesize + valuesize,
|
||||||
|
sizeof(ULONG)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
@ -175,6 +175,36 @@ static int ptfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
|
|||||||
return -1 != fsync(fd) ? 0 : -errno;
|
return -1 != fsync(fd) ? 0 : -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ptfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
ptfs_impl_fullpath(path);
|
||||||
|
|
||||||
|
return -1 != lsetxattr(path, name, value, size, flags) ? 0 : -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptfs_getxattr(const char *path, const char *name, char *value, size_t size)
|
||||||
|
{
|
||||||
|
ptfs_impl_fullpath(path);
|
||||||
|
|
||||||
|
int nb;
|
||||||
|
return -1 != (nb = lgetxattr(path, name, value, size)) ? nb : -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptfs_listxattr(const char *path, char *namebuf, size_t size)
|
||||||
|
{
|
||||||
|
ptfs_impl_fullpath(path);
|
||||||
|
|
||||||
|
int nb;
|
||||||
|
return -1 != (nb = llistxattr(path, namebuf, size)) ? nb : -errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ptfs_removexattr(const char *path, const char *name)
|
||||||
|
{
|
||||||
|
ptfs_impl_fullpath(path);
|
||||||
|
|
||||||
|
return -1 != lremovexattr(path, name) ? 0 : -errno;
|
||||||
|
}
|
||||||
|
|
||||||
static int ptfs_opendir(const char *path, struct fuse_file_info *fi)
|
static int ptfs_opendir(const char *path, struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
ptfs_impl_fullpath(path);
|
ptfs_impl_fullpath(path);
|
||||||
@ -300,6 +330,10 @@ static struct fuse_operations ptfs_ops =
|
|||||||
.statfs = ptfs_statfs,
|
.statfs = ptfs_statfs,
|
||||||
.release = ptfs_release,
|
.release = ptfs_release,
|
||||||
.fsync = ptfs_fsync,
|
.fsync = ptfs_fsync,
|
||||||
|
.setxattr = ptfs_setxattr,
|
||||||
|
.getxattr = ptfs_getxattr,
|
||||||
|
.listxattr = ptfs_listxattr,
|
||||||
|
.removexattr = ptfs_removexattr,
|
||||||
.opendir = ptfs_opendir,
|
.opendir = ptfs_opendir,
|
||||||
.readdir = ptfs_readdir,
|
.readdir = ptfs_readdir,
|
||||||
.releasedir = ptfs_releasedir,
|
.releasedir = ptfs_releasedir,
|
||||||
|
@ -33,6 +33,33 @@
|
|||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
#include "winposix.h"
|
#include "winposix.h"
|
||||||
|
|
||||||
|
#pragma comment(lib, "ntdll.lib")
|
||||||
|
|
||||||
|
typedef struct _FILE_GET_EA_INFORMATION
|
||||||
|
{
|
||||||
|
ULONG NextEntryOffset;
|
||||||
|
UCHAR EaNameLength;
|
||||||
|
CHAR EaName[1];
|
||||||
|
} FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION;
|
||||||
|
|
||||||
|
NTSYSAPI NTSTATUS NTAPI NtQueryEaFile(
|
||||||
|
IN HANDLE FileHandle,
|
||||||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
OUT PVOID Buffer,
|
||||||
|
IN ULONG Length,
|
||||||
|
IN BOOLEAN ReturnSingleEntry,
|
||||||
|
IN PVOID EaList OPTIONAL,
|
||||||
|
IN ULONG EaListLength,
|
||||||
|
IN PULONG EaIndex OPTIONAL,
|
||||||
|
IN BOOLEAN RestartScan);
|
||||||
|
NTSYSAPI NTSTATUS NTAPI NtSetEaFile(
|
||||||
|
IN HANDLE FileHandle,
|
||||||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
IN PVOID EaBuffer,
|
||||||
|
IN ULONG EaBufferSize);
|
||||||
|
#define NEXT_EA(Ea, EaEnd) \
|
||||||
|
(0 != (Ea)->NextEntryOffset ? (PVOID)((PUINT8)(Ea) + (Ea)->NextEntryOffset) : (EaEnd))
|
||||||
|
|
||||||
struct _DIR
|
struct _DIR
|
||||||
{
|
{
|
||||||
HANDLE h, fh;
|
HANDLE h, fh;
|
||||||
@ -419,6 +446,233 @@ int rename(const char *oldpath, const char *newpath)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lsetea(const char *path, PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
|
||||||
|
{
|
||||||
|
HANDLE h = CreateFileA(path,
|
||||||
|
FILE_WRITE_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
0,
|
||||||
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||||
|
if (INVALID_HANDLE_VALUE == h)
|
||||||
|
return error();
|
||||||
|
|
||||||
|
IO_STATUS_BLOCK Iosb;
|
||||||
|
NTSTATUS Status = NtSetEaFile(h, &Iosb, Ea, EaLength);
|
||||||
|
|
||||||
|
CloseHandle(h);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
switch (Status)
|
||||||
|
{
|
||||||
|
case STATUS_INVALID_EA_NAME:
|
||||||
|
case STATUS_EA_LIST_INCONSISTENT:
|
||||||
|
case STATUS_EA_CORRUPT_ERROR:
|
||||||
|
case STATUS_NONEXISTENT_EA_ENTRY:
|
||||||
|
case STATUS_NO_MORE_EAS:
|
||||||
|
case STATUS_NO_EAS_ON_FILE:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
default:
|
||||||
|
SetLastError(RtlNtStatusToDosError(Status));
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lgetea(const char *path,
|
||||||
|
PFILE_GET_EA_INFORMATION GetEa, ULONG GetEaLength,
|
||||||
|
PFILE_FULL_EA_INFORMATION Ea, ULONG EaLength)
|
||||||
|
{
|
||||||
|
HANDLE h = CreateFileA(path,
|
||||||
|
FILE_READ_EA | SYNCHRONIZE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||||
|
0,
|
||||||
|
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||||
|
if (INVALID_HANDLE_VALUE == h)
|
||||||
|
return error();
|
||||||
|
|
||||||
|
IO_STATUS_BLOCK Iosb;
|
||||||
|
NTSTATUS Status = NtQueryEaFile(h, &Iosb, Ea, EaLength, FALSE, GetEa, GetEaLength, 0, TRUE);
|
||||||
|
|
||||||
|
CloseHandle(h);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
switch (Status)
|
||||||
|
{
|
||||||
|
case STATUS_INVALID_EA_NAME:
|
||||||
|
case STATUS_EA_LIST_INCONSISTENT:
|
||||||
|
case STATUS_EA_CORRUPT_ERROR:
|
||||||
|
case STATUS_NONEXISTENT_EA_ENTRY:
|
||||||
|
case STATUS_NO_MORE_EAS:
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
case STATUS_NO_EAS_ON_FILE:
|
||||||
|
if (0 == GetEa)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = ENODATA;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
SetLastError(RtlNtStatusToDosError(Status));
|
||||||
|
return error();
|
||||||
|
}
|
||||||
|
else if (0 == GetEa &&
|
||||||
|
(FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) > Iosb.Information || 0 == Ea->EaValueLength))
|
||||||
|
{
|
||||||
|
errno = ENODATA;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ULONG)Iosb.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags)
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
FILE_FULL_EA_INFORMATION V;
|
||||||
|
UINT8 B[1024];
|
||||||
|
} EaBuf;
|
||||||
|
PFILE_FULL_EA_INFORMATION Ea = &EaBuf.V;
|
||||||
|
ULONG EaLength;
|
||||||
|
|
||||||
|
size_t namelen = strlen(name);
|
||||||
|
if (254 < namelen || 0xffff < size)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EaLength = (ULONG)(FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + namelen + 1 + size);
|
||||||
|
if (sizeof EaBuf < EaLength)
|
||||||
|
{
|
||||||
|
Ea = malloc(EaLength); /* sets errno */
|
||||||
|
if (0 == Ea)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(Ea, 0, sizeof(FILE_FULL_EA_INFORMATION));
|
||||||
|
Ea->EaNameLength = (UCHAR)namelen;
|
||||||
|
Ea->EaValueLength = (USHORT)size;
|
||||||
|
memcpy(Ea->EaName, name, namelen + 1);
|
||||||
|
memcpy(Ea->EaName + namelen + 1, value, size);
|
||||||
|
|
||||||
|
int res = lsetea(path, Ea, EaLength); /* sets errno */
|
||||||
|
|
||||||
|
if (&EaBuf.V != Ea)
|
||||||
|
free(Ea);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lgetxattr(const char *path, const char *name, void *value, size_t size0)
|
||||||
|
{
|
||||||
|
size_t size = 0 == size0 || 0xffff < size0 ? 0xffff : size0;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
FILE_GET_EA_INFORMATION V;
|
||||||
|
UINT8 B[FIELD_OFFSET(FILE_GET_EA_INFORMATION, EaName) + 255];
|
||||||
|
} GetEaBuf;
|
||||||
|
PFILE_GET_EA_INFORMATION GetEa = &GetEaBuf.V;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
FILE_FULL_EA_INFORMATION V;
|
||||||
|
UINT8 B[1024];
|
||||||
|
} EaBuf;
|
||||||
|
PFILE_FULL_EA_INFORMATION Ea = &EaBuf.V;
|
||||||
|
ULONG GetEaLength, EaLength;
|
||||||
|
|
||||||
|
size_t namelen = strlen(name);
|
||||||
|
if (254 < namelen)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EaLength = (ULONG)(FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + namelen + 1 + size);
|
||||||
|
if (sizeof EaBuf < EaLength)
|
||||||
|
{
|
||||||
|
Ea = malloc(EaLength); /* sets errno */
|
||||||
|
if (0 == Ea)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetEaLength = (ULONG)(FIELD_OFFSET(FILE_GET_EA_INFORMATION, EaName) + namelen + 1);
|
||||||
|
memset(GetEa, 0, sizeof(FILE_GET_EA_INFORMATION));
|
||||||
|
GetEa->EaNameLength = (UCHAR)namelen;
|
||||||
|
memcpy(GetEa->EaName, name, namelen + 1);
|
||||||
|
|
||||||
|
int res = lgetea(path, GetEa, GetEaLength, Ea, EaLength);
|
||||||
|
if (0 < res)
|
||||||
|
{
|
||||||
|
res = Ea->EaValueLength;
|
||||||
|
if (0 == size0)
|
||||||
|
;
|
||||||
|
else if (res <= size0)
|
||||||
|
memcpy(value, Ea->EaName + Ea->EaNameLength + 1, res);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = ERANGE;
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (0 == res) /* should not happen! */
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (&EaBuf.V != Ea)
|
||||||
|
free(Ea);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int llistxattr(const char *path, char *namebuf, size_t size)
|
||||||
|
{
|
||||||
|
PFILE_FULL_EA_INFORMATION Ea = 0;
|
||||||
|
ULONG EaLength;
|
||||||
|
|
||||||
|
EaLength = (ULONG)(FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName) + 254 + 1 + 0xffff);
|
||||||
|
Ea = malloc(EaLength); /* sets errno */
|
||||||
|
if (0 == Ea)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int res = lgetea(path, 0, 0, Ea, EaLength);
|
||||||
|
if (0 < res)
|
||||||
|
{
|
||||||
|
PFILE_FULL_EA_INFORMATION EaEnd = (PVOID)((PUINT8)Ea + res);
|
||||||
|
res = 0;
|
||||||
|
for (PFILE_FULL_EA_INFORMATION EaPtr = Ea; EaEnd > EaPtr; EaPtr = NEXT_EA(EaPtr, EaEnd))
|
||||||
|
res += EaPtr->EaNameLength + 1;
|
||||||
|
|
||||||
|
if (0 == size)
|
||||||
|
;
|
||||||
|
else if (res <= size)
|
||||||
|
{
|
||||||
|
char *p = namebuf;
|
||||||
|
for (PFILE_FULL_EA_INFORMATION EaPtr = Ea; EaEnd > EaPtr; EaPtr = NEXT_EA(EaPtr, EaEnd))
|
||||||
|
{
|
||||||
|
memcpy(p, EaPtr->EaName, EaPtr->EaNameLength + 1);
|
||||||
|
p += EaPtr->EaNameLength + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
errno = ERANGE;
|
||||||
|
res = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(Ea);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lremovexattr(const char *path, const char *name)
|
||||||
|
{
|
||||||
|
return lsetxattr(path, name, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int mkdir(const char *path, fuse_mode_t mode)
|
int mkdir(const char *path, fuse_mode_t mode)
|
||||||
{
|
{
|
||||||
if (!CreateDirectoryA(path, 0/* default security */))
|
if (!CreateDirectoryA(path, 0/* default security */))
|
||||||
|
@ -64,6 +64,11 @@ int setcrtime(const char *path, const struct fuse_timespec *tv);
|
|||||||
int unlink(const char *path);
|
int unlink(const char *path);
|
||||||
int rename(const char *oldpath, const char *newpath);
|
int rename(const char *oldpath, const char *newpath);
|
||||||
|
|
||||||
|
int lsetxattr(const char *path, const char *name, const void *value, size_t size, int flags);
|
||||||
|
int lgetxattr(const char *path, const char *name, void *value, size_t size);
|
||||||
|
int llistxattr(const char *path, char *namebuf, size_t size);
|
||||||
|
int lremovexattr(const char *path, const char *name);
|
||||||
|
|
||||||
int mkdir(const char *path, fuse_mode_t mode);
|
int mkdir(const char *path, fuse_mode_t mode);
|
||||||
int rmdir(const char *path);
|
int rmdir(const char *path);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user