Support for user extended attributes.
authorFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 15 Oct 2013 11:17:01 +0000 (13:17 +0200)
committerFrantišek Dvořák <valtri@civ.zcu.cz>
Tue, 15 Oct 2013 11:17:01 +0000 (13:17 +0200)
src/CMakeLists.txt
src/VfsNs.cpp
src/VfsNs.h

index d4ee889..18dac15 100644 (file)
@@ -9,7 +9,7 @@ add_library (vfs MODULE Vfs.cpp
                         Throw.cpp
             )
 
-target_link_libraries (vfs ${DMLITE_LIBRARIES})
+target_link_libraries (vfs ${DMLITE_LIBRARIES} -lattr)
 set_target_properties (vfs PROPERTIES PREFIX "plugin_")
 
 install (TARGETS       vfs
index b9fe4b1..d46c012 100644 (file)
@@ -3,6 +3,7 @@
 /// @author Alejandro Álvarez Ayllón <aalvarez@cern.ch>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <attr/attributes.h>
 #include <utime.h>
 #include <cstdio>
 #include <cstdlib>
@@ -133,7 +134,7 @@ std::string VfsCatalog::getWorkingDir(void) throw (DmException)
 
 //
 // helper function
-// (without setting st_nlink and checking permissions)
+// (stat() only, without setting st_nlink, checking permissions, or xattr)
 //
 ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& name, const std::string& path, bool follow) throw (DmException) {
   ExtendedStat xStat;
@@ -149,7 +150,6 @@ ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& name, const std::str
   xStat.stat    = fstat;
   xStat.parent  = 0;
   xStat.status  = ExtendedStat::kOnline;
-  xStat["pool"] = std::string("vfs");
 
   return xStat;
 }
@@ -159,6 +159,7 @@ ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& name, const std::str
 ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) throw (DmException)
 {
   ExtendedStat meta;
+  Extensible xattrs;
   std::string dir, c;
   std::vector<std::string> components;
 
@@ -179,6 +180,15 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro
   }
 
   meta = vfsExtendedStat(components.back(), path, follow);
+  // not require working xattrs
+  try {
+    xattrs = vfsGetXattrs(path, follow);
+    meta.copy(xattrs);
+  } catch (DmException e) {
+    if (e.code() != ENOTSUP) throw;
+  }
+
+  meta["pool"] = std::string("vfs");
 
 #if 0
   // XXX: black magic
@@ -511,8 +521,41 @@ void VfsCatalog::setGuid(const std::string&, const std::string&) throw (DmExcept
 void VfsCatalog::updateExtendedAttributes(const std::string& path,
                                                 const Extensible& attr) throw (DmException)
 {
-  throw DmException(DMLITE_SYSERR(ENOSYS),
-                    "VfsCatalog does not support extended attributes");
+  ExtendedStat meta;
+  Extensible oldXattrs, newXattrs;
+  Extensible::const_iterator it;
+  std::string key, value, oldvalue;
+
+  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);
+  newXattrs.copy(attr);
+
+  for (it = newXattrs.begin(); it != newXattrs.end(); it++) {
+    key = it->first;
+    // XXX: bug in Extensible? for bool type "true" not mapped to true
+    if (it->second.type() == typeid(bool)) value = Extensible::anyToBoolean(it->second) ? std::string("1") : std::string("0");
+    else value = Extensible::anyToString(it->second);
+    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());
+      }
+      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());
+    }
+  }
+  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());
+  }
 }
 
 
@@ -773,3 +816,34 @@ int VfsCatalog::checkPermissions(const SecurityContext *context, const Acl &acl,
 //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) {
+  int len;
+  std::string attrValue;
+  Extensible xattrs;
+  attrlist_cursor_t attr_cursor;
+  attrlist_t *list;
+  attrlist_ent_t *entry;
+
+  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());
+    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
+      if (strcmp(entry->a_name, "selinux") == 0) {
+        //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());
+        syslog(LOG_DEBUG, "%s: '%s' = '%.*s'", __func__, entry->a_name, len, this->xattrValue);
+        attrValue.assign(this->xattrValue, len);
+        xattrs[entry->a_name] = attrValue;
+      }
+    }
+  } while (list->al_more);
+
+  return xattrs;
+}
index 11491de..51e3128 100644 (file)
@@ -103,6 +103,7 @@ namespace dmlite {
                           std::string* name) throw (DmException);
     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);
 
     StackInstance* si_;
     const SecurityContext* secCtx_;
@@ -114,6 +115,8 @@ namespace dmlite {
     regex_t *allowRegex, *denyRegex;
     bool allowCurrent;
     std::string clientName;
+
+    char xattrBuffer[1024], xattrValue[1024];
   };
 
 };