1
0
mirror of https://github.com/falk-werner/webfuse synced 2024-10-27 20:34:10 +00:00

added filesystem interface

This commit is contained in:
Falk Werner 2022-11-13 14:17:47 +01:00
parent 9e60323429
commit 9f300ec2d4
29 changed files with 1149 additions and 2 deletions

View File

@ -6,7 +6,16 @@ pkg_check_modules(FUSE REQUIRED IMPORTED_TARGET fuse3)
pkg_check_modules(LWS REQUIRED IMPORTED_TARGET libwebsockets)
add_library(webfuse_static STATIC
src/webfuse/webfuse.cpp)
src/webfuse/webfuse.cpp
src/webfuse/filesystem/status.cpp
src/webfuse/filesystem/accessmode.cpp
src/webfuse/filesystem/openflags.cpp
src/webfuse/filesystem/userid.cpp
src/webfuse/filesystem/groupid.cpp
src/webfuse/filesystem/filemode.cpp
src/webfuse/filesystem/filetime.cpp
src/webfuse/filesystem/fileattributes.cpp
)
target_include_directories(webfuse_static PUBLIC src)
target_link_libraries(webfuse_static PUBLIC PkgConfig::FUSE PkgConfig::LWS)
@ -22,7 +31,14 @@ if(NOT(WITHOUT_TEST))
pkg_check_modules(GMOCK REQUIRED gmock)
add_executable(alltests
test/webfuse/test_app.cpp
test-src/webfuse/test_app.cpp
test-src/webfuse/filesystem/test_status.cpp
test-src/webfuse/filesystem/test_accessmode.cpp
test-src/webfuse/filesystem/test_openflags.cpp
test-src/webfuse/filesystem/test_filemode.cpp
test-src/webfuse/filesystem/test_userid.cpp
test-src/webfuse/filesystem/test_groupid.cpp
test-src/webfuse/filesystem/test_fileattributes.cpp
)
target_include_directories(alltests PRIVATE ${GTEST_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS})

View File

@ -0,0 +1,41 @@
#include "webfuse/filesystem/accessmode.hpp"
#include <unistd.h>
namespace webfuse
{
access_mode::access_mode(int8_t value)
: value_(value)
{
}
access_mode::operator int8_t() const
{
return value_;
}
access_mode access_mode::from_int(int value)
{
int8_t result = 0;
if (0 != (value & R_OK)) { result |= r_ok; }
if (0 != (value & W_OK)) { result |= w_ok; }
if (0 != (value & X_OK)) { result |= x_ok; }
return access_mode(result);
}
int access_mode::to_int() const
{
int result = 0;
if (0 != (value_ & r_ok)) { result |= R_OK; }
if (0 != (value_ & w_ok)) { result |= W_OK; }
if (0 != (value_ & x_ok)) { result |= X_OK; }
return result;
}
}

View File

@ -0,0 +1,28 @@
#ifndef WEBFUSE_ACCESSMODE_HPP
#define WEBFUSE_ACCESSMODE_HPP
#include <cinttypes>
namespace webfuse
{
class access_mode
{
public:
static constexpr int8_t const f_ok = 0; // F_OK
static constexpr int8_t const r_ok = 4; // R_OK
static constexpr int8_t const w_ok = 2; // W_OK
static constexpr int8_t const x_ok = 1; // X_OK
access_mode(int8_t value = f_ok);
operator int8_t() const;
static access_mode from_int(int value);
int to_int() const;
private:
int8_t value_;
};
}
#endif

View File

@ -0,0 +1,46 @@
#include "webfuse/filesystem/fileattributes.hpp"
namespace webfuse
{
file_attributes::file_attributes()
: inode(0)
, nlink(0)
, rdev(0)
, size(0)
, blocks(0)
{
}
file_attributes::file_attributes(struct stat const & other)
{
inode = static_cast<uint64_t>(other.st_ino);
nlink = static_cast<uint64_t>(other.st_nlink);
mode = filemode::from_mode(other.st_mode);
uid = user_id::from_uid(other.st_uid);
gid = group_id::from_gid(other.st_gid);
rdev = static_cast<uint64_t>(other.st_rdev);
size = static_cast<uint64_t>(other.st_size);
blocks = static_cast<uint64_t>(other.st_blocks);
atime = filetime::from_timespec(other.st_atim);
mtime = filetime::from_timespec(other.st_mtim);
ctime = filetime::from_timespec(other.st_ctim);
}
void file_attributes::to_stat(struct stat & other) const
{
other.st_ino = inode;
other.st_nlink = nlink;
other.st_mode = mode.to_mode();
other.st_uid = uid.to_uid();
other.st_gid = gid.to_gid();
other.st_rdev = rdev;
other.st_size = size;
other.st_blocks = blocks;
atime.to_timespec(other.st_atim);
mtime.to_timespec(other.st_mtim);
ctime.to_timespec(other.st_ctim);
}
}

