From fc6e9a3316b608b30b5a25b347774181f1730c59 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 31 Aug 2020 19:52:11 +0100 Subject: First cut extensible mapper Replaces the weird fallback half implementation with something that looks remotely fit for purpose. --- netfs/daemon/daemonVolume.cpp | 4 ++- netfs/fuse/Jamfile.jam | 4 +++ netfs/fuse/fuseApp.cpp | 16 +++++----- netfs/fuse/fuseApp.h | 2 -- netfs/fuse/fuseConfig.ice | 3 ++ netfs/ice/Jamfile.jam | 6 +++- netfs/ice/entryResolver.h | 20 ------------- netfs/ice/mapper.ice | 31 +++++++++++++++++++ netfs/ice/typeConverter.cpp | 16 +++++----- netfs/ice/typeConverter.h | 11 +++---- netfs/lib/defaultMapper.cpp | 26 ++++++++++++++++ netfs/lib/defaultMapper.h | 21 +++++++++++++ netfs/lib/entCache.h | 31 +++++++++---------- netfs/lib/entCache.impl.h | 70 ++++++------------------------------------- netfs/lib/entryResolver.h | 14 +++++++++ netfs/unittests/Jamfile.jam | 2 +- netfs/unittests/testLib.cpp | 62 ++++---------------------------------- 17 files changed, 157 insertions(+), 182 deletions(-) delete mode 100644 netfs/ice/entryResolver.h create mode 100644 netfs/ice/mapper.ice create mode 100644 netfs/lib/defaultMapper.cpp create mode 100644 netfs/lib/defaultMapper.h create mode 100644 netfs/lib/entryResolver.h diff --git a/netfs/daemon/daemonVolume.cpp b/netfs/daemon/daemonVolume.cpp index 3ae43da..7ae3a1f 100644 --- a/netfs/daemon/daemonVolume.cpp +++ b/netfs/daemon/daemonVolume.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -16,7 +17,8 @@ extern std::map files; VolumeServer::VolumeServer(const std::filesystem::path & r, const EntCache & u, const EntCache & g) : - root(std::filesystem::canonical(r)), userLookup(u), groupLookup(g), converter(u, g) + root(std::filesystem::canonical(r)), userLookup(u), groupLookup(g), + converter(std::make_shared()) { } diff --git a/netfs/fuse/Jamfile.jam b/netfs/fuse/Jamfile.jam index 14338d5..8516d8b 100644 --- a/netfs/fuse/Jamfile.jam +++ b/netfs/fuse/Jamfile.jam @@ -6,6 +6,8 @@ obj fuseConfig : fuseConfig.ice : tidy:none ../ice//netfs-api ../ice//netfs-api + ..//slicer + . ; lib netfs-client-configuration : fuseConfig @@ -19,9 +21,11 @@ lib netfs-client-configuration : ..//Ice ..//slicer ..//adhocutil + . : : ..//Ice ..//slicer + . ; lib netfs-client : diff --git a/netfs/fuse/fuseApp.cpp b/netfs/fuse/fuseApp.cpp index 78a3a03..f0576b3 100644 --- a/netfs/fuse/fuseApp.cpp +++ b/netfs/fuse/fuseApp.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -17,10 +18,7 @@ namespace AdHoc { template class CallCacheable; } -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 +78,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(); + } BOOST_ASSERT(fcr); + converter.mapper = fcr->mapper; return this; } @@ -275,8 +277,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 d373e94..b905b23 100644 --- a/netfs/fuse/fuseApp.h +++ b/netfs/fuse/fuseApp.h @@ -111,8 +111,6 @@ namespace NetFS { OpenFiles openFiles; int openHandleId; - EntCache userLookup; - EntCache groupLookup; EntryTypeConverter converter; using StatCache = AdHoc::Cache; diff --git a/netfs/fuse/fuseConfig.ice b/netfs/fuse/fuseConfig.ice index 52116ea..2d2bf9f 100644 --- a/netfs/fuse/fuseConfig.ice +++ b/netfs/fuse/fuseConfig.ice @@ -1,4 +1,5 @@ #include +#include module NetFS { module Client { @@ -20,6 +21,8 @@ module NetFS { ["slicer:name:async"] bool Async = false; + + Mapping::Mapper mapper; }; ["slicer:key:name","slicer:value:resource","slicer:item:resource"] 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 : tidy:none ; obj service : service.ice : tidy:none ; obj types : types.ice : tidy:none ; obj volume : volume.ice : tidy:none ; -alias gen : directory exceptions file service types volume ; +obj mapper : mapper.ice : tidy:none ; +alias gen : directory exceptions file service types volume mapper ; lib netfs-api : gen + mapper.ice [ glob *.cpp ] : ..//Ice ..//pthread ..//adhocutil + ..//slicer gen + pure : : . ..//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 -#include - -enum class ResolvedAs : uint8_t { - Real, - Fallback, -}; - -template 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..d2f31e8 --- /dev/null +++ b/netfs/ice/mapper.ice @@ -0,0 +1,31 @@ +#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; + }; + + 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..6b33828 100644 --- a/netfs/ice/typeConverter.cpp +++ b/netfs/ice/typeConverter.cpp @@ -1,7 +1,7 @@ #include "typeConverter.h" #include -EntryTypeConverter::EntryTypeConverter(const UserLookup & u, const GroupLookup & g) : userLookup(u), groupLookup(g) { } +EntryTypeConverter::EntryTypeConverter(NetFS::Mapping::MapperPtr m) : mapper(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; + 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 #include #include #include @@ -16,17 +16,14 @@ public: class DLL_PUBLIC EntryTypeConverter : public TypeConverter { public: - using UserLookup = EntryResolver; - using GroupLookup = EntryResolver; - 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/defaultMapper.cpp b/netfs/lib/defaultMapper.cpp new file mode 100644 index 0000000..1d75e12 --- /dev/null +++ b/netfs/lib/defaultMapper.cpp @@ -0,0 +1,26 @@ +#include "defaultMapper.h" +#include + +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(u->id), static_cast(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..719c7bf --- /dev/null +++ b/netfs/lib/defaultMapper.h @@ -0,0 +1,21 @@ +#ifndef NETFS_MAPPING_DEFAULTIMPL_H +#define NETFS_MAPPING_DEFAULTIMPL_H + +#include "entCache.h" +#include + +namespace NetFS { + namespace Mapping { + class DefaultMapper : public Mapper { + public: + Transport mapFileSystem(int uid, int gid) override; + FileSystem mapTransport(const std::string & un, const std::string & gn) override; + + protected: + UserEntCache users; + GroupEntCache groups; + }; + } +} + +#endif diff --git a/netfs/lib/entCache.h b/netfs/lib/entCache.h index e8c6461..02224f5 100644 --- a/netfs/lib/entCache.h +++ b/netfs/lib/entCache.h @@ -1,11 +1,12 @@ #ifndef ENTCACHE_H #define ENTCACHE_H +#include "entryResolver.h" #include -#include #include #include #include +#include class User { public: @@ -26,11 +27,10 @@ public: std::set members; }; -template class EntCache : public EntryResolver { +template class EntCache : public EntryResolver { public: EntCache(); - EntCache(entry_t fb); - ~EntCache() override; + ~EntCache() noexcept override; SPECIAL_MEMBERS_DEFAULT_MOVE_NO_COPY(EntCache); @@ -38,27 +38,24 @@ public: using name_t = decltype(entry_t::name); using entry_ptr = std::shared_ptr; - 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(i); + } + [[nodiscard]] entry_ptr inline getEntry(const name_t & n) const noexcept override + { + return getEntryInternal(n); }; - ResolvedAs getID(const name_t &, id_t *) const override; - ResolvedAs getName(const id_t &, name_t *) const override; - template Resolution getEntry(const key_t &) const; - - void setFallback(entry_t fb); - void clearFallback(); - protected: - void fillCache() const; - template entry_ptr getEntryNoFill(const key_t &) const; + void fillCache() const noexcept; + template[[nodiscard]] entry_ptr getEntryInternal(const key_t &) const noexcept; + template[[nodiscard]] entry_ptr getEntryNoFill(const key_t &) const noexcept; class Ids; std::unique_ptr idcache; mutable std::shared_mutex lock; mutable time_t fillTime {0}; - entry_ptr fallback; }; using UserEntCache = EntCache; diff --git a/netfs/lib/entCache.impl.h b/netfs/lib/entCache.impl.h index 0021f00..6243d7d 100644 --- a/netfs/lib/entCache.impl.h +++ b/netfs/lib/entCache.impl.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -21,41 +20,12 @@ class EntCache::Ids : }; template EntCache::EntCache() : idcache(std::make_unique()) { } - -template EntCache::EntCache(entry_t fb) : idcache(std::make_unique()) -{ - setFallback(std::move(fb)); -} - -template EntCache::~EntCache() = default; - -template -ResolvedAs -EntCache::getID(const EntCache::name_t & u, EntCache::id_t * target) const -{ - auto e = getEntry(u); - *target = e->id; - return e.resolution; -} - -template -ResolvedAs -EntCache::getName(const EntCache::id_t & u, EntCache::name_t * target) const -{ - auto e = getEntry(u); - *target = e->name; - return e.resolution; -} - -template -EntCache::Resolution::Resolution(entry_ptr e, ResolvedAs res) : entry_ptr(std::move(e)), resolution(res) -{ -} +template EntCache::~EntCache() noexcept = default; template template -typename EntCache::Resolution -EntCache::getEntry(const key_t & key) const +typename EntCache::entry_ptr +EntCache::getEntryInternal(const key_t & key) const noexcept { if (fillTime + 60 > time(nullptr)) { if (auto ent = getEntryNoFill(key)) { @@ -63,19 +33,13 @@ EntCache::getEntry(const key_t & key) const } } fillCache(); - if (auto ent = getEntryNoFill(key)) { - return ent; - } - if (fallback) { - return {fallback, ResolvedAs::Fallback}; - } - throw NetFS::SystemError(EPERM); + return getEntryNoFill(key); } template template typename EntCache::entry_ptr -EntCache::getEntryNoFill(const key_t & key) const +EntCache::getEntryNoFill(const key_t & key) const noexcept { SharedLock(lock); auto & collection = idcache->template get(); @@ -86,27 +50,13 @@ EntCache::getEntryNoFill(const key_t & key) const return nullptr; } -template -void -EntCache::setFallback(entry_t fb) -{ - fallback = std::make_shared(std::move(fb)); -} - -template -void -EntCache::clearFallback() -{ - fallback.reset(); -} - User::User(uid_t u, std::string n, gid_t g) : id(u), name(std::move(n)), group(g) { } const int BUFLEN = 8196; template<> void -EntCache::fillCache() const +EntCache::fillCache() const noexcept { Lock(lock); setpwent(); @@ -125,7 +75,7 @@ Group::Group(gid_t g, std::string n) : id(g), name(std::move(n)) { } template<> void -EntCache::fillCache() const +EntCache::fillCache() const noexcept { Lock(lock); setgrent(); @@ -137,10 +87,8 @@ EntCache::fillCache() const while (getgrent_r(&grpbuf, buf.data(), buf.size(), &grp) == 0) { auto g = std::make_shared(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 &) { + if (auto ent = instance.getEntry((const gid_t &)*member)) { + g->members.insert(ent->id); } } idcache->insert(std::move(g)); diff --git a/netfs/lib/entryResolver.h b/netfs/lib/entryResolver.h new file mode 100644 index 0000000..84eb6ed --- /dev/null +++ b/netfs/lib/entryResolver.h @@ -0,0 +1,14 @@ +#ifndef NETFS_ENTRYRESOLVER_H +#define NETFS_ENTRYRESOLVER_H + +#include + +template class EntryResolver { +public: + virtual ~EntryResolver() noexcept = default; + + virtual std::shared_ptr getEntry(const decltype(entry_t::id) &) const noexcept = 0; + virtual std::shared_ptr getEntry(const decltype(entry_t::name) &) const noexcept = 0; +}; + +#endif diff --git a/netfs/unittests/Jamfile.jam b/netfs/unittests/Jamfile.jam index f1f3dba..18abadd 100644 --- a/netfs/unittests/Jamfile.jam +++ b/netfs/unittests/Jamfile.jam @@ -74,7 +74,6 @@ run testLib.cpp testMocks ; -# explicit testFuse ; run testFuse.cpp : -- : defaultDaemon.xml @@ -82,5 +81,6 @@ run testFuse.cpp BOOST_TEST_DYN_LINK boost_utf testMocks + testCore ; diff --git a/netfs/unittests/testLib.cpp b/netfs/unittests/testLib.cpp index b44ab37..14ea71f 100644 --- a/netfs/unittests/testLib.cpp +++ b/netfs/unittests/testLib.cpp @@ -4,15 +4,6 @@ #include #include -namespace std { - ostream & - operator<<(ostream & strm, const ResolvedAs & r) - { - strm << r; - return strm; - } -} - struct TestEntry { TestEntry(int i, std::string n) : id(i), name(std::move(n)) { } @@ -23,7 +14,7 @@ using TestEntCache = EntCache; template<> void -EntCache::fillCache() const +EntCache::fillCache() const noexcept { Lock(lock); idcache->insert(std::make_shared(1, "user1")); @@ -40,65 +31,22 @@ 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_DATA_TEST_CASE(notfoundname, BadNames, name) -{ - int outid; - BOOST_CHECK_THROW(getID(name, &outid), NetFS::SystemError); -} - -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_DATA_TEST_CASE(foundname, GoodNames ^ GoodIds, name, id) -{ - int outid; - BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Real); - BOOST_CHECK_EQUAL(id, outid); -} - -BOOST_AUTO_TEST_SUITE_END(); - -class TestEntCacheWithFallback : public TestEntCache { -public: - TestEntCacheWithFallback() : TestEntCache({4, "fallback"}) { } -}; - -BOOST_FIXTURE_TEST_SUITE(tecfb, TestEntCacheWithFallback); - -BOOST_DATA_TEST_CASE(notfoundid, BadIds, id) -{ - std::string outname; - BOOST_CHECK_EQUAL(getName(id, &outname), ResolvedAs::Fallback); - BOOST_CHECK_EQUAL(outname, fallback->name); + BOOST_CHECK(!getEntry(id)); } BOOST_DATA_TEST_CASE(notfoundname, BadNames, name) { - int outid; - BOOST_CHECK_EQUAL(getID(name, &outid), ResolvedAs::Fallback); - BOOST_CHECK_EQUAL(outid, fallback->id); + 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(); -- cgit v1.2.3