From 91800e2387cc4308d49c86aa696d79873c5576b8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Tue, 15 Oct 2013 13:35:20 +0200 Subject: [PATCH] Namespace prefix - NSPrefix. --- src/Vfs.cpp | 5 ++- src/Vfs.h | 1 + src/VfsNs.cpp | 118 ++++++++++++++++++++++++++++++++++++---------------------- src/VfsNs.h | 11 ++++-- 4 files changed, 87 insertions(+), 48 deletions(-) diff --git a/src/Vfs.cpp b/src/Vfs.cpp index 57d2430..0550ef3 100644 --- a/src/Vfs.cpp +++ b/src/Vfs.cpp @@ -70,6 +70,9 @@ void VfsFactory::configure(const std::string& key, const std::string& value) thr else if (key == "Deny") { this->deny_ = value; } + else if (key == "NSPrefix") { + this->nsPrefix_ = value; + } else throw DmException(DMLITE_CFGERR(DMLITE_UNKNOWN_KEY), "Unrecognised option " + key); @@ -80,7 +83,7 @@ void VfsFactory::configure(const std::string& key, const std::string& value) thr Catalog* VfsFactory::createCatalog(PluginManager*) throw (DmException) { syslog(LOG_DEBUG, "%s", __func__); - return new VfsCatalog(this->hostName_, this->allow_, this->deny_); + return new VfsCatalog(this->hostName_, this->nsPrefix_, this->allow_, this->deny_); } diff --git a/src/Vfs.h b/src/Vfs.h index f36f1fd..a87511a 100644 --- a/src/Vfs.h +++ b/src/Vfs.h @@ -55,6 +55,7 @@ namespace dmlite { protected: std::string hostName_; + std::string nsPrefix_; std::string tokenPasswd_; bool tokenUseIp_; diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index d46c012..9d62146 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -32,8 +32,8 @@ static gid_t getGid(const SecurityContext* ctx) { } -VfsCatalog::VfsCatalog(const std::string& host, const std::string &allow, const std::string &deny) throw (DmException): Catalog(), - hostName_(host) +VfsCatalog::VfsCatalog(const std::string& host, const std::string& prefix, const std::string &allow, const std::string &deny) throw (DmException): Catalog(), + hostName_(host), prefix_(prefix) { regex_t regex; int ret; @@ -55,6 +55,8 @@ VfsCatalog::VfsCatalog(const std::string& host, const std::string &allow, const vfsThrow(EINVAL, "invalid regular expresion for 'Deny': %s", buf); this->denyRegex = new regex_t(regex); } + + if (prefix.empty()) this->prefix_ = ""; } @@ -112,13 +114,15 @@ void VfsCatalog::setSecurityContext(const SecurityContext* ctx) throw (DmExcepti void VfsCatalog::changeDir(const std::string& path) throw (DmException) { ExtendedStat meta; + std::string lpath; meta = this->extendedStat(path); if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IEXEC | S_IREAD) != 0) vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), meta.name.c_str()); - wrapCall(chdir(path.c_str())); - syslog(LOG_DEBUG, "%s: changed to '%s'", __func__, path.c_str()); + lpath = getLocalPath(path); + wrapCall(chdir(lpath.c_str())); + syslog(LOG_DEBUG, "%s: changed to '%s'", __func__, lpath.c_str()); } @@ -126,8 +130,17 @@ void VfsCatalog::changeDir(const std::string& path) throw (DmException) std::string VfsCatalog::getWorkingDir(void) throw (DmException) { char buffer[1024]; + size_t len; + wrapCall(getcwd(buffer, sizeof(buffer))); - return std::string(buffer); + len = strlen(buffer); + + // working directory out of namespace prefix ==> "/" + if (this->prefix_.size() >= len || this->prefix_.compare(0, len, buffer, this->prefix_.size()) != 0 || buffer[this->prefix_.size()] != '/') + return std::string("/"); + + // strip the prefix + return std::string(buffer + this->prefix_.size()); } @@ -168,8 +181,9 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro else dir = this->getWorkingDir() + "/" + path; components = Url::splitPath(dir); - dir = ""; + dir = this->prefix_; for (unsigned int i = 0; i < components.size() - 1; i++) { + // the first component always '/', let's use it as separator if (i < 2) dir += components[i]; else dir = dir + "/" + components[i]; @@ -179,10 +193,10 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro vfsThrow(EACCES, "not enough permissions for '%s' to list '%s'", clientName.c_str(), meta.name.c_str()); } - meta = vfsExtendedStat(components.back(), path, follow); + meta = vfsExtendedStat(components.back(), getLocalPath(path), follow); // not require working xattrs try { - xattrs = vfsGetXattrs(path, follow); + xattrs = vfsGetXattrs(path, getLocalPath(path), follow); meta.copy(xattrs); } catch (DmException e) { if (e.code() != ENOTSUP) throw; @@ -239,7 +253,7 @@ bool VfsCatalog::access(const std::string& path, int mode) throw (DmException) if (checkPermissions(this->secCtx_, meta.acl, meta.stat, perm) != 0) return false; - if (::access(path.c_str(), mode) == -1) { + if (::access(getLocalPath(path).c_str(), mode) == -1) { if (errno == ENOENT) { // stat() performed OK, but access() failed with ENOENT vfsThrowErrno("access() failed with ENOENT on '" + path + "' (dangling symlink?)"); @@ -253,7 +267,7 @@ bool VfsCatalog::access(const std::string& path, int mode) throw (DmException) bool VfsCatalog::accessReplica(const std::string& replica, int mode) throw (DmException) { - return access(replica, mode); + return this->access(replica, mode); } @@ -313,7 +327,7 @@ void VfsCatalog::symlink(const std::string& oldPath, const std::string& newPath) if (checkPermissions(this->secCtx_, parent.acl, parent.stat, S_IWRITE | S_IEXEC) != 0) vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), parentPath.c_str()); - wrapCall(::symlink(oldPath.c_str(), newPath.c_str())); + wrapCall(::symlink(getLocalPath(oldPath).c_str(), getLocalPath(newPath).c_str())); } @@ -327,7 +341,7 @@ std::string VfsCatalog::readLink(const std::string& path) throw (DmException) vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), path.c_str()); memset(buf, 0, sizeof(buf)); - wrapCall(readlink(path.c_str(), buf, sizeof(buf) - 1)); + wrapCall(readlink(getLocalPath(path).c_str(), buf, sizeof(buf) - 1)); return buf; } @@ -353,7 +367,7 @@ void VfsCatalog::unlink(const std::string& path) throw (DmException) } } - wrapCall(::unlink(path.c_str())); + wrapCall(::unlink(getLocalPath(path).c_str())); } @@ -361,7 +375,7 @@ void VfsCatalog::unlink(const std::string& path) throw (DmException) void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException) { FILE *f; - std::string parentPath, name; + std::string parentPath, name, lpath; int code = DMLITE_SUCCESS; ExtendedStat file; @@ -394,9 +408,10 @@ void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException } #endif + lpath = getLocalPath(path); if (code == ENOENT) { // Create new - wrapCall(f = fopen(path.c_str(), "w")); + wrapCall(f = fopen(lpath.c_str(), "w")); wrapCall(fclose(f)); } else { // Truncate @@ -406,7 +421,7 @@ void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException checkPermissions(this->secCtx_, file.acl, file.stat, S_IWRITE) != 0) { vfsThrow(EACCES, "not enough permissions for '%s' to truncate '%s'", clientName.c_str(), path.c_str()); } - wrapCall(truncate(path.c_str(), 0)); + wrapCall(truncate(lpath.c_str(), 0)); } setMode(path, mode); @@ -437,7 +452,7 @@ void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmExceptio // TODO: buildin resets S_ISGID if not in the group // TODO: update ACL (kUserObj, kGroupObj/kMask, kOther) - wrapCall(chmod(path.c_str(), mode)); + wrapCall(chmod(getLocalPath(path).c_str(), mode)); } @@ -459,7 +474,7 @@ void VfsCatalog::setSize(const std::string& path, size_t newSize) throw (DmExcep checkPermissions(this->secCtx_, file.acl, file.stat, S_IWRITE) != 0) { vfsThrow(EACCES, "not enough permissions for '%s' to truncate '%s'", clientName.c_str(), path.c_str()); } - wrapCall(truncate(path.c_str(), newSize)); + wrapCall(truncate(getLocalPath(path).c_str(), newSize)); } @@ -489,7 +504,7 @@ void VfsCatalog::utime(const std::string& path, const struct utimbuf* buf) throw vfsThrow(EACCES, "not enough permissions for '%s' to modify the time of '%s'", clientName.c_str(), path.c_str()); } - wrapCall(::utime(path.c_str(), buf)); + wrapCall(::utime(getLocalPath(path).c_str(), buf)); } @@ -525,12 +540,15 @@ void VfsCatalog::updateExtendedAttributes(const std::string& path, Extensible oldXattrs, newXattrs; Extensible::const_iterator it; std::string key, value, oldvalue; + std::string lpath; meta = this->extendedStat(path, true); if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IWRITE) != 0) vfsThrow(EACCES, "not enough permissions for '%s' to change attributes on '%s'", clientName.c_str(), path.c_str()); - oldXattrs = vfsGetXattrs(path, true); + lpath = getLocalPath(path); + + oldXattrs = vfsGetXattrs(path, lpath, true); newXattrs.copy(attr); for (it = newXattrs.begin(); it != newXattrs.end(); it++) { @@ -541,33 +559,34 @@ void VfsCatalog::updateExtendedAttributes(const std::string& path, if (oldXattrs.hasField(key)) { oldvalue = Extensible::anyToString(oldXattrs[key]); if (oldvalue != value) { - syslog(LOG_DEBUG, "%s: replacing '%s' from '%s' to '%s' on '%s'", __func__, key.c_str(), oldvalue.c_str(), value.c_str(), path.c_str()); - wrapCall(attr_set(path.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_REPLACE), "could not replace extended attribute '%s' on '%s'", key.c_str(), path.c_str()); + syslog(LOG_DEBUG, "%s: replacing '%s' from '%s' to '%s' on '%s'", __func__, key.c_str(), oldvalue.c_str(), value.c_str(), lpath.c_str()); + wrapCall(attr_set(lpath.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_REPLACE), "could not replace extended attribute '%s' on '%s'", key.c_str(), path.c_str()); } oldXattrs.erase(key); } else { - syslog(LOG_DEBUG, "%s: creating '%s' = '%s' on '%s'", __func__, key.c_str(), value.c_str(), path.c_str()); - wrapCall(attr_set(path.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_CREATE), "could not create extended attribute '%s' on '%s'", key.c_str(), path.c_str()); + syslog(LOG_DEBUG, "%s: creating '%s' = '%s' on '%s'", __func__, key.c_str(), value.c_str(), lpath.c_str()); + wrapCall(attr_set(lpath.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_CREATE), "could not create extended attribute '%s' on '%s'", key.c_str(), path.c_str()); } } for (it = oldXattrs.begin(); it != oldXattrs.end(); it++) { key = it->first; value = Extensible::anyToString(it->second); - syslog(LOG_DEBUG, "%s: removing '%s' = '%s' from '%s'", __func__, key.c_str(), value.c_str(), path.c_str()); - wrapCall(attr_remove(path.c_str(), key.c_str(), 0), "could not remove '%s' on '%s'", key.c_str(), path.c_str()); + syslog(LOG_DEBUG, "%s: removing '%s' = '%s' from '%s'", __func__, key.c_str(), value.c_str(), lpath.c_str()); + wrapCall(attr_remove(lpath.c_str(), key.c_str(), 0), "could not remove '%s' on '%s'", key.c_str(), path.c_str()); } } -PrivateDir* VfsCatalog::vfsOpenDir(const std::string& path) throw (DmException) +PrivateDir* VfsCatalog::vfsOpenDir(const std::string& lpath, const std::string& path) throw (DmException) { PrivateDir *privateDir; privateDir = new PrivateDir(); try { privateDir->path = path; - privateDir->dir = opendir(path.c_str()); + privateDir->lpath = lpath; + privateDir->dir = opendir(lpath.c_str()); if (privateDir->dir == NULL) vfsThrowErrno("error opening directory '%s'", path.c_str()); } catch (...) { @@ -584,14 +603,16 @@ Directory* VfsCatalog::openDir(const std::string& path) throw (DmException) { PrivateDir *privateDir; ExtendedStat meta; + std::string lpath; meta = this->extendedStat(path); if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IREAD) != 0) vfsThrow(EACCES, "not enough permissions for '%s' to read '%s'", clientName.c_str(), path.c_str()); - privateDir = vfsOpenDir(path); + lpath = getLocalPath(path); + privateDir = vfsOpenDir(lpath, path); - syslog(LOG_DEBUG, "%s: directory '%s' opened", __func__, path.c_str()); + syslog(LOG_DEBUG, "%s: directory '%s' opened", __func__, lpath.c_str()); return privateDir; } @@ -602,6 +623,7 @@ void VfsCatalog::closeDir(Directory* dir) throw (DmException) int r; PrivateDir *privateDir = dynamic_cast(dir); std::string path = privateDir->path; + std::string lpath = privateDir->lpath; if (privateDir == NULL) throw DmException(DMLITE_SYSERR(EFAULT), @@ -610,8 +632,8 @@ void VfsCatalog::closeDir(Directory* dir) throw (DmException) r = closedir(privateDir->dir); delete privateDir; - wrapCall(r); - syslog(LOG_DEBUG, "%s: directory '%s' closed", __func__, path.c_str()); + wrapCall(r, "error closing directory '%s'", path.c_str()); + syslog(LOG_DEBUG, "%s: directory '%s' closed", __func__, lpath.c_str()); } @@ -644,8 +666,9 @@ ExtendedStat* VfsCatalog::readDirx(Directory* dir) throw (DmException) struct stat fstat; - wrapCall(fstatat(dirfd(privateDir->dir), ent->d_name, - &fstat, AT_SYMLINK_NOFOLLOW)); + wrapCall( + fstatat(dirfd(privateDir->dir), ent->d_name, &fstat, AT_SYMLINK_NOFOLLOW), + "can't stat '%s' at '%s'", ent->d_name, privateDir->path.c_str()); privateDir->stat.stat = fstat; privateDir->stat.name = ent->d_name; @@ -672,7 +695,7 @@ void VfsCatalog::makeDir(const std::string& path, mode_t mode) throw (DmExceptio mode &= ~S_IFMT; // TODO: S_ISGID // TODO: inherit default ACL - wrapCall(mkdir(path.c_str(), mode)); + wrapCall(mkdir(getLocalPath(path).c_str(), mode)); } @@ -685,11 +708,11 @@ void VfsCatalog::rename(const std::string& oldPath, const std::string& newPath) vfsThrow(EINVAL, "not the source, neither the destination, can be '/'"); ExtendedStat oldParent = this->getParent(oldPath, &oldParentPath, &oldName); - ExtendedStat newParent = this->getParent(newPath, &oldParentPath, &newName); + ExtendedStat newParent = this->getParent(newPath, &newParentPath, &newName); if (checkPermissions(this->secCtx_, oldParent.acl, oldParent.stat, S_IWRITE) != 0) - vfsThrow(EACCES, "Not enough permissions for '%s' on origin '%s'", clientName.c_str(), oldPath.c_str()); + vfsThrow(EACCES, "not enough permissions for '%s' on origin '%s'", clientName.c_str(), oldPath.c_str()); if (checkPermissions(this->secCtx_, newParent.acl, newParent.stat, S_IWRITE) != 0) - vfsThrow(EACCES, "Not enough permissions for '%s' on destination '%s'", clientName.c_str(), newPath.c_str()); + vfsThrow(EACCES, "not enough permissions for '%s' on destination '%s'", clientName.c_str(), newPath.c_str()); // Check sticky if (oldParent.stat.st_mode & S_ISVTX) { @@ -703,7 +726,7 @@ void VfsCatalog::rename(const std::string& oldPath, const std::string& newPath) // XXX: test-rename should probably accept both ENOTEMPTY and EEXIST instead // of changing it here? try { - wrapCall(::rename(oldPath.c_str(), newPath.c_str())); + wrapCall(::rename(getLocalPath(oldPath).c_str(), getLocalPath(newPath).c_str())); } catch (DmException e) { if (e.code() == ENOTEMPTY) e = DmException(EEXIST, e.what()); throw e; @@ -744,7 +767,7 @@ void VfsCatalog::removeDir(const std::string& path) throw (DmException) } ::chdir(cwd); // OK, we can try to remove - wrapCall(rmdir(path.c_str())); + wrapCall(rmdir(getLocalPath(path).c_str())); } catch (...) { if (cwd) ::chdir(cwd); free(cwd); @@ -763,7 +786,7 @@ Replica VfsCatalog::getReplicaByRFN(const std::string& rfn) throw (DmException) Replica replica; struct stat fstat; - wrapCall(stat(rfn.c_str(), &fstat)); + wrapCall(stat(getLocalPath(rfn).c_str(), &fstat)); replica.atime = fstat.st_atime; replica.fileid = fstat.st_ino; @@ -812,13 +835,20 @@ ExtendedStat VfsCatalog::getParent(const std::string& path, +const std::string VfsCatalog::getLocalPath(const std::string &path) { + if (path.empty() || path[0] != '/') return path; + return this->prefix_ + path; +} + + + int VfsCatalog::checkPermissions(const SecurityContext *context, const Acl &acl, const struct stat &stat, mode_t mode) { //fprintf(stderr, "VfsCatalog::checkPermissions(inode %lu, %04o)\n", stat.st_ino, mode); return this->allowCurrent ? 0 : 1; } -Extensible VfsCatalog::vfsGetXattrs(const std::string& path, bool follow) throw (DmException) { +Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow) throw (DmException) { int len; std::string attrValue; Extensible xattrs; @@ -829,7 +859,7 @@ Extensible VfsCatalog::vfsGetXattrs(const std::string& path, bool follow) throw list = (attrlist_t *)this->xattrBuffer; memset(&attr_cursor, 0, sizeof attr_cursor); do { - wrapCall(attr_list(path.c_str(), this->xattrBuffer, sizeof this->xattrBuffer, follow ? 0 : ATTR_DONTFOLLOW, &attr_cursor), "could not get list of extended attributes on '%s'", path.c_str()); + wrapCall(attr_list(lpath.c_str(), this->xattrBuffer, sizeof this->xattrBuffer, follow ? 0 : ATTR_DONTFOLLOW, &attr_cursor), "could not get list of extended attributes on '%s'", path.c_str()); for (int i = 0; i < list->al_count; i++) { entry = ATTR_ENTRY(this->xattrBuffer, i); // "selinux" is returned in the list, but failing to get the value @@ -837,7 +867,7 @@ Extensible VfsCatalog::vfsGetXattrs(const std::string& path, bool follow) throw //syslog(LOG_DEBUG, "%s: skipping attribute '%s'", __func__, entry->a_name); } else { len = sizeof this->xattrValue; - wrapCall(attr_get(path.c_str(), entry->a_name, this->xattrValue, &len, follow ? 0 : ATTR_DONTFOLLOW), "could not get extended attribute '%s' on '%s'", entry->a_name, path.c_str()); + wrapCall(attr_get(lpath.c_str(), entry->a_name, this->xattrValue, &len, follow ? 0 : ATTR_DONTFOLLOW), "could not get extended attribute '%s' on '%s'", entry->a_name, path.c_str()); syslog(LOG_DEBUG, "%s: '%s' = '%.*s'", __func__, entry->a_name, len, this->xattrValue); attrValue.assign(this->xattrValue, len); xattrs[entry->a_name] = attrValue; diff --git a/src/VfsNs.h b/src/VfsNs.h index 51e3128..9015757 100644 --- a/src/VfsNs.h +++ b/src/VfsNs.h @@ -17,6 +17,7 @@ namespace dmlite { struct PrivateDir: public Directory { virtual ~PrivateDir() {}; std::string path; ///< Directory opened + std::string lpath; ///< Real directory opened (local) DIR *dir; ///< Used for calls to the dpns API. ExtendedStat stat; ///< Where the data is actually stored. }; @@ -27,7 +28,7 @@ namespace dmlite { public: /// Constructor /// @param retryLimit Limit of retrials. - VfsCatalog(const std::string& host, const std::string& allow, const std::string& deny) throw (DmException); + VfsCatalog(const std::string& host, const std::string& prefix, const std::string& allow, const std::string& deny) throw (DmException); /// Destructor ~VfsCatalog(); @@ -101,13 +102,17 @@ namespace dmlite { /// @return The parent metadata. ExtendedStat getParent(const std::string& path, std::string* parentPath, std::string* name) throw (DmException); + /// Get path on the local disk according to "public" path. + /// Relative paths are unchanged. + const std::string getLocalPath(const std::string &path); ExtendedStat vfsExtendedStat(const std::string& name, const std::string& path, bool follow) throw (DmException); - PrivateDir* vfsOpenDir(const std::string& path) throw (DmException); - Extensible vfsGetXattrs(const std::string& path, bool follow) throw (DmException); + PrivateDir* vfsOpenDir(const std::string& lpath, const std::string& path) throw (DmException); + Extensible vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow) throw (DmException); StackInstance* si_; const SecurityContext* secCtx_; std::string hostName_; + std::string prefix_; private: int checkPermissions(const SecurityContext *context, const Acl &acl, const struct stat &stat, mode_t mode); -- 1.8.2.3