tst: memfs-fuse: add FUSE reference file system

This commit is contained in:
Bill Zissimopoulos 2021-11-13 10:11:45 +00:00
parent 2a86cd2c90
commit d67a917c6f
No known key found for this signature in database
GPG Key ID: 3D4F95D52C7B3EA3
8 changed files with 1040 additions and 0 deletions

10
tst/memfs-fuse/.gitignore vendored Normal file
View 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
View 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
View 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
View 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

View 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);
}

View 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

View 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>

View 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>