diff options
31 files changed, 433 insertions, 102 deletions
diff --git a/libfusepp/Jamfile.jam b/libfusepp/Jamfile.jam deleted file mode 100644 index 1ba4a26..0000000 --- a/libfusepp/Jamfile.jam +++ /dev/null @@ -1,5 +0,0 @@ -project - : usage-requirements - <include>. - ; - diff --git a/libfusepp/fuseapp.cpp b/libfusepp/fuseAppBase.cpp index 1a6494a..a1ea491 100644 --- a/libfusepp/fuseapp.cpp +++ b/libfusepp/fuseAppBase.cpp @@ -1,4 +1,4 @@ -#include "fuseapp.h" +#include "fuseAppBase.h" #include <errno.h> #include <assert.h> #include <stdio.h> @@ -184,7 +184,7 @@ int FuseAppBase::fallocate(const char *, int, off_t, off_t, struct fuse_file_inf } int FuseAppBase::onError(const std::exception & e) throw() { - fprintf(stderr, "Unknown exception calling (what: %s)\n", e.what()); + fprintf(stderr, "Unknown exception (what: %s)\n", e.what()); return -ENOSYS; } @@ -198,12 +198,12 @@ void FuseAppBase::fuseDestroy(void *) } struct fuse_args -FuseAppBase::runint(int & argc, char** & argv, FuseAppBase * fa) +FuseAppBase::runint(int & argc, char** & argv) { struct fuse_opt fuse_opts[] = { { NULL, 0, 0 } }; - fuseApp = fa; + fuseApp = this; struct fuse_args args = FUSE_ARGS_INIT(argc, argv); if (fuse_opt_parse(&args, fuseApp, fuse_opts, fuseCall<void *, const char *, int, struct fuse_args *>::helper<&FuseAppBase::opt_parse>) == -1) { diff --git a/libfusepp/fuseapp.h b/libfusepp/fuseAppBase.h index a320d36..d76fbff 100644 --- a/libfusepp/fuseapp.h +++ b/libfusepp/fuseAppBase.h @@ -56,11 +56,14 @@ class FuseAppBase { virtual int fallocate(const char *, int, off_t, off_t, struct fuse_file_info *); virtual int onError(const std::exception & err) throw(); + virtual int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc) = 0; + virtual int main(int &, char **, const struct fuse_operations *) = 0; + #define GetHelper(func) getHelper<&FuseAppBase::func>(typeid(&FuseAppBase::func) != typeid(&FuseApp::func)) template <typename FuseApp> static int run(int & argc, char** & argv, FuseApp * fa) { - auto args = runint(argc, argv, fa); + auto args = fa->runint(argc, argv); struct fuse_operations operations = { fuseCall<const char *, struct stat *>::GetHelper(getattr), fuseCall<const char *, char *, size_t>::GetHelper(readlink), @@ -119,10 +122,11 @@ class FuseAppBase { #endif #endif }; - return fuse_main(args.argc, args.argv, &operations, fa); + return fa->main(args.argc, args.argv, &operations); } + struct fuse_args runint(int &, char ** &); + private: - static struct fuse_args runint(int &, char ** &, FuseAppBase *); static void * fuseInit(struct fuse_conn_info *conn); static void fuseDestroy(void *); diff --git a/netfs/Jamfile.jam b/netfs/Jamfile.jam index d006225..6df8110 100644 --- a/netfs/Jamfile.jam +++ b/netfs/Jamfile.jam @@ -13,10 +13,12 @@ lib Ice : : <name>Ice ; lib IceUtil : : <name>IceUtil ; lib IceBox : : <name>IceBox ; lib pthread : : <name>pthread ; -lib fuse : : <name>fuse ; +lib slicer : : : : <include>/usr/include/slicer ; +lib slicer-xml : : : : <include>/usr/include/slicer ; build-project daemon ; build-project fuse ; +build-project unittests ; explicit install ; package.install install : : fuse//netfs : daemon//netfsd ; diff --git a/netfs/daemon/Jamfile.jam b/netfs/daemon/Jamfile.jam index fd8c463..53ac99d 100644 --- a/netfs/daemon/Jamfile.jam +++ b/netfs/daemon/Jamfile.jam @@ -1,5 +1,3 @@ -lib slicer : : : : <include>/usr/include/slicer ; -lib slicer-xml : : : : <include>/usr/include/slicer ; cpp-pch pch : pch.hpp : <define>_FILE_OFFSET_BITS=64 @@ -13,21 +11,21 @@ cpp-pch pch : pch.hpp : ; lib netfsdConfiguration : - configuration.ice + daemonConfig.ice : <library>..//Ice <library>..//IceUtil <library>..//pthread <library>..//boost_filesystem <library>..//boost_system - <library>slicer + <library>..//slicer <slicer>yes : : <include>. <library>..//IceUtil <library>..//Ice <library>..//boost_system - <library>slicer + <library>..//slicer ; lib netfsd : @@ -49,7 +47,13 @@ lib netfsd : <library>..//IceUtil <library>..//IceBox <library>..//libxmlpp - <library>slicer-xml + <library>..//slicer-xml + : : + <include>. + <implicit-dependency>../ice//netfsComms + <library>netfsdConfiguration + <implicit-dependency>netfsdConfiguration + <library>..//IceBox ; diff --git a/netfs/daemon/daemon.cpp b/netfs/daemon/daemon.cpp index d36e63f..3ad6294 100644 --- a/netfs/daemon/daemon.cpp +++ b/netfs/daemon/daemon.cpp @@ -1,4 +1,4 @@ -#include "pch.hpp" +#include <pch.hpp> #include <Ice/Ice.h> #include "daemon.h" #include "daemonService.h" @@ -8,19 +8,33 @@ #include "ioHelpers.h" #include <sys/stat.h> +NetFSDaemon::NetFSDaemon(const Ice::CommunicatorPtr & i) : + ic(i) +{ +} + +NetFSDaemon::~NetFSDaemon() +{ + adapter->deactivate(); +} + std::string NetFSDaemon::hostname() { - char buf[128]; - gethostname(buf, sizeof(buf)); - return buf; + auto props = ic->getProperties(); + auto hostNameOverride = props->getProperty("NetFSD.HostNameOverride"); + if (hostNameOverride.empty()) { + char buf[128]; + gethostname(buf, sizeof(buf)); + return buf; + } + return hostNameOverride; } // name = NetFSDaemonAdapter void -NetFSDaemon::start(const std::string & name, const Ice::CommunicatorPtr & ic, const Ice::StringSeq&) +NetFSDaemon::start(const std::string & name, const Ice::CommunicatorPtr &, const Ice::StringSeq&) { - this->ic = ic; Ice::PropertiesPtr props = ic->getProperties(); LoadConfiguration(props->getProperty("NetFSD.ConfigPath")); @@ -29,11 +43,17 @@ NetFSDaemon::start(const std::string & name, const Ice::CommunicatorPtr & ic, co adapter->activate(); } +NetFS::Daemon::ConfigurationPtr +NetFSDaemon::ReadConfiguration(const boost::filesystem::path & path) const +{ + return Slicer::Deserialize<Slicer::XmlFileDeserializer, NetFS::Daemon::Configuration>(path); +} + void NetFSDaemon::LoadConfiguration(const boost::filesystem::path & path) { dc = new NetFS::Daemon::RuntimeConfiguration(); - dc->CurrentConfiguration = Slicer::Deserialize<Slicer::XmlFileDeserializer, NetFS::Daemon::Configuration>(path); + dc->CurrentConfiguration = ReadConfiguration(path); auto selfItr = dc->CurrentConfiguration->Hosts.find(hostname()); if (selfItr == dc->CurrentConfiguration->Hosts.end()) { throw std::runtime_error("This host is not defined in the configuration."); @@ -49,15 +69,15 @@ NetFSDaemon::stop() extern "C" { IceBox::Service * - createNetFSDaemon(Ice::CommunicatorPtr) + createNetFSDaemon(Ice::CommunicatorPtr ic) { - return new NetFSDaemon(); + return new NetFSDaemon(ic); } } TempPrivs::TempPrivs(const NetFS::ReqEnv & re, const boost::filesystem::path & r) : - myu(UserEntCache::instance.getID(re.user)), - myg(GroupEntCache::instance.getID(re.grp)), + myu(UserEntCache::instance.getEntry(re.user)->id), + myg(GroupEntCache::instance.getEntry(re.grp)->id), root(r) { } diff --git a/netfs/daemon/daemon.h b/netfs/daemon/daemon.h index 471a296..7ed5cb4 100644 --- a/netfs/daemon/daemon.h +++ b/netfs/daemon/daemon.h @@ -3,23 +3,29 @@ #include <Ice/Ice.h> #include <IceBox/IceBox.h> -#include <configuration.h> +#include <daemonConfig.h> #include <types.h> #include <boost/filesystem/path.hpp> class NetFSDaemon : public IceBox::Service { public: - virtual void start(const std::string&, const Ice::CommunicatorPtr&, const Ice::StringSeq&); - virtual void stop(); + NetFSDaemon(const Ice::CommunicatorPtr &); + virtual ~NetFSDaemon(); + + virtual void start(const std::string&, const Ice::CommunicatorPtr&, const Ice::StringSeq&) override; + virtual void stop() override; + + protected: + virtual NetFS::Daemon::ConfigurationPtr ReadConfiguration(const boost::filesystem::path & path) const; private: void LoadConfiguration(const boost::filesystem::path & path); - Ice::CommunicatorPtr ic; + const Ice::CommunicatorPtr ic; Ice::ObjectAdapterPtr adapter; NetFS::Daemon::RuntimeConfigurationPtr dc; - static std::string hostname(); + std::string hostname(); }; class TempPrivs { diff --git a/netfs/daemon/configuration.ice b/netfs/daemon/daemonConfig.ice index bb77344..bb77344 100644 --- a/netfs/daemon/configuration.ice +++ b/netfs/daemon/daemonConfig.ice diff --git a/netfs/daemon/daemonDirectory.cpp b/netfs/daemon/daemonDirectory.cpp index b43806f..b61b8be 100644 --- a/netfs/daemon/daemonDirectory.cpp +++ b/netfs/daemon/daemonDirectory.cpp @@ -1,4 +1,4 @@ -#include "pch.hpp" +#include <pch.hpp> #include <Ice/ObjectAdapter.h> #include <dirent.h> #include <errno.h> diff --git a/netfs/daemon/daemonFile.cpp b/netfs/daemon/daemonFile.cpp index 79077a1..3acd1ca 100644 --- a/netfs/daemon/daemonFile.cpp +++ b/netfs/daemon/daemonFile.cpp @@ -1,4 +1,4 @@ -#include "pch.hpp" +#include <pch.hpp> #include <Ice/ObjectAdapter.h> #include <errno.h> #include <map> @@ -36,7 +36,7 @@ FileServer::fgetattr(const NetFS::ReqEnv & re, const Ice::Current &) throw NetFS::SystemError(errno); } NetFS::Attr a; - a << StatSource { s, boost::bind(&UserEntCache::getName, &UserEntCache::instance, _1), boost::bind(&GroupEntCache::getName, &GroupEntCache::instance, _1) }; + a << StatSource { s, boost::bind(&UserEntCache::getName, &UserEntCache::instance, _1, _2), boost::bind(&GroupEntCache::getName, &GroupEntCache::instance, _1, _2) }; return a; } diff --git a/netfs/daemon/daemonService.cpp b/netfs/daemon/daemonService.cpp index 4b9e804..fe587f1 100644 --- a/netfs/daemon/daemonService.cpp +++ b/netfs/daemon/daemonService.cpp @@ -1,4 +1,4 @@ -#include "pch.hpp" +#include <pch.hpp> #include "daemon.h" #include "daemonService.h" #include "daemonVolume.h" diff --git a/netfs/daemon/daemonService.h b/netfs/daemon/daemonService.h index 783ad96..345df2c 100644 --- a/netfs/daemon/daemonService.h +++ b/netfs/daemon/daemonService.h @@ -3,6 +3,7 @@ #include <service.h> #include <entCache.h> +#include <daemonConfig.h> class ServiceServer : public NetFS::Service { public: diff --git a/netfs/daemon/daemonVolume.cpp b/netfs/daemon/daemonVolume.cpp index 0caead6..0556d9a 100644 --- a/netfs/daemon/daemonVolume.cpp +++ b/netfs/daemon/daemonVolume.cpp @@ -1,4 +1,4 @@ -#include "pch.hpp" +#include <pch.hpp> #include <Ice/ObjectAdapter.h> #include <errno.h> #include <map> @@ -70,7 +70,7 @@ VolumeServer::getattr(const NetFS::ReqEnv & re, const std::string & path, const throw NetFS::SystemError(errno); } NetFS::Attr a; - a << StatSource { s, boost::bind(&UserEntCache::getName, &UserEntCache::instance, _1), boost::bind(&GroupEntCache::getName, &GroupEntCache::instance, _1) }; + a << StatSource { s, boost::bind(&UserEntCache::getName, &UserEntCache::instance, _1, _2), boost::bind(&GroupEntCache::getName, &GroupEntCache::instance, _1, _2) }; return a; } diff --git a/netfs/daemon/pch.hpp b/netfs/daemon/pch.hpp index 3229655..adc5ff2 100644 --- a/netfs/daemon/pch.hpp +++ b/netfs/daemon/pch.hpp @@ -6,8 +6,8 @@ #include <boost/filesystem/path.hpp> #include "daemon.h" #include <IceBox/IceBox.h> +#include <Ice/Ice.h> #endif #endif - diff --git a/netfs/fuse/Jamfile.jam b/netfs/fuse/Jamfile.jam index 8223aa7..c5d3a7a 100644 --- a/netfs/fuse/Jamfile.jam +++ b/netfs/fuse/Jamfile.jam @@ -1,5 +1,4 @@ -lib slicer : : : : <include>/usr/include/slicer ; -lib slicer-xml : : : : <include>/usr/include/slicer ; +lib fuse : : <name>fuse ; cpp-pch pch : pch.hpp : <define>_FILE_OFFSET_BITS=64 @@ -8,46 +7,60 @@ cpp-pch pch : pch.hpp : <implicit-dependency>../ice//netfsComms <library>../ice//netfsComms <library>..//boost_thread - <library>..//fuse + <library>fuse <library>..//Ice ; -obj configuration : - configuration.ice +lib netfsClientConfiguration : + fuseConfig.ice : <slicer>yes <library>..//Ice <library>..//IceUtil <library>..//pthread - <library>slicer + <library>..//slicer : : <library>..//IceUtil <library>..//Ice <library>..//boost_system - <library>slicer + <library>..//slicer ; -exe netfs : +lib netfsClient : pch - configuration - [ glob *.cpp ] + netfsClientConfiguration + [ glob *.cpp : netfs.cpp ] [ glob ../../libfusepp/fuse*.cpp ] : <define>_FILE_OFFSET_BITS=64 <include>../../libmisc <include>../../libfusepp <implicit-dependency>../ice//netfsComms - <implicit-dependency>configuration + <library>netfsClientConfiguration + <implicit-dependency>netfsClientConfiguration <library>../ice//netfsComms <library>../lib//netfsCommon <library>..//boost_thread <library>..//boost_system - <library>..//fuse <library>..//Ice <library>..//IceUtil <library>..//pthread - <library>slicer + <library>..//slicer <library>..//libxmlpp - <library>slicer-xml + <library>..//slicer-xml + : : + <include>. + <include>../../libfusepp + <library>../ice//netfsComms + <implicit-dependency>../ice//netfsComms + <library>netfsClientConfiguration + <implicit-dependency>netfsClientConfiguration + <define>_FILE_OFFSET_BITS=64 + ; + +exe netfs : + netfs.cpp : + <library>netfsClient + <library>fuse ; diff --git a/netfs/fuse/fuse.cpp b/netfs/fuse/fuseApp.cpp index 7f90710..fdcce57 100644 --- a/netfs/fuse/fuse.cpp +++ b/netfs/fuse/fuseApp.cpp @@ -1,6 +1,6 @@ -#include "pch.hpp" +#include <pch.hpp> #include <string.h> -#include "fuse.h" +#include "fuseApp.h" #include "lockHelpers.h" #include "cache.impl.h" #include <entCache.h> @@ -34,11 +34,17 @@ NetFS::FuseApp::~FuseApp() } } +NetFS::Client::ConfigurationPtr +NetFS::FuseApp::ReadConfiguration(const std::string & path) const +{ + return Slicer::Deserialize<Slicer::XmlFileDeserializer, NetFS::Client::Configuration>(path); +} + void * NetFS::FuseApp::init(struct fuse_conn_info *) { ic = Ice::initialize(_argc, _argv); - fc = Slicer::Deserialize<Slicer::XmlFileDeserializer, NetFS::Client::Configuration>(configPath); + fc = ReadConfiguration(configPath); return NULL; } @@ -98,7 +104,7 @@ NetFS::FuseApp::connectToVolume() } volume = service->connect(e->second->ExportName, "bar"); if (!volume) { - throw "Invalid filesystem proxy"; + throw std::runtime_error("Invalid filesystem proxy"); } } } @@ -165,12 +171,9 @@ NetFS::FuseApp::reqEnv() connectToService(); connectToVolume(); struct fuse_context * c = fuse_get_context(); - return { UserEntCache::instance.getName(c->uid), GroupEntCache::instance.getName(c->gid) }; -} - -int -main(int argc, char* argv[]) -{ - return FuseAppBase::run(argc, argv, new NetFS::FuseApp(argc, argv)); + NetFS::ReqEnv re; + UserEntCache::instance.getName(c->uid, &re.user); + GroupEntCache::instance.getName(c->gid, &re.grp); + return re; } diff --git a/netfs/fuse/fuse.h b/netfs/fuse/fuseApp.h index 3821285..e514b55 100644 --- a/netfs/fuse/fuse.h +++ b/netfs/fuse/fuseApp.h @@ -4,8 +4,8 @@ #include <boost/thread/shared_mutex.hpp> #include <Ice/Ice.h> #include <service.h> -#include "fuseapp.h" -#include "configuration.h" +#include "fuseAppBase.h" +#include "fuseConfig.h" #include "cache.h" namespace NetFS { @@ -78,6 +78,11 @@ namespace NetFS { // stuff int onError(const std::exception & err) throw(); + virtual struct fuse_context * fuse_get_context() = 0; + + protected: + virtual NetFS::Client::ConfigurationPtr ReadConfiguration(const std::string &) const; + private: void setProxy(OpenFilePtr, uint64_t & fh); OpenFilePtr getFileProxy(uint64_t localID) const; diff --git a/netfs/fuse/configuration.ice b/netfs/fuse/fuseConfig.ice index db37770..db37770 100644 --- a/netfs/fuse/configuration.ice +++ b/netfs/fuse/fuseConfig.ice diff --git a/netfs/fuse/fuseDirs.cpp b/netfs/fuse/fuseDirs.cpp index 75cb5a5..1da9484 100644 --- a/netfs/fuse/fuseDirs.cpp +++ b/netfs/fuse/fuseDirs.cpp @@ -1,5 +1,5 @@ -#include "pch.hpp" -#include "fuse.h" +#include <pch.hpp> +#include "fuseApp.h" #include "misc.h" #include "lockHelpers.h" #include <typeConvert.h> @@ -79,7 +79,7 @@ NetFS::FuseApp::readdir(const char * p, void * buf, fuse_fill_dir_t filler, off_ statCache.Add(new OptimisticCallCacheable<struct stat, std::string, IceUtil::Shared>( [asga,this]() { struct stat s; - s << AttrSource { volume->end_getattr(asga), boost::bind(&UserEntCache::getID, &UserEntCache::instance, _1), boost::bind(&GroupEntCache::getID, &GroupEntCache::instance, _1) }; + s << AttrSource { volume->end_getattr(asga), boost::bind(&UserEntCache::getID, &UserEntCache::instance, _1, _2), boost::bind(&GroupEntCache::getID, &GroupEntCache::instance, _1, _2) }; return s; }, epath, time_t(NULL) + 2)); } diff --git a/netfs/fuse/fuseFiles.cpp b/netfs/fuse/fuseFiles.cpp index 9ce260c..c6d4283 100644 --- a/netfs/fuse/fuseFiles.cpp +++ b/netfs/fuse/fuseFiles.cpp @@ -1,7 +1,7 @@ -#include "pch.hpp" +#include <pch.hpp> #include <string.h> #include <typeConvert.h> -#include "fuse.h" +#include "fuseApp.h" #include "lockHelpers.h" #include <entCache.h> @@ -135,7 +135,7 @@ NetFS::FuseApp::fgetattr(const char *, struct stat * s, fuse_file_info * fi) { try { auto remote = getFileProxy(fi->fh)->remote; - *s << AttrSource { remote->fgetattr(reqEnv()), boost::bind(&UserEntCache::getID, &UserEntCache::instance, _1), boost::bind(&GroupEntCache::getID, &GroupEntCache::instance, _1) }; + *s << AttrSource { remote->fgetattr(reqEnv()), boost::bind(&UserEntCache::getID, &UserEntCache::instance, _1, _2), boost::bind(&GroupEntCache::getID, &GroupEntCache::instance, _1, _2) }; return 0; } catch (NetFS::SystemError & e) { diff --git a/netfs/fuse/fuseMisc.cpp b/netfs/fuse/fuseMisc.cpp index 0e366be..1f999bd 100644 --- a/netfs/fuse/fuseMisc.cpp +++ b/netfs/fuse/fuseMisc.cpp @@ -1,5 +1,5 @@ -#include "pch.hpp" -#include "fuse.h" +#include <pch.hpp> +#include "fuseApp.h" #include <string.h> #include <typeConvert.h> #include <entCache.h> @@ -19,7 +19,7 @@ NetFS::FuseApp::getattr(const char * p, struct stat * s) *s = *cacehedStat; } else { - *s << AttrSource { volume->getattr(reqEnv(), p), boost::bind(&UserEntCache::getID, &UserEntCache::instance, _1), boost::bind(&GroupEntCache::getID, &GroupEntCache::instance, _1) }; + *s << AttrSource { volume->getattr(reqEnv(), p), boost::bind(&UserEntCache::getID, &UserEntCache::instance, _1, _2), boost::bind(&GroupEntCache::getID, &GroupEntCache::instance, _1, _2) }; } return 0; } diff --git a/netfs/fuse/fuseSystem.cpp b/netfs/fuse/fuseSystem.cpp index 0b29d86..e2a9ab7 100644 --- a/netfs/fuse/fuseSystem.cpp +++ b/netfs/fuse/fuseSystem.cpp @@ -1,6 +1,6 @@ -#include "pch.hpp" +#include <pch.hpp> #include <typeConvert.h> -#include "fuse.h" +#include "fuseApp.h" int NetFS::FuseApp::statfs(const char * p, struct statvfs * vfs) diff --git a/netfs/fuse/netfs.cpp b/netfs/fuse/netfs.cpp new file mode 100644 index 0000000..f700a74 --- /dev/null +++ b/netfs/fuse/netfs.cpp @@ -0,0 +1,29 @@ +#include "fuseApp.h" + +class FuseImpl : public NetFS::FuseApp { + public: + FuseImpl(int & argc, char ** argv) : NetFS::FuseApp(argc, argv) { } + + struct fuse_context * fuse_get_context() override + { + return ::fuse_get_context(); + } + + int fuse_opt_parse(struct fuse_args * args, void * data, const struct fuse_opt opts[], fuse_opt_proc_t proc) override + { + return ::fuse_opt_parse(args, data, opts, proc); + } + + int main(int & argc, char ** argv, const struct fuse_operations * ops) override + { + return ::fuse_main(argc, argv, ops, this); + } + +}; + +int +main(int argc, char* argv[]) +{ + return FuseAppBase::run(argc, argv, new FuseImpl(argc, argv)); +} + diff --git a/netfs/fuse/pch.hpp b/netfs/fuse/pch.hpp index 7cb79ed..2342973 100644 --- a/netfs/fuse/pch.hpp +++ b/netfs/fuse/pch.hpp @@ -3,11 +3,10 @@ #define NETFS_FUSE_PCH #include "../lib/pch.hpp" -#include "../../libfusepp/fuseapp.h" +#include "../../libfusepp/fuseAppBase.h" #include <fuse.h> +#include <Ice/Ice.h> #endif #endif - - diff --git a/netfs/ice/typeConvert.cpp b/netfs/ice/typeConvert.cpp index 538b894..cc3ee93 100644 --- a/netfs/ice/typeConvert.cpp +++ b/netfs/ice/typeConvert.cpp @@ -7,8 +7,8 @@ operator<<(struct stat & s, const AttrSource & a) s.st_ino = a.attr.inode; s.st_mode = a.attr.mode; s.st_nlink = a.attr.links; - s.st_uid = a.user(a.attr.uid); - s.st_gid = a.group(a.attr.gid); + a.user(a.attr.uid, &s.st_uid); + a.group(a.attr.gid, &s.st_gid); s.st_rdev = a.attr.rdev; s.st_size = a.attr.size; s.st_blksize = a.attr.blockSize; @@ -41,8 +41,8 @@ operator<<(NetFS::Attr & a, const struct StatSource & s) a.inode = s.stat.st_ino; a.mode = s.stat.st_mode; a.links = s.stat.st_nlink; - a.uid = s.user(s.stat.st_uid); - a.gid = s.group(s.stat.st_gid); + s.user(s.stat.st_uid, &a.uid); + s.group(s.stat.st_gid, &a.gid); a.rdev = s.stat.st_rdev; a.size = s.stat.st_size; a.blockSize = s.stat.st_blksize; diff --git a/netfs/ice/typeConvert.h b/netfs/ice/typeConvert.h index dd56a3f..13e2b44 100644 --- a/netfs/ice/typeConvert.h +++ b/netfs/ice/typeConvert.h @@ -3,11 +3,11 @@ #include <sys/statvfs.h> #include <boost/function.hpp> -typedef boost::function<uid_t(const std::string &)> UserIdLookup; -typedef boost::function<gid_t(const std::string &)> GroupIdLookup; +typedef boost::function<void(const std::string &, uid_t *)> UserIdLookup; +typedef boost::function<void(const std::string &, gid_t *)> GroupIdLookup; -typedef boost::function<std::string(uid_t)> UserNameLookup; -typedef boost::function<std::string(gid_t)> GroupNameLookup; +typedef boost::function<void(uid_t, std::string *)> UserNameLookup; +typedef boost::function<void(gid_t, std::string *)> GroupNameLookup; struct AttrSource { const NetFS::Attr & attr; diff --git a/netfs/lib/entCache.cpp b/netfs/lib/entCache.cpp index a4cf27d..286c017 100644 --- a/netfs/lib/entCache.cpp +++ b/netfs/lib/entCache.cpp @@ -1,4 +1,4 @@ -#include "pch.hpp" +#include <pch.hpp> #include "entCache.h" #include <exceptions.h> #include "lockHelpers.h" @@ -17,17 +17,19 @@ EntCache<entry_t>::~EntCache() } template<class entry_t> -const typename EntCache<entry_t>::id_t & -EntCache<entry_t>::getID(const EntCache<entry_t>::name_t & u) const +void +EntCache<entry_t>::getID(const EntCache<entry_t>::name_t & u, EntCache<entry_t>::id_t * target) const { - return getEntry(u)->id; + auto e = getEntry(u); + *target = e->id; } template<class entry_t> -const typename EntCache<entry_t>::name_t & -EntCache<entry_t>::getName(const EntCache<entry_t>::id_t & u) const +void +EntCache<entry_t>::getName(const EntCache<entry_t>::id_t & u, EntCache<entry_t>::name_t * target) const { - return getEntry(u)->name; + auto e = getEntry(u); + *target = e->name; } template<class entry_t> @@ -107,7 +109,7 @@ EntCache<Group>::fillCache() const auto g = new Group(grp->gr_gid, grp->gr_name); for (auto member = grp->gr_mem; *member; member++) { try { - g->members.insert(EntCache<User>::instance.getID(*member)); + g->members.insert(EntCache<User>::instance.getEntry((const name_t &)*member)->id); } catch (const NetFS::SystemError &) { } diff --git a/netfs/lib/entCache.h b/netfs/lib/entCache.h index ea941e8..443474f 100644 --- a/netfs/lib/entCache.h +++ b/netfs/lib/entCache.h @@ -38,8 +38,8 @@ class EntCache { virtual ~EntCache(); - const id_t & getID(const name_t & ) const; - const name_t & getName(const id_t &) const; + void getID(const name_t &, id_t *) const; + void getName(const id_t &, name_t *) const; template<class key_t> entry_ptr getEntry(const key_t &) const; diff --git a/netfs/lib/pch.hpp b/netfs/lib/pch.hpp index ffd9890..fc37faa 100644 --- a/netfs/lib/pch.hpp +++ b/netfs/lib/pch.hpp @@ -7,7 +7,8 @@ #include <boost/multi_index/member.hpp> #include <boost/multi_index/ordered_index.hpp> #include <exception> -#include <Ice/Ice.h> +#include <IceUtil/Shared.h> +#include <IceUtil/Handle.h> #include <map> #include <set> #include <string> diff --git a/netfs/unittests/Jamfile.jam b/netfs/unittests/Jamfile.jam new file mode 100644 index 0000000..af02411 --- /dev/null +++ b/netfs/unittests/Jamfile.jam @@ -0,0 +1,26 @@ +import testing ; + +lib boost_utf : : <name>boost_unit_test_framework ; +lib boost_system ; +lib boost_filesystem ; +lib IceUtil ; +lib Ice ; + +path-constant me : . ; + +run + testCore.cpp + : : + : + <define>BOOST_TEST_DYN_LINK + <library>IceUtil + <library>Ice + <library>boost_system + <library>boost_filesystem + <library>boost_utf + <library>../daemon//netfsd + <library>../fuse//netfsClient + <library>../ice//netfsComms + <define>ROOT=\"$(me)\" + : testCore ; + diff --git a/netfs/unittests/testCore.cpp b/netfs/unittests/testCore.cpp new file mode 100644 index 0000000..1fc1817 --- /dev/null +++ b/netfs/unittests/testCore.cpp @@ -0,0 +1,221 @@ +#define BOOST_TEST_MODULE TestNetFSCore +#include <boost/test/unit_test.hpp> +#include <boost/filesystem/operations.hpp> +#include <Ice/ObjectAdapter.h> +#include <Ice/Service.h> +#include <daemon.h> +#include <fuseApp.h> +#include <boost/filesystem/path.hpp> + +#ifndef ROOT +#error "ROOT needs to be defined at compilation time" +#endif + +#define XSTR(s) STR(s) +#define STR(s) #s +const boost::filesystem::path RootDir(XSTR(ROOT)); +const boost::filesystem::path TestExportRoot(RootDir / "testExport"); + +std::string testEndpoint("tcp -h localhost -p 12012"); + +class MockDaemon : public NetFSDaemon { + public: + MockDaemon(const Ice::CommunicatorPtr & ic) : NetFSDaemon(ic) { } + + protected: + virtual NetFS::Daemon::ConfigurationPtr ReadConfiguration(const boost::filesystem::path &) const override + { + return new NetFS::Daemon::Configuration( + { + { "testvol", new NetFS::Daemon::Export(TestExportRoot.string()) } + }, + { + { "unittest", new NetFS::Daemon::Host(testEndpoint) } + }); + } +}; + +class MockDaemonHost { + public: + MockDaemonHost() : + params({}), + ic(Ice::initialize(params)), + daemon(new MockDaemon(ic)) + { + ic->getProperties()->setProperty("NetFSD.HostNameOverride", "unittest"); + daemon->start("NetFSDaemonAdapter", ic, {}); + + } + + ~MockDaemonHost() + { + delete daemon; + ic->destroy(); + } + + Ice::StringSeq params; + Ice::CommunicatorPtr ic; + NetFSDaemon * daemon; +}; +typedef boost::shared_ptr<MockDaemonHost> MockDaemonHostPtr; + +char * argv[] = { + strdup((RootDir / ":testvol").string().c_str()), + strdup((RootDir / "test").string().c_str()) +}; + +class FuseMock : public NetFS::FuseApp { + public: + FuseMock(int & argc, char ** argv) : + NetFS::FuseApp(argc, argv) + { + ::memset(&context, 0, sizeof(fuse_context)); + context.pid = getpid(); + context.uid = getuid(); + context.gid = getgid(); + } + + struct fuse_context * fuse_get_context() override + { + return &context; + } + + int fuse_opt_parse(struct fuse_args * args, void * data, const struct fuse_opt [], fuse_opt_proc_t proc) override + { + for (int n = 0; n < args->argc; n += 1) { + proc(data, args->argv[n], n, args); + } + return 0; + } + + int main(int &, char **, const struct fuse_operations * o) override + { + o->init(NULL); + ops = *o; + return 0; + } + + fuse_operations ops; + + protected: + virtual NetFS::Client::ConfigurationPtr ReadConfiguration(const std::string &) const override + { + return new NetFS::Client::Configuration( + { + { "testvol", new NetFS::Client::Resource("testvol", "Service", { testEndpoint }) } + }); + } + + private: + fuse_context context; +}; + +class FuseMockHost { + public: + FuseMockHost() : + argc(2), + app(new FuseMock(argc, argv)), + fuse(&app->ops) + { + char ** a = argv; + FuseAppBase::run(argc, a, app); + } + + int argc; + FuseMock * app; + fuse_operations * fuse; +}; + +class Core { + public: + Core() : + ic(daemonHost.ic), + daemon(daemonHost.daemon), + fuse(fuseHost.fuse) + { + } + + protected: + MockDaemonHost daemonHost; + FuseMockHost fuseHost; + + Ice::CommunicatorPtr ic; + NetFSDaemon * const daemon; + fuse_operations * fuse;; +}; + +class GlobalSandBox { + public: + GlobalSandBox() + { + boost::filesystem::remove_all(TestExportRoot); + boost::filesystem::create_directories(TestExportRoot); + } + ~GlobalSandBox() + { + boost::filesystem::remove_all(TestExportRoot); + } +}; + +BOOST_GLOBAL_FIXTURE(GlobalSandBox); + +BOOST_FIXTURE_TEST_SUITE( NetfsCore, Core ) + +BOOST_AUTO_TEST_CASE ( daemonInitialised ) +{ + auto service = NetFS::ServicePrx::checkedCast(ic->stringToProxy("Service")); + BOOST_REQUIRE(service); + service->ice_ping(); +} + +BOOST_AUTO_TEST_CASE ( clientInitialised ) +{ + struct statvfs s; + BOOST_REQUIRE_EQUAL(0, fuse->statfs("/", &s)); +} + +BOOST_AUTO_TEST_SUITE_END(); + + +BOOST_AUTO_TEST_CASE ( createAndDaemonRestart ) +{ + MockDaemonHostPtr daemon(new MockDaemonHost()); + FuseMockHost fuse; + + struct statvfs s; + BOOST_REQUIRE_EQUAL(0, fuse.fuse->statfs("/", &s)); + + const char * fileName = "/createMe"; + BOOST_CHECKPOINT("Create a new file"); + struct fuse_file_info fh; + memset(&fh, 0, sizeof(fh)); + fh.flags = O_WRONLY | O_CREAT | O_APPEND; + BOOST_REQUIRE_EQUAL(0, fuse.fuse->create(fileName, 0100644, &fh)); + BOOST_REQUIRE(fh.fh); + + BOOST_CHECKPOINT("Fetch file attributes"); + struct stat st; + BOOST_REQUIRE_EQUAL(0, fuse.fuse->fgetattr(fileName, &st, &fh)); + BOOST_REQUIRE_EQUAL(st.st_size, 0); + BOOST_REQUIRE_EQUAL(st.st_uid, getuid()); + BOOST_REQUIRE_EQUAL(st.st_gid, getgid()); + + BOOST_CHECKPOINT("Write some data"); + char someData[890]; + BOOST_REQUIRE_EQUAL(sizeof(someData), fuse.fuse->write(fileName, someData, sizeof(someData), 0, &fh)); + + BOOST_REQUIRE_EQUAL(0, fuse.fuse->fgetattr(fileName, &st, &fh)); + BOOST_REQUIRE_EQUAL(st.st_size, sizeof(someData)); + + BOOST_CHECKPOINT("Delete old daemon object"); + daemon.reset(); + BOOST_CHECKPOINT("Create new daemon object"); + daemon = MockDaemonHostPtr(new MockDaemonHost()); + + BOOST_CHECKPOINT("Fetch file attributes again"); + BOOST_REQUIRE_EQUAL(0, fuse.fuse->fgetattr(fileName, &st, &fh)); + + BOOST_CHECKPOINT("Close file"); + BOOST_REQUIRE_EQUAL(0, fuse.fuse->release(fileName, &fh)); +} + |