From c780b944680dff278d06ef07d7aba0a4f97c3dd8 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Tue, 15 Oct 2013 13:17:01 +0200 Subject: [PATCH] Support for user extended attributes. --- src/CMakeLists.txt | 2 +- src/VfsNs.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/VfsNs.h | 3 ++ 3 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d4ee889..18dac15 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index b9fe4b1..d46c012 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -3,6 +3,7 @@ /// @author Alejandro Álvarez Ayllón #include #include +#include #include #include #include @@ -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 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; +} diff --git a/src/VfsNs.h b/src/VfsNs.h index 11491de..51e3128 100644 --- a/src/VfsNs.h +++ b/src/VfsNs.h @@ -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]; }; }; -- 1.8.2.3