tst: passthrough-fuse: FSP_FUSE_CAP_*

This commit is contained in:
Bill Zissimopoulos 2017-02-13 21:53:37 -08:00
parent 35d1adb360
commit 712870ddd9
7 changed files with 137 additions and 54 deletions

View File

@ -41,6 +41,15 @@ extern "C" {
#define FUSE_CAP_EXPORT_SUPPORT (1 << 4) #define FUSE_CAP_EXPORT_SUPPORT (1 << 4)
#define FUSE_CAP_BIG_WRITES (1 << 5) #define FUSE_CAP_BIG_WRITES (1 << 5)
#define FUSE_CAP_DONT_MASK (1 << 6) #define FUSE_CAP_DONT_MASK (1 << 6)
#define FUSE_CAP_ALLOCATE (1 << 27) /* reserved (OSXFUSE) */
#define FUSE_CAP_EXCHANGE_DATA (1 << 28) /* reserved (OSXFUSE) */
#define FUSE_CAP_CASE_INSENSITIVE (1 << 29) /* file system is case insensitive */
#define FUSE_CAP_VOL_RENAME (1 << 30) /* reserved (OSXFUSE) */
#define FUSE_CAP_XTIMES (1 << 31) /* reserved (OSXFUSE) */
#define FSP_FUSE_CAP_READDIR_PLUS (1 << 21) /* file system supports enhanced readdir */
#define FSP_FUSE_CAP_READ_ONLY (1 << 22) /* file system is marked read-only */
#define FSP_FUSE_CAP_CASE_INSENSITIVE FUSE_CAP_CASE_INSENSITIVE
#define FUSE_IOCTL_COMPAT (1 << 0) #define FUSE_IOCTL_COMPAT (1 << 0)
#define FUSE_IOCTL_UNRESTRICTED (1 << 1) #define FUSE_IOCTL_UNRESTRICTED (1 << 1)

View File

@ -38,8 +38,6 @@ struct fsp_fuse_core_opt_data
set_attr_timeout, attr_timeout, set_attr_timeout, attr_timeout,
rellinks; rellinks;
int set_FileInfoTimeout; int set_FileInfoTimeout;
int CaseInsensitiveSearch,
ReadOnlyVolume;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;
}; };
@ -89,8 +87,6 @@ static struct fuse_opt fsp_fuse_core_opts[] =
FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0), FSP_FUSE_CORE_OPT("VolumeSerialNumber=%lx", VolumeParams.VolumeSerialNumber, 0),
FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1), FSP_FUSE_CORE_OPT("FileInfoTimeout=", set_FileInfoTimeout, 1),
FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0), FSP_FUSE_CORE_OPT("FileInfoTimeout=%d", VolumeParams.FileInfoTimeout, 0),
FSP_FUSE_CORE_OPT("CaseInsensitiveSearch", CaseInsensitiveSearch, 1),
FSP_FUSE_CORE_OPT("ReadOnlyVolume", ReadOnlyVolume, 1),
FUSE_OPT_KEY("--UNC=", 'U'), FUSE_OPT_KEY("--UNC=", 'U'),
FUSE_OPT_KEY("--VolumePrefix=", 'U'), FUSE_OPT_KEY("--VolumePrefix=", 'U'),
FUSE_OPT_KEY("--FileSystemName=", 'F'), FUSE_OPT_KEY("--FileSystemName=", 'F'),
@ -252,9 +248,17 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
//FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */ //FUSE_CAP_ATOMIC_O_TRUNC | /* due to Windows/WinFsp design, no support */
//FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */ //FUSE_CAP_EXPORT_SUPPORT | /* not needed in Windows/WinFsp */
FUSE_CAP_BIG_WRITES | FUSE_CAP_BIG_WRITES |
FUSE_CAP_DONT_MASK; FUSE_CAP_DONT_MASK |
FSP_FUSE_CAP_READDIR_PLUS |
FSP_FUSE_CAP_READ_ONLY |
FSP_FUSE_CAP_CASE_INSENSITIVE;
if (0 != f->ops.init) if (0 != f->ops.init)
{
context->private_data = f->data = f->ops.init(&conn); context->private_data = f->data = f->ops.init(&conn);
f->VolumeParams.ReadOnlyVolume = 0 != (conn.want & FSP_FUSE_CAP_READ_ONLY);
f->VolumeParams.CaseSensitiveSearch = 0 == (conn.want & FSP_FUSE_CAP_CASE_INSENSITIVE);
f->conn_want = conn.want;
}
f->fsinit = TRUE; f->fsinit = TRUE;
if (0 != f->ops.statfs) if (0 != f->ops.statfs)
{ {
@ -417,7 +421,6 @@ static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
" -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n" " -o VolumeCreationTime=T volume creation time (FILETIME hex format)\n"
" -o VolumeSerialNumber=N 32-bit wide\n" " -o VolumeSerialNumber=N 32-bit wide\n"
" -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n" " -o FileInfoTimeout=N FileInfo/Security/VolumeInfo timeout (millisec)\n"
" -o CaseInsensitiveSearch file system supports case-insensitive file names\n"
" --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n" " --UNC=U --VolumePrefix=U UNC prefix (\\Server\\Share)\n"
" --FileSystemName=FSN Name of user mode file system\n"); " --FileSystemName=FSN Name of user mode file system\n");
opt_data->help = 1; opt_data->help = 1;
@ -501,12 +504,12 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout) if (!opt_data.set_FileInfoTimeout && opt_data.set_attr_timeout)
opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000; opt_data.VolumeParams.FileInfoTimeout = opt_data.set_attr_timeout * 1000;
opt_data.VolumeParams.CaseSensitiveSearch = !opt_data.CaseInsensitiveSearch; opt_data.VolumeParams.CaseSensitiveSearch = TRUE;
opt_data.VolumeParams.PersistentAcls = TRUE; opt_data.VolumeParams.PersistentAcls = TRUE;
opt_data.VolumeParams.ReparsePoints = TRUE; opt_data.VolumeParams.ReparsePoints = TRUE;
opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE; opt_data.VolumeParams.ReparsePointsAccessCheck = FALSE;
opt_data.VolumeParams.NamedStreams = FALSE; opt_data.VolumeParams.NamedStreams = FALSE;
opt_data.VolumeParams.ReadOnlyVolume = !!opt_data.ReadOnlyVolume; opt_data.VolumeParams.ReadOnlyVolume = FALSE;
opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE; opt_data.VolumeParams.PostCleanupWhenModifiedOnly = TRUE;
opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE; opt_data.VolumeParams.UmFileContextIsUserContext2 = TRUE;
if (L'\0' == opt_data.VolumeParams.FileSystemName[0]) if (L'\0' == opt_data.VolumeParams.FileSystemName[0])

