#include "Vfs.h"
#include "VfsNs.h"
+#define VFS_XATTR "#vfs."
+#define VFS_XATTR_LENGTH 5
+#define VFS_XATTR_TYPE_PERMS 1
+#define VFS_XATTR_TYPE_NONPERMS 2
+#define VFS_XATTR_TYPE_USER 4
+#define VFS_XATTR_TYPE_ALL 7
+#define IS_VFS_XATTR(NAME) (strncmp((NAME), VFS_XATTR, VFS_XATTR_LENGTH) == 0)
#define IS_VFS_FILE(NAME) (strncmp((NAME), VFS_FILE, VFS_FILE_LENGTH) == 0)
+// force everything to current owner for now
+#define VFS_UID_NONE xStat.stat.st_uid
+#define VFS_GID_NONE xStat.stat.st_gid
+
using namespace dmlite;
///
+/// Update ExtendedStat fields related to permissions.
+/// Requires user extended attributes retrieved with VFS_XATTR_TYPE_PERMS or
+/// VFS_XATTR_TYPE_ALL.
+///
+/// @param xStat Updated ExtendedStat class.
+/// @param xattrs User extended attributes (requires acl, group, and owner VFS
+/// attributes).
+///
+void VfsCatalog::vfsUpdateStat(ExtendedStat &xStat, Extensible xattrs) throw (DmException) {
+ if (xattrs.hasField(VFS_XATTR "acl"))
+ xStat.acl = Acl(xattrs.getString(VFS_XATTR "acl"));
+ xStat.stat.st_gid = xattrs.getUnsigned(VFS_XATTR "group", VFS_GID_NONE);
+ xStat.stat.st_uid = xattrs.getUnsigned(VFS_XATTR "owner", VFS_UID_NONE);
+}
+
+
+
+///
/// Do simple stat()/lstat() without setting st_nlink and checking permissions.
/// Optionally retrieves also the information related to permissions in
/// optimized way (using only attributes related to permissions).
/// @param name file name
/// @param path local disk namespace path
/// @param follow follow symlinks (to use stat() or lstat())
+/// @param perms get information related to permissions
//
-ExtendedStat VfsCatalog::vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow) throw (DmException) {
+ExtendedStat VfsCatalog::vfsSimpleStat(const std::string& name, const std::string& path, const std::string& lpath, bool follow, bool perms) throw (DmException) {
ExtendedStat xStat;
struct stat fstat;
+ Extensible xattrs;
if (follow)
wrapCall(stat(lpath.c_str(), &fstat), "could not stat '%s'", path.c_str());
xStat.status = ExtendedStat::kOnline;
xStat.acl = Acl();
+ if (perms) {
+ xattrs = vfsGetXattrs(path, lpath, true, VFS_XATTR_TYPE_PERMS);
+ vfsUpdateStat(xStat, xattrs);
+ } else {
+ xStat.acl = Acl();
+ xStat.stat.st_uid = VFS_UID_NONE;
+ xStat.stat.st_gid = VFS_GID_NONE;
+ }
+
return xStat;
}
///
/// @param path public namespace path
/// @param follow follow symlinks
+/// @param parms get information related to permissions
///
-ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& path, bool follow) throw (DmException) {
+ExtendedStat VfsCatalog::vfsExtendedStat(const std::string& path, bool follow, bool perms) throw (DmException) {
ExtendedStat meta;
std::vector<std::string> components;
std::string dir;
if (i < 2) dir += components[i];
else dir = dir + "/" + components[i];
- meta = vfsSimpleStat(components[i], dir, getLocalPath(dir), true);
+ meta = vfsSimpleStat(components[i], dir, getLocalPath(dir), true, true);
if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IEXEC) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' to list '%s'", clientName.c_str(), meta.name.c_str());
}
- return vfsSimpleStat(components.back(), path, getLocalPath(path), follow);
+ return vfsSimpleStat(components.back(), path, getLocalPath(path), follow, perms);
}
if (vfsCheckPermissions(path, S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- meta = vfsExtendedStat(path, follow);
+ meta = vfsExtendedStat(path, follow, false);
//
// User extended attributes are not supported on symlinks. We need the same
// owner, permissions and other atributes like the original file anyway.
// ==> always follow the symlinks.
//
- xattrs = vfsGetXattrs(path, getLocalPath(path), true);
+ xattrs = vfsGetXattrs(path, getLocalPath(path), true, VFS_XATTR_TYPE_ALL);
- // copy attributes
+ // copy non-VFS attributes
for (it = xattrs.begin(); it != xattrs.end(); it++) {
key = it->first;
- meta[key] = xattrs[key];
+ if (!IS_VFS_XATTR(key.c_str()))
+ meta[key] = xattrs[key];
}
+ vfsUpdateStat(meta, xattrs);
+
meta["pool"] = std::string("vfs");
#if 0
if (vfsCheckPermissions(path, S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- xStat = this->vfsExtendedStat(path, true);
+ xStat = this->vfsExtendedStat(path, true, true);
if (checkPermissions(this->secCtx_, xStat.acl, xStat.stat, S_IREAD) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' to read '%s'", clientName.c_str(), path.c_str());
if (vfsCheckPermissions(path, S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- meta = this->vfsExtendedStat(path, false);
+ meta = this->vfsExtendedStat(path, false, true);
if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IREAD) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), path.c_str());
// Sticky bit set ==> only directory or file owner can delete
if ((parent.stat.st_mode & S_ISVTX) == S_ISVTX) {
// not follow symlinks (remove them instead)
- ExtendedStat file = this->vfsSimpleStat(name, path, lpath, false);
+ ExtendedStat file = this->vfsSimpleStat(name, path, lpath, false, true);
if (getUid(this->secCtx_) != file.stat.st_uid &&
getUid(this->secCtx_) != parent.stat.st_uid) {
vfsThrow(EACCES, "not enough permissions for '%s' to unlink '%s' (sticky bit set)", clientName.c_str(), path.c_str());
try {
// follow symlinks
- file = this->vfsSimpleStat(name, path, lpath, true);
+ file = this->vfsSimpleStat(name, path, lpath, true, true);
} catch (DmException e) {
code = DMLITE_ERRNO(e.code());
if (code != ENOENT) throw;
for (it = newXattrs.begin(); it != newXattrs.end(); it++) {
key = it->first;
+ // not synchronize anything VFS plugin related
+ if (IS_VFS_XATTR(key.c_str()))
+ vfsThrow(EPERM, "change VFS plugin attribute not permitted (%s)", key.c_str());
+
// used to be bug in Extensible? 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);
for (it = oldXattrs.begin(); it != oldXattrs.end(); it++) {
key = it->first;
+ // not synchronize anything VFS plugin related
+ if (IS_VFS_XATTR(key.c_str()))
+ vfsThrow(DMLITE_SYSERR(EINVAL), "internal error: got VFS plugin attribute from extendedStat(), this should not happen");
+
value = Extensible::anyToString(it->second);
debug("removing '%s' = '%s' from '%s'", 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());
///
/// @param path local disk namespace path
/// @param follow follow symlinks (not well supported, it should be always true), XXX: dangling symlinks fails
-Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow) throw (DmException) {
+/// @param amount what to retrieve, bitmask:
+/// VFS_XATTR_TYPE_PERMS = 1: permissions related attributes (#vfs.acl, #vfs.owner, #vfs.group, ...),
+/// VFS_XATTR_TYPE_NONPERMS = 2: other VFS plugin related attributes (#vfs.replica*, ...),
+/// VFS_XATTR_TYPE_USER = 4: user attributes
+Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow, int amount) throw (DmException) {
int len;
std::string attrValue;
Extensible xattrs;
attrlist_cursor_t attr_cursor;
attrlist_t *list;
attrlist_ent_t *entry;
+ int attrType;
list = (attrlist_t *)this->buffer;
memset(&attr_cursor, 0, sizeof attr_cursor);
wrapCall(attr_list(lpath.c_str(), this->buffer, sizeof this->buffer, 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->buffer, i);
- // "selinux" is returned in the list, but failing to get the value
- if (strcmp(entry->a_name, "selinux") == 0) {
- //debug("skipping attribute '%s'", entry->a_name);
+ if (IS_VFS_XATTR(entry->a_name)) {
+ if (strcmp(entry->a_name + VFS_XATTR_LENGTH, "acl") == 0 ||
+ strcmp(entry->a_name + VFS_XATTR_LENGTH, "group") == 0 ||
+ strcmp(entry->a_name + VFS_XATTR_LENGTH, "owner") == 0)
+ {
+ attrType = VFS_XATTR_TYPE_PERMS;
+ } else {
+ attrType = VFS_XATTR_TYPE_NONPERMS;
+ }
} else {
+ // "selinux" is returned in the list, but failing to get the value
+ if (strcmp(entry->a_name, "selinux") == 0) attrType = 0;
+ else attrType = VFS_XATTR_TYPE_USER;
+ }
+
+ if ((attrType & amount) != 0) {
len = sizeof this->xattrValue;
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());
- debug("'%s' = '%.*s'", entry->a_name, len, this->xattrValue);
+ debug("'%s' (type %d) = '%.*s'", entry->a_name, attrType, len, this->xattrValue);
attrValue.assign(this->xattrValue, len);
xattrs[entry->a_name] = attrValue;
}