diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2021-12-15 00:20:23 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2021-12-15 00:20:23 +0000 |
commit | a38270df3ddad2ac60524a40eb986ab37e473c04 (patch) | |
tree | 2b0ff976a616fb970e62b93b3ffb52517efc1343 | |
parent | Add missing include (diff) | |
parent | Bump to C++20, required by new Slicer (diff) | |
download | netfs-a38270df3ddad2ac60524a40eb986ab37e473c04.tar.bz2 netfs-a38270df3ddad2ac60524a40eb986ab37e473c04.tar.xz netfs-a38270df3ddad2ac60524a40eb986ab37e473c04.zip |
Psycho-rebased branch mapper on top of netfs-1.4netfs-1.4.0.1-mark
37 files changed, 729 insertions, 273 deletions
diff --git a/Jamroot.jam b/Jamroot.jam index 38959db..e78971c 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -33,7 +33,10 @@ project <toolset>tidy:<xcheckxx>hicpp-named-parameter <toolset>tidy:<checkxx>performance-* <toolset>tidy:<exclude>daemonConfig.h + <toolset>tidy:<exclude>slicer-daemonConfig.cpp <toolset>tidy:<exclude>fuseConfig.h + <toolset>tidy:<exclude>slicer-fuseConfig.cpp + <toolset>tidy:<exclude>slicer-mapper.cpp <toolset>tidy:<exclude>directory.h <toolset>tidy:<exclude>exceptions.h <toolset>tidy:<exclude>file.h diff --git a/netfs/daemon/daemonService.cpp b/netfs/daemon/daemonService.cpp index 18b050d..38d40c7 100644 --- a/netfs/daemon/daemonService.cpp +++ b/netfs/daemon/daemonService.cpp @@ -1,9 +1,14 @@ #include "daemonService.h" #include "daemon.h" #include "daemonVolume.h" +#include <entCache.h> #include <safeMapFind.h> -ServiceServer::ServiceServer(NetFS::Daemon::ConfigurationPtr c) : config(std::move(c)) { } +ServiceServer::ServiceServer(NetFS::Daemon::ConfigurationPtr c) : + userLookup(std::make_shared<UserEntCache>()), groupLookup(std::make_shared<GroupEntCache>(userLookup)), + config(std::move(c)) +{ +} NetFS::VolumePrxPtr ServiceServer::connect(const std::string share, const std::string authtoken, const Ice::Current & ice) diff --git a/netfs/daemon/daemonService.h b/netfs/daemon/daemonService.h index e0f80ef..753583e 100644 --- a/netfs/daemon/daemonService.h +++ b/netfs/daemon/daemonService.h @@ -2,7 +2,8 @@ #define DAEMONSERVICE_H #include <daemonConfig.h> -#include <entCache.h> +#include <entries.h> +#include <entryResolver.h> #include <service.h> class ServiceServer : public NetFS::Service { @@ -12,8 +13,8 @@ public: NetFS::VolumePrxPtr connect(const std::string share, const std::string auth, const Ice::Current &) override; private: - EntCache<User> userLookup; - EntCache<Group> groupLookup; + EntryResolverPtr<User> userLookup; + EntryResolverPtr<Group> groupLookup; NetFS::Daemon::ConfigurationPtr config; }; diff --git a/netfs/daemon/daemonVolume.cpp b/netfs/daemon/daemonVolume.cpp index 3ae43da..ff75e06 100644 --- a/netfs/daemon/daemonVolume.cpp +++ b/netfs/daemon/daemonVolume.cpp @@ -7,6 +7,7 @@ #include <boost/algorithm/string/predicate.hpp> #include <cerrno> #include <climits> +#include <defaultMapper.h> #include <entCache.h> #include <fcntl.h> #include <map> @@ -15,8 +16,10 @@ extern std::map<Ice::Int, int> files; -VolumeServer::VolumeServer(const std::filesystem::path & r, const EntCache<User> & u, const EntCache<Group> & g) : - root(std::filesystem::canonical(r)), userLookup(u), groupLookup(g), converter(u, g) +VolumeServer::VolumeServer( + const std::filesystem::path & r, const EntryResolverPtr<User> & u, const EntryResolverPtr<Group> & g) : + root(std::filesystem::canonical(r)), + userLookup(*u), groupLookup(*g), converter(std::make_shared<NetFS::Mapping::DefaultMapper>(u, g)) { } diff --git a/netfs/daemon/daemonVolume.h b/netfs/daemon/daemonVolume.h index b75c5d6..649d8c2 100644 --- a/netfs/daemon/daemonVolume.h +++ b/netfs/daemon/daemonVolume.h @@ -1,7 +1,8 @@ #ifndef DAEMONVOLUME_H #define DAEMONVOLUME_H -#include <entCache.h> +#include <entries.h> +#include <entryResolver.h> #include <filesystem> #include <shared_mutex> #include <typeConverter.h> @@ -9,7 +10,7 @@ class VolumeServer : public NetFS::Volume { public: - VolumeServer(const std::filesystem::path & root, const EntCache<User> &, const EntCache<Group> &); + VolumeServer(const std::filesystem::path & root, const EntryResolverPtr<User> &, const EntryResolverPtr<Group> &); NetFS::DirectoryPrxPtr opendir(const NetFS::ReqEnv, std::string path, const Ice::Current &) override; @@ -47,8 +48,8 @@ protected: private: const std::filesystem::path root; - const EntCache<User> & userLookup; - const EntCache<Group> & groupLookup; + EntryResolver<User> & userLookup; + EntryResolver<Group> & groupLookup; EntryTypeConverter converter; }; diff --git a/netfs/daemon/modeCheck.cpp b/netfs/daemon/modeCheck.cpp index 49cea44..d63163a 100644 --- a/netfs/daemon/modeCheck.cpp +++ b/netfs/daemon/modeCheck.cpp @@ -1,9 +1,8 @@ #include "modeCheck.h" -#include <entCache.h> #include <exceptions.h> -ModeCheck::ModeCheck(const NetFS::ReqEnv & re, const std::filesystem::path & r, const EntCache<User> & u, - const EntCache<Group> & g) : +ModeCheck::ModeCheck(const NetFS::ReqEnv & re, const std::filesystem::path & r, const EntryResolver<User> & u, + const EntryResolver<Group> & g) : myu(u.getEntry(re.user)->id), myg(g.getEntry(re.grp)->id), root(r), userLookup(u), groupLookup(g) { diff --git a/netfs/daemon/modeCheck.h b/netfs/daemon/modeCheck.h index 693ad8d..6365816 100644 --- a/netfs/daemon/modeCheck.h +++ b/netfs/daemon/modeCheck.h @@ -1,14 +1,16 @@ #ifndef NETFS_DAEMON_IOHELPERS #define NETFS_DAEMON_IOHELPERS -#include <entCache.h> +#include <entries.h> +#include <entryResolver.h> #include <filesystem> #include <sys/stat.h> #include <types.h> class ModeCheck { public: - ModeCheck(const NetFS::ReqEnv & re, const std::filesystem::path &, const EntCache<User> &, const EntCache<Group> &); + ModeCheck(const NetFS::ReqEnv & re, const std::filesystem::path &, const EntryResolver<User> &, + const EntryResolver<Group> &); void AssertReadParent(const std::filesystem::path &) const; void AssertRead(const std::filesystem::path &) const; @@ -27,8 +29,8 @@ public: private: static struct stat lstat(const std::filesystem::path &); - const EntCache<User> & userLookup; - const EntCache<Group> & groupLookup; + const EntryResolver<User> & userLookup; + const EntryResolver<Group> & groupLookup; }; #endif diff --git a/netfs/fuse/Jamfile.jam b/netfs/fuse/Jamfile.jam index 14338d5..4d000be 100644 --- a/netfs/fuse/Jamfile.jam +++ b/netfs/fuse/Jamfile.jam @@ -1,34 +1,48 @@ import package ; lib Glacier2 : : <name>Glacier2++11 ; +constant FUSE_VER : 35 ; + +rule iceobj ( name : ice ) { + obj $(name) : $(ice) : + <toolset>tidy:<checker>none + <library>../ice//netfs-api + <implicit-dependency>../ice//netfs-api + <library>..//slicer + <include>. + ; +} +iceobj fuseConfig : fuseConfig.ice ; +iceobj fuseMappers : fuseMappers.ice ; -obj fuseConfig : fuseConfig.ice : - <toolset>tidy:<checker>none - <library>../ice//netfs-api - <implicit-dependency>../ice//netfs-api -; lib netfs-client-configuration : fuseConfig + fuseMappers fuseConfig.ice + fuseMappers.ice fuseConfigImpl.cpp + fuseMappersImpl.cpp : <slicer>pure <library>../ice//netfs-api + <library>../lib//netfs-common <implicit-dependency>../ice//netfs-api <implicit-dependency>fuseConfig <library>..//Ice <library>..//slicer <library>..//adhocutil + <include>. : : <library>..//Ice <library>..//slicer + <include>. ; lib netfs-client : netfs-client-configuration [ glob *.cpp : fuseConfigImpl.cpp netfs.cpp ] : - <define>FUSE_USE_VERSION=35 + <define>FUSE_USE_VERSION=$(FUSE_VER) <implicit-dependency>../ice//netfs-api <library>netfs-client-configuration <implicit-dependency>netfs-client-configuration @@ -42,7 +56,7 @@ lib netfs-client : <library>..//slicer-xml <use>../..//fuse : : - <define>FUSE_USE_VERSION=31 + <define>FUSE_USE_VERSION=$(FUSE_VER) <include>. <library>../ice//netfs-api <library>Glacier2 diff --git a/netfs/fuse/fuseApp.cpp b/netfs/fuse/fuseApp.cpp index 41f86ef..b6d59b1 100644 --- a/netfs/fuse/fuseApp.cpp +++ b/netfs/fuse/fuseApp.cpp @@ -2,11 +2,13 @@ #include "cache.impl.h" #include "fuseDirs.h" #include "fuseFiles.h" +#include "fuseMappersImpl.h" #include "lockHelpers.h" #include <Glacier2/Router.h> #include <boost/lexical_cast.hpp> #include <compileTimeFormatter.h> #include <cstring> +#include <defaultMapper.h> #include <entCache.h> #include <safeMapFind.h> #include <slicer/slicer.h> @@ -17,10 +19,7 @@ namespace AdHoc { template class CallCacheable<struct stat, std::string>; } -NetFS::FuseApp::FuseApp(Ice::StringSeq && a) : - iceArgs(std::move(a)), sessionOpened(false), openHandleId(0), converter(userLookup, groupLookup) -{ -} +NetFS::FuseApp::FuseApp(Ice::StringSeq && a) : iceArgs(std::move(a)), sessionOpened(false), openHandleId(0) { } NetFS::FuseApp::~FuseApp() { @@ -80,7 +79,11 @@ NetFS::FuseApp::init(struct fuse_conn_info *, struct fuse_config *) fcr = configureFromFile(arg.substr(0, colon), arg.substr(colon + 1)); } } + if (!fcr->Mapper) { + fcr->Mapper = std::make_shared<Mapping::DefaultMapper>(); + } BOOST_ASSERT(fcr); + converter.mapper = fcr->Mapper; return this; } @@ -109,7 +112,26 @@ NetFS::FuseApp::configureFromUri(const std::string & uriString) setting = boost::lexical_cast<std::remove_reference_t<decltype(setting)>>(p->second); } }; + auto setWith = [&uri](const auto & param, auto & setting, auto && f) { + if (auto p = uri.query.find(param); p != uri.query.end()) { + setting = f(p->second); + } + }; set("async", r->Async); + setWith("mapper", r->Mapper, [&set, &setWith](auto && m) -> NetFS::Mapping::MapperPtr { + if (m == "hide") { + return std::make_shared<NetFS::Client::HideUnknownMapperImpl>(); + } + else if (m == "mask") { + auto mi = std::make_shared<NetFS::Client::MaskUnknownMapperImpl>(); + set("mapper.unknownuser", mi->UnknownUser); + set("mapper.unknowngroup", mi->UnknownGroup); + setWith("mapper.usermask", mi->UserMask, Client::from_octal); + setWith("mapper.groupmask", mi->GroupMask, Client::from_octal); + return mi; + } + return {}; + }); return r; } @@ -274,8 +296,6 @@ NetFS::ReqEnv NetFS::FuseApp::reqEnv() { struct fuse_context * c = fuse_get_context(); - NetFS::ReqEnv re; - userLookup.getName(c->uid, &re.user); - groupLookup.getName(c->gid, &re.grp); - return re; + const auto t = converter.mapper->mapFileSystem(c->uid, c->gid); + return {t.username, t.groupname}; } diff --git a/netfs/fuse/fuseApp.h b/netfs/fuse/fuseApp.h index 80deed2..9eafb7f 100644 --- a/netfs/fuse/fuseApp.h +++ b/netfs/fuse/fuseApp.h @@ -111,8 +111,6 @@ namespace NetFS { OpenFiles openFiles; int openHandleId; - EntCache<User> userLookup; - EntCache<Group> groupLookup; EntryTypeConverter converter; using StatCache = AdHoc::Cache<struct stat, std::string>; diff --git a/netfs/fuse/fuseApp.impl.h b/netfs/fuse/fuseApp.impl.h index e433ee7..9947f36 100644 --- a/netfs/fuse/fuseApp.impl.h +++ b/netfs/fuse/fuseApp.impl.h @@ -12,8 +12,7 @@ namespace NetFS { { auto & map = getMap<Handle>(); Lock(_proxymaplock); - while (map.find(fh = ++openHandleId) != map.end()) - ; + while (map.find(fh = ++openHandleId) != map.end()) { } map.emplace(fh, std::make_shared<typename Handle::element_type>(params...)); } diff --git a/netfs/fuse/fuseConfig.ice b/netfs/fuse/fuseConfig.ice index 52116ea..ea489ac 100644 --- a/netfs/fuse/fuseConfig.ice +++ b/netfs/fuse/fuseConfig.ice @@ -1,4 +1,5 @@ #include <exceptions.ice> +#include <mapper.ice> module NetFS { module Client { @@ -20,6 +21,9 @@ module NetFS { ["slicer:name:async"] bool Async = false; + + ["slicer:name:mapper"] + Mapping::Mapper Mapper; }; ["slicer:key:name","slicer:value:resource","slicer:item:resource"] diff --git a/netfs/fuse/fuseDirs.cpp b/netfs/fuse/fuseDirs.cpp index c1a91bd..d23f5d7 100644 --- a/netfs/fuse/fuseDirs.cpp +++ b/netfs/fuse/fuseDirs.cpp @@ -50,13 +50,16 @@ namespace NetFS { auto expiry = time(nullptr) + 2; if (flags == FUSE_READDIR_PLUS) { for (const auto & e : od->remote->listdir()) { - filler(buf, e.first.c_str(), nullptr, 0, FUSE_FILL_DIR_PLUS); - std::string k(path + e.first); - statCache.remove(k); - statCache.add(k, converter.convert(e.second), expiry); + if (auto stat = converter.convert(e.second); stat.st_mode) { + filler(buf, e.first.c_str(), nullptr, 0, FUSE_FILL_DIR_PLUS); + std::string k(path + e.first); + statCache.remove(k); + statCache.add(k, std::move(stat), expiry); + } } } else { + // Standard read dir cannot know the local system cannot represent the inode for (const auto & e : od->remote->readdir()) { filler(buf, e.c_str(), nullptr, 0, (fuse_fill_dir_flags)0); } diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp index 0a59252..8014732 100644 --- a/netfs/fuse/fuseFiles.cpp +++ b/netfs/fuse/fuseFiles.cpp @@ -256,7 +256,7 @@ namespace NetFS { *s = converter.convert(volume->getattr(reqEnv(), p)); } } - return 0; + return s->st_mode ? 0 : -ENOENT; } catch (SystemError & e) { return -e.syserrno; diff --git a/netfs/fuse/fuseMappers.ice b/netfs/fuse/fuseMappers.ice new file mode 100644 index 0000000..0eb5ea5 --- /dev/null +++ b/netfs/fuse/fuseMappers.ice @@ -0,0 +1,23 @@ +#include <mapper.ice> + +["slicer:include:fuseMappersImpl.h"] +module NetFS { + module Client { + ["slicer:implementation:NetFS.Client.HideUnknownMapperImpl","slicer:typename:hide"] + local class HideUnknownMapper extends Mapping::Mapper { + + }; + ["slicer:implementation:NetFS.Client.MaskUnknownMapperImpl","slicer:typename:mask"] + local class MaskUnknownMapper extends Mapping::Mapper { + ["slicer:name:unknownuser"] + string UnknownUser = "nobody"; + ["slicer:name:unknowngroup"] + string UnknownGroup = "nogroup"; + ["slicer:name:usermask","slicer:conversion:std.string:NetFS.Client.from_octal:NetFS.Client.to_octal:nodeclare"] + int UserMask = 0700; + ["slicer:name:groupmask","slicer:conversion:std.string:NetFS.Client.from_octal:NetFS.Client.to_octal:nodeclare"] + int GroupMask = 0070; + }; + }; +}; + diff --git a/netfs/fuse/fuseMappersImpl.cpp b/netfs/fuse/fuseMappersImpl.cpp new file mode 100644 index 0000000..c7fef9e --- /dev/null +++ b/netfs/fuse/fuseMappersImpl.cpp @@ -0,0 +1,74 @@ +#include "fuseMappersImpl.h" +#include <entCache.h> + +namespace NetFS::Client { + constexpr int MASK_EVERYTHING = ~0; + static_assert(MASK_EVERYTHING == static_cast<int>(0xFFFFFFFF)); + + Mapping::FileSystem + HideUnknownMapperImpl::mapTransport(const std::string & un, const std::string & gn) + { + auto u = users->getEntry(un); + auto g = groups->getEntry(gn); + if (!u || !g) { + return {0, 0, MASK_EVERYTHING}; + } + return {static_cast<int>(u->id), static_cast<int>(g->id), 0}; + } + + Mapping::Transport + HideUnknownMapperImpl::mapFileSystem(int uid, int gid) + { + auto u = users->getEntry(uid); + auto g = groups->getEntry(gid); + if (!u || !g) { + throw NetFS::SystemError(EPERM); + } + return {u->name, g->name, 0}; + } + + Mapping::FileSystem + MaskUnknownMapperImpl::mapTransport(const std::string & un, const std::string & gn) + { + int mask = 0; + auto apply = [&mask](const auto & resolver, const auto & entry, const auto & fallbackentry, auto entrymask) { + auto e = resolver->getEntry(entry); + if (!e) { + e = resolver->getEntry(fallbackentry); + if (!e) { + throw NetFS::SystemError(EPERM); + } + mask |= entrymask; + } + return e; + }; + auto u = apply(users, un, UnknownUser, UserMask); + auto g = apply(groups, gn, UnknownGroup, GroupMask); + return {static_cast<int>(u->id), static_cast<int>(g->id), mask}; + } + + Mapping::Transport + MaskUnknownMapperImpl::mapFileSystem(int uid, int gid) + { + auto u = users->getEntry(uid); + auto g = groups->getEntry(gid); + if (!u || !g) { + throw NetFS::SystemError(EPERM); + } + return {u->name, g->name, 0}; + } + + Ice::Int + from_octal(const std::string & in) + { + return std::stoi(in, nullptr, 8); + } + + std::string + to_octal(const Ice::Int & in) + { + std::stringstream s; + s << std::oct << in; + return s.str(); + } +} diff --git a/netfs/fuse/fuseMappersImpl.h b/netfs/fuse/fuseMappersImpl.h new file mode 100644 index 0000000..fd9e2aa --- /dev/null +++ b/netfs/fuse/fuseMappersImpl.h @@ -0,0 +1,33 @@ +#ifndef NETFS_MAPPING_CLIENTIMPL_H +#define NETFS_MAPPING_CLIENTIMPL_H + +#include "baseMapper.h" +#include "entries.h" +#include "entryResolver.h" +#include <fuseMappers.h> +#include <visibility.h> + +namespace NetFS { + namespace Client { + std::string to_octal(const Ice::Int &); + Ice::Int from_octal(const std::string &); + + class DLL_PUBLIC HideUnknownMapperImpl : public HideUnknownMapper, Mapping::BaseMapper { + public: + using BaseMapper::BaseMapper; + + Mapping::Transport mapFileSystem(int uid, int gid) override; + Mapping::FileSystem mapTransport(const std::string & un, const std::string & gn) override; + }; + + class DLL_PUBLIC MaskUnknownMapperImpl : public MaskUnknownMapper, Mapping::BaseMapper { + public: + using BaseMapper::BaseMapper; + + Mapping::Transport mapFileSystem(int uid, int gid) override; + Mapping::FileSystem mapTransport(const std::string & un, const std::string & gn) override; + }; + } +} + +#endif diff --git a/netfs/ice/Jamfile.jam b/netfs/ice/Jamfile.jam index cfb4f14..a695712 100644 --- a/netfs/ice/Jamfile.jam +++ b/netfs/ice/Jamfile.jam @@ -6,14 +6,18 @@ obj file : file.ice : <toolset>tidy:<checker>none ; obj service : service.ice : <toolset>tidy:<checker>none ; obj types : types.ice : <toolset>tidy:<checker>none ; obj volume : volume.ice : <toolset>tidy:<checker>none ; -alias gen : directory exceptions file service types volume ; +obj mapper : mapper.ice : <toolset>tidy:<checker>none ; +alias gen : directory exceptions file service types volume mapper ; lib netfs-api : gen + mapper.ice [ glob *.cpp ] : <library>..//Ice <library>..//pthread <library>..//adhocutil + <library>..//slicer <implicit-dependency>gen + <slicer>pure : : <include>. <library>..//Ice diff --git a/netfs/ice/entryResolver.h b/netfs/ice/entryResolver.h deleted file mode 100644 index 973af4c..0000000 --- a/netfs/ice/entryResolver.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef NETFS_ENTRYRESOLVER_H -#define NETFS_ENTRYRESOLVER_H - -#include <cstdint> -#include <unistd.h> - -enum class ResolvedAs : uint8_t { - Real, - Fallback, -}; - -template<typename id_t, typename name_t> class EntryResolver { -public: - virtual ~EntryResolver() = default; - - virtual ResolvedAs getID(const name_t &, id_t *) const = 0; - virtual ResolvedAs getName(const id_t &, name_t *) const = 0; -}; - -#endif diff --git a/netfs/ice/mapper.ice b/netfs/ice/mapper.ice new file mode 100644 index 0000000..505b53a --- /dev/null +++ b/netfs/ice/mapper.ice @@ -0,0 +1,32 @@ +#ifndef _MAPPER +#define _MAPPER + +#include "exceptions.ice" + +module NetFS { + module Mapping { + ["slicer:ignore"] + local struct Transport { + string username; + string groupname; + int mask; + }; + + ["slicer:ignore"] + local struct FileSystem { + int uid; + int gid; + int mask; + }; + + ["slicer:typename:default","slicer:typeid:type"] + local class Mapper { + Transport mapFileSystem(int uid, int gid) throws SystemError; + FileSystem mapTransport(string un, string gn) throws SystemError; + }; + }; + +} + +#endif + diff --git a/netfs/ice/typeConverter.cpp b/netfs/ice/typeConverter.cpp index e365c5d..b1ade2b 100644 --- a/netfs/ice/typeConverter.cpp +++ b/netfs/ice/typeConverter.cpp @@ -1,7 +1,7 @@ #include "typeConverter.h" #include <boost/numeric/conversion/cast.hpp> -EntryTypeConverter::EntryTypeConverter(const UserLookup & u, const GroupLookup & g) : userLookup(u), groupLookup(g) { } +EntryTypeConverter::EntryTypeConverter(NetFS::Mapping::MapperPtr m) : mapper(std::move(m)) { } // Wrapper function to assure no unexpected corruption occurs // during narrowing assignments. @@ -16,14 +16,15 @@ safeAssign(T & t, const S & s) struct stat EntryTypeConverter::convert(const NetFS::Attr & a) const { + auto map = mapper->mapTransport(a.uid, a.gid); struct stat s { }; s.st_dev = a.dev; s.st_ino = a.inode; - s.st_mode = a.mode; + s.st_mode = a.mode & ~map.mask; s.st_nlink = a.links; - userLookup.getID(a.uid, &s.st_uid); - groupLookup.getID(a.gid, &s.st_gid); + s.st_uid = map.uid; + s.st_gid = map.gid; s.st_rdev = a.rdev; s.st_size = a.size; s.st_blksize = a.blockSize; @@ -62,13 +63,14 @@ TypeConverter::convert(const NetFS::VFS & v) const NetFS::Attr EntryTypeConverter::convert(const struct stat & s) const { + auto map = mapper->mapFileSystem(s.st_uid, s.st_gid); NetFS::Attr a {}; a.dev = s.st_dev; a.inode = s.st_ino; - a.mode = s.st_mode; + safeAssign(a.mode, s.st_mode & ~map.mask); a.links = s.st_nlink; - userLookup.getName(s.st_uid, &a.uid); - groupLookup.getName(s.st_gid, &a.gid); + a.uid = std::move(map.username); + a.gid = std::move(map.groupname); a.rdev = s.st_rdev; a.size = s.st_size; a.blockSize = s.st_blksize; diff --git a/netfs/ice/typeConverter.h b/netfs/ice/typeConverter.h index 3cd2941..0baff2b 100644 --- a/netfs/ice/typeConverter.h +++ b/netfs/ice/typeConverter.h @@ -1,7 +1,7 @@ #ifndef NETFS_TYPECONVERT_H #define NETFS_TYPECONVERT_H -#include "entryResolver.h" +#include <mapper.h> #include <sys/stat.h> #include <sys/statvfs.h> #include <types.h> @@ -16,17 +16,14 @@ public: class DLL_PUBLIC EntryTypeConverter : public TypeConverter { public: - using UserLookup = EntryResolver<uid_t, std::string>; - using GroupLookup = EntryResolver<gid_t, std::string>; - EntryTypeConverter(const UserLookup &, const GroupLookup &); + EntryTypeConverter() = default; + EntryTypeConverter(NetFS::Mapping::MapperPtr); // Attributes struct stat convert(const NetFS::Attr &) const; NetFS::Attr convert(const struct stat &) const; -protected: - const UserLookup & userLookup; - const GroupLookup & groupLookup; + NetFS::Mapping::MapperPtr mapper; }; #endif diff --git a/netfs/lib/baseMapper.cpp b/netfs/lib/baseMapper.cpp new file mode 100644 index 0000000..c3518e4 --- /dev/null +++ b/netfs/lib/baseMapper.cpp @@ -0,0 +1,13 @@ +#include "baseMapper.h" +#include "entCache.h" + +namespace NetFS::Mapping { + BaseMapper::BaseMapper() : BaseMapper(std::make_shared<UserEntCache>()) { } + + BaseMapper::BaseMapper(EntryResolverPtr<User> u) : BaseMapper(std::move(u), std::make_shared<GroupEntCache>(u)) { } + + BaseMapper::BaseMapper(EntryResolverPtr<User> u, EntryResolverPtr<Group> g) : + users(std::move(u)), groups(std::move(g)) + { + } +} diff --git a/netfs/lib/baseMapper.h b/netfs/lib/baseMapper.h new file mode 100644 index 0000000..c3bd46e --- /dev/null +++ b/netfs/lib/baseMapper.h @@ -0,0 +1,23 @@ +#ifndef NETFS_MAPPING_BASEIMPL_H +#define NETFS_MAPPING_BASEIMPL_H + +#include "entries.h" +#include "entryResolver.h" +#include <mapper.h> + +namespace NetFS { + namespace Mapping { + class BaseMapper { + public: + BaseMapper(); + BaseMapper(EntryResolverPtr<User> users); + BaseMapper(EntryResolverPtr<User> users, EntryResolverPtr<Group> groups); + + protected: + EntryResolverPtr<User> users; + EntryResolverPtr<Group> groups; + }; + } +} + +#endif diff --git a/netfs/lib/defaultMapper.cpp b/netfs/lib/defaultMapper.cpp new file mode 100644 index 0000000..c57f340 --- /dev/null +++ b/netfs/lib/defaultMapper.cpp @@ -0,0 +1,26 @@ +#include "defaultMapper.h" +#include <exceptions.h> + +namespace NetFS::Mapping { + FileSystem + DefaultMapper::mapTransport(const std::string & un, const std::string & gn) + { + auto u = users->getEntry(un); + auto g = groups->getEntry(gn); + if (!u || !g) { + throw NetFS::SystemError(EPERM); + } + return {static_cast<int>(u->id), static_cast<int>(g->id), 0}; + } + + Transport + DefaultMapper::mapFileSystem(int uid, int gid) + { + auto u = users->getEntry(uid); + auto g = groups->getEntry(gid); + if (!u || !g) { + throw NetFS::SystemError(EPERM); + } + return {u->name, g->name, 0}; + } +} diff --git a/netfs/lib/defaultMapper.h b/netfs/lib/defaultMapper.h new file mode 100644 index 0000000..9f063a8 --- /dev/null +++ b/netfs/lib/defaultMapper.h @@ -0,0 +1,21 @@ +#ifndef NETFS_MAPPING_DEFAULTIMPL_H +#define NETFS_MAPPING_DEFAULTIMPL_H + +#include "baseMapper.h" +#include "entries.h" +#include "entryResolver.h" +#include <mapper.h> + +namespace NetFS { + namespace Mapping { + class DefaultMapper : public Mapper, BaseMapper { + public: + using BaseMapper::BaseMapper; + + Transport mapFileSystem(int uid, int gid) override; + FileSystem mapTransport(const std::string & un, const std::string & gn) override; + }; + } +} + +#endif diff --git a/netfs/lib/entCache.cpp b/netfs/lib/entCache.cpp index d9f61df..a2ea685 100644 --- a/netfs/lib/entCache.cpp +++ b/netfs/lib/entCache.cpp @@ -1,9 +1,46 @@ #include "entCache.impl.h" - -static_assert(std::is_nothrow_move_constructible_v<User>); -static_assert(std::is_nothrow_move_assignable_v<User>); -static_assert(std::is_nothrow_move_constructible_v<Group>); -static_assert(std::is_nothrow_move_assignable_v<Group>); +#include "entries.h" template class EntCache<User>; template class EntCache<Group>; + +const int BUFLEN = 8196; + +void +UserEntCache::fillCache() const noexcept +{ + setpwent(); + idcache->clear(); + std::array<char, BUFLEN> buf {}; + struct passwd pwbuf { + }, *pwp; + while (getpwent_r(&pwbuf, buf.data(), buf.size(), &pwp) == 0) { + idcache->insert(std::make_shared<User>(pwp->pw_uid, pwp->pw_name, pwp->pw_gid)); + } + endpwent(); + time(&fillTime); +} + +GroupEntCache::GroupEntCache(EntryResolverPtr<User> u) : users(std::move(u)) { } + +void +GroupEntCache::fillCache() const noexcept +{ + setgrent(); + std::array<char, BUFLEN> buf {}; + idcache->clear(); + struct group grpbuf { + }, *grp; + while (getgrent_r(&grpbuf, buf.data(), buf.size(), &grp) == 0) { + auto g = std::make_shared<Group>(grp->gr_gid, grp->gr_name); + for (auto member = grp->gr_mem; *member; member++) { + if (auto ent = users->getEntry(*member)) { + g->members.insert(ent->id); + } + } + g->members.insert(g->id); + idcache->insert(std::move(g)); + } + endgrent(); + time(&fillTime); +} diff --git a/netfs/lib/entCache.h b/netfs/lib/entCache.h index 6024d17..7c8567a 100644 --- a/netfs/lib/entCache.h +++ b/netfs/lib/entCache.h @@ -1,37 +1,16 @@ #ifndef ENTCACHE_H #define ENTCACHE_H +#include "entries.h" +#include "entryResolver.h" #include <c++11Helpers.h> -#include <entryResolver.h> #include <memory> -#include <set> #include <shared_mutex> -#include <string> -class User { -public: - User(uid_t, std::string, gid_t); - uid_t id; - std::string name; - gid_t group; -}; - -class Group { -public: - Group(gid_t, std::string); - - bool hasMember(uid_t) const; - - gid_t id; - std::string name; - std::set<uid_t> members; -}; - -template<class entry_t> class EntCache : public EntryResolver<decltype(entry_t::id), decltype(entry_t::name)> { +template<class entry_t> class EntCache : public EntryResolver<entry_t> { public: EntCache(); - EntCache(entry_t fb); - ~EntCache() override; + ~EntCache() noexcept override; SPECIAL_MEMBERS_DEFAULT_MOVE_NO_COPY(EntCache); @@ -39,30 +18,37 @@ public: using name_t = decltype(entry_t::name); using entry_ptr = std::shared_ptr<entry_t>; - struct Resolution : public entry_ptr { - Resolution(entry_ptr, ResolvedAs = ResolvedAs::Real); - ResolvedAs resolution; + [[nodiscard]] entry_ptr inline getEntry(const id_t & i) const noexcept override + { + return getEntryInternal<id_t>(i); + } + [[nodiscard]] entry_ptr inline getEntry(const name_t & n) const noexcept override + { + return getEntryInternal<name_t>(n); }; - ResolvedAs getID(const name_t &, id_t *) const override; - ResolvedAs getName(const id_t &, name_t *) const override; - template<class key_t> Resolution getEntry(const key_t &) const; - - void setFallback(entry_t fb); - void clearFallback(); - protected: - void fillCache() const; - template<class key_t> entry_ptr getEntryNoFill(const key_t &) const; + virtual void fillCache() const noexcept = 0; + template<class key_t> [[nodiscard]] entry_ptr getEntryInternal(const key_t &) const noexcept; + template<class key_t> [[nodiscard]] entry_ptr getEntryNoFill(const key_t &) const noexcept; class Ids; std::unique_ptr<Ids> idcache; mutable std::shared_mutex lock; mutable time_t fillTime {0}; - entry_ptr fallback; }; -using UserEntCache = EntCache<User>; -using GroupEntCache = EntCache<Group>; +class UserEntCache : public EntCache<User> { + void fillCache() const noexcept override; +}; + +class GroupEntCache : public EntCache<Group> { +public: + GroupEntCache(EntryResolverPtr<User>); + +private: + void fillCache() const noexcept override; + EntryResolverPtr<User> users; +}; #endif diff --git a/netfs/lib/entCache.impl.h b/netfs/lib/entCache.impl.h index 37aecfd..96bf4eb 100644 --- a/netfs/lib/entCache.impl.h +++ b/netfs/lib/entCache.impl.h @@ -2,12 +2,13 @@ #define ENTCACHE_IMPL_H #include "entCache.h" +#include "entries.h" #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> #include <boost/multi_index_container.hpp> -#include <exceptions.h> #include <grp.h> #include <lockHelpers.h> +#include <mutex> #include <pwd.h> #include <type_traits> @@ -21,41 +22,12 @@ class EntCache<entry_t>::Ids : }; template<class entry_t> EntCache<entry_t>::EntCache() : idcache(std::make_unique<Ids>()) { } - -template<class entry_t> EntCache<entry_t>::EntCache(entry_t fb) : idcache(std::make_unique<Ids>()) -{ - setFallback(std::move(fb)); -} - -template<class entry_t> EntCache<entry_t>::~EntCache() = default; - -template<class entry_t> -ResolvedAs -EntCache<entry_t>::getID(const EntCache<entry_t>::name_t & u, EntCache<entry_t>::id_t * target) const -{ - auto e = getEntry(u); - *target = e->id; - return e.resolution; -} - -template<class entry_t> -ResolvedAs -EntCache<entry_t>::getName(const EntCache<entry_t>::id_t & u, EntCache<entry_t>::name_t * target) const -{ - auto e = getEntry(u); - *target = e->name; - return e.resolution; -} - -template<class entry_t> -EntCache<entry_t>::Resolution::Resolution(entry_ptr e, ResolvedAs res) : entry_ptr(std::move(e)), resolution(res) -{ -} +template<class entry_t> EntCache<entry_t>::~EntCache() noexcept = default; template<class entry_t> template<class key_t> -typename EntCache<entry_t>::Resolution -EntCache<entry_t>::getEntry(const key_t & key) const +typename EntCache<entry_t>::entry_ptr +EntCache<entry_t>::getEntryInternal(const key_t & key) const noexcept { SharedScopeLock(lock) { if (fillTime + 60 > time(nullptr)) { @@ -70,16 +42,13 @@ EntCache<entry_t>::getEntry(const key_t & key) const return ent; } } - if (fallback) { - return {fallback, ResolvedAs::Fallback}; - } - throw NetFS::SystemError(EPERM); + return getEntryNoFill<key_t>(key); } template<class entry_t> template<class key_t> typename EntCache<entry_t>::entry_ptr -EntCache<entry_t>::getEntryNoFill(const key_t & key) const +EntCache<entry_t>::getEntryNoFill(const key_t & key) const noexcept { auto & collection = idcache->template get<key_t>(); auto i = collection.find(key); @@ -89,67 +58,4 @@ EntCache<entry_t>::getEntryNoFill(const key_t & key) const return nullptr; } -template<typename entry_t> -void -EntCache<entry_t>::setFallback(entry_t fb) -{ - fallback = std::make_shared<entry_t>(std::move(fb)); -} - -template<typename entry_t> -void -EntCache<entry_t>::clearFallback() -{ - fallback.reset(); -} - -User::User(uid_t u, std::string n, gid_t g) : id(u), name(std::move(n)), group(g) { } - -template<> -void -EntCache<User>::fillCache() const -{ - setpwent(); - idcache->clear(); - std::array<char, BUFSIZ> buf {}; - passwd pwbuf {}, *pwp; - while (getpwent_r(&pwbuf, buf.data(), buf.size(), &pwp) == 0) { - idcache->insert(std::make_shared<User>(pwp->pw_uid, pwp->pw_name, pwp->pw_gid)); - } - endpwent(); - time(&fillTime); -} - -Group::Group(gid_t g, std::string n) : id(g), name(std::move(n)) { } - -template<> -void -EntCache<Group>::fillCache() const -{ - setgrent(); - std::array<char, BUFSIZ> buf {}; - idcache->clear(); - group grpbuf {}, *grp; - EntCache<User> instance; - while (getgrent_r(&grpbuf, buf.data(), buf.size(), &grp) == 0) { - auto g = std::make_shared<Group>(grp->gr_gid, grp->gr_name); - for (auto member = grp->gr_mem; *member; member++) { - try { - g->members.insert(instance.getEntry((const name_t &)*member)->id); - } - catch (const NetFS::SystemError &) { - } - } - idcache->insert(std::move(g)); - } - endgrent(); - time(&fillTime); -} - -bool -Group::hasMember(uid_t u) const -{ - return (members.find(u) != members.end()); -} - #endif diff --git a/netfs/lib/entries.cpp b/netfs/lib/entries.cpp new file mode 100644 index 0000000..bde15e6 --- /dev/null +++ b/netfs/lib/entries.cpp @@ -0,0 +1,16 @@ +#include "entries.h" + +static_assert(std::is_nothrow_move_constructible_v<User>); +static_assert(std::is_nothrow_move_assignable_v<User>); +static_assert(std::is_nothrow_move_constructible_v<Group>); +static_assert(std::is_nothrow_move_assignable_v<Group>); + +User::User(uid_t u, std::string n, gid_t g) : id(u), name(std::move(n)), group(g) { } + +Group::Group(gid_t g, std::string n) : id(g), name(std::move(n)) { } + +bool +Group::hasMember(uid_t u) const noexcept +{ + return (members.find(u) != members.end()); +} diff --git a/netfs/lib/entries.h b/netfs/lib/entries.h new file mode 100644 index 0000000..6e032e1 --- /dev/null +++ b/netfs/lib/entries.h @@ -0,0 +1,27 @@ +#ifndef ENTRIES_H +#define ENTRIES_H + +#include <set> +#include <string> +#include <unistd.h> + +class User { +public: + User(uid_t, std::string, gid_t); + uid_t id; + std::string name; + gid_t group; +}; + +class Group { +public: + Group(gid_t, std::string); + + bool hasMember(uid_t) const noexcept; + + gid_t id; + std::string name; + std::set<uid_t> members; +}; + +#endif diff --git a/netfs/lib/entryResolver.h b/netfs/lib/entryResolver.h new file mode 100644 index 0000000..86aaace --- /dev/null +++ b/netfs/lib/entryResolver.h @@ -0,0 +1,17 @@ +#ifndef NETFS_ENTRYRESOLVER_H +#define NETFS_ENTRYRESOLVER_H + +#include <memory> + +template<typename entry_t> class EntryResolver { +public: + virtual ~EntryResolver() noexcept = default; + using EntryPtr = std::shared_ptr<entry_t>; + + virtual EntryPtr getEntry(const decltype(entry_t::id) &) const noexcept = 0; + virtual EntryPtr getEntry(const decltype(entry_t::name) &) const noexcept = 0; +}; + +template<typename entry_t> using EntryResolverPtr = std::shared_ptr<EntryResolver<entry_t>>; + +#endif diff --git a/netfs/unittests/Jamfile.jam b/netfs/unittests/Jamfile.jam index dcb2322..fc9d00b 100644 --- a/netfs/unittests/Jamfile.jam +++ b/netfs/unittests/Jamfile.jam @@ -79,13 +79,15 @@ run testLib.cpp <library>testMocks ; -# explicit testFuse ; run testFuse.cpp : -- : defaultDaemon.xml + defaultFuseHide.xml + defaultFuseMask.xml : <define>BOOST_TEST_DYN_LINK <library>boost_utf <library>testMocks + <dependency>testCore ; diff --git a/netfs/unittests/defaultFuseHide.xml b/netfs/unittests/defaultFuseHide.xml new file mode 100644 index 0000000..098a597 --- /dev/null +++ b/netfs/unittests/defaultFuseHide.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="ascii"?> +<config> + <resources> + <resource> + <name>testvol</name> + <resource> + <export>testvol</export> + <endpoints> + <endpoint>overridden</endpoint> + </endpoints> + <mapper type="hide"/> + </resource> + </resource> + </resources> +</config> diff --git a/netfs/unittests/defaultFuseMask.xml b/netfs/unittests/defaultFuseMask.xml new file mode 100644 index 0000000..5d45a53 --- /dev/null +++ b/netfs/unittests/defaultFuseMask.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="ascii"?> +<config> + <resources> + <resource> + <name>testvol</name> + <resource> + <export>testvol</export> + <endpoints> + <endpoint>overridden</endpoint> + </endpoints> + <mapper type="mask"> + <unknownuser>uu</unknownuser> + <unknowngroup>ug</unknowngroup> + <usermask>0100</usermask> + <groupmask>0010</groupmask> + </mapper> + </resource> + </resource> + </resources> +</config> diff --git a/netfs/unittests/testFuse.cpp b/netfs/unittests/testFuse.cpp index 0810fbf..b0603b0 100644 --- a/netfs/unittests/testFuse.cpp +++ b/netfs/unittests/testFuse.cpp @@ -7,6 +7,7 @@ #include <filesystem> #include <fuse.h> #include <fuseApp.h> +#include <fuseMappersImpl.h> #include <lockHelpers.h> #include <ostream> #include <thread> @@ -187,3 +188,51 @@ BOOST_AUTO_TEST_CASE(url_params_2) auto fcs = NetFS::FuseApp::configureFromUri("tcp://localhost/foo?0&async=0"); BOOST_CHECK_EQUAL(fcs->Async, false); } + +BOOST_AUTO_TEST_CASE(url_params_hide) +{ + auto fcs = NetFS::FuseApp::configureFromUri("tcp://localhost/foo?mapper=hide"); + BOOST_REQUIRE(fcs->Mapper); + BOOST_REQUIRE(std::dynamic_pointer_cast<NetFS::Client::HideUnknownMapperImpl>(fcs->Mapper)); +} + +BOOST_AUTO_TEST_CASE(url_params_mask_default) +{ + auto fcs = NetFS::FuseApp::configureFromUri("tcp://localhost/foo?mapper=mask"); + BOOST_REQUIRE(fcs->Mapper); + auto mapper = std::dynamic_pointer_cast<NetFS::Client::MaskUnknownMapperImpl>(fcs->Mapper); + BOOST_REQUIRE(mapper); +} + +BOOST_AUTO_TEST_CASE(url_params_mask_nondefault) +{ + auto fcs = NetFS::FuseApp::configureFromUri( + "tcp://localhost/" + "foo?mapper=mask&mapper.unknownuser=uu&mapper.unknowngroup=ug&mapper.usermask=0100&mapper.groupmask=0010"); + BOOST_REQUIRE(fcs->Mapper); + auto mapper = std::dynamic_pointer_cast<NetFS::Client::MaskUnknownMapperImpl>(fcs->Mapper); + BOOST_REQUIRE(mapper); + BOOST_CHECK_EQUAL(mapper->UnknownUser, "uu"); + BOOST_CHECK_EQUAL(mapper->UnknownGroup, "ug"); + BOOST_CHECK_EQUAL(mapper->UserMask, 0100); + BOOST_CHECK_EQUAL(mapper->GroupMask, 0010); +} + +BOOST_AUTO_TEST_CASE(config_file_hide) +{ + auto fcs = NetFS::FuseApp::configureFromFile(rootDir / "defaultFuseHide.xml", "testvol"); + BOOST_REQUIRE(fcs->Mapper); + BOOST_REQUIRE(std::dynamic_pointer_cast<NetFS::Client::HideUnknownMapperImpl>(fcs->Mapper)); +} + +BOOST_AUTO_TEST_CASE(config_file_mask) +{ + auto fcs = NetFS::FuseApp::configureFromFile(rootDir / "defaultFuseMask.xml", "testvol"); + BOOST_REQUIRE(fcs->Mapper); + auto mapper = std::dynamic_pointer_cast<NetFS::Client::MaskUnknownMapperImpl>(fcs->Mapper); + BOOST_REQUIRE(mapper); + BOOST_CHECK_EQUAL(mapper->UnknownUser, "uu"); + BOOST_CHECK_EQUAL(mapper->UnknownGroup, "ug"); + BOOST_CHECK_EQUAL(mapper->UserMask, 0100); + BOOST_CHECK_EQUAL(mapper->GroupMask, 0010); +} diff --git a/netfs/unittests/testLib.cpp b/netfs/unittests/testLib.cpp index ff82040..7c41340 100644 --- a/netfs/unittests/testLib.cpp +++ b/netfs/unittests/testLib.cpp @@ -1,36 +1,27 @@ #define BOOST_TEST_MODULE TestNetFSLib #include <boost/test/data/test_case.hpp> #include <boost/test/unit_test.hpp> +#include <defaultMapper.h> #include <entCache.impl.h> +#include <fuseMappersImpl.h> #include <lockHelpers.h> -/// @cond -namespace std { - ostream & - operator<<(ostream & strm, const ResolvedAs & r) - { - strm << (int)r; - return strm; - } -} -/// @endcond - struct TestEntry { TestEntry(int i, std::string n) : id(i), name(std::move(n)) { } int id; std::string name; }; -using TestEntCache = EntCache<TestEntry>; -template<> -void -EntCache<TestEntry>::fillCache() const -{ - idcache->insert(std::make_shared<TestEntry>(1, "user1")); - idcache->insert(std::make_shared<TestEntry>(2, "user2")); - idcache->insert(std::make_shared<TestEntry>(3, "user3")); -} +struct TestEntCache : public EntCache<TestEntry> { + void + fillCache() const noexcept + { + idcache->insert(std::make_shared<TestEntry>(1, "user1")); + idcache->insert(std::make_shared<TestEntry>(2, "user2")); + idcache->insert(std::make_shared<TestEntry>(3, "user3")); + } +}; const auto GoodIds = boost::unit_test::data::make({1, 2, 3}); const auto BadIds = boost::unit_test::data::make({0, -1, 10}); @@ -41,65 +32,175 @@ BOOST_FIXTURE_TEST_SUITE(tec, TestEntCache); BOOST_DATA_TEST_CASE(notfoundid, BadIds, id) { - std::string outname; - BOOST_CHECK_THROW(getName(id, &outname), NetFS::SystemError); + BOOST_CHECK(!getEntry(id)); } BOOST_DATA_TEST_CASE(notfoundname, BadNames, name) { - int outid; - BOOST_CHECK_THROW(getID(name, &outid), NetFS::SystemError); + BOOST_CHECK(!getEntry(name)); } BOOST_DATA_TEST_CASE(foundid, GoodNames ^ GoodIds, name, id) { - std::string outname; - BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Real); - BOOST_CHECK_EQUAL(name, outname); + BOOST_CHECK_EQUAL(getEntry(id)->name, name); } BOOST_DATA_TEST_CASE(foundname, GoodNames ^ GoodIds, name, id) { - int outid; - BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Real); - BOOST_CHECK_EQUAL(id, outid); + BOOST_CHECK_EQUAL(getEntry(name)->id, id); } BOOST_AUTO_TEST_SUITE_END(); -class TestEntCacheWithFallback : public TestEntCache { -public: - TestEntCacheWithFallback() : TestEntCache({4, "fallback"}) { } +BOOST_AUTO_TEST_CASE(group_membership) +{ + Group g(0, "root"); + g.members.insert(0); + g.members.insert(1); + g.members.insert(5); + + BOOST_REQUIRE_EQUAL(3, g.members.size()); + BOOST_CHECK(g.hasMember(0)); + BOOST_CHECK(g.hasMember(1)); + BOOST_CHECK(g.hasMember(5)); + BOOST_CHECK(!g.hasMember(3)); + BOOST_CHECK(!g.hasMember(6)); +} + +// These tests make some assumptions about local system users +BOOST_FIXTURE_TEST_CASE(usercache, UserEntCache) +{ + auto root = getEntry(0); + BOOST_REQUIRE(root); + BOOST_CHECK_EQUAL(root->id, 0); + BOOST_CHECK_EQUAL(root->name, "root"); + BOOST_CHECK_EQUAL(root->group, 0); + + auto rootByName = getEntry(root->name); + BOOST_REQUIRE_EQUAL(root, rootByName); +} + +struct TestGroupEntCache : public GroupEntCache { + TestGroupEntCache() : GroupEntCache(std::make_shared<UserEntCache>()) { } }; -BOOST_FIXTURE_TEST_SUITE(tecfb, TestEntCacheWithFallback); +BOOST_FIXTURE_TEST_CASE(groupcache, TestGroupEntCache) +{ + auto root = getEntry(0); + BOOST_REQUIRE(root); + BOOST_CHECK_EQUAL(root->id, 0); + BOOST_CHECK_EQUAL(root->name, "root"); + BOOST_CHECK_EQUAL(root->members.size(), 1); + BOOST_CHECK(root->hasMember(0)); + + auto rootByName = getEntry(root->name); + BOOST_REQUIRE_EQUAL(root, rootByName); +} -BOOST_DATA_TEST_CASE(notfoundid, BadIds, id) +BOOST_FIXTURE_TEST_SUITE(dm, NetFS::Mapping::DefaultMapper); + +BOOST_AUTO_TEST_CASE(good_maptransport) { - std::string outname; - BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Fallback); - BOOST_CHECK_EQUAL(outname, fallback->name); + auto fs = mapTransport("root", "root"); + BOOST_CHECK_EQUAL(0, fs.uid); + BOOST_CHECK_EQUAL(0, fs.gid); + BOOST_CHECK_EQUAL(0, fs.mask); } -BOOST_DATA_TEST_CASE(notfoundname, BadNames, name) +BOOST_AUTO_TEST_CASE(good_mapfs) { - int outid; - BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Fallback); - BOOST_CHECK_EQUAL(outid, fallback->id); + auto tn = mapFileSystem(0, 0); + BOOST_CHECK_EQUAL("root", tn.username); + BOOST_CHECK_EQUAL("root", tn.groupname); } -BOOST_DATA_TEST_CASE(foundid, GoodNames ^ GoodIds, name, id) +BOOST_AUTO_TEST_CASE(bad_maptransport) { - std::string outname; - BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Real); - BOOST_CHECK_EQUAL(name, outname); + BOOST_REQUIRE_THROW(mapTransport("root", ""), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapTransport("", "root"), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapTransport("", ""), NetFS::SystemError); } -BOOST_DATA_TEST_CASE(foundname, GoodNames ^ GoodIds, name, id) +BOOST_AUTO_TEST_CASE(bad_mapfilesystem) +{ + BOOST_REQUIRE_THROW(mapFileSystem(0, -1), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapFileSystem(-1, 0), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapFileSystem(-1, -1), NetFS::SystemError); +} + +BOOST_AUTO_TEST_SUITE_END(); + +BOOST_FIXTURE_TEST_SUITE(hm, NetFS::Client::HideUnknownMapperImpl); + +BOOST_AUTO_TEST_CASE(good_maptransport) +{ + auto fs = mapTransport("root", "root"); + BOOST_CHECK_EQUAL(0, fs.uid); + BOOST_CHECK_EQUAL(0, fs.gid); + BOOST_CHECK_EQUAL(0, fs.mask); +} + +BOOST_AUTO_TEST_CASE(good_mapfs) +{ + auto tn = mapFileSystem(0, 0); + BOOST_CHECK_EQUAL("root", tn.username); + BOOST_CHECK_EQUAL("root", tn.groupname); +} + +BOOST_AUTO_TEST_CASE(bad_maptransport) +{ + BOOST_CHECK_EQUAL(mapTransport("root", "").mask, ~0); + BOOST_CHECK_EQUAL(mapTransport("", "root").mask, ~0); + BOOST_CHECK_EQUAL(mapTransport("", "").mask, ~0); +} + +BOOST_AUTO_TEST_CASE(bad_mapfilesystem) +{ + BOOST_REQUIRE_THROW(mapFileSystem(0, -1), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapFileSystem(-1, 0), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapFileSystem(-1, -1), NetFS::SystemError); +} + +BOOST_AUTO_TEST_SUITE_END(); + +BOOST_FIXTURE_TEST_SUITE(mm, NetFS::Client::MaskUnknownMapperImpl); + +BOOST_AUTO_TEST_CASE(good_maptransport) +{ + auto fs = mapTransport("root", "root"); + BOOST_CHECK_EQUAL(0, fs.uid); + BOOST_CHECK_EQUAL(0, fs.gid); + BOOST_CHECK_EQUAL(0, fs.mask); +} + +BOOST_AUTO_TEST_CASE(good_mapfs) +{ + auto tn = mapFileSystem(0, 0); + BOOST_CHECK_EQUAL("root", tn.username); + BOOST_CHECK_EQUAL("root", tn.groupname); +} + +BOOST_AUTO_TEST_CASE(bad_maptransport) +{ + BOOST_CHECK_EQUAL(mapTransport("root", "").mask, 0070); + BOOST_CHECK_EQUAL(mapTransport("", "root").mask, 0700); + BOOST_CHECK_EQUAL(mapTransport("", "").mask, 0770); +} + +BOOST_AUTO_TEST_CASE(bad_maptransport_badfallback) +{ + UnknownUser = "not existing"; + UnknownGroup = "not existing"; + BOOST_REQUIRE_THROW(mapTransport("root", ""), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapTransport("", "root"), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapTransport("", ""), NetFS::SystemError); +} + +BOOST_AUTO_TEST_CASE(bad_mapfilesystem) { - int outid; - BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Real); - BOOST_CHECK_EQUAL(id, outid); + BOOST_REQUIRE_THROW(mapFileSystem(0, -1), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapFileSystem(-1, 0), NetFS::SystemError); + BOOST_REQUIRE_THROW(mapFileSystem(-1, -1), NetFS::SystemError); } BOOST_AUTO_TEST_SUITE_END(); |