mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
tst: passthrough-fuse3
This commit is contained in:
parent
d43c0c2c85
commit
2ff21529d5
7
tst/passthrough-fuse3/.gitignore
vendored
Normal file
7
tst/passthrough-fuse3/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
build
|
||||
*.ncb
|
||||
*.suo
|
||||
*.vcproj.*
|
||||
*.vcxproj.user
|
||||
*.exe
|
||||
*.install
|
18
tst/passthrough-fuse3/Makefile
Normal file
18
tst/passthrough-fuse3/Makefile
Normal file
@ -0,0 +1,18 @@
|
||||
usage:
|
||||
@echo "make cygfuse3|winfsp-fuse3" 1>&2
|
||||
@echo "" 1>&2
|
||||
@echo " cygfuse3 Link with CYGFUSE3" 1>&2
|
||||
@echo " winfsp-fuse3 Link with WinFsp-FUSE3" 1>&2
|
||||
@exit 2
|
||||
|
||||
cygfuse3: passthrough-cygfuse3
|
||||
|
||||
winfsp-fuse3: passthrough-winfsp-fuse3
|
||||
|
||||
passthrough-cygfuse3: passthrough-fuse3.c
|
||||
gcc $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
|
||||
|
||||
passthrough-winfsp-fuse3: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib
|
||||
passthrough-winfsp-fuse3: passthrough-fuse3.c
|
||||
ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install
|
||||
gcc $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
|
7
tst/passthrough-fuse3/README.md
Normal file
7
tst/passthrough-fuse3/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
`Passthrough-fuse3` is a simple FUSE3 file system that passes all file system operations to an underlying file system.
|
||||
|
||||
It can be built with the following tools:
|
||||
|
||||
- Using Visual Studio (`winfsp.sln`).
|
||||
- Using Cygwin GCC and linking directly with the WinFsp DLL (`make winfsp-fuse3`).
|
||||
- Using Cygwin GCC and linking to CYGFUSE3 (`make cygfuse3`).
|
331
tst/passthrough-fuse3/passthrough-fuse3.c
Normal file
331
tst/passthrough-fuse3/passthrough-fuse3.c
Normal file
@ -0,0 +1,331 @@
|
||||
/**
|
||||
* @file passthrough-fuse.c
|
||||
*
|
||||
* @copyright 2015-2018 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
#include "winposix.h"
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#define FSNAME "passthrough"
|
||||
#define PROGNAME "passthrough-fuse"
|
||||
|
||||
#define concat_path(ptfs, fn, fp) (sizeof fp > (unsigned)snprintf(fp, sizeof fp, "%s%s", ptfs->rootdir, fn))
|
||||
|
||||
#define fi_dirbit (0x8000000000000000ULL)
|
||||
#define fi_fh(fi, MASK) ((fi)->fh & (MASK))
|
||||
#define fi_setfh(fi, FH, MASK) ((fi)->fh = (intptr_t)(FH) | (MASK))
|
||||
#define fi_fd(fi) (fi_fh(fi, fi_dirbit) ? \
|
||||
dirfd((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit)) : (int)fi_fh(fi, ~fi_dirbit))
|
||||
#define fi_dirp(fi) ((DIR *)(intptr_t)fi_fh(fi, ~fi_dirbit))
|
||||
#define fi_setfd(fi, fd) (fi_setfh(fi, fd, 0))
|
||||
#define fi_setdirp(fi, dirp) (fi_setfh(fi, dirp, fi_dirbit))
|
||||
|
||||
#define ptfs_impl_fullpath(n) \
|
||||
char full ## n[PATH_MAX]; \
|
||||
if (!concat_path(((PTFS *)fuse_get_context()->private_data), n, full ## n))\
|
||||
return -ENAMETOOLONG; \
|
||||
n = full ## n
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *rootdir;
|
||||
} PTFS;
|
||||
|
||||
static int ptfs_getattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi)
|
||||
{
|
||||
if (0 == fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != lstat(path, stbuf) ? 0 : -errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
return -1 != fstat(fd, stbuf) ? 0 : -errno;
|
||||
}
|
||||
}
|
||||
|
||||
static int ptfs_mkdir(const char *path, fuse_mode_t mode)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != mkdir(path, mode) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_unlink(const char *path)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != unlink(path) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_rmdir(const char *path)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != rmdir(path) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_rename(const char *oldpath, const char *newpath, unsigned int flags)
|
||||
{
|
||||
ptfs_impl_fullpath(newpath);
|
||||
ptfs_impl_fullpath(oldpath);
|
||||
|
||||
return -1 != rename(oldpath, newpath) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_chmod(const char *path, fuse_mode_t mode, struct fuse_file_info *fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != chmod(path, mode) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_chown(const char *path, fuse_uid_t uid, fuse_gid_t gid, struct fuse_file_info *fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != lchown(path, uid, gid) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_truncate(const char *path, fuse_off_t size, struct fuse_file_info *fi)
|
||||
{
|
||||
if (0 == fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != truncate(path, size) ? 0 : -errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
return -1 != ftruncate(fd, size) ? 0 : -errno;
|
||||
}
|
||||
}
|
||||
|
||||
static int ptfs_open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
int fd;
|
||||
return -1 != (fd = open(path, fi->flags)) ? (fi_setfd(fi, fd), 0) : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_read(const char *path, char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
int nb;
|
||||
return -1 != (nb = pread(fd, buf, size, off)) ? nb : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_write(const char *path, const char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
int nb;
|
||||
return -1 != (nb = pwrite(fd, buf, size, off)) ? nb : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_statfs(const char *path, struct fuse_statvfs *stbuf)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != statvfs(path, stbuf) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_release(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ptfs_fsync(const char *path, int datasync, struct fuse_file_info *fi)
|
||||
{
|
||||
int fd = fi_fd(fi);
|
||||
|
||||
return -1 != fsync(fd) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_opendir(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
DIR *dirp;
|
||||
return 0 != (dirp = opendir(path)) ? (fi_setdirp(fi, dirp), 0) : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse_file_info *fi, enum fuse_readdir_flags flags)
|
||||
{
|
||||
DIR *dirp = fi_dirp(fi);
|
||||
struct dirent *de;
|
||||
|
||||
rewinddir(dirp);
|
||||
for (;;)
|
||||
{
|
||||
errno = 0;
|
||||
if (0 == (de = readdir(dirp)))
|
||||
break;
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
if (0 != filler(buf, de->d_name, &de->d_stat, 0, FUSE_FILL_DIR_PLUS))
|
||||
#else
|
||||
if (0 != filler(buf, de->d_name, 0, 0, 0))
|
||||
#endif
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
static int ptfs_releasedir(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
DIR *dirp = fi_dirp(fi);
|
||||
|
||||
return -1 != closedir(dirp) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static void *ptfs_init(struct fuse_conn_info *conn, struct fuse_config *conf)
|
||||
{
|
||||
conn->want |= (conn->capable & FUSE_CAP_READDIRPLUS);
|
||||
|
||||
#if 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)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
int fd;
|
||||
return -1 != (fd = open(path, fi->flags, mode)) ? (fi_setfd(fi, fd), 0) : -errno;
|
||||
}
|
||||
|
||||
static int ptfs_utimens(const char *path, const struct fuse_timespec tv[2], struct fuse_file_info *fi)
|
||||
{
|
||||
ptfs_impl_fullpath(path);
|
||||
|
||||
return -1 != utimensat(AT_FDCWD, path, tv, AT_SYMLINK_NOFOLLOW) ? 0 : -errno;
|
||||
}
|
||||
|
||||
static struct fuse_operations ptfs_ops =
|
||||
{
|
||||
.getattr = ptfs_getattr,
|
||||
.mkdir = ptfs_mkdir,
|
||||
.unlink = ptfs_unlink,
|
||||
.rmdir = ptfs_rmdir,
|
||||
.rename = ptfs_rename,
|
||||
.chmod = ptfs_chmod,
|
||||
.chown = ptfs_chown,
|
||||
.truncate = ptfs_truncate,
|
||||
.open = ptfs_open,
|
||||
.read = ptfs_read,
|
||||
.write = ptfs_write,
|
||||
.statfs = ptfs_statfs,
|
||||
.release = ptfs_release,
|
||||
.fsync = ptfs_fsync,
|
||||
.opendir = ptfs_opendir,
|
||||
.readdir = ptfs_readdir,
|
||||
.releasedir = ptfs_releasedir,
|
||||
.init = ptfs_init,
|
||||
.create = ptfs_create,
|
||||
.utimens = ptfs_utimens,
|
||||
};
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: " PROGNAME " [FUSE options] rootdir mountpoint\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
PTFS ptfs = { 0 };
|
||||
|
||||
if (3 <= argc && '-' != argv[argc - 2][0] && '-' != argv[argc - 1][0])
|
||||
{
|
||||
ptfs.rootdir = realpath(argv[argc - 2], 0); /* memory freed at process end */
|
||||
argv[argc - 2] = argv[argc - 1];
|
||||
argc--;
|
||||
}
|
||||
|
||||
#if defined(_WIN64) || defined(_WIN32)
|
||||
/*
|
||||
* When building for Windows (rather than Cygwin or POSIX OS)
|
||||
* allow the path to be specified using the --VolumePrefix
|
||||
* switch using the syntax \\passthrough-fuse\C$\Path. This
|
||||
* allows us to run the file system under the WinFsp.Launcher
|
||||
* and start it using commands like:
|
||||
*
|
||||
* net use z: \\passthrough-fuse\C$\Path
|
||||
*/
|
||||
if (0 == ptfs.rootdir)
|
||||
for (int argi = 1; argc > argi; argi++)
|
||||
{
|
||||
int strncmp(const char *a, const char *b, size_t length);
|
||||
char *strchr(const char *s, int c);
|
||||
char *p = 0;
|
||||
|
||||
if (0 == strncmp("--UNC=", argv[argi], sizeof "--UNC=" - 1))
|
||||
p = argv[argi] + sizeof "--UNC=" - 1;
|
||||
else if (0 == strncmp("--VolumePrefix=", argv[argi], sizeof "--VolumePrefix=" - 1))
|
||||
p = argv[argi] + sizeof "--VolumePrefix=" - 1;
|
||||
|
||||
if (0 != p && '\\' != p[1])
|
||||
{
|
||||
p = strchr(p + 1, '\\');
|
||||
if (0 != p &&
|
||||
(
|
||||
('A' <= p[1] && p[1] <= 'Z') ||
|
||||
('a' <= p[1] && p[1] <= 'z')
|
||||
) &&
|
||||
'$' == p[2])
|
||||
{
|
||||
p[2] = ':';
|
||||
ptfs.rootdir = realpath(p + 1, 0); /* memory freed at process end */
|
||||
p[2] = '$';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (0 == ptfs.rootdir)
|
||||
usage();
|
||||
|
||||
return fuse_main(argc, argv, &ptfs_ops, &ptfs);
|
||||
}
|
28
tst/passthrough-fuse3/passthrough-fuse3.sln
Normal file
28
tst/passthrough-fuse3/passthrough-fuse3.sln
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "passthrough-fuse3", "passthrough-fuse3.vcxproj", "{5E99498C-D30C-48EF-A04A-7977C0305FAC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x64.Build.0 = Debug|x64
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Debug|x86.Build.0 = Debug|Win32
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x64.ActiveCfg = Release|x64
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x64.Build.0 = Release|x64
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x86.ActiveCfg = Release|Win32
|
||||
{5E99498C-D30C-48EF-A04A-7977C0305FAC}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
190
tst/passthrough-fuse3/passthrough-fuse3.vcxproj
Normal file
190
tst/passthrough-fuse3/passthrough-fuse3.vcxproj
Normal file
@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5E99498C-D30C-48EF-A04A-7977C0305FAC}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>passthroughfuse3</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\</IntDir>
|
||||
<TargetName>$(ProjectName)-$(PlatformTarget)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>$(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<DelayLoadDLLs>winfsp-$(PlatformTarget).dll</DelayLoadDLLs>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="passthrough-fuse3.c" />
|
||||
<ClCompile Include="winposix.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="winposix.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
21
tst/passthrough-fuse3/passthrough-fuse3.vcxproj.filters
Normal file
21
tst/passthrough-fuse3/passthrough-fuse3.vcxproj.filters
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source">
|
||||
<UniqueIdentifier>{bfbcc136-ea14-4445-8f9b-1fa7f8aedc71}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="passthrough-fuse3.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="winposix.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="winposix.h">
|
||||
<Filter>Source</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
634
tst/passthrough-fuse3/winposix.c
Normal file
634
tst/passthrough-fuse3/winposix.c
Normal file
@ -0,0 +1,634 @@
|
||||
/**
|
||||
* @file winposix.c
|
||||
*
|
||||
* @copyright 2015-2018 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a very simple Windows POSIX layer. It handles all the POSIX
|
||||
* file API's required to implement passthrough-fuse in POSIX, however
|
||||
* the API handling is rather unsophisticated.
|
||||
*
|
||||
* Ways to improve it: use the FspPosix* API's to properly handle
|
||||
* file names and security.
|
||||
*/
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <fcntl.h>
|
||||
#include <fuse.h>
|
||||
#include "winposix.h"
|
||||
|
||||
struct _DIR
|
||||
{
|
||||
HANDLE h, fh;
|
||||
struct dirent de;
|
||||
char path[];
|
||||
};
|
||||
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
static inline uint32_t MapFileAttributesToFlags(UINT32 FileAttributes)
|
||||
{
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_READONLY)
|
||||
flags |= FSP_FUSE_UF_READONLY;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
||||
flags |= FSP_FUSE_UF_HIDDEN;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_SYSTEM)
|
||||
flags |= FSP_FUSE_UF_SYSTEM;
|
||||
if (FileAttributes & FILE_ATTRIBUTE_ARCHIVE)
|
||||
flags |= FSP_FUSE_UF_ARCHIVE;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline UINT32 MapFlagsToFileAttributes(uint32_t flags)
|
||||
{
|
||||
UINT32 FileAttributes = 0;
|
||||
|
||||
if (flags & FSP_FUSE_UF_READONLY)
|
||||
FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
if (flags & FSP_FUSE_UF_HIDDEN)
|
||||
FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
if (flags & FSP_FUSE_UF_SYSTEM)
|
||||
FileAttributes |= FILE_ATTRIBUTE_SYSTEM;
|
||||
if (flags & FSP_FUSE_UF_ARCHIVE)
|
||||
FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
|
||||
|
||||
return FileAttributes;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int maperror(int winerrno);
|
||||
|
||||
static inline void *error0(void)
|
||||
{
|
||||
errno = maperror(GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int error(void)
|
||||
{
|
||||
errno = maperror(GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *realpath(const char *path, char *resolved)
|
||||
{
|
||||
char *result;
|
||||
|
||||
if (0 == resolved)
|
||||
{
|
||||
result = malloc(PATH_MAX); /* sets errno */
|
||||
if (0 == result)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
result = resolved;
|
||||
|
||||
int err = 0;
|
||||
DWORD len = GetFullPathNameA(path, PATH_MAX, result, 0);
|
||||
if (0 == len)
|
||||
err = GetLastError();
|
||||
else if (PATH_MAX < len)
|
||||
err = ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (0 == err)
|
||||
{
|
||||
HANDLE h = CreateFileA(result,
|
||||
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE != h)
|
||||
CloseHandle(h);
|
||||
else
|
||||
err = GetLastError();
|
||||
}
|
||||
|
||||
if (0 != err)
|
||||
{
|
||||
if (result != resolved)
|
||||
free(result);
|
||||
|
||||
errno = maperror(err);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int statvfs(const char *path, struct fuse_statvfs *stbuf)
|
||||
{
|
||||
char root[PATH_MAX];
|
||||
DWORD
|
||||
VolumeSerialNumber,
|
||||
MaxComponentLength,
|
||||
SectorsPerCluster,
|
||||
BytesPerSector,
|
||||
NumberOfFreeClusters,
|
||||
TotalNumberOfClusters;
|
||||
|
||||
if (!GetVolumePathNameA(path, root, PATH_MAX) ||
|
||||
!GetVolumeInformationA(root, 0, 0, &VolumeSerialNumber, &MaxComponentLength, 0, 0, 0) ||
|
||||
!GetDiskFreeSpaceA(root, &SectorsPerCluster, &BytesPerSector,
|
||||
&NumberOfFreeClusters, &TotalNumberOfClusters))
|
||||
{
|
||||
return error();
|
||||
}
|
||||
|
||||
memset(stbuf, 0, sizeof *stbuf);
|
||||
stbuf->f_bsize = SectorsPerCluster * BytesPerSector;
|
||||
stbuf->f_frsize = SectorsPerCluster * BytesPerSector;
|
||||
stbuf->f_blocks = TotalNumberOfClusters;
|
||||
stbuf->f_bfree = NumberOfFreeClusters;
|
||||
stbuf->f_bavail = TotalNumberOfClusters;
|
||||
stbuf->f_fsid = VolumeSerialNumber;
|
||||
stbuf->f_namemax = MaxComponentLength;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open(const char *path, int oflag, ...)
|
||||
{
|
||||
static DWORD da[] = { GENERIC_READ, GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE, 0 };
|
||||
static DWORD cd[] = { OPEN_EXISTING, OPEN_ALWAYS, TRUNCATE_EXISTING, CREATE_ALWAYS };
|
||||
DWORD DesiredAccess = 0 == (oflag & _O_APPEND) ?
|
||||
da[oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)] :
|
||||
(da[oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR)] & ~FILE_WRITE_DATA) | FILE_APPEND_DATA;
|
||||
DWORD CreationDisposition = (_O_CREAT | _O_EXCL) == (oflag & (_O_CREAT | _O_EXCL)) ?
|
||||
CREATE_NEW :
|
||||
cd[(oflag & (_O_CREAT | _O_TRUNC)) >> 8];
|
||||
|
||||
HANDLE h = CreateFileA(path,
|
||||
DesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0/* default security */,
|
||||
CreationDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
return (int)(intptr_t)h;
|
||||
}
|
||||
|
||||
int fstat(int fd, struct fuse_stat *stbuf)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
BY_HANDLE_FILE_INFORMATION FileInfo;
|
||||
|
||||
if (!GetFileInformationByHandle(h, &FileInfo))
|
||||
return error();
|
||||
|
||||
memset(stbuf, 0, sizeof *stbuf);
|
||||
stbuf->st_mode = 0777 |
|
||||
((FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0040000/* S_IFDIR */ : 0);
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = ((UINT64)FileInfo.nFileSizeHigh << 32) | ((UINT64)FileInfo.nFileSizeLow);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftCreationTime, (void *)&stbuf->st_birthtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastAccessTime, (void *)&stbuf->st_atim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_mtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FileInfo.ftLastWriteTime, (void *)&stbuf->st_ctim);
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
stbuf->st_flags = MapFileAttributesToFlags(FileInfo.dwFileAttributes);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftruncate(int fd, fuse_off_t size)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
FILE_END_OF_FILE_INFO EndOfFileInfo;
|
||||
|
||||
EndOfFileInfo.EndOfFile.QuadPart = size;
|
||||
|
||||
if (!SetFileInformationByHandle(h, FileEndOfFileInfo, &EndOfFileInfo, sizeof EndOfFileInfo))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
OVERLAPPED Overlapped = { 0 };
|
||||
DWORD BytesTransferred;
|
||||
|
||||
Overlapped.Offset = (DWORD)offset;
|
||||
Overlapped.OffsetHigh = (DWORD)(offset >> 32);
|
||||
|
||||
if (!ReadFile(h, buf, (DWORD)nbyte, &BytesTransferred, &Overlapped))
|
||||
{
|
||||
if (ERROR_HANDLE_EOF == GetLastError())
|
||||
return 0;
|
||||
return error();
|
||||
}
|
||||
|
||||
return BytesTransferred;
|
||||
}
|
||||
|
||||
int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
OVERLAPPED Overlapped = { 0 };
|
||||
DWORD BytesTransferred;
|
||||
|
||||
Overlapped.Offset = (DWORD)offset;
|
||||
Overlapped.OffsetHigh = (DWORD)(offset >> 32);
|
||||
|
||||
if (!WriteFile(h, buf, (DWORD)nbyte, &BytesTransferred, &Overlapped))
|
||||
return error();
|
||||
|
||||
return BytesTransferred;
|
||||
}
|
||||
|
||||
int fsync(int fd)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
|
||||
if (!FlushFileBuffers(h))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int close(int fd)
|
||||
{
|
||||
HANDLE h = (HANDLE)(intptr_t)fd;
|
||||
|
||||
if (!CloseHandle(h))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lstat(const char *path, struct fuse_stat *stbuf)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
int res = fstat((int)(intptr_t)h, stbuf);
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int chmod(const char *path, fuse_mode_t mode)
|
||||
{
|
||||
/* we do not support file security */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid)
|
||||
{
|
||||
/* we do not support file security */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lchflags(const char *path, uint32_t flags)
|
||||
{
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
UINT32 FileAttributes = MapFlagsToFileAttributes(flags);
|
||||
|
||||
if (0 == FileAttributes)
|
||||
FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
if (!SetFileAttributesA(path, FileAttributes))
|
||||
return error();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int truncate(const char *path, fuse_off_t size)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_WRITE_DATA, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
int res = ftruncate((int)(intptr_t)h, size);
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int utime(const char *path, const struct fuse_utimbuf *timbuf)
|
||||
{
|
||||
if (0 == timbuf)
|
||||
return utimensat(AT_FDCWD, path, 0, AT_SYMLINK_NOFOLLOW);
|
||||
else
|
||||
{
|
||||
struct fuse_timespec times[2];
|
||||
times[0].tv_sec = timbuf->actime;
|
||||
times[0].tv_nsec = 0;
|
||||
times[1].tv_sec = timbuf->modtime;
|
||||
times[1].tv_nsec = 0;
|
||||
return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
}
|
||||
|
||||
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag)
|
||||
{
|
||||
/* ignore dirfd and assume that it is always AT_FDCWD */
|
||||
/* ignore flag and assume that it is always AT_SYMLINK_NOFOLLOW */
|
||||
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
UINT64 LastAccessTime, LastWriteTime;
|
||||
if (0 == times)
|
||||
{
|
||||
FILETIME FileTime;
|
||||
GetSystemTimeAsFileTime(&FileTime);
|
||||
LastAccessTime = LastWriteTime = *(PUINT64)&FileTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
FspPosixUnixTimeToFileTime((void *)×[0], &LastAccessTime);
|
||||
FspPosixUnixTimeToFileTime((void *)×[1], &LastWriteTime);
|
||||
}
|
||||
|
||||
int res = SetFileTime(h,
|
||||
0, (PFILETIME)&LastAccessTime, (PFILETIME)&LastWriteTime) ? 0 : error();
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int setcrtime(const char *path, const struct fuse_timespec *tv)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error();
|
||||
|
||||
UINT64 CreationTime;
|
||||
FspPosixUnixTimeToFileTime((void *)tv, &CreationTime);
|
||||
|
||||
int res = SetFileTime(h,
|
||||
(PFILETIME)&CreationTime, 0, 0) ? 0 : error();
|
||||
|
||||
CloseHandle(h);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int unlink(const char *path)
|
||||
{
|
||||
if (!DeleteFileA(path))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rename(const char *oldpath, const char *newpath)
|
||||
{
|
||||
if (!MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mkdir(const char *path, fuse_mode_t mode)
|
||||
{
|
||||
if (!CreateDirectoryA(path, 0/* default security */))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rmdir(const char *path)
|
||||
{
|
||||
if (!RemoveDirectoryA(path))
|
||||
return error();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR *opendir(const char *path)
|
||||
{
|
||||
HANDLE h = CreateFileA(path,
|
||||
FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
0,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
|
||||
if (INVALID_HANDLE_VALUE == h)
|
||||
return error0();
|
||||
|
||||
size_t pathlen = strlen(path);
|
||||
if (0 < pathlen && '/' == path[pathlen - 1])
|
||||
pathlen--;
|
||||
|
||||
DIR *dirp = malloc(sizeof *dirp + pathlen + 3); /* sets errno */
|
||||
if (0 == dirp)
|
||||
{
|
||||
CloseHandle(h);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(dirp, 0, sizeof *dirp);
|
||||
dirp->h = h;
|
||||
dirp->fh = INVALID_HANDLE_VALUE;
|
||||
memcpy(dirp->path, path, pathlen);
|
||||
dirp->path[pathlen + 0] = '/';
|
||||
dirp->path[pathlen + 1] = '*';
|
||||
dirp->path[pathlen + 2] = '\0';
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
||||
int dirfd(DIR *dirp)
|
||||
{
|
||||
return (int)(intptr_t)dirp->h;
|
||||
}
|
||||
|
||||
void rewinddir(DIR *dirp)
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE != dirp->fh)
|
||||
{
|
||||
FindClose(dirp->fh);
|
||||
dirp->fh = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
struct dirent *readdir(DIR *dirp)
|
||||
{
|
||||
WIN32_FIND_DATAA FindData;
|
||||
struct fuse_stat *stbuf = &dirp->de.d_stat;
|
||||
|
||||
if (INVALID_HANDLE_VALUE == dirp->fh)
|
||||
{
|
||||
dirp->fh = FindFirstFileA(dirp->path, &FindData);
|
||||
if (INVALID_HANDLE_VALUE == dirp->fh)
|
||||
return error0();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!FindNextFileA(dirp->fh, &FindData))
|
||||
{
|
||||
if (ERROR_NO_MORE_FILES == GetLastError())
|
||||
return 0;
|
||||
return error0();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftCreationTime, (void *)&stbuf->st_birthtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastAccessTime, (void *)&stbuf->st_atim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_mtim);
|
||||
FspPosixFileTimeToUnixTime(*(PUINT64)&FindData.ftLastWriteTime, (void *)&stbuf->st_ctim);
|
||||
#if defined(FSP_FUSE_USE_STAT_EX)
|
||||
stbuf->st_flags = MapFileAttributesToFlags(FindData.dwFileAttributes);
|
||||
#endif
|
||||
|
||||
strcpy(dirp->de.d_name, FindData.cFileName);
|
||||
|
||||
return &dirp->de;
|
||||
}
|
||||
|
||||
int closedir(DIR *dirp)
|
||||
{
|
||||
if (INVALID_HANDLE_VALUE != dirp->fh)
|
||||
FindClose(dirp->fh);
|
||||
|
||||
CloseHandle(dirp->h);
|
||||
free(dirp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int maperror(int winerrno)
|
||||
{
|
||||
switch (winerrno)
|
||||
{
|
||||
case ERROR_INVALID_FUNCTION:
|
||||
return EINVAL;
|
||||
case ERROR_FILE_NOT_FOUND:
|
||||
return ENOENT;
|
||||
case ERROR_PATH_NOT_FOUND:
|
||||
return ENOENT;
|
||||
case ERROR_TOO_MANY_OPEN_FILES:
|
||||
return EMFILE;
|
||||
case ERROR_ACCESS_DENIED:
|
||||
return EACCES;
|
||||
case ERROR_INVALID_HANDLE:
|
||||
return EBADF;
|
||||
case ERROR_ARENA_TRASHED:
|
||||
return ENOMEM;
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
return ENOMEM;
|
||||
case ERROR_INVALID_BLOCK:
|
||||
return ENOMEM;
|
||||
case ERROR_BAD_ENVIRONMENT:
|
||||
return E2BIG;
|
||||
case ERROR_BAD_FORMAT:
|
||||
return ENOEXEC;
|
||||
case ERROR_INVALID_ACCESS:
|
||||
return EINVAL;
|
||||
case ERROR_INVALID_DATA:
|
||||
return EINVAL;
|
||||
case ERROR_INVALID_DRIVE:
|
||||
return ENOENT;
|
||||
case ERROR_CURRENT_DIRECTORY:
|
||||
return EACCES;
|
||||
case ERROR_NOT_SAME_DEVICE:
|
||||
return EXDEV;
|
||||
case ERROR_NO_MORE_FILES:
|
||||
return ENOENT;
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
return EACCES;
|
||||
case ERROR_BAD_NETPATH:
|
||||
return ENOENT;
|
||||
case ERROR_NETWORK_ACCESS_DENIED:
|
||||
return EACCES;
|
||||
case ERROR_BAD_NET_NAME:
|
||||
return ENOENT;
|
||||
case ERROR_FILE_EXISTS:
|
||||
return EEXIST;
|
||||
case ERROR_CANNOT_MAKE:
|
||||
return EACCES;
|
||||
case ERROR_FAIL_I24:
|
||||
return EACCES;
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
return EINVAL;
|
||||
case ERROR_NO_PROC_SLOTS:
|
||||
return EAGAIN;
|
||||
case ERROR_DRIVE_LOCKED:
|
||||
return EACCES;
|
||||
case ERROR_BROKEN_PIPE:
|
||||
return EPIPE;
|
||||
case ERROR_DISK_FULL:
|
||||
return ENOSPC;
|
||||
case ERROR_INVALID_TARGET_HANDLE:
|
||||
return EBADF;
|
||||
case ERROR_WAIT_NO_CHILDREN:
|
||||
return ECHILD;
|
||||
case ERROR_CHILD_NOT_COMPLETE:
|
||||
return ECHILD;
|
||||
case ERROR_DIRECT_ACCESS_HANDLE:
|
||||
return EBADF;
|
||||
case ERROR_NEGATIVE_SEEK:
|
||||
return EINVAL;
|
||||
case ERROR_SEEK_ON_DEVICE:
|
||||
return EACCES;
|
||||
case ERROR_DIR_NOT_EMPTY:
|
||||
return ENOTEMPTY;
|
||||
case ERROR_NOT_LOCKED:
|
||||
return EACCES;
|
||||
case ERROR_BAD_PATHNAME:
|
||||
return ENOENT;
|
||||
case ERROR_MAX_THRDS_REACHED:
|
||||
return EAGAIN;
|
||||
case ERROR_LOCK_FAILED:
|
||||
return EACCES;
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return EEXIST;
|
||||
case ERROR_FILENAME_EXCED_RANGE:
|
||||
return ENOENT;
|
||||
case ERROR_NESTING_NOT_ALLOWED:
|
||||
return EAGAIN;
|
||||
case ERROR_NOT_ENOUGH_QUOTA:
|
||||
return ENOMEM;
|
||||
default:
|
||||
if (ERROR_WRITE_PROTECT <= winerrno && winerrno <= ERROR_SHARING_BUFFER_EXCEEDED)
|
||||
return EACCES;
|
||||
else if (ERROR_INVALID_STARTING_CODESEG <= winerrno && winerrno <= ERROR_INFLOOP_IN_RELOC_CHAIN)
|
||||
return ENOEXEC;
|
||||
else
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
long WinFspLoad(void)
|
||||
{
|
||||
return FspLoad(0);
|
||||
}
|
77
tst/passthrough-fuse3/winposix.h
Normal file
77
tst/passthrough-fuse3/winposix.h
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* @file winposix.h
|
||||
*
|
||||
* @copyright 2015-2018 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#ifndef WINPOSIX_H_INCLUDED
|
||||
#define WINPOSIX_H_INCLUDED
|
||||
|
||||
#define O_RDONLY _O_RDONLY
|
||||
#define O_WRONLY _O_WRONLY
|
||||
#define O_RDWR _O_RDWR
|
||||
#define O_APPEND _O_APPEND
|
||||
#define O_CREAT _O_CREAT
|
||||
#define O_EXCL _O_EXCL
|
||||
#define O_TRUNC _O_TRUNC
|
||||
|
||||
#define PATH_MAX 1024
|
||||
#define AT_FDCWD -2
|
||||
#define AT_SYMLINK_NOFOLLOW 2
|
||||
|
||||
typedef struct _DIR DIR;
|
||||
struct dirent
|
||||
{
|
||||
struct fuse_stat d_stat;
|
||||
char d_name[255];
|
||||
};
|
||||
|
||||
char *realpath(const char *path, char *resolved);
|
||||
|
||||
int statvfs(const char *path, struct fuse_statvfs *stbuf);
|
||||
|
||||
int open(const char *path, int oflag, ...);
|
||||
int fstat(int fd, struct fuse_stat *stbuf);
|
||||
int ftruncate(int fd, fuse_off_t size);
|
||||
int pread(int fd, void *buf, size_t nbyte, fuse_off_t offset);
|
||||
int pwrite(int fd, const void *buf, size_t nbyte, fuse_off_t offset);
|
||||
int fsync(int fd);
|
||||
int close(int fd);
|
||||
|
||||
int lstat(const char *path, struct fuse_stat *stbuf);
|
||||
int chmod(const char *path, fuse_mode_t mode);
|
||||
int lchown(const char *path, fuse_uid_t uid, fuse_gid_t gid);
|
||||
int lchflags(const char *path, uint32_t flags);
|
||||
int truncate(const char *path, fuse_off_t size);
|
||||
int utime(const char *path, const struct fuse_utimbuf *timbuf);
|
||||
int utimensat(int dirfd, const char *path, const struct fuse_timespec times[2], int flag);
|
||||
int setcrtime(const char *path, const struct fuse_timespec *tv);
|
||||
int unlink(const char *path);
|
||||
int rename(const char *oldpath, const char *newpath);
|
||||
|
||||
int mkdir(const char *path, fuse_mode_t mode);
|
||||
int rmdir(const char *path);
|
||||
|
||||
DIR *opendir(const char *path);
|
||||
int dirfd(DIR *dirp);
|
||||
void rewinddir(DIR *dirp);
|
||||
struct dirent *readdir(DIR *dirp);
|
||||
int closedir(DIR *dirp);
|
||||
|
||||
long WinFspLoad(void);
|
||||
#undef fuse_main
|
||||
#define fuse_main(argc, argv, ops, data)\
|
||||
(WinFspLoad(), fuse_main_real(argc, argv, ops, sizeof *(ops), data))
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user