View File

@ -0,0 +1,37 @@
#ifndef WEBFUSE_FILEATTRIBUTES_HPP
#define WEBFUSE_FILEATTRIBUTES_HPP
#include "webfuse/filesystem/filemode.hpp"
#include "webfuse/filesystem/filetime.hpp"
#include "webfuse/filesystem/userid.hpp"
#include "webfuse/filesystem/groupid.hpp"
#include <sys/stat.h>
#include <cinttypes>
namespace webfuse
{
class file_attributes
{
public:
file_attributes();
explicit file_attributes(struct stat const & other);
void to_stat(struct stat & other) const;
uint64_t inode;
uint64_t nlink;
filemode mode;
user_id uid;
group_id gid;
uint64_t rdev;
uint64_t size;
uint64_t blocks;
filetime atime;
filetime mtime;
filetime ctime;
};
}
#endif

View File

@ -0,0 +1,16 @@
#ifndef WEBFUSE_FILEHANDLE_HPP
#define WEBFUSE_FILEHANDLE_HPP
#include <cinttypes>
namespace webfuse
{
using filehandle = uint64_t;
constexpr filehandle const invalid_handle = (filehandle) -1;
}
#endif

View File

@ -0,0 +1,50 @@
#include "webfuse/filesystem/filemode.hpp"
#include <sys/stat.h>
namespace webfuse
{
filemode::filemode(uint32_t value)
: value_(value)
{
}
filemode::operator uint32_t() const
{
return value_;
}
filemode filemode::from_mode(mode_t value)
{
uint32_t result = value & 07777;
if (S_ISREG(value) ) { result |= filemode::reg; }
if (S_ISDIR(value) ) { result |= filemode::dir; }
if (S_ISCHR(value) ) { result |= filemode::chr; }
if (S_ISBLK(value) ) { result |= filemode::blk; }
if (S_ISFIFO(value)) { result |= filemode::fifo; }
if (S_ISLNK(value) ) { result |= filemode::lnk; }
if (S_ISSOCK(value)) { result |= filemode::sock; }
return filemode(result);
}
mode_t filemode::to_mode() const
{
mode_t result = value_ & 07777;
if (is_reg() ) { result |= S_IFREG; }
if (is_dir() ) { result |= S_IFDIR; }
if (is_chr() ) { result |= S_IFCHR; }
if (is_blk() ) { result |= S_IFBLK; }
if (is_fifo()) { result |= S_IFIFO; }
if (is_lnk() ) { result |= S_IFLNK; }
if (is_sock()) { result |= S_IFSOCK; }
return result;
}
}

View File

@ -0,0 +1,75 @@
#ifndef WEBFUSE_FILEMODE_HPP
#define WEBFUSE_FILEMODE_HPP
#include <fcntl.h>
#include <cinttypes>
namespace webfuse
{
class filemode
{
public:
static constexpr uint32_t const protection_mask = 0000777;
static constexpr uint32_t const sticky_mask = 0007000;
static constexpr uint32_t const filetype_mask = 0170000;
static constexpr uint32_t const suid = 04000; // S_ISUID
static constexpr uint32_t const sgid = 02000; // S_ISGID
static constexpr uint32_t const svtx = 01000; // S_ISVTX
static constexpr uint32_t const reg = 0100000; // S_IFREG
static constexpr uint32_t const dir = 0040000; // S_IFDIR
static constexpr uint32_t const chr = 0020000; // S_IFCHR
static constexpr uint32_t const blk = 0060000; // S_IFBLK
static constexpr uint32_t const fifo = 0010000; // S_IFIFO
static constexpr uint32_t const lnk = 0120000; // S_IFLNK
static constexpr uint32_t const sock = 0140000; // S_IFSOCK
explicit filemode(uint32_t value = 0);
operator uint32_t() const;
static filemode from_mode(mode_t value);
mode_t to_mode() const;
inline bool is_reg() const
{
return (filemode::reg == (value_ & filemode::filetype_mask));
}
inline bool is_dir() const
{
return (filemode::dir == (value_ & filemode::filetype_mask));
}
inline bool is_chr() const
{
return (filemode::chr == (value_ & filemode::filetype_mask));
}
inline bool is_blk() const
{
return (filemode::blk == (value_ & filemode::filetype_mask));
}
inline bool is_fifo() const
{
return (filemode::fifo == (value_ & filemode::filetype_mask));
}
inline bool is_lnk() const
{
return (filemode::lnk == (value_ & filemode::filetype_mask));
}
inline bool is_sock() const
{
return (filemode::sock == (value_ & filemode::filetype_mask));
}
private:
uint32_t value_;
};
}
#endif

View File

