#include #include #include #include #include #include #include #include #include "daemonVolume.h" #include "daemonFile.h" #include "daemonDirectory.h" #include "lockHelpers.h" #include "modeCheck.h" #include #include #include #include "daemon.h" extern std::map files; VolumeServer::VolumeServer(const boost::filesystem::path & r, const EntCache & u, const EntCache & g) : root(boost::filesystem::canonical(r)), userLookup(u), groupLookup(g) { } VolumeServer::~VolumeServer() { } void VolumeServer::disconnect(const Ice::Current & ice) { ice.adapter->remove(ice.id); } Ice::Int VolumeServer::access(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); struct stat s; boost::filesystem::path p(resolvePath(path)); if (::stat(p.c_str(), &s) != 0) { return errno; } if (mode == F_OK) { // stat succeeded, file must exist return 0; } mc.AssertReadParent(p); if (mode & R_OK && !mc.ReadableBy(s, mc.myu, mc.myg)) { return EACCES; } if (mode & W_OK && !mc.WritableBy(s, mc.myu, mc.myg)) { return EACCES; } if (mode & X_OK && !mc.ExecutableBy(s, mc.myu, mc.myg)) { return EACCES; } return 0; } NetFS::Attr VolumeServer::getattr(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); struct stat s; boost::filesystem::path p(resolvePath(path)); mc.AssertReadParent(p); if (::lstat(p.c_str(), &s) != 0) { throw NetFS::SystemError(errno); } NetFS::Attr a; a << StatSource { s, userLookup, groupLookup }; return a; } void VolumeServer::mknod(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, Ice::Int dev, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWriteParent(p); if (::mknod(p.c_str(), mode, dev) != 0) { throw NetFS::SystemError(errno); } } void VolumeServer::symlink(const NetFS::ReqEnv & re, const std::string & path1, const std::string & path2, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path2)); mc.AssertWriteParent(p); if (::symlink(path1.c_str(), p.c_str()) != 0) { throw NetFS::SystemError(errno); } if (::lchown(p.c_str(), mc.myu, mc.myg) != 0) { ::unlink(p.c_str()); throw NetFS::SystemError(errno); } } void VolumeServer::link(const NetFS::ReqEnv & re, const std::string & path1, const std::string & path2, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p1(resolvePath(path1)); boost::filesystem::path p2(resolvePath(path2)); if (::link(p1.c_str(), p2.c_str()) != 0) { throw NetFS::SystemError(errno); } if (::chown(p2.c_str(), mc.myu, mc.myg) != 0) { ::unlink(p2.c_str()); throw NetFS::SystemError(errno); } } void VolumeServer::rename(const NetFS::ReqEnv & re, const std::string & from, const std::string & to, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path f(resolvePath(from)); boost::filesystem::path t(resolvePath(to)); mc.AssertWriteParent(f); mc.AssertWrite(f); if (boost::filesystem::is_directory(t)) { mc.AssertWrite(t); } else { mc.AssertWriteParent(t); } if (::rename(f.c_str(), t.c_str()) != 0) { throw NetFS::SystemError(errno); } } std::string VolumeServer::readlink(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; char buf[PATH_MAX]; boost::filesystem::path p(resolvePath(path)); mc.AssertRead(p); ssize_t rc = ::readlink(p.c_str(), buf, PATH_MAX); if (rc == -1) { throw NetFS::SystemError(errno); } return std::string(buf, rc); } void VolumeServer::chmod(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWrite(p); if (::chmod(p.c_str(), mode) != 0) { throw NetFS::SystemError(errno); } } void VolumeServer::chown(const NetFS::ReqEnv & re, const std::string & path, Ice::Int uid, Ice::Int gid, const Ice::Current &) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWrite(p); if (::lchown(p.c_str(), uid, gid) != 0) { throw NetFS::SystemError(errno); } } void VolumeServer::utimens(const NetFS::ReqEnv & re, const std::string & path, Ice::Long s0, Ice::Long ns0, Ice::Long s1, Ice::Long ns1, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; struct timespec times[2]; times[0].tv_sec = s0; times[0].tv_nsec = ns0; times[1].tv_sec = s1; times[1].tv_nsec = ns1; boost::filesystem::path p(resolvePath(path)); mc.AssertWrite(p); if (::utimensat(0, p.c_str(), times, AT_SYMLINK_NOFOLLOW) != 0) { throw NetFS::SystemError(errno); } } NetFS::VFS VolumeServer::statfs(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; struct statvfs s; boost::filesystem::path p(resolvePath(path)); mc.AssertRead(p); if (::statvfs(p.c_str(), &s) != 0) { throw NetFS::SystemError(errno); } NetFS::VFS t; t << s; return t; } void VolumeServer::truncate(const NetFS::ReqEnv & re, const std::string & path, Ice::Long size, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWrite(p); if (::truncate(p.c_str(), size) != 0) { throw NetFS::SystemError(errno); } } void VolumeServer::unlink(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWrite(p); mc.AssertWriteParent(p); if (::unlink(p.c_str()) != 0) { throw NetFS::SystemError(errno); } } NetFS::FilePrx VolumeServer::open(const NetFS::ReqEnv & re, const std::string & path, Ice::Int flags, const Ice::Current & ice) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertRead(p); if (flags & O_CREAT) { throw NetFS::SystemError(EINVAL); } int fd = ::open(p.c_str(), flags); if (fd == -1) { throw NetFS::SystemError(errno); } return NetFS::FilePrx::checkedCast(ice.adapter->addWithUUID(new FileServer(fd, userLookup, groupLookup))); } NetFS::FilePrx VolumeServer::create(const NetFS::ReqEnv & re, const std::string & path, Ice::Int flags, Ice::Int mode, const Ice::Current & ice) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWriteParent(p); int fd = ::open(p.c_str(), O_CREAT | flags, mode); if (fd == -1) { throw NetFS::SystemError(errno); } if (fchown(fd, mc.myu, mc.myg) != 0) { ::close(fd); ::unlink(p.c_str()); throw NetFS::SystemError(errno); } return NetFS::FilePrx::checkedCast(ice.adapter->addWithUUID(new FileServer(fd, userLookup, groupLookup))); } NetFS::DirectoryPrx VolumeServer::opendir(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current & ice) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertRead(p); DIR * od = ::opendir(p.c_str()); if (!od) { throw NetFS::SystemError(errno); } return NetFS::DirectoryPrx::checkedCast(ice.adapter->addWithUUID(new DirectoryServer(od))); } void VolumeServer::mkdir(const NetFS::ReqEnv & re, const std::string & path, Ice::Int mode, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWriteParent(p); if (::mkdir(p.c_str(), mode) != 0) { throw NetFS::SystemError(errno); } if (::chown(p.c_str(), mc.myu, mc.myg) != 0) { ::rmdir(p.c_str()); throw NetFS::SystemError(errno); } } void VolumeServer::rmdir(const NetFS::ReqEnv & re, const std::string & path, const Ice::Current&) { ModeCheck mc(re, root, userLookup, groupLookup); errno = 0; boost::filesystem::path p(resolvePath(path)); mc.AssertWrite(p); mc.AssertWriteParent(p); if (::rmdir(p.c_str()) != 0) { throw NetFS::SystemError(errno); } } boost::filesystem::path normalizedAppend(boost::filesystem::path out, const boost::filesystem::path & in) { unsigned int depth = 0; for(auto e : in) { if (e.empty() || e == "." || e == "/") { continue; } else if (e == "..") { if (depth == 0) { throw NetFS::SystemError(EPERM); } out.remove_leaf(); depth -= 1; } else { out /= e; depth += 1; } } return out; } boost::filesystem::path VolumeServer::resolvePath(const std::string & path) const { return normalizedAppend(root, path); }