From 8e0b05570f655acbdf2a50b1fe7b56515cade952 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Franti=C5=A1ek=20Dvo=C5=99=C3=A1k?= Date: Wed, 11 Sep 2013 16:06:30 +0200 Subject: [PATCH] First experiments with metadata files (ACLs write only). --- src/Vfs.h | 2 ++ src/VfsNs.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/Vfs.h b/src/Vfs.h index 02ca183..53ee84e 100644 --- a/src/Vfs.h +++ b/src/Vfs.h @@ -19,6 +19,8 @@ #define wrapCall(RETVAL, ...) dmlite::vfsWrapCallHelper(__func__, (RETVAL) , ##__VA_ARGS__) #endif +#define VFS_METAFILE_PREFIX ".#vfs" + namespace dmlite { /// Concrete factory for DPM wrapper diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index 7732a4a..9a0a40e 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -18,6 +18,8 @@ using namespace dmlite; +static void pathGetParts(const std::string &path, std::string &dirName, std::string& baseName); + VfsCatalog::VfsCatalog(const std::string& host) throw (DmException): Catalog(), hostName_(host) @@ -75,6 +77,10 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro { ExtendedStat xStat; struct stat fstat; + FILE *f; + char buf[100]; + size_t l; + std::string *aclstr; if (follow) wrapCall(stat(path.c_str(), &fstat)); @@ -89,6 +95,21 @@ ExtendedStat VfsCatalog::extendedStat(const std::string& path, bool follow) thro xStat.status = ExtendedStat::kOnline; xStat["pool"] = std::string("vfs"); + if ((f = fopen(VFS_METAFILE_PREFIX, "r")) == NULL) { + if (errno != ENOENT) vfsThrowErrno("opening directory metadata failed"); + } else { + l = fread(buf, 1, sizeof(buf) - 1, f); + if (ferror(f)) vfsThrow(DMLITE_SYSERR(EIO), "reading directory metadata failed"); + buf[l] = '\0'; + try { + xStat.acl = Acl(std::string(buf)); + } catch (...) { + fclose(f); + throw; + } + wrapCall(fclose(f), "closing directory metadata failed"); + } + return xStat; } @@ -182,12 +203,26 @@ std::string VfsCatalog::readLink(const std::string& path) throw (DmException) -void VfsCatalog::unlink(const std::string& path) throw (DmException) +static void rawUnlink(const std::string& path) throw (DmException) { wrapCall(::unlink(path.c_str())); } +void VfsCatalog::unlink(const std::string& path) throw (DmException) +{ + std::string dir, name; + + pathGetParts(path, dir, name); + try { + rawUnlink(dir + "/" + VFS_METAFILE_PREFIX + name); + } catch (dmlite::DmException& e) { + if (e.code() != ENOENT) throw; + } + rawUnlink(path); +} + + void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException) { @@ -240,7 +275,67 @@ void VfsCatalog::setChecksum(const std::string& path, void VfsCatalog::setAcl(const std::string& path, const Acl& acl) throw (DmException) { - throw DmException(EACCES, "Write mode not supported"); + ExtendedStat meta = this->extendedStat(path, false); + Acl aclCopy(acl); + mode_t oldmode; + std::string aclstr, parentPath, fileName; + FILE *f; + +//FIXME: who can set ACLs? + + // Make sure the owner and group matches! + for (size_t i = 0; i < aclCopy.size(); i++) { + if (aclCopy[i].type == AclEntry::kUserObj) + aclCopy[i].id = meta.stat.st_uid; + else if (aclCopy[i].type == AclEntry::kGroupObj) + aclCopy[i].id = meta.stat.st_gid; + else if (aclCopy[i].type & AclEntry::kDefault && !S_ISDIR(meta.stat.st_mode)) + vfsThrow(EINVAL, "Defaults can be only applied to directories"); + } + + // Validate the ACL + aclCopy.validate(); + + // Update the file mode + oldmode = meta.stat.st_mode; + for (size_t i = 0; i < aclCopy.size(); i++) { + switch (aclCopy[i].type) { + case AclEntry::kUserObj: + meta.stat.st_mode = (meta.stat.st_mode & 0177077) | + (aclCopy[i].perm << 6); + break; + case AclEntry::kGroupObj: + meta.stat.st_mode = (meta.stat.st_mode & 0177707) | + (aclCopy[i].perm << 3); + break; + case AclEntry::kMask: + meta.stat.st_mode = (meta.stat.st_mode & ~070) | + (meta.stat.st_mode & aclCopy[i].perm << 3); + break; + case AclEntry::kOther: + meta.stat.st_mode = (meta.stat.st_mode & 0177770) | + (aclCopy[i].perm); + break; + default: + continue; + } + } + + if (oldmode != meta.stat.st_mode) { + wrapCall(chmod(path.c_str(), meta.stat.st_mode)); + } + + aclstr = aclCopy.serialize(); + if (S_ISDIR(meta.stat.st_mode)) { + f = fopen((path + "/" + VFS_METAFILE_PREFIX).c_str(), "w"); + wrapCall(f, "creating directory metadata failed"); + } else { + pathGetParts(path, parentPath, fileName); + f = fopen((parentPath + "/" + VFS_METAFILE_PREFIX + fileName).c_str(), "w"); + wrapCall(f, "creating file metadata failed"); + } + fprintf(f, "%s", aclstr.c_str()); + wrapCall(fclose(f), "closing metadata failed"); } @@ -371,7 +466,12 @@ void VfsCatalog::rename(const std::string& oldPath, const std::string& newPath) void VfsCatalog::removeDir(const std::string& path) throw (DmException) { - wrapCall(rmdir(path.c_str())); + try { + VfsCatalog::unlink(path + "/" + VFS_METAFILE_PREFIX); + } catch (dmlite::DmException& e) { + if (e.code() != ENOENT) throw; + } + wrapCall(::rmdir(path.c_str())); } @@ -403,3 +503,11 @@ void VfsCatalog::updateReplica(const Replica& replica) throw (DmException) { // Nothing } + + +static void pathGetParts(const std::string &path, std::string &dirName, std::string& baseName) { + std::vector components = Url::splitPath(path); + baseName = components.back(); + components.pop_back(); + dirName = Url::joinPath(components); +} -- 1.8.2.3