/// @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>
//
// 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;
xStat.stat = fstat;
xStat.parent = 0;
xStat.status = ExtendedStat::kOnline;
- xStat["pool"] = std::string("vfs");
return xStat;
}
ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) throw (DmException)
{
ExtendedStat meta;
+ Extensible xattrs;
std::string dir, c;
std::vector<std::string> components;
}
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
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());
+ }
}
//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;
+}