summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Jamroot.jam3
-rw-r--r--netfs/daemon/daemonService.cpp7
-rw-r--r--netfs/daemon/daemonService.h7
-rw-r--r--netfs/daemon/daemonVolume.cpp7
-rw-r--r--netfs/daemon/daemonVolume.h9
-rw-r--r--netfs/daemon/modeCheck.cpp5
-rw-r--r--netfs/daemon/modeCheck.h10
-rw-r--r--netfs/fuse/Jamfile.jam28
-rw-r--r--netfs/fuse/fuseApp.cpp36
-rw-r--r--netfs/fuse/fuseApp.h2
-rw-r--r--netfs/fuse/fuseApp.impl.h3
-rw-r--r--netfs/fuse/fuseConfig.ice4
-rw-r--r--netfs/fuse/fuseDirs.cpp11
-rw-r--r--netfs/fuse/fuseFiles.cpp2
-rw-r--r--netfs/fuse/fuseMappers.ice23
-rw-r--r--netfs/fuse/fuseMappersImpl.cpp74
-rw-r--r--netfs/fuse/fuseMappersImpl.h33
-rw-r--r--netfs/ice/Jamfile.jam6
-rw-r--r--netfs/ice/entryResolver.h20
-rw-r--r--netfs/ice/mapper.ice32
-rw-r--r--netfs/ice/typeConverter.cpp16
-rw-r--r--netfs/ice/typeConverter.h11
-rw-r--r--netfs/lib/baseMapper.cpp13
-rw-r--r--netfs/lib/baseMapper.h23
-rw-r--r--netfs/lib/defaultMapper.cpp26
-rw-r--r--netfs/lib/defaultMapper.h21
-rw-r--r--netfs/lib/entCache.cpp47
-rw-r--r--netfs/lib/entCache.h66
-rw-r--r--netfs/lib/entCache.impl.h108
-rw-r--r--netfs/lib/entries.cpp16
-rw-r--r--netfs/lib/entries.h27
-rw-r--r--netfs/lib/entryResolver.h17
-rw-r--r--netfs/unittests/Jamfile.jam4
-rw-r--r--netfs/unittests/defaultFuseHide.xml15
-rw-r--r--netfs/unittests/defaultFuseMask.xml20
-rw-r--r--netfs/unittests/testFuse.cpp49
-rw-r--r--netfs/unittests/testLib.cpp201
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();