@ -0,0 +1,56 @@
#ifndef WEBFUSE_FILESYSTEM_I_HPP
#define WEBFUSE_FILESYSTEM_I_HPP
#include "webfuse/filesystem/filehandle.hpp"
#include "webfuse/filesystem/accessmode.hpp"
#include "webfuse/filesystem/filemode.hpp"
#include "webfuse/filesystem/fileattributes.hpp"
#include "webfuse/filesystem/openflags.hpp"
#include "webfuse/filesystem/userid.hpp"
#include "webfuse/filesystem/groupid.hpp"
#include "webfuse/filesystem/status.hpp"
#include "webfuse/filesystem/filesystem_statistics.hpp"
#include <cinttypes>
#include <string>
#include <vector>
namespace webfuse
{
class filesystem_i
{
public:
virtual ~filesystem_i() = default;
virtual status access(std::string const & path, access_mode mode) = 0;
virtual status getattr(std::string const & path, file_attributes & attr) = 0;
virtual status readlink(std::string const & path, std::string & out) = 0;
virtual status symlink(std::string const & target, std::string const & linkpath) = 0;
virtual status link(std::string const & old_path, std::string const & new_path) = 0;
virtual status rename(std::string const & old_path, std::string const & new_path) = 0;
virtual status chmod(std::string const & path, filemode mode) = 0;
virtual status chown(std::string const & path, user_id uid, group_id gid);
virtual status truncate(std::string const & path, uint64_t offset, filehandle handle) = 0;
virtual status fsync(std::string const & path, bool is_datasync, filehandle handle) = 0;
virtual status open(std::string const & path, openflags flags, filehandle & handle) = 0;
virtual status mknod(std::string const & path, filemode mode, uint64_t rdev) = 0;
virtual status create(std::string const & path, filemode mode, filehandle & handle) = 0;
virtual status release(std::string const & path, filehandle handle) = 0;
virtual status unlink(std::string const & path) = 0;
virtual status read(std::string const & path, char * buffer, size_t buffer_size, uint64_t offset, filehandle handle) = 0;
virtual status write(std::string const & path, char const * buffer, size_t buffer_size, uint64_t offset, filehandle handle) = 0;
virtual status readdir(std::string const & path, std::vector<std::string> entries, filehandle handle) = 0;
virtual status rmdir(std::string const & path) = 0;
virtual status statfs(std::string const & path, filesystem_statistics & statistics) = 0;
};
}
#endif

View File

@ -0,0 +1,31 @@
#ifndef WEBFUSE_FILESYSTEMSTATISTICS_HPP
#define WEBFUSE_FILESYSTEMSTATISTICS_HPP
#include <sys/statvfs.h>
#include <cinttypes>
namespace webfuse
{
class filesystem_statistics
{
public:
filesystem_statistics();
explicit filesystem_statistics(struct statvfs const & other);
void copy_to(struct statvfs & other) const;
uint64_t bsize;
uint64_t frsize;
uint64_t blocks;
uint64_t bfree;
uint64_t bavail;
uint64_t files;
uint64_t ffree;
uint64_t f_namemax;
};
}
#endif

View File

@ -0,0 +1,43 @@
#include "webfuse/filesystem/filetime.hpp"
namespace webfuse
{
filetime::filetime()
: seconds(0)
, nsec(0)
{
}
filetime filetime::from_timespec(timespec const & other)
{
filetime result;
result.seconds = static_cast<uint64_t>(other.tv_sec);
result.nsec = static_cast<uint32_t>(other.tv_nsec);
return result;
}
filetime filetime::from_time(time_t const & other)
{
filetime result;
result.seconds = static_cast<uint64_t>(other);
result.nsec = 0;
return result;
}
void filetime::to_timespec(timespec & other) const
{
other.tv_sec = seconds;
other.tv_nsec = static_cast<time_t>(nsec);
}
time_t filetime::to_time() const
{
return static_cast<time_t>(seconds);
}
}

View File

@ -0,0 +1,25 @@
#ifndef WEBFUSE_FILETIME_HPP
#define WEBFUSE_FILETIME_HPP
#include <ctime>
#include <cinttypes>
namespace webfuse
{
class filetime
{
public:
filetime();
static filetime from_timespec(timespec const & other);
static filetime from_time(time_t const & other);
void to_timespec(timespec & other) const;
time_t to_time() const;
uint64_t seconds;
uint32_t nsec;
};
}
#endif

View File

@ -0,0 +1,27 @@
#include "webfuse/filesystem/groupid.hpp"
namespace webfuse
{
group_id::group_id(uint32_t value)
: value_(value)
{
}
group_id::operator uint32_t() const
{
return value_;
}
group_id group_id::from_gid(gid_t value)
{
return group_id(static_cast<uint32_t>(value));
}
gid_t group_id::to_gid() const
{
return static_cast<gid_t>(value_);
}
}

View File

