mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
tst: add memfs-fuse3 file system
This commit is contained in:
parent
6f1f1cda71
commit
d3d75bf977
@ -382,6 +382,29 @@
|
||||
<File Name="memfs-main.c" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="SMPDIR.memfs_fuse3" Name="memfs-fuse3">
|
||||
<Component Id="C.memfs_fuse3.cpp">
|
||||
<File Name="memfs-fuse3.cpp" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.memfs_fuse3.compat.h">
|
||||
<File Id="F.memfs_fuse3.compat.h" Name="compat.h" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.memfs_fuse3.sln">
|
||||
<File Name="memfs-fuse3.sln" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.memfs_fuse3.vcxproj">
|
||||
<File Name="memfs-fuse3.vcxproj" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.memfs_fuse3.vcxproj.filters">
|
||||
<File Name="memfs-fuse3.vcxproj.filters" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.memfs_fuse3.Makefile">
|
||||
<File Id="F.memfs_fuse3.Makefile" Name="Makefile" KeyPath="yes" />
|
||||
</Component>
|
||||
<Component Id="C.memfs_fuse3.README.md">
|
||||
<File Id="F.memfsx_fuse3.README.md" Name="README.md" KeyPath="yes" />
|
||||
</Component>
|
||||
</Directory>
|
||||
<Directory Id="SMPDIR.memfs_dotnet" Name="memfs-dotnet">
|
||||
<Component Id="C.memfs_dotnet.Program.cs">
|
||||
<File Id="FILE.memfs_dotnet.Program.cs" Name="Program.cs" KeyPath="yes" />
|
||||
@ -592,6 +615,13 @@
|
||||
<ComponentRef Id="C.memfs.h" />
|
||||
<ComponentRef Id="C.memfs.cpp" />
|
||||
<ComponentRef Id="C.memfs_main.c" />
|
||||
<ComponentRef Id="C.memfs_fuse3.cpp" />
|
||||
<ComponentRef Id="C.memfs_fuse3.compat.h" />
|
||||
<ComponentRef Id="C.memfs_fuse3.sln" />
|
||||
<ComponentRef Id="C.memfs_fuse3.vcxproj" />
|
||||
<ComponentRef Id="C.memfs_fuse3.vcxproj.filters" />
|
||||
<ComponentRef Id="C.memfs_fuse3.Makefile" />
|
||||
<ComponentRef Id="C.memfs_fuse3.README.md" />
|
||||
<ComponentRef Id="C.airfs.cpp" />
|
||||
<ComponentRef Id="C.persistence.cpp" />
|
||||
<ComponentRef Id="C.common.h" />
|
||||
|
10
tst/memfs-fuse3/.gitignore
vendored
Normal file
10
tst/memfs-fuse3/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
build
|
||||
*.ncb
|
||||
*.suo
|
||||
*.vcproj.*
|
||||
*.vcxproj.user
|
||||
*.VC.db
|
||||
*.VC.opendb
|
||||
.vs
|
||||
*.exe
|
||||
*.install
|
18
tst/memfs-fuse3/Makefile
Normal file
18
tst/memfs-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: memfs-cygfuse3
|
||||
|
||||
winfsp-fuse3: memfs-winfsp-fuse3
|
||||
|
||||
memfs-cygfuse3: memfs-fuse3.cpp
|
||||
g++ $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
|
||||
|
||||
memfs-winfsp-fuse3: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib
|
||||
memfs-winfsp-fuse3: memfs-fuse3.cpp
|
||||
ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install
|
||||
g++ $^ -o $@ -g -Wall `pkg-config fuse3 --cflags --libs`
|
7
tst/memfs-fuse3/README.md
Normal file
7
tst/memfs-fuse3/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
`Memfs-fuse3` is an in-memory FUSE3 file system.
|
||||
|
||||
It can be built with the following tools:
|
||||
|
||||
- Using Visual Studio (`memfs-fuse3.sln`).
|
||||
- Using Cygwin GCC and linking directly with the WinFsp DLL (`make winfsp-fuse3`).
|
||||
- Using Cygwin GCC and linking to CYGFUSE3 (`make cygfuse3`).
|
97
tst/memfs-fuse3/compat.h
Normal file
97
tst/memfs-fuse3/compat.h
Normal file
@ -0,0 +1,97 @@
|
||||
/**
|
||||
* @file compat.h
|
||||
*
|
||||
* @copyright 2015-2019 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 software
|
||||
* in accordance with the commercial license agreement provided in
|
||||
* conjunction with the software. The terms and conditions of any such
|
||||
* commercial license agreement shall govern, supersede, and render
|
||||
* ineffective any application of the GPLv3 license to this software,
|
||||
* notwithstanding of any reference thereto in the software or
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#ifndef COMPAT_H_INCLUDED
|
||||
#define COMPAT_H_INCLUDED
|
||||
|
||||
#if !defined(_WIN32) && !defined(fuse_stat)
|
||||
|
||||
#define fuse_uid_t uid_t
|
||||
#define fuse_gid_t gid_t
|
||||
#define fuse_pid_t pid_t
|
||||
|
||||
#define fuse_dev_t dev_t
|
||||
#define fuse_mode_t mode_t
|
||||
#define fuse_nlink_t nlink_t
|
||||
#define fuse_off_t off_t
|
||||
|
||||
#define fuse_fsblkcnt_t fsblkcnt_t
|
||||
#define fuse_fsfilcnt_t fsfilcnt_t
|
||||
#define fuse_blksize_t blksize_t
|
||||
#define fuse_blkcnt_t blkcnt_t
|
||||
|
||||
#define fuse_timespec timespec
|
||||
|
||||
#define fuse_stat stat
|
||||
|
||||
#define fuse_statvfs statvfs
|
||||
|
||||
#define fuse_flock flock
|
||||
|
||||
#define fuse_iovec iovec
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(S_IFMT)
|
||||
#define S_IFMT 0170000
|
||||
#endif
|
||||
#if !defined(S_IFDIR)
|
||||
#define S_IFDIR 0040000
|
||||
#endif
|
||||
#if !defined(S_IFCHR)
|
||||
#define S_IFCHR 0020000
|
||||
#endif
|
||||
#if !defined(S_IFBLK)
|
||||
#define S_IFBLK 0060000
|
||||
#endif
|
||||
#if !defined(S_IFREG)
|
||||
#define S_IFREG 0100000
|
||||
#endif
|
||||
#if !defined(S_IFLNK)
|
||||
#define S_IFLNK 0120000
|
||||
#endif
|
||||
#if !defined(S_IFSOCK)
|
||||
#define S_IFSOCK 0140000
|
||||
#endif
|
||||
#if !defined(S_IFIFO)
|
||||
#define S_IFIFO 0010000
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#define st_atim st_atimespec
|
||||
#define st_ctim st_ctimespec
|
||||
#define st_mtim st_mtimespec
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__linux__) || defined(__CYGWIN__)
|
||||
#include <sys/xattr.h>
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(_WIN32)
|
||||
#define XATTR_CREATE 1
|
||||
#define XATTR_REPLACE 2
|
||||
#endif
|
||||
|
||||
#if !defined(ENOATTR)
|
||||
#define ENOATTR ENODATA
|
||||
#elif !defined(ENODATA)
|
||||
#define ENODATA ENOATTR
|
||||
#endif
|
||||
|
||||
#endif
|
606
tst/memfs-fuse3/memfs-fuse3.cpp
Normal file
606
tst/memfs-fuse3/memfs-fuse3.cpp
Normal file
@ -0,0 +1,606 @@
|
||||
/**
|
||||
* @file memfs-fuse3.c
|
||||
*
|
||||
* @copyright 2015-2019 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 software
|
||||
* in accordance with the commercial license agreement provided in
|
||||
* conjunction with the software. The terms and conditions of any such
|
||||
* commercial license agreement shall govern, supersede, and render
|
||||
* ineffective any application of the GPLv3 license to this software,
|
||||
* notwithstanding of any reference thereto in the software or
|
||||
* associated repository.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <fuse3/fuse.h>
|
||||
#include "compat.h"
|
||||
|
||||
class memfs
|
||||
{
|
||||
public:
|
||||
memfs() : _ino(1), _root(std::make_shared<node_t>(_ino, S_IFDIR | 00777, 0, 0))
|
||||
{
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static fuse_operations ops =
|
||||
{
|
||||
getattr,
|
||||
readlink,
|
||||
mknod,
|
||||
mkdir,
|
||||
unlink,
|
||||
rmdir,
|
||||
symlink,
|
||||
rename,
|
||||
link,
|
||||
chmod,
|
||||
chown,
|
||||
truncate,
|
||||
open,
|
||||
read,
|
||||
write,
|
||||
statfs,
|
||||
flush,
|
||||
release,
|
||||
0, // fsync
|
||||
setxattr,
|
||||
getxattr,
|
||||
listxattr,
|
||||
removexattr,
|
||||
opendir,
|
||||
readdir,
|
||||
releasedir,
|
||||
0, // fsyncdir
|
||||
init,
|
||||
0, // destroy
|
||||
0, // access
|
||||
0, // create
|
||||
0, // lock
|
||||
utimens,
|
||||
0, // bmap
|
||||
ioctl,
|
||||
};
|
||||
return fuse_main(argc, argv, &ops, this);
|
||||
}
|
||||
|
||||
private:
|
||||
struct node_t
|
||||
{
|
||||
node_t(fuse_ino_t ino, fuse_mode_t mode, fuse_uid_t uid, fuse_gid_t gid, fuse_dev_t dev = 0)
|
||||
: stat()
|
||||
{
|
||||
stat.st_ino = ino;
|
||||
stat.st_mode = mode;
|
||||
stat.st_nlink = 1;
|
||||
stat.st_uid = uid;
|
||||
stat.st_gid = gid;
|
||||
stat.st_rdev = dev;
|
||||
stat.st_atim = stat.st_mtim = stat.st_ctim = now();
|
||||
}
|
||||
|
||||
void resize(size_t size, bool capacity)
|
||||
{
|
||||
if (capacity)
|
||||
{
|
||||
const size_t unit = 64 * 1024;
|
||||
size_t newcap = (size + unit - 1) / unit * unit;
|
||||
size_t oldcap = data.capacity();
|
||||
if (newcap > oldcap)
|
||||
data.reserve(newcap);
|
||||
else if (newcap < oldcap)
|
||||
{
|
||||
data.resize(newcap);
|
||||
data.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
data.resize(size);
|
||||
stat.st_size = size;
|
||||
}
|
||||
|
||||
struct fuse_stat stat;
|
||||
std::vector<uint8_t> data;
|
||||
std::unordered_map<std::string, std::shared_ptr<node_t>> childmap;
|
||||
std::unordered_map<std::string, std::vector<uint8_t>> xattrmap;
|
||||
};
|
||||
|
||||
static fuse_timespec now()
|
||||
{
|
||||
fuse_timespec ts = { static_cast<decltype(ts.tv_sec)>(std::time(0)) };
|
||||
return ts;
|
||||
}
|
||||
|
||||
static memfs *getself()
|
||||
{
|
||||
return static_cast<memfs *>(fuse_get_context()->private_data);
|
||||
}
|
||||
|
||||
static int getattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
*stbuf = node->stat;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int readlink(const char *path, char *buf, size_t size)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (S_IFLNK != (node->stat.st_mode & S_IFMT))
|
||||
return EINVAL;
|
||||
size = std::min(size - 1, node->data.size());
|
||||
std::memcpy(buf, node->data.data(), size);
|
||||
buf[size] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mknod(const char *path, fuse_mode_t mode, fuse_dev_t dev)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->make_node(path, mode, dev);
|
||||
}
|
||||
|
||||
static int mkdir(const char *path, fuse_mode_t mode)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->make_node(path, S_IFDIR | (mode & 07777), 0);
|
||||
}
|
||||
|
||||
static int unlink(const char *path)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->remove_node(path, false);
|
||||
}
|
||||
|
||||
static int rmdir(const char *path)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->remove_node(path, true);
|
||||
}
|
||||
|
||||
static int symlink(const char *dstpath, const char *srcpath)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->make_node(srcpath, S_IFLNK | 00777, 0, dstpath);
|
||||
}
|
||||
|
||||
static int rename(const char *oldpath, const char *newpath, unsigned int flags)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto oldlookup = self->lookup_node(oldpath);
|
||||
auto oldprnt = std::get<0>(oldlookup);
|
||||
auto oldname = std::get<1>(oldlookup);
|
||||
auto oldnode = std::get<2>(oldlookup);
|
||||
if (!oldnode)
|
||||
return -ENOENT;
|
||||
auto newlookup = self->lookup_node(newpath);
|
||||
auto newprnt = std::get<0>(newlookup);
|
||||
auto newname = std::get<1>(newlookup);
|
||||
auto newnode = std::get<2>(newlookup);
|
||||
if (!newprnt)
|
||||
return -ENOENT;
|
||||
if (newname.empty())
|
||||
// guard against directory loop creation
|
||||
return -EINVAL;
|
||||
if (oldprnt == newprnt && oldname == newname)
|
||||
return 0;
|
||||
if (newnode)
|
||||
{
|
||||
if (int errc = self->remove_node(newpath, S_IFDIR == (oldnode->stat.st_mode & S_IFMT)))
|
||||
return errc;
|
||||
}
|
||||
oldprnt->childmap.erase(oldname);
|
||||
newprnt->childmap[newname] = oldnode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link(const char *oldpath, const char *newpath)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto oldlookup = self->lookup_node(oldpath);
|
||||
auto oldnode = std::get<2>(oldlookup);
|
||||
if (!oldnode)
|
||||
return -ENOENT;
|
||||
auto newlookup = self->lookup_node(newpath);
|
||||
auto newprnt = std::get<0>(newlookup);
|
||||
auto newname = std::get<1>(newlookup);
|
||||
auto newnode = std::get<2>(newlookup);
|
||||
if (!newprnt)
|
||||
return -ENOENT;
|
||||
if (newnode)
|
||||
return -EEXIST;
|
||||
oldnode->stat.st_nlink++;
|
||||
newprnt->childmap[newname] = oldnode;
|
||||
oldnode->stat.st_ctim = newprnt->stat.st_ctim = newprnt->stat.st_mtim = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chmod(const char *path, fuse_mode_t mode,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
node->stat.st_mode = (node->stat.st_mode & S_IFMT) | (mode & 07777);
|
||||
node->stat.st_ctim = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chown(const char *path, fuse_uid_t uid, fuse_gid_t gid,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (-1 != uid)
|
||||
node->stat.st_uid = uid;
|
||||
if (-1 != gid)
|
||||
node->stat.st_gid = gid;
|
||||
node->stat.st_ctim = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int truncate(const char *path, fuse_off_t size,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (SIZE_MAX < size)
|
||||
return -EFBIG;
|
||||
node->resize(static_cast<size_t>(size), true);
|
||||
node->stat.st_ctim = node->stat.st_mtim = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->open_node(path, false, fi);
|
||||
}
|
||||
|
||||
static int read(const char *path, char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
fuse_off_t endoff = std::min(
|
||||
off + static_cast<fuse_off_t>(size), static_cast<fuse_off_t>(node->data.size()));
|
||||
if (off > endoff)
|
||||
return 0;
|
||||
std::memcpy(buf, node->data.data() + off, static_cast<int>(endoff - off));
|
||||
node->stat.st_atim = now();
|
||||
return static_cast<int>(endoff - off);
|
||||
}
|
||||
|
||||
static int write(const char *path, const char *buf, size_t size, fuse_off_t off,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
fuse_off_t endoff = off + static_cast<fuse_off_t>(size);
|
||||
if (SIZE_MAX < endoff)
|
||||
return -EFBIG;
|
||||
if (node->data.size() < endoff)
|
||||
node->resize(static_cast<size_t>(endoff), true);
|
||||
std::memcpy(node->data.data() + off, buf, static_cast<int>(endoff - off));
|
||||
node->stat.st_ctim = node->stat.st_mtim = now();
|
||||
return static_cast<int>(endoff - off);
|
||||
}
|
||||
|
||||
static int statfs(const char *path, struct fuse_statvfs *stbuf)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int flush(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
static int release(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->close_node(fi);
|
||||
}
|
||||
|
||||
static int setxattr(const char *path, const char *name0, const char *value, size_t size,
|
||||
int flags)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (0 == std::strcmp("com.apple.ResourceFork", name0))
|
||||
return -ENOTSUP;
|
||||
std::string name = name0;
|
||||
if (XATTR_CREATE == flags)
|
||||
{
|
||||
if (node->xattrmap.end() != node->xattrmap.find(name))
|
||||
return -EEXIST;
|
||||
}
|
||||
else if (XATTR_REPLACE == flags)
|
||||
{
|
||||
if (node->xattrmap.end() == node->xattrmap.find(name))
|
||||
return -ENOATTR;
|
||||
}
|
||||
node->xattrmap[name].assign(value, value + size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int getxattr(const char *path, const char *name0, char *value, size_t size)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (0 == std::strcmp("com.apple.ResourceFork", name0))
|
||||
return -ENOTSUP;
|
||||
std::string name = name0;
|
||||
auto iter = node->xattrmap.find(name);
|
||||
if (node->xattrmap.end() == iter)
|
||||
return -ENOATTR;
|
||||
if (0 != size)
|
||||
{
|
||||
if (iter->second.size() > size)
|
||||
return -ERANGE;
|
||||
std::memcpy(value, iter->second.data(), iter->second.size());
|
||||
}
|
||||
return static_cast<int>(iter->second.size());
|
||||
}
|
||||
|
||||
static int listxattr(const char *path, char *namebuf, size_t size)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
size_t copysize = 0;
|
||||
for (auto elem : node->xattrmap)
|
||||
{
|
||||
size_t namesize = elem.first.size() + 1;
|
||||
if (0 != size)
|
||||
{
|
||||
if (copysize + namesize > size)
|
||||
return -ERANGE;
|
||||
std::memcpy(namebuf + copysize, elem.first.c_str(), namesize);
|
||||
copysize += namesize;
|
||||
}
|
||||
}
|
||||
return static_cast<int>(copysize);
|
||||
}
|
||||
|
||||
static int removexattr(const char *path, const char *name0)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (0 == std::strcmp("com.apple.ResourceFork", name0))
|
||||
return -ENOTSUP;
|
||||
std::string name = name0;
|
||||
return node->xattrmap.erase(name) ? 0 : -ENOATTR;
|
||||
}
|
||||
|
||||
static int opendir(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->open_node(path, true, fi);
|
||||
}
|
||||
|
||||
static int readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
||||
struct fuse_file_info *fi, enum fuse_readdir_flags)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
filler(buf, ".", &node->stat, 0, FUSE_FILL_DIR_PLUS);
|
||||
filler(buf, "..", nullptr, 0, FUSE_FILL_DIR_PLUS);
|
||||
for (auto elem : node->childmap)
|
||||
if (!filler(buf, elem.first.c_str(), &elem.second->stat, 0, FUSE_FILL_DIR_PLUS))
|
||||
break;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int releasedir(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
return self->close_node(fi);
|
||||
}
|
||||
|
||||
static void *init(struct fuse_conn_info *conn,
|
||||
struct fuse_config *conf)
|
||||
{
|
||||
conn->want |= (conn->capable & FUSE_CAP_READDIRPLUS);
|
||||
return getself();
|
||||
}
|
||||
|
||||
static int utimens(const char *path, const struct fuse_timespec tmsp[2],
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
auto self = getself();
|
||||
std::lock_guard<std::mutex> lock(self->_mutex);
|
||||
auto node = self->get_node(path, fi);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (tmsp)
|
||||
{
|
||||
node->stat.st_ctim = now();
|
||||
node->stat.st_atim = tmsp[0];
|
||||
node->stat.st_mtim = tmsp[1];
|
||||
}
|
||||
else
|
||||
node->stat.st_ctim = node->stat.st_atim = node->stat.st_mtim = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
||||
unsigned int flags, void *data)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
std::tuple<std::shared_ptr<node_t>, std::string, std::shared_ptr<node_t>>
|
||||
lookup_node(const char *path, node_t *ancestor = nullptr)
|
||||
{
|
||||
auto prnt = _root;
|
||||
std::string name;
|
||||
auto node = prnt;
|
||||
for (const char *part = path, *p; *part; part = p + !!(*p))
|
||||
{
|
||||
for (p = part; *p && '/' != *p; p++)
|
||||
;
|
||||
if (part == p)
|
||||
continue;
|
||||
prnt = node;
|
||||
if (!node)
|
||||
break;
|
||||
name.assign(part, p);
|
||||
auto iter = node->childmap.find(name);
|
||||
node = node->childmap.end() != iter ? iter->second : nullptr;
|
||||
if (ancestor && node.get() == ancestor)
|
||||
{
|
||||
name.assign(""); // special case loop condition
|
||||
break;
|
||||
}
|
||||
}
|
||||
return std::make_tuple(prnt, name, node);
|
||||
}
|
||||
|
||||
int make_node(const char *path, fuse_mode_t mode, fuse_dev_t dev, const char *data = nullptr)
|
||||
{
|
||||
auto lookup = lookup_node(path);
|
||||
auto prnt = std::get<0>(lookup);
|
||||
auto name = std::get<1>(lookup);
|
||||
auto node = std::get<2>(lookup);
|
||||
if (!prnt)
|
||||
return -ENOENT;
|
||||
if (node)
|
||||
return -EEXIST;
|
||||
fuse_context *context = fuse_get_context();
|
||||
node = std::make_shared<node_t>(++_ino, mode, context->uid, context->gid, dev);
|
||||
if (data)
|
||||
{
|
||||
node->resize(std::strlen(data), false);
|
||||
std::memcpy(node->data.data(), data, node->data.size());
|
||||
}
|
||||
prnt->childmap[name] = node;
|
||||
prnt->stat.st_ctim = prnt->stat.st_mtim = node->stat.st_ctim;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove_node(const char *path, bool dir)
|
||||
{
|
||||
auto lookup = lookup_node(path);
|
||||
auto prnt = std::get<0>(lookup);
|
||||
auto name = std::get<1>(lookup);
|
||||
auto node = std::get<2>(lookup);
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (!dir && S_IFDIR == (node->stat.st_mode & S_IFMT))
|
||||
return -EISDIR;
|
||||
if (dir && S_IFDIR == (node->stat.st_mode & S_IFMT))
|
||||
return -ENOTDIR;
|
||||
if (0 < node->childmap.size())
|
||||
return -ENOTEMPTY;
|
||||
node->stat.st_nlink--;
|
||||
prnt->childmap.erase(name);
|
||||
node->stat.st_ctim = prnt->stat.st_ctim = prnt->stat.st_mtim = now();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int open_node(const char *path, bool dir, struct fuse_file_info *fi)
|
||||
{
|
||||
auto node = std::get<2>(lookup_node(path));
|
||||
if (!node)
|
||||
return -ENOENT;
|
||||
if (!dir && S_IFDIR == (node->stat.st_mode & S_IFMT))
|
||||
return -EISDIR;
|
||||
if (dir && S_IFDIR == (node->stat.st_mode & S_IFMT))
|
||||
return -ENOTDIR;
|
||||
// A file descriptor is a raw pointer to a shared_ptr.
|
||||
// This has the effect of incrementing the shared_ptr
|
||||
// refcount, thus keeping an open node around even
|
||||
// if the node is unlinked.
|
||||
fi->fh = (uint64_t)(uintptr_t)new std::shared_ptr<node_t>(node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int close_node(struct fuse_file_info *fi)
|
||||
{
|
||||
delete (std::shared_ptr<node_t> *)(uintptr_t)fi->fh;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<node_t> get_node(const char *path, struct fuse_file_info *fi = nullptr)
|
||||
{
|
||||
if (!fi)
|
||||
return std::get<2>(lookup_node(path));
|
||||
else
|
||||
return *(std::shared_ptr<node_t> *)(uintptr_t)fi->fh;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex _mutex;
|
||||
fuse_ino_t _ino;
|
||||
std::shared_ptr<node_t> _root;
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return memfs().main(argc, argv);
|
||||
}
|
28
tst/memfs-fuse3/memfs-fuse3.sln
Normal file
28
tst/memfs-fuse3/memfs-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}") = "memfs-fuse3", "memfs-fuse3.vcxproj", "{CF538F42-C714-4653-B351-E72FD7B0B217}"
|
||||
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
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x64.Build.0 = Debug|x64
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Debug|x86.Build.0 = Debug|Win32
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x64.ActiveCfg = Release|x64
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x64.Build.0 = Release|x64
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x86.ActiveCfg = Release|Win32
|
||||
{CF538F42-C714-4653-B351-E72FD7B0B217}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
189
tst/memfs-fuse3/memfs-fuse3.vcxproj
Normal file
189
tst/memfs-fuse3/memfs-fuse3.vcxproj
Normal file
@ -0,0 +1,189 @@
|
||||
<?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>{CF538F42-C714-4653-B351-E72FD7B0B217}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>memfsfuse3</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>$(DefaultPlatformToolset)</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>MultiThreadedDebug</RuntimeLibrary>
|
||||
<DisableSpecificWarnings>4018</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>MultiThreadedDebug</RuntimeLibrary>
|
||||
<DisableSpecificWarnings>4018</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>4018</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>4018</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>
|
||||
<ClInclude Include="compat.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="memfs-fuse3.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
19
tst/memfs-fuse3/memfs-fuse3.vcxproj.filters
Normal file
19
tst/memfs-fuse3/memfs-fuse3.vcxproj.filters
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="compat.h">
|
||||
<Filter>Source</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="memfs-fuse3.cpp">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user