From: František Dvořák Date: Wed, 16 Oct 2013 15:36:24 +0000 (+0200) Subject: Fix setMode() vs VFS internal xattr: use separated "mode" attribute for the mode... X-Git-Url: http://scientific.zcu.cz/git/?a=commitdiff_plain;h=e5a0a728df967830de6928c20a3be2dd2b3c1af8;p=dmlite-plugins-vfs-old.git Fix setMode() vs VFS internal xattr: use separated "mode" attribute for the mode and always set read+write for the owner on filesystem. --- diff --git a/src/VfsNs.cpp b/src/VfsNs.cpp index 109c145..b881eb8 100644 --- a/src/VfsNs.cpp +++ b/src/VfsNs.cpp @@ -158,12 +158,37 @@ std::string VfsCatalog::getWorkingDir(void) throw (DmException) /// attributes). /// void VfsCatalog::vfsUpdateStat(ExtendedStat &xStat, Extensible xattrs) throw (DmException) { + std::string modeStr; + mode_t mode; + char *parse; + if (xattrs.hasField(VFS_XATTR "acl")) xStat.acl = Acl(xattrs.getString(VFS_XATTR "acl")); else xStat.acl = 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); + + modeStr = xattrs.getString(VFS_XATTR "mode", ""); + if (!modeStr.empty()) { + errno = 0; + mode = strtoull(modeStr.c_str(), &parse, 8); + if (*parse || errno) { +#ifdef DEBUG + // let's not throw up in ExtendedStat() + // ==> only debug + vfsThrowErrno("conversion of the mode '%s' failed on '%s'", modeStr.c_str(), xStat.name.c_str()); +#else + log(LOG_ERR, "conversion of the mode '%s' failed on '%s'", modeStr.c_str(), xStat.name.c_str()); +#endif + } else { + // prefer type from the filesystem + mode &= ~S_IFMT; + mode |= xStat.stat.st_mode & S_IFMT; + // use xattr for everything else + xStat.stat.st_mode = mode; + } + } } @@ -579,6 +604,7 @@ mode_t VfsCatalog::umask(mode_t mask) throw () void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmException) { ExtendedStat meta; + char buf[20]; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -590,14 +616,24 @@ void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmExceptio getUid(this->secCtx_) != 0) { vfsThrow(EACCES, "'%s' neither owner nor root, setting the mode of '%s' rejected", clientName.c_str(), path.c_str()); } - // Clean up unwanted bits + + // Clean up unwanted bits (keep type, read/write for owner, correct sticky bit) mode &= ~S_IFMT; - // Keep type bits mode |= (meta.stat.st_mode & S_IFMT); - // TODO: buildin resets S_ISGID if not in the group - // TODO: update ACL (kUserObj, kGroupObj/kMask, kOther) + if (getUid(this->secCtx_) != 0 && + !hasGroup(this->secCtx_->groups, meta.stat.st_gid)) + mode &= ~S_ISGID; - wrapCall(chmod(getLocalPath(path).c_str(), mode)); + // + // Set the mode on the filesystem + // + // But keep read/write for owner. + // Filesystem mode couldn't be needed, but let's set it anyway. + // + wrapCall(chmod(getLocalPath(path).c_str(), mode | S_IRUSR | S_IWUSR)); + + snprintf(buf, sizeof buf, "%04o", mode); + vfsSetXattr(path, getLocalPath(path), VFS_XATTR "mode", buf, 0); } @@ -979,7 +1015,8 @@ ExtendedStat* VfsCatalog::readDirx(Directory* dir) throw (DmException) void VfsCatalog::makeDir(const std::string& path, mode_t mode) throw (DmException) { - std::string parentPath, name; + std::string lpath, parentPath, name; + char buf[20]; if (vfsCheckPermissions(path, S_IWRITE)) vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str()); @@ -994,11 +1031,19 @@ void VfsCatalog::makeDir(const std::string& path, mode_t mode) throw (DmExceptio if (checkPermissions(this->secCtx_, parent.acl, parent.stat, S_IWRITE) != 0) vfsThrow(EACCES, "need write access for '%s' on '%s' to create directory '%s'", clientName.c_str(), parentPath.c_str(), name.c_str()); + lpath = getLocalPath(path); + // Clean up unwanted bits mode &= ~S_IFMT; + mode |= S_IFDIR; // TODO: S_ISGID // TODO: inherit default ACL - wrapCall(mkdir(getLocalPath(path).c_str(), mode)); + + // Keep read/write for owner in the mode + wrapCall(mkdir(lpath.c_str(), mode | S_IRUSR | S_IWUSR)); + + snprintf(buf, sizeof buf, "%04o", mode); + vfsSetXattr(path, lpath, VFS_XATTR "mode", buf, 0); } @@ -1214,6 +1259,7 @@ Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& 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, "mode") == 0 || strcmp(entry->a_name + VFS_XATTR_LENGTH, "owner") == 0) { attrType = VFS_XATTR_TYPE_PERMS;