@ -0,0 +1,25 @@
#ifndef WEBFUSE_GROUPID_HPP
#define WEBFUSE_GROUPID_HPP
#include <unistd.h>
#include <cinttypes>
namespace webfuse
{
class group_id
{
public:
static constexpr uint32_t const invalid = (uint32_t) -1;
explicit group_id(uint32_t value = invalid);
operator uint32_t() const;
static group_id from_gid(gid_t value);
gid_t to_gid() const;
private:
uint32_t value_;
};
}
#endif

View File

@ -0,0 +1,69 @@
#include "webfuse/filesystem/openflags.hpp"
#include <fcntl.h>
namespace webfuse
{
openflags::openflags(int32_t value)
: value_(value)
{
}
openflags::operator int32_t() const
{
return value_;
}
openflags openflags::from_int(int value)
{
int32_t result = 0;
if (O_RDONLY == (value & O_RDONLY )) { result |= openflags::rdonly; }
if (O_WRONLY == (value & O_WRONLY )) { result |= openflags::wronly; }
if (O_RDWR == (value & O_RDWR )) { result |= openflags::rdwr; }
if (O_CLOEXEC == (value & O_CLOEXEC )) { result |= openflags::cloexec; }
if (O_CREAT == (value & O_CREAT )) { result |= openflags::creat; }
if (O_DIRECT == (value & O_DIRECT )) { result |= openflags::direct; }
if (O_DIRECTORY == (value & O_DIRECTORY)) { result |= openflags::directory; }
if (O_EXCL == (value & O_EXCL )) { result |= openflags::excl; }
if (O_NOCTTY == (value & O_NOCTTY )) { result |= openflags::noctty; }
if (O_NOFOLLOW == (value & O_NOFOLLOW )) { result |= openflags::nofollow; }
if (O_TRUNC == (value & O_TRUNC )) { result |= openflags::trunc; }
if (O_ASYNC == (value & O_ASYNC )) { result |= openflags::async; }
if (O_LARGEFILE == (value & O_LARGEFILE)) { result |= openflags::largefile; }
if (O_NOATIME == (value & O_NOATIME )) { result |= openflags::noatime; }
if (O_NONBLOCK == (value & O_NONBLOCK )) { result |= openflags::nonblock; }
if (O_NDELAY == (value & O_NDELAY )) { result |= openflags::ndelay; }
if (O_SYNC == (value & O_SYNC )) { result |= openflags::sync; }
return openflags(result);
}
int openflags::to_int() const
{
int result = 0;
if (openflags::rdonly == (value_ & openflags::rdonly )) { result |= O_RDONLY; }
if (openflags::wronly == (value_ & openflags::wronly )) { result |= O_WRONLY; }
if (openflags::rdwr == (value_ & openflags::rdwr )) { result |= O_RDWR; }
if (openflags::cloexec == (value_ & openflags::cloexec )) { result |= O_CLOEXEC; }
if (openflags::creat == (value_ & openflags::creat )) { result |= O_CREAT; }
if (openflags::direct == (value_ & openflags::direct )) { result |= O_DIRECT; }
if (openflags::directory == (value_ & openflags::directory)) { result |= O_DIRECTORY; }
if (openflags::excl == (value_ & openflags::excl )) { result |= O_EXCL; }
if (openflags::noctty == (value_ & openflags::noctty )) { result |= O_NOCTTY; }
if (openflags::nofollow == (value_ & openflags::nofollow )) { result |= O_NOFOLLOW; }
if (openflags::trunc == (value_ & openflags::trunc )) { result |= O_TRUNC; }
if (openflags::async == (value_ & openflags::async )) { result |= O_ASYNC; }
if (openflags::largefile == (value_ & openflags::largefile)) { result |= O_LARGEFILE; }
if (openflags::noatime == (value_ & openflags::noatime )) { result |= O_NOATIME; }
if (openflags::nonblock == (value_ & openflags::nonblock )) { result |= O_NONBLOCK; }
if (openflags::ndelay == (value_ & openflags::ndelay )) { result |= O_NDELAY; }
if (openflags::sync == (value_ & openflags::sync )) { result |= O_SYNC; }
return result;
}
}

View File

@ -0,0 +1,43 @@
#ifndef WEBFUSE_OPENFLAGS_HPP
#define WEBFUSE_OPENFLAGS_HPP
#include <cinttypes>
namespace webfuse
{
class openflags
{
public:
static constexpr int32_t const accessmode_mask = 3; // O_ACCMODE
static constexpr int32_t const rdonly = 00000000; // O_RDONLY
static constexpr int32_t const wronly = 00000001; // O_WRONLY
static constexpr int32_t const rdwr = 00000002; // O_RDWR
static constexpr int32_t const cloexec = 02000000; // O_CLOEXEC
static constexpr int32_t const creat = 00000100; // O_CREAT
static constexpr int32_t const direct = 00040000; // O_DIRECT
static constexpr int32_t const directory = 00200000; // O_DIRECTORY
static constexpr int32_t const excl = 00000200; // O_EXCL
static constexpr int32_t const noctty = 00000400; // O_NOCTTY
static constexpr int32_t const nofollow = 00400000; // O_NOFOLLOW
static constexpr int32_t const trunc = 00001000; // O_TRUNC
static constexpr int32_t const async = 00002000; // O_ASYNC
static constexpr int32_t const largefile = 00000000; // O_LARGEFILE
static constexpr int32_t const noatime = 01000000; // O_NOATIME
static constexpr int32_t const nonblock = 00004000; // O_NONBLOCK
static constexpr int32_t const ndelay = 00004000; // O_NDELAY
static constexpr int32_t const sync = 04010000; // O_SYNC
explicit openflags(int32_t value = 0);
operator int32_t() const;
static openflags from_int(int value);
int to_int() const;
private:
int32_t value_;
};
}
#endif