View File

@ -311,28 +311,34 @@ static BOOLEAN fsp_fuse_intf_CheckSymlinkDirectory(FSP_FILE_SYSTEM *FileSystem,
} }
#define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\ #define fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, fi, PUid, PGid, PMode, FileInfo)\
fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, PUid, PGid, PMode, 0, FileInfo) fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0, PUid, PGid, PMode, 0, FileInfo)
static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem, static NTSTATUS fsp_fuse_intf_GetFileInfoFunnel(FSP_FILE_SYSTEM *FileSystem,
const char *PosixPath, struct fuse_file_info *fi, const char *PosixPath, struct fuse_file_info *fi, const struct fuse_stat *stbufp,
PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev, PUINT32 PUid, PUINT32 PGid, PUINT32 PMode, PUINT32 PDev,
FSP_FSCTL_FILE_INFO *FileInfo) FSP_FSCTL_FILE_INFO *FileInfo)
{ {
struct fuse *f = FileSystem->UserContext; struct fuse *f = FileSystem->UserContext;
UINT64 AllocationUnit; UINT64 AllocationUnit;
struct fuse_stat stbuf; struct fuse_stat stbuf;
int err;
memset(&stbuf, 0, sizeof stbuf); if (0 != stbufp)
memcpy(&stbuf, stbufp, sizeof stbuf);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr)
err = f->ops.getattr(PosixPath, (void *)&stbuf);
else else
return STATUS_INVALID_DEVICE_REQUEST; {
int err;
if (0 != err) memset(&stbuf, 0, sizeof stbuf);
return fsp_fuse_ntstatus_from_errno(f->env, err);
if (0 != f->ops.fgetattr && 0 != fi && -1 != fi->fh)
err = f->ops.fgetattr(PosixPath, (void *)&stbuf, fi);
else if (0 != f->ops.getattr)
err = f->ops.getattr(PosixPath, (void *)&stbuf);
else
return STATUS_INVALID_DEVICE_REQUEST;
if (0 != err)
return fsp_fuse_ntstatus_from_errno(f->env, err);
}
if (f->set_umask) if (f->set_umask)
stbuf.st_mode = (stbuf.st_mode & 0170000) | (0777 & ~f->umask); stbuf.st_mode = (stbuf.st_mode & 0170000) | (0777 & ~f->umask);
@ -513,7 +519,7 @@ static NTSTATUS fsp_fuse_intf_GetReparsePointEx(FSP_FILE_SYSTEM *FileSystem,
SIZE_T Size; SIZE_T Size;
NTSTATUS Result; NTSTATUS Result;
Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, Result = fsp_fuse_intf_GetFileInfoFunnel(FileSystem, PosixPath, fi, 0,
&Uid, &Gid, &Mode, &Dev, &FileInfo); &Uid, &Gid, &Mode, &Dev, &FileInfo);
if (!NT_SUCCESS(Result)) if (!NT_SUCCESS(Result))
return Result; return Result;
@ -1576,6 +1582,17 @@ static int fsp_fuse_intf_AddDirInfo(void *buf, const char *name,
memset(DirInfo, 0, sizeof *DirInfo); memset(DirInfo, 0, sizeof *DirInfo);
DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR)); DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + SizeW * sizeof(WCHAR));
if (dh->ReaddirPlus && 0 != stbuf)
{
UINT32 Uid, Gid, Mode;
NTSTATUS Result0;
Result0 = fsp_fuse_intf_GetFileInfoFunnel(dh->FileSystem, 0, 0, stbuf,
&Uid, &Gid, &Mode, 0, &DirInfo->FileInfo);
if (NT_SUCCESS(Result0))
DirInfo->Padding[0] = 1; /* HACK: remember that the FileInfo is valid */
}
return !FspFileSystemFillDirectoryBuffer(&filedesc->DirBuffer, DirInfo, &dh->Result); return !FspFileSystemFillDirectoryBuffer(&filedesc->DirBuffer, DirInfo, &dh->Result);
} }
@ -1619,44 +1636,53 @@ static NTSTATUS fsp_fuse_intf_FixDirInfo(FSP_FILE_SYSTEM *FileSystem,
DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index); DirInfo = (FSP_FSCTL_DIR_INFO *)(Buffer + *Index);
SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR); SizeW = (DirInfo->Size - sizeof *DirInfo) / sizeof(WCHAR);
if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0]) if (DirInfo->Padding[0])
{ {
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName; /* DirInfo has been filled already! */
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0'; DirInfo->Padding[0] = 0;
}
else
if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
PosixPathEnd--;
if (PosixPath == PosixPathEnd)
PosixPathEnd++;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
} }
else else
{ {
PosixPathEnd = 0; if (1 == SizeW && L'.' == DirInfo->FileNameBuf[0])
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
if (0 == SizeA)
{ {
/* this should never happen because we just converted using MultiByteToWideChar */ PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 1 : PosixName;
Result = STATUS_OBJECT_NAME_INVALID; SavedPathChar = *PosixPathEnd;
goto exit; *PosixPathEnd = '\0';
} }
PosixName[SizeA] = '\0'; else
if (2 == SizeW && L'.' == DirInfo->FileNameBuf[0] && L'.' == DirInfo->FileNameBuf[1])
{
PosixPathEnd = 1 < PosixName - PosixPath ? PosixName - 2 : PosixName;
while (PosixPath < PosixPathEnd && '/' != *PosixPathEnd)
PosixPathEnd--;
if (PosixPath == PosixPathEnd)
PosixPathEnd++;
SavedPathChar = *PosixPathEnd;
*PosixPathEnd = '\0';
}
else
{
PosixPathEnd = 0;
SizeA = WideCharToMultiByte(CP_UTF8, 0, DirInfo->FileNameBuf, SizeW, PosixName, 255, 0, 0);
if (0 == SizeA)
{
/* this should never happen because we just converted using MultiByteToWideChar */
Result = STATUS_OBJECT_NAME_INVALID;
goto exit;
}
PosixName[SizeA] = '\0';
}
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
} }
Result = fsp_fuse_intf_GetFileInfoEx(FileSystem, PosixPath, 0,
&Uid, &Gid, &Mode, &DirInfo->FileInfo);
if (!NT_SUCCESS(Result))
goto exit;
if (0 != PosixPathEnd)
*PosixPathEnd = SavedPathChar;
FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW); FspPosixDecodeWindowsPath(DirInfo->FileNameBuf, SizeW);
} }
@ -1683,6 +1709,8 @@ static NTSTATUS fsp_fuse_intf_ReadDirectory(FSP_FILE_SYSTEM *FileSystem,
{ {
memset(&dh, 0, sizeof dh); memset(&dh, 0, sizeof dh);
dh.filedesc = filedesc; dh.filedesc = filedesc;
dh.FileSystem = FileSystem;
dh.ReaddirPlus = 0 != (f->conn_want & FSP_FUSE_CAP_READDIR_PLUS);
dh.Result = STATUS_SUCCESS; dh.Result = STATUS_SUCCESS;
if (0 != f->ops.readdir) if (0 != f->ops.readdir)

View File

@ -40,12 +40,13 @@ struct fuse
int rellinks; int rellinks;
struct fuse_operations ops; struct fuse_operations ops;
void *data; void *data;
unsigned conn_want;
BOOLEAN fsinit;
UINT32 DebugLog; UINT32 DebugLog;
FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy; FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY OpGuardStrategy;
FSP_FSCTL_VOLUME_PARAMS VolumeParams; FSP_FSCTL_VOLUME_PARAMS VolumeParams;
PWSTR MountPoint; PWSTR MountPoint;
FSP_FILE_SYSTEM *FileSystem; FSP_FILE_SYSTEM *FileSystem;
BOOLEAN fsinit;
FSP_SERVICE *Service; /* weak */ FSP_SERVICE *Service; /* weak */
}; };
@ -66,8 +67,12 @@ struct fsp_fuse_file_desc
struct fuse_dirhandle struct fuse_dirhandle
{ {
/* ReadDirectory */
struct fsp_fuse_file_desc *filedesc; struct fsp_fuse_file_desc *filedesc;
FSP_FILE_SYSTEM *FileSystem;
BOOLEAN ReaddirPlus;
NTSTATUS Result; NTSTATUS Result;
/* CanDelete */
BOOLEAN DotFiles, HasChild; BOOLEAN DotFiles, HasChild;
}; };

View File

@ -187,7 +187,11 @@ static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fus
errno = 0; errno = 0;
if (0 == (de = readdir(dirp))) if (0 == (de = readdir(dirp)))
break; break;
#if defined(_WIN64) || defined(_WIN32)
if (0 != filler(buf, de->d_name, &de->d_stat, 0))
#else
if (0 != filler(buf, de->d_name, 0, 0)) if (0 != filler(buf, de->d_name, 0, 0))
#endif
return -ENOMEM; return -ENOMEM;
} }
@ -201,6 +205,19 @@ static int ptfs_releasedir(const char *path, struct fuse_file_info *fi)
return -1 != closedir(dirp) ? 0 : -errno; return -1 != closedir(dirp) ? 0 : -errno;
} }
static void *ptfs_init(struct fuse_conn_info *conn)
{
#if 0 && defined(FSP_FUSE_CAP_READDIR_PLUS)
conn->want |= (conn->capable & FSP_FUSE_CAP_READDIR_PLUS);
#endif
#if 0 && defined(FSP_FUSE_CAP_CASE_INSENSITIVE)
conn->want |= (conn->capable & FSP_FUSE_CAP_CASE_INSENSITIVE);
#endif
return fuse_get_context()->private_data;
}
static int ptfs_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi) static int ptfs_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi)
{ {
ptfs_impl_fullpath(path); ptfs_impl_fullpath(path);
@ -254,7 +271,7 @@ static struct fuse_operations ptfs_ops =
ptfs_readdir, ptfs_readdir,
ptfs_releasedir, ptfs_releasedir,
0, //fsyncdir 0, //fsyncdir
0, //init ptfs_init,
0, //destroy 0, //destroy
0, //access 0, //access
ptfs_create, ptfs_create,

View File

@ -115,7 +115,7 @@ int statvfs(const char *path, struct fuse_statvfs *stbuf)
memset(stbuf, 0, sizeof *stbuf); memset(stbuf, 0, sizeof *stbuf);
stbuf->f_bsize = SectorsPerCluster * BytesPerSector; stbuf->f_bsize = SectorsPerCluster * BytesPerSector;
stbuf->f_frsize = BytesPerSector; stbuf->f_frsize = SectorsPerCluster * BytesPerSector;
stbuf->f_blocks = TotalNumberOfClusters; stbuf->f_blocks = TotalNumberOfClusters;
stbuf->f_bfree = NumberOfFreeClusters; stbuf->f_bfree = NumberOfFreeClusters;
stbuf->f_bavail = TotalNumberOfClusters; stbuf->f_bavail = TotalNumberOfClusters;
@ -388,6 +388,8 @@ void rewinddir(DIR *dirp)
struct dirent *readdir(DIR *dirp) struct dirent *readdir(DIR *dirp)
{ {
WIN32_FIND_DATAA FindData; WIN32_FIND_DATAA FindData;
UINT64 CreationTime, LastAccessTime, LastWriteTime;
struct fuse_stat *stbuf = &dirp->de.d_stat;
if (INVALID_HANDLE_VALUE == dirp->fh) if (INVALID_HANDLE_VALUE == dirp->fh)
{ {
@ -405,6 +407,24 @@ struct dirent *readdir(DIR *dirp)
} }
} }
CreationTime = ((PLARGE_INTEGER)(&FindData.ftCreationTime))->QuadPart - 116444736000000000;
LastAccessTime = ((PLARGE_INTEGER)(&FindData.ftLastAccessTime))->QuadPart - 116444736000000000;
LastWriteTime = ((PLARGE_INTEGER)(&FindData.ftLastWriteTime))->QuadPart - 116444736000000000;
memset(stbuf, 0, sizeof *stbuf);
stbuf->st_mode = 0777 |
((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
stbuf->st_nlink = 1;
stbuf->st_size = ((UINT64)FindData.nFileSizeHigh << 32) | ((UINT64)FindData.nFileSizeLow);
stbuf->st_atim.tv_sec = LastAccessTime / 10000000;
stbuf->st_atim.tv_nsec = LastAccessTime % 10000000 * 100;
stbuf->st_mtim.tv_sec = LastWriteTime / 10000000;
stbuf->st_mtim.tv_nsec = LastWriteTime % 10000000 * 100;
stbuf->st_ctim.tv_sec = LastWriteTime / 10000000;
stbuf->st_ctim.tv_nsec = LastWriteTime % 10000000 * 100;
stbuf->st_birthtim.tv_sec = CreationTime / 10000000;
stbuf->st_birthtim.tv_nsec = CreationTime % 10000000 * 100;
strcpy(dirp->de.d_name, FindData.cFileName); strcpy(dirp->de.d_name, FindData.cFileName);
return &dirp->de; return &dirp->de;

View File

@ -31,6 +31,7 @@
typedef struct _DIR DIR; typedef struct _DIR DIR;
struct dirent struct dirent
{ {
struct fuse_stat d_stat;
char d_name[255]; char d_name[255];
}; };