Namespace prefix - NSPrefix.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 15 Oct 2013 11:35:20 +0000 (13:35 +0200)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 15 Oct 2013 11:35:20 +0000 (13:35 +0200)
src/Vfs.cpp
src/Vfs.h
src/VfsNs.cpp
src/VfsNs.h

index 57d2430..0550ef3 100644 (file)
@@ -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_);
 }
 
 
index f36f1fd..a87511a 100644 (file)
--- 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_;
index d46c012..9d62146 100644 (file)
@@ -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<PrivateDir*>(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;
index 51e3128..9015757 100644 (file)
@@ -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);