View File

@ -0,0 +1,120 @@
#include "webfuse/filesystem/status.hpp"
#include <errno.h>
namespace webfuse
{
status::status(int32_t value)
: value_(value)
{
}
status::operator int32_t() const
{
return value_;
}
status status::from_fusestatus(int value)
{
if (value >= 0)
{
return static_cast<int32_t>(value);
}
else
{
switch(value)
{
case -E2BIG: return status::bad_e2big;
case -EACCES: return status::bad_eacces;
case -EAGAIN: return status::bad_eagain;
case -EBADF: return status::bad_ebadf;
case -EBUSY: return status::bad_ebusy;
case -EDESTADDRREQ: return status::bad_edestaddrreq;
case -EDQUOT: return status::bad_edquot;
case -EEXIST: return status::bad_eexist;
case -EFAULT: return status::bad_efault;
case -EFBIG: return status::bad_efbig;
case -EINTR: return status::bad_eintr;
case -EINVAL: return status::bad_einval;
case -EIO: return status::bad_eio;
case -EISDIR: return status::bad_eisdir;
case -ELOOP: return status::bad_eloop;
case -EMFILE: return status::bad_emfile;
case -EMLINK: return status::bad_emlink;
case -ENAMETOOLONG: return status::bad_enametoolong;
case -ENFILE: return status::bad_enfile;
case -ENODATA: return status::bad_enodata;
case -ENODEV: return status::bad_enodev;
case -ENOENT: return status::bad_enoent;
case -ENOMEM: return status::bad_enomem;
case -ENOSPC: return status::bad_enospc;
case -ENOSYS: return status::bad_enosys;
case -ENOTDIR: return status::bad_enotdir;
case -ENOTEMPTY: return status::bad_enotempty;
case -ENOTSUP: return status::bad_enotsup;
case -ENXIO: return status::bad_enxio;
case -EOVERFLOW: return status::bad_eoverflow;
case -EPERM: return status ::bad_eperm;
case -EPIPE: return status::bad_epipe;
case -ERANGE: return status::bad_erange;
case -EROFS: return status::bad_erofs;
case -ETXTBSY: return status::bad_etxtbsy;
case -EXDEV: return status::bad_exdev;
default: return static_cast<int32_t>(value);
}
}
}
int status::to_fusestatus() const
{
if (value_ >= 0)
{
return static_cast<int>(value_);
}
else
{
switch(value_)
{
case status::bad_e2big: return -E2BIG;
case status::bad_eacces: return -EACCES;
case status::bad_eagain: return -EAGAIN;
case status::bad_ebadf: return -EBADF;
case status::bad_ebusy: return -EBUSY;
case status::bad_edestaddrreq: return -EDESTADDRREQ;
case status::bad_edquot: return -EDQUOT;
case status::bad_eexist: return -EEXIST;
case status::bad_efault: return -EFAULT;
case status::bad_efbig: return -EFBIG;
case status::bad_eintr: return -EINTR;
case status::bad_einval: return -EINVAL;
case status::bad_eio: return -EIO;
case status::bad_eisdir: return -EISDIR;
case status::bad_eloop: return -ELOOP;
case status::bad_emfile: return -EMFILE;
case status::bad_emlink: return -EMLINK;
case status::bad_enametoolong: return -ENAMETOOLONG;
case status::bad_enfile: return -ENFILE;
case status::bad_enodata: return -ENODATA;
case status::bad_enodev: return -ENODEV;
case status::bad_enoent: return -ENOENT;
case status::bad_enomem: return -ENOMEM;
case status::bad_enospc: return -ENOSPC;
case status::bad_enosys: return -ENOSYS;
case status::bad_enotdir: return -ENOTDIR;
case status::bad_enotempty: return -ENOTEMPTY;
case status::bad_enotsup: return -ENOTSUP;
case status::bad_enxio: return -ENXIO;
case status::bad_eoverflow: return -EOVERFLOW;
case status::bad_eperm: return -EPERM;
case status::bad_epipe: return -EPIPE;
case status::bad_erange: return -ERANGE;
case status::bad_erofs: return -EROFS;
case status::bad_etxtbsy: return -ETXTBSY;
case status::bad_exdev: return -EXDEV;
default: return static_cast<int32_t>(value_);
}
}
}
}

