diff --git a/build/VStudio/installer/Product.wxs b/build/VStudio/installer/Product.wxs index b10f28ba..cd2501bd 100644 --- a/build/VStudio/installer/Product.wxs +++ b/build/VStudio/installer/Product.wxs @@ -382,6 +382,29 @@ + + + + + + + + + + + + + + + + + + + + + + + @@ -592,6 +615,13 @@ + + + + + + + diff --git a/tst/memfs-fuse3/.gitignore b/tst/memfs-fuse3/.gitignore new file mode 100644 index 00000000..a7872d37 --- /dev/null +++ b/tst/memfs-fuse3/.gitignore @@ -0,0 +1,10 @@ +build +*.ncb +*.suo +*.vcproj.* +*.vcxproj.user +*.VC.db +*.VC.opendb +.vs +*.exe +*.install diff --git a/tst/memfs-fuse3/Makefile b/tst/memfs-fuse3/Makefile new file mode 100644 index 00000000..5bbe98b8 --- /dev/null +++ b/tst/memfs-fuse3/Makefile @@ -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` diff --git a/tst/memfs-fuse3/README.md b/tst/memfs-fuse3/README.md new file mode 100644 index 00000000..ccfc716e --- /dev/null +++ b/tst/memfs-fuse3/README.md @@ -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`). diff --git a/tst/memfs-fuse3/compat.h b/tst/memfs-fuse3/compat.h new file mode 100644 index 00000000..c2e05ed2 --- /dev/null +++ b/tst/memfs-fuse3/compat.h @@ -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 +#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-fuse3/memfs-fuse3.cpp b/tst/memfs-fuse3/memfs-fuse3.cpp new file mode 100644 index 00000000..6c49d5b3 --- /dev/null +++ b/tst/memfs-fuse3/memfs-fuse3.cpp @@ -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 +#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, + 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 data; + std::unordered_map> childmap; + std::unordered_map> xattrmap; + }; + + static fuse_timespec now() + { + fuse_timespec ts = { static_cast(std::time(0)) }; + return ts; + } + + static memfs *getself() + { + return static_cast(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 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, unsigned int flags) + { + 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, + 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; + 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 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 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(); + 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(); + return static_cast(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 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, enum fuse_readdir_flags) + { + 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, 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 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 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::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 (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-fuse3/memfs-fuse3.sln b/tst/memfs-fuse3/memfs-fuse3.sln new file mode 100644 index 00000000..9e3b6efa --- /dev/null +++ b/tst/memfs-fuse3/memfs-fuse3.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-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 diff --git a/tst/memfs-fuse3/memfs-fuse3.vcxproj b/tst/memfs-fuse3/memfs-fuse3.vcxproj new file mode 100644 index 00000000..ca26671f --- /dev/null +++ b/tst/memfs-fuse3/memfs-fuse3.vcxproj @@ -0,0 +1,189 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {CF538F42-C714-4653-B351-E72FD7B0B217} + Win32Proj + memfsfuse3 + $(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 + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreadedDebug + 4018 + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + + + Level3 + Disabled + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreadedDebug + 4018 + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4018 + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + + + MaxSpeed + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc\fuse3;$(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + 4018 + + + 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-fuse3/memfs-fuse3.vcxproj.filters b/tst/memfs-fuse3/memfs-fuse3.vcxproj.filters new file mode 100644 index 00000000..cc996b8d --- /dev/null +++ b/tst/memfs-fuse3/memfs-fuse3.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