mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 19:48:38 -05:00 
			
		
		
		
	tst: memfs-fuse: add FUSE reference file system
This commit is contained in:
		
							
								
								
									
										10
									
								
								tst/memfs-fuse/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								tst/memfs-fuse/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | build | ||||||
|  | *.ncb | ||||||
|  | *.suo | ||||||
|  | *.vcproj.* | ||||||
|  | *.vcxproj.user | ||||||
|  | *.VC.db | ||||||
|  | *.VC.opendb | ||||||
|  | .vs | ||||||
|  | *.exe | ||||||
|  | *.install | ||||||
							
								
								
									
										18
									
								
								tst/memfs-fuse/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								tst/memfs-fuse/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -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` | ||||||
							
								
								
									
										7
									
								
								tst/memfs-fuse/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								tst/memfs-fuse/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -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`). | ||||||
							
								
								
									
										104
									
								
								tst/memfs-fuse/compat.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								tst/memfs-fuse/compat.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <winfsp/winfsp.h> | ||||||
|  | #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 <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 | ||||||
							
								
								
									
										661
									
								
								tst/memfs-fuse/memfs-fuse.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										661
									
								
								tst/memfs-fuse/memfs-fuse.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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 <cerrno> | ||||||
|  | #include <chrono> | ||||||
|  | #include <cstring> | ||||||
|  | #include <algorithm> | ||||||
|  | #include <memory> | ||||||
|  | #include <mutex> | ||||||
|  | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | #include <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 = 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<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() | ||||||
|  |     { | ||||||
|  |         using namespace std::chrono; | ||||||
|  |         auto now = system_clock::now(); | ||||||
|  |         auto sec = floor<seconds>(now); | ||||||
|  |         auto nsec = floor<nanoseconds>(now) - floor<nanoseconds>(sec); | ||||||
|  |         return fuse_timespec | ||||||
|  |         { | ||||||
|  |             static_cast<decltype(fuse_timespec::tv_sec)>(sec.time_since_epoch().count()), | ||||||
|  |                 /* std::chrono epoch is UNIX epoch in C++20 */ | ||||||
|  |             static_cast<decltype(fuse_timespec::tv_nsec)>(nsec.count()), | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static memfs *getself() | ||||||
|  |     { | ||||||
|  |         return static_cast<memfs *>(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<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) | ||||||
|  |     { | ||||||
|  |         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) | ||||||
|  |     { | ||||||
|  |         auto self = getself(); | ||||||
|  |         std::lock_guard<std::mutex> 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<std::mutex> 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<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(); | ||||||
|  | #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<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(); | ||||||
|  | #if defined(FSP_FUSE_USE_STAT_EX) | ||||||
|  |         node->stat.st_flags |= UF_ARCHIVE; | ||||||
|  | #endif | ||||||
|  |         return static_cast<int>(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<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) | ||||||
|  |     { | ||||||
|  |         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); | ||||||
|  |         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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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::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 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_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-fuse/memfs-fuse.sln
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tst/memfs-fuse/memfs-fuse.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-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 | ||||||
							
								
								
									
										193
									
								
								tst/memfs-fuse/memfs-fuse.vcxproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								tst/memfs-fuse/memfs-fuse.vcxproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,193 @@ | |||||||
|  | <?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>memfsfuse</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>FSP_FUSE_USE_STAT_EX;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||||||
|  |       <SDLCheck>true</SDLCheck> | ||||||
|  |       <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> | ||||||
|  |       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> | ||||||
|  |       <DisableSpecificWarnings>4018</DisableSpecificWarnings> | ||||||
|  |       <LanguageStandard>stdcpp20</LanguageStandard> | ||||||
|  |     </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>FSP_FUSE_USE_STAT_EX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||||||
|  |       <SDLCheck>true</SDLCheck> | ||||||
|  |       <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> | ||||||
|  |       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> | ||||||
|  |       <DisableSpecificWarnings>4018</DisableSpecificWarnings> | ||||||
|  |       <LanguageStandard>stdcpp20</LanguageStandard> | ||||||
|  |     </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>FSP_FUSE_USE_STAT_EX;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||||||
|  |       <SDLCheck>true</SDLCheck> | ||||||
|  |       <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> | ||||||
|  |       <RuntimeLibrary>MultiThreaded</RuntimeLibrary> | ||||||
|  |       <DisableSpecificWarnings>4018</DisableSpecificWarnings> | ||||||
|  |       <LanguageStandard>stdcpp20</LanguageStandard> | ||||||
|  |     </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>FSP_FUSE_USE_STAT_EX;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> | ||||||
|  |       <SDLCheck>true</SDLCheck> | ||||||
|  |       <AdditionalIncludeDirectories>$(MSBuildProgramFiles32)\WinFsp\inc\fuse;$(MSBuildProgramFiles32)\WinFsp\inc</AdditionalIncludeDirectories> | ||||||
|  |       <RuntimeLibrary>MultiThreaded</RuntimeLibrary> | ||||||
|  |       <DisableSpecificWarnings>4018</DisableSpecificWarnings> | ||||||
|  |       <LanguageStandard>stdcpp20</LanguageStandard> | ||||||
|  |     </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-fuse.cpp" /> | ||||||
|  |   </ItemGroup> | ||||||
|  |   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> | ||||||
|  |   <ImportGroup Label="ExtensionTargets"> | ||||||
|  |   </ImportGroup> | ||||||
|  | </Project> | ||||||
							
								
								
									
										19
									
								
								tst/memfs-fuse/memfs-fuse.vcxproj.filters
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tst/memfs-fuse/memfs-fuse.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-fuse.cpp"> | ||||||
|  |       <Filter>Source</Filter> | ||||||
|  |     </ClCompile> | ||||||
|  |   </ItemGroup> | ||||||
|  | </Project> | ||||||
		Reference in New Issue
	
	Block a user