View File

@ -0,0 +1,62 @@
#ifndef WEBFUSE_STATUS_HPP
#define WEBFUSE_STATUS_HPP
#include <cinttypes>
namespace webfuse
{
class status
{
public:
static constexpr int32_t const good = 0;
static constexpr int32_t const bad_e2big = -7; // -E2BIG
static constexpr int32_t const bad_eacces = -13; // -EACCES
static constexpr int32_t const bad_eagain = -11; // -EAGAIN
static constexpr int32_t const bad_ebadf = -9; // -EBADF
static constexpr int32_t const bad_ebusy = -16; // -EBUSY
static constexpr int32_t const bad_edestaddrreq = -89; // -EDESTADDRREQ
static constexpr int32_t const bad_edquot = -122; // -EDQUOT
static constexpr int32_t const bad_eexist = -17; // -EEXIST
static constexpr int32_t const bad_efault = -14; // -EFAULT
static constexpr int32_t const bad_efbig = -27; // -EFBIG
static constexpr int32_t const bad_eintr = -4; // -EINTR
static constexpr int32_t const bad_einval = -22; // -EINVAL
static constexpr int32_t const bad_eio = -5; // -EIO
static constexpr int32_t const bad_eisdir = -21; // -EISDIR
static constexpr int32_t const bad_eloop = -40; // -ELOOP
static constexpr int32_t const bad_emfile = -24; // -EMFILE
static constexpr int32_t const bad_emlink = -31; // -EMLINK
static constexpr int32_t const bad_enametoolong = -36; // -ENAMETOOLONG
static constexpr int32_t const bad_enfile = -23; // -ENFILE
static constexpr int32_t const bad_enodata = -61; // -ENODATA
static constexpr int32_t const bad_enodev = -19; // -ENODEV
static constexpr int32_t const bad_enoent = -2; // -ENOENT
static constexpr int32_t const bad_enomem = -12; // -ENOMEM
static constexpr int32_t const bad_enospc = -28; // -ENOSPC
static constexpr int32_t const bad_enosys = -38; // -ENOSYS
static constexpr int32_t const bad_enotdir = -20; // -ENOTDIR
static constexpr int32_t const bad_enotempty = -39; // -ENOTEMPTY
static constexpr int32_t const bad_enotsup = -95; // -ENOTSUP
static constexpr int32_t const bad_enxio = -6; // -ENXIO
static constexpr int32_t const bad_eoverflow = -75; // -EOVERFLOW
static constexpr int32_t const bad_eperm = -1; // -EPERM
static constexpr int32_t const bad_epipe = -32; // -EPIPE
static constexpr int32_t const bad_erange = -34; // -ERANGE
static constexpr int32_t const bad_erofs = -30; // -EROFS
static constexpr int32_t const bad_etxtbsy = -26; // -ETXTBSY
static constexpr int32_t const bad_exdev = -18; // -EXDEV
static constexpr int32_t const bad_ewouldblock = -11; // -EWOULDBLOCK
status(int32_t value = status::good);
operator int32_t() const;
static status from_fusestatus(int value);
int to_fusestatus() const;
private:
int32_t value_;
};
}
#endif

View File

@ -0,0 +1,28 @@
#include "webfuse/filesystem/userid.hpp"
namespace webfuse
{
user_id::user_id(uint32_t value)
: value_(value)
{
}
user_id::operator uint32_t() const
{
return value_;
}
user_id user_id::from_uid(uid_t value)
{
return user_id(static_cast<uint32_t>(value));
}
uid_t user_id::to_uid() const
{
return static_cast<uid_t>(value_);
}
}

View File

@ -0,0 +1,25 @@
#ifndef WEBFUSE_USERID_HPP
#define WEBFUSE_USERID_HPP
#include <unistd.h>
#include <cinttypes>
namespace webfuse
{
class user_id
{
public:
static constexpr uint32_t const invalid = (uint32_t) -1;
explicit user_id(uint32_t value = invalid);
operator uint32_t() const;
static user_id from_uid(uid_t value);
uid_t to_uid() const;
private:
uint32_t value_;
};
}
#endif

26
src/webfuse/fuse.hpp Normal file
View File

@ -0,0 +1,26 @@
#ifndef WEBFUSE_FUSE_HPP
#define WEBFUSE_FUSE_HPP
#include "webfuse/filesystem/filesystem_i.hpp"
namespace webfuse
{
class fuse
{
fuse (fuse const &) = delete;
fuse& operator=(fuse const &) = delete;
public:
explicit fuse(filesystem_i & filesystem);
~fuse();
fuse (fuse &&) = delete;
fuse& operator=(fuse &&) = delete;
void run(int argc, char * argv[]);
private:
class detail;
detail * d;
};
}
#endif

