From d67a917c6f08205fef65a38886580e1281e38b55 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Sat, 13 Nov 2021 10:11:45 +0000 Subject: [PATCH] tst: memfs-fuse: add FUSE reference file system --- tst/memfs-fuse/.gitignore | 10 + tst/memfs-fuse/Makefile | 18 + tst/memfs-fuse/README.md | 7 + tst/memfs-fuse/compat.h | 104 ++++ tst/memfs-fuse/memfs-fuse.cpp | 661 ++++++++++++++++++++++ tst/memfs-fuse/memfs-fuse.sln | 28 + tst/memfs-fuse/memfs-fuse.vcxproj | 193 +++++++ tst/memfs-fuse/memfs-fuse.vcxproj.filters | 19 + 8 files changed, 1040 insertions(+) create mode 100644 tst/memfs-fuse/.gitignore create mode 100644 tst/memfs-fuse/Makefile create mode 100644 tst/memfs-fuse/README.md create mode 100644 tst/memfs-fuse/compat.h create mode 100644 tst/memfs-fuse/memfs-fuse.cpp create mode 100644 tst/memfs-fuse/memfs-fuse.sln create mode 100644 tst/memfs-fuse/memfs-fuse.vcxproj create mode 100644 tst/memfs-fuse/memfs-fuse.vcxproj.filters diff --git a/tst/memfs-fuse/.gitignore b/tst/memfs-fuse/.gitignore new file mode 100644 index 00000000..a7872d37 --- /dev/null +++ b/tst/memfs-fuse/.gitignore @@ -0,0 +1,10 @@ +build +*.ncb +*.suo +*.vcproj.* +*.vcxproj.user +*.VC.db +*.VC.opendb +.vs +*.exe +*.install diff --git a/tst/memfs-fuse/Makefile b/tst/memfs-fuse/Makefile new file mode 100644 index 00000000..45f131f3 --- /dev/null +++ b/tst/memfs-fuse/Makefile @@ -0,0 +1,18 @@ +usage: + @echo "make cygfuse|winfsp-fuse" 1>&2 + @echo "" 1>&2 + @echo " cygfuse Link with CYGFUSE" 1>&2 + @echo " winfsp-fuse Link with WinFsp-FUSE" 1>&2 + @exit 2 + +cygfuse: memfs-cygfuse + +winfsp-fuse: memfs-winfsp-fuse + +memfs-cygfuse: memfs-fuse.cpp + g++ $^ -o $@ -g -Wall -std=gnu++17 `pkg-config fuse --cflags --libs` + +memfs-winfsp-fuse: export PKG_CONFIG_PATH=$(PWD)/winfsp.install/lib +memfs-winfsp-fuse: memfs-fuse.cpp + ln -nsf "`regtool --wow32 get '/HKLM/Software/WinFsp/InstallDir' | cygpath -au -f -`" winfsp.install + g++ $^ -o $@ -g -Wall -std=gnu++17 `pkg-config fuse --cflags --libs` diff --git a/tst/memfs-fuse/README.md b/tst/memfs-fuse/README.md new file mode 100644 index 00000000..87994104 --- /dev/null +++ b/tst/memfs-fuse/README.md @@ -0,0 +1,7 @@ +`Memfs-fuse` is an in-memory FUSE file system. + +It can be built with the following tools: + +- Using Visual Studio (`memfs-fuse.sln`). +- Using Cygwin GCC and linking directly with the WinFsp DLL (`make winfsp-fuse`). +- Using Cygwin GCC and linking to CYGFUSE (`make cygfuse`). diff --git a/tst/memfs-fuse/compat.h b/tst/memfs-fuse/compat.h new file mode 100644 index 00000000..30c4b7ee --- /dev/null +++ b/tst/memfs-fuse/compat.h @@ -0,0 +1,104 @@ +/** + * @file compat.h + * + * @copyright 2015-2021 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(FSP_FUSE_SYM) +#include +#undef fuse_main +#define fuse_main(argc, argv, ops, data)\ + (FspLoad(0), fuse_main_real(argc, argv, ops, sizeof *(ops), data)) +#endif + +#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 +#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 diff --git a/tst/memfs-fuse/memfs-fuse.cpp b/tst/memfs-fuse/memfs-fuse.cpp new file mode 100644 index 00000000..74da03bd --- /dev/null +++ b/tst/memfs-fuse/memfs-fuse.cpp @@ -0,0 +1,661 @@ +/** + * @file memfs-fuse.c + * + * @copyright 2015-2021 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "compat.h" + +class memfs +{ +public: + memfs() : _ino(1), _root(std::make_shared(_ino, S_IFDIR | 00777, 0, 0)) + { + } + + int main(int argc, char *argv[]) + { + static fuse_operations ops = + { + .getattr = getattr, + .readlink = readlink, + .mknod = mknod, + .mkdir = mkdir, + .unlink = unlink, + .rmdir = rmdir, + .symlink = symlink, + .rename = rename, + .link = link, + .chmod = chmod, + .chown = chown, + .truncate = truncate, + .open = open, + .read = read, + .write = write, + .statfs = statfs, + .flush = flush, + .release = release, + .setxattr = setxattr, + .getxattr = getxattr, + .listxattr = listxattr, + .removexattr = removexattr, + .opendir = opendir, + .readdir = readdir, + .releasedir = releasedir, + .init = init, + .ftruncate = ftruncate, + .fgetattr = fgetattr, + .utimens = utimens, + .setcrtime = setcrtime, +#if defined(FSP_FUSE_USE_STAT_EX) + .chflags = chflags, +#endif + }; + 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 = stat.st_birthtim = 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 data; + std::unordered_map> childmap; + std::unordered_map> xattrmap; + }; + + static fuse_timespec now() + { + using namespace std::chrono; + auto now = system_clock::now(); + auto sec = floor(now); + auto nsec = floor(now) - floor(sec); + return fuse_timespec + { + static_cast(sec.time_since_epoch().count()), + /* std::chrono epoch is UNIX epoch in C++20 */ + static_cast(nsec.count()), + }; + } + + static memfs *getself() + { + return static_cast(fuse_get_context()->private_data); + } + + static int getattr(const char *path, struct fuse_stat *stbuf) + { + return fgetattr(path, stbuf, nullptr); + } + + static int fgetattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi) + { + auto self = getself(); + std::lock_guard 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 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 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 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 lock(self->_mutex); + return self->remove_node(path, false); + } + + static int rmdir(const char *path) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + return self->remove_node(path, true); + } + + static int symlink(const char *dstpath, const char *srcpath) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + return self->make_node(srcpath, S_IFLNK | 00777, 0, dstpath); + } + + static int rename(const char *oldpath, const char *newpath) + { + auto self = getself(); + std::lock_guard 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 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) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + auto node = self->get_node(path); + 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) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + auto node = self->get_node(path); + 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) + { + return ftruncate(path, size, nullptr); + } + + static int ftruncate(const char *path, fuse_off_t size, + struct fuse_file_info *fi) + { + auto self = getself(); + std::lock_guard 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), true); + node->stat.st_ctim = node->stat.st_mtim = now(); +#if defined(FSP_FUSE_USE_STAT_EX) + node->stat.st_flags |= UF_ARCHIVE; +#endif + return 0; + } + + static int open(const char *path, struct fuse_file_info *fi) + { + auto self = getself(); + std::lock_guard 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 lock(self->_mutex); + auto node = self->get_node(path, fi); + if (!node) + return -ENOENT; + fuse_off_t endoff = (std::min)( + off + static_cast(size), static_cast(node->data.size())); + if (off > endoff) + return 0; + std::memcpy(buf, node->data.data() + off, static_cast(endoff - off)); + node->stat.st_atim = now(); + return static_cast(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 lock(self->_mutex); + auto node = self->get_node(path, fi); + if (!node) + return -ENOENT; + fuse_off_t endoff = off + static_cast(size); + if (SIZE_MAX < endoff) + return -EFBIG; + if (node->data.size() < endoff) + node->resize(static_cast(endoff), true); + std::memcpy(node->data.data() + off, buf, static_cast(endoff - off)); + node->stat.st_ctim = node->stat.st_mtim = now(); +#if defined(FSP_FUSE_USE_STAT_EX) + node->stat.st_flags |= UF_ARCHIVE; +#endif + return static_cast(endoff - off); + } + + static int statfs(const char *path, struct fuse_statvfs *stbuf) + { + std::memset(stbuf, 0, sizeof *stbuf); + return 0; + } + + 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 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 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 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(iter->second.size()); + } + + static int listxattr(const char *path, char *namebuf, size_t size) + { + auto self = getself(); + std::lock_guard 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(copysize); + } + + static int removexattr(const char *path, const char *name0) + { + auto self = getself(); + std::lock_guard 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 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) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + auto node = self->get_node(path, fi); + if (!node) + return -ENOENT; + filler(buf, ".", &node->stat, 0); + filler(buf, "..", nullptr, 0); + for (auto elem : node->childmap) + if (0 != filler(buf, elem.first.c_str(), &elem.second->stat, 0)) + break; + return 0; + } + + static int releasedir(const char *path, struct fuse_file_info *fi) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + return self->close_node(fi); + } + + static void *init(struct fuse_conn_info *conn) + { +#if defined(FSP_FUSE_CAP_READDIR_PLUS) + conn->want |= (conn->capable & FSP_FUSE_CAP_READDIR_PLUS); +#endif + +#if defined(FSP_FUSE_USE_STAT_EX) && defined(FSP_FUSE_CAP_STAT_EX) + conn->want |= (conn->capable & FSP_FUSE_CAP_STAT_EX); +#endif + + return getself(); + } + + static int utimens(const char *path, const struct fuse_timespec tmsp[2]) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + auto node = self->get_node(path); + 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 setcrtime(const char *path, const struct fuse_timespec *tmsp) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + auto node = self->get_node(path); + if (!node) + return -ENOENT; + if (tmsp) + { + node->stat.st_ctim = now(); + node->stat.st_birthtim = tmsp[0]; + } + else + node->stat.st_ctim = node->stat.st_birthtim = now(); + return 0; + } + +#if defined(FSP_FUSE_USE_STAT_EX) + static int chflags(const char *path, uint32_t flags) + { + auto self = getself(); + std::lock_guard lock(self->_mutex); + auto node = self->get_node(path); + if (!node) + return -ENOENT; + node->stat.st_flags = flags; + node->stat.st_ctim = now(); + return 0; + } +#endif + + std::tuple, std::string, std::shared_ptr> + 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(++_ino, mode, context->uid, context->gid, dev); +#if defined(FSP_FUSE_USE_STAT_EX) + if (S_IFDIR != (mode & S_IFMT)) + node->stat.st_flags |= UF_ARCHIVE; +#endif + 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); + return 0; + } + + int close_node(struct fuse_file_info *fi) + { + delete (std::shared_ptr *)(uintptr_t)fi->fh; + return 0; + } + + std::shared_ptr 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 *)(uintptr_t)fi->fh; + } + +private: + std::mutex _mutex; + fuse_ino_t _ino; + std::shared_ptr _root; +}; + +int main(int argc, char *argv[]) +{ + return memfs().main(argc, argv); +} diff --git a/tst/memfs-fuse/memfs-fuse.sln b/tst/memfs-fuse/memfs-fuse.sln new file mode 100644 index 00000000..b2db2e81 --- /dev/null +++ b/tst/memfs-fuse/memfs-fuse.sln @@ -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-fuse", "memfs-fuse.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 diff --git a/tst/memfs-fuse/memfs-fuse.vcxproj b/tst/memfs-fuse/memfs-fuse.vcxproj new file mode 100644 index 00000000..de118d17 --- /dev/null +++ b/tst/memfs-fuse/memfs-fuse.vcxproj @@ -0,0 +1,193 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {CF538F42-C714-4653-B351-E72FD7B0B217} + Win32Proj + memfsfuse + $(LatestTargetPlatformVersion) + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + + + + Level3 + Disabled + FSP_FUSE_USE_STAT_EX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreadedDebug + 4018 + stdcpp20 + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + + + Level3 + Disabled + FSP_FUSE_USE_STAT_EX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreadedDebug + 4018 + stdcpp20 + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + + + MaxSpeed + true + true + FSP_FUSE_USE_STAT_EX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4018 + stdcpp20 + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + + + MaxSpeed + true + true + FSP_FUSE_USE_STAT_EX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4018 + stdcpp20 + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + + + + + + + + \ No newline at end of file diff --git a/tst/memfs-fuse/memfs-fuse.vcxproj.filters b/tst/memfs-fuse/memfs-fuse.vcxproj.filters new file mode 100644 index 00000000..14a0b689 --- /dev/null +++ b/tst/memfs-fuse/memfs-fuse.vcxproj.filters @@ -0,0 +1,19 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source + + + + + Source + + + \ No newline at end of file