View File

@ -0,0 +1,26 @@
#include "webfuse/filesystem/accessmode.hpp"
#include <gtest/gtest.h>
using webfuse::access_mode;
TEST(accessmode, f_ok)
{
ASSERT_EQ(0, access_mode::f_ok);
ASSERT_EQ(F_OK, access_mode::f_ok);
}
class accessmode_test: public testing::TestWithParam<int> { };
TEST_P(accessmode_test, conversion)
{
int const expected = GetParam();
auto mode = access_mode::from_int(expected);
ASSERT_EQ(expected, mode.to_int());
}
INSTANTIATE_TEST_CASE_P(accesmode_values, accessmode_test,
testing::Values(
F_OK, R_OK, W_OK, X_OK,
R_OK | W_OK, R_OK | X_OK, W_OK | X_OK,
R_OK | W_OK | X_OK)
);

View File

@ -0,0 +1,101 @@
#include "webfuse/filesystem/fileattributes.hpp"
#include <gtest/gtest.h>
using webfuse::file_attributes;
using webfuse::user_id;
using webfuse::group_id;
using webfuse::filemode;
TEST(file_attibutes, create_empty)
{
file_attributes attributes;
ASSERT_EQ(0, attributes.inode);
ASSERT_EQ(0, attributes.nlink);
ASSERT_EQ(0, attributes.mode);
ASSERT_EQ(user_id::invalid, attributes.uid);
ASSERT_EQ(group_id::invalid, attributes.gid);
ASSERT_EQ(0, attributes.rdev);
ASSERT_EQ(0, attributes.size);
ASSERT_EQ(0, attributes.blocks);
ASSERT_EQ(0, attributes.atime.seconds);
ASSERT_EQ(0, attributes.atime.nsec);
ASSERT_EQ(0, attributes.mtime.seconds);
ASSERT_EQ(0, attributes.mtime.nsec);
ASSERT_EQ(0, attributes.ctime.seconds);
ASSERT_EQ(0, attributes.ctime.nsec);
}
TEST(file_attibutes, from_stat)
{
struct stat info;
info.st_ino = 1;
info.st_nlink = 2;
info.st_mode = S_IFREG | 0644;
info.st_uid = 1000;
info.st_gid = 1234;
info.st_rdev = 0;
info.st_size = 21 * 1024;
info.st_blocks = 42;
info.st_atim.tv_sec = 1;
info.st_atim.tv_nsec = 2;
info.st_mtim.tv_sec = 3;
info.st_mtim.tv_nsec = 4;
info.st_ctim.tv_sec = 5;
info.st_ctim.tv_nsec = 6;
file_attributes attributes(info);
ASSERT_EQ(info.st_ino, attributes.inode);
ASSERT_EQ(info.st_nlink, attributes.nlink);
ASSERT_EQ(info.st_mode, attributes.mode.to_mode());
ASSERT_EQ(info.st_uid, attributes.uid.to_uid());
ASSERT_EQ(info.st_gid, attributes.gid.to_gid());
ASSERT_EQ(info.st_rdev, attributes.rdev);
ASSERT_EQ(info.st_size, attributes.size);
ASSERT_EQ(info.st_blocks, attributes.blocks);
ASSERT_EQ(info.st_atim.tv_sec, attributes.atime.seconds);
ASSERT_EQ(info.st_atim.tv_nsec, attributes.atime.nsec);
ASSERT_EQ(info.st_mtim.tv_sec, attributes.mtime.seconds);
ASSERT_EQ(info.st_mtim.tv_nsec, attributes.mtime.nsec);
ASSERT_EQ(info.st_ctim.tv_sec, attributes.ctime.seconds);
ASSERT_EQ(info.st_ctim.tv_nsec, attributes.ctime.nsec);
}
TEST(file_attibutes, to_stat)
{
file_attributes attributes;
attributes.inode = 1;
attributes.nlink = 2;
attributes.mode = filemode(S_IFREG | 0644);
attributes.uid = user_id(1000);
attributes.gid = group_id(1234);
attributes.rdev = 0;
attributes.size = 21 * 1024;
attributes.blocks = 42;
attributes.atime.seconds = 1;
attributes.atime.nsec = 2;
attributes.mtime.seconds = 3;
attributes.mtime.nsec = 4;
attributes.ctime.seconds = 5;
attributes.ctime.nsec = 6;
struct stat info;
attributes.to_stat(info);
ASSERT_EQ(attributes.inode, info.st_ino);
ASSERT_EQ(attributes.nlink, info.st_nlink);
ASSERT_EQ(attributes.mode.to_mode(), info.st_mode);
ASSERT_EQ(attributes.uid.to_uid(), info.st_uid);
ASSERT_EQ(attributes.gid.to_gid(), info.st_gid);
ASSERT_EQ(attributes.rdev, info.st_rdev);
ASSERT_EQ(attributes.size, info.st_size);
ASSERT_EQ(attributes.blocks, info.st_blocks);
ASSERT_EQ(attributes.atime.seconds, info.st_atim.tv_sec);
ASSERT_EQ(attributes.atime.nsec, info.st_atim.tv_nsec);
ASSERT_EQ(attributes.mtime.seconds, info.st_mtim.tv_sec);
ASSERT_EQ(attributes.mtime.nsec, info.st_mtim.tv_nsec);
ASSERT_EQ(attributes.ctime.seconds, info.st_ctim.tv_sec);
ASSERT_EQ(attributes.ctime.nsec, info.st_ctim.tv_nsec);
}

View File

@ -0,0 +1,25 @@
#include "webfuse/filesystem/filemode.hpp"
#include <gtest/gtest.h>
using webfuse::filemode;
class filemode_test: public testing::TestWithParam<mode_t> { };
TEST_P(filemode_test, conversion)
{
mode_t const expected = GetParam();
auto value = filemode::from_mode(expected);
ASSERT_EQ(expected, value.to_mode());
}
INSTANTIATE_TEST_CASE_P(filemode_value, filemode_test,
testing::Values(
S_IROTH, S_IWOTH, S_IXOTH,
S_IRGRP, S_IWGRP, S_IXGRP,
S_IRUSR, S_IWUSR, S_IXUSR,
S_ISUID, S_ISGID, S_ISVTX,
S_IFREG, S_IFCHR, S_IFBLK, S_IFDIR, S_IFIFO, S_IFLNK, S_IFSOCK,
S_IFREG | 0644,
S_IFDIR | 0755
)
);

View File

@ -0,0 +1,27 @@
#include "webfuse/filesystem/groupid.hpp"
#include <gtest/gtest.h>
using webfuse::group_id;
TEST(group_id, invalid)
{
group_id invalid_group;
ASSERT_EQ(group_id::invalid, invalid_group);
}
TEST(group_id, to_gid)
{
group_id group(69);
gid_t id = group.to_gid();
ASSERT_EQ(69, id);
}
TEST(group_id, from_gid)
{
gid_t id = 99;
auto group = group_id::from_gid(id);
ASSERT_EQ(99, group);
}

View File

@ -0,0 +1,24 @@
#include "webfuse/filesystem/openflags.hpp"
#include <gtest/gtest.h>
#include <fcntl.h>
using webfuse::openflags;
class openflags_test: public testing::TestWithParam<int> { };
TEST_P(openflags_test, conversion)
{
int const expected = GetParam();
auto flags = openflags::from_int(expected);
ASSERT_EQ(expected, flags.to_int());
}
INSTANTIATE_TEST_CASE_P(openflags_values, openflags_test,
testing::Values<>(
O_RDONLY, O_WRONLY, O_RDWR, O_CLOEXEC, O_CREAT,
O_DIRECT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW,
O_TRUNC, O_ASYNC, O_LARGEFILE, O_NOATIME, O_NONBLOCK,
O_NDELAY, O_SYNC,
O_WRONLY | O_CREAT | O_TRUNC
)
);

View File

@ -0,0 +1,28 @@
#include "webfuse/filesystem/status.hpp"
#include <gtest/gtest.h>
#include <errno.h>
using webfuse::status;
class status_test: public testing::TestWithParam<int> { };
TEST_P(status_test, conversion)
{
int const expected = GetParam();
auto status = status::from_fusestatus(expected);
ASSERT_EQ(expected, status.to_fusestatus());
}
INSTANTIATE_TEST_CASE_P(status_values, status_test,
testing::Values(
0, 1, 2, 3, 42,
-E2BIG, -EACCES, -EBADF, -EBUSY, -EDESTADDRREQ,
-EDQUOT, -EEXIST, -EFAULT, -EFBIG, -EINTR,
-EINVAL, -EIO, -EISDIR, -ELOOP, -EMFILE,
-ENAMETOOLONG, -ENFILE, -ENODATA, -ENODEV,
-ENOENT, -ENOMEM, -ENOSPC, -ENOSYS, -ENOTDIR,
-ENOTEMPTY, -ENOTSUP, -ENXIO, -EOVERFLOW, -EPERM,
-EPIPE, -ERANGE, -EROFS, -EXDEV, -EWOULDBLOCK,
-EAGAIN, -12345
)
);

View File

@ -0,0 +1,27 @@
#include "webfuse/filesystem/userid.hpp"
#include <gtest/gtest.h>
using webfuse::user_id;
TEST(user_id, invalid)
{
user_id invalid_user;
ASSERT_EQ(user_id::invalid, invalid_user);
}
TEST(user_id, to_uid)
{
user_id user(42);
uid_t id = user.to_uid();
ASSERT_EQ(42, id);
}
TEST(user_id, from_uid)
{
uid_t id = 23;
auto user = user_id::from_uid(id);
ASSERT_EQ(23, user);
}