std::string parentPath, name, lpath;
int code = DMLITE_SUCCESS;
ExtendedStat file;
+ gid_t egid;
+ Acl newAcl;
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
if (code != ENOENT) throw;
}
-#if 0
- // Effective gid
- gid_t egid;
- if (parent.stat.st_mode & S_ISGID) {
- egid = parent.stat.st_gid;
- mode |= S_ISGID;
- } else {
- egid = getGid(this->secCtx_);
- }
- // Generate inherited ACL's if there are defaults
- if (parent.acl.has(AclEntry::kDefault | AclEntry::kUserObj)) {
- newFile.acl = Acl(parent.acl, getUid(this->secCtx_), egid, mode, &newFile.stat.st_mode);
- }
-#endif
-
if (code == ENOENT) {
+ // Cleanup mode
+ mode = (mode & ~S_IFMT) | S_IFREG;
+
+ // Effective gid
+ if (parent.stat.st_mode & S_ISGID) {
+ egid = parent.stat.st_gid;
+ mode |= S_ISGID;
+ } else {
+ egid = getGid(this->secCtx_);
+ }
+
+ // Generate inherited ACL's if there are defaults
+ if (parent.acl.has(AclEntry::kDefault | AclEntry::kUserObj))
+ newAcl = Acl(parent.acl, getUid(this->secCtx_), egid, mode, &mode);
+
// Create new
wrapCall(f = fopen(lpath.c_str(), "w"));
wrapCall(fclose(f));
+ vfsSetOwner(path, lpath, getUid(this->secCtx_), egid, true);
+ vfsSetMode(path, lpath, mode);
+ if (!newAcl.empty())
+ vfsSetAcl(path, lpath, newAcl);
} else {
// Truncate
if (S_ISDIR(file.stat.st_mode))
if (getUid(this->secCtx_) != file.stat.st_uid &&
checkPermissions(this->secCtx_, file.acl, file.stat, S_IWRITE) != 0) {
vfsThrow(EACCES, "not enough permissions for '%s' to truncate '%s'", clientName.c_str(), path.c_str());
+ // TODO: check replicas
}
wrapCall(truncate(lpath.c_str(), 0));
}
-
- setMode(path, mode);
}
void VfsCatalog::setMode(const std::string& path, mode_t mode) throw (DmException)
{
ExtendedStat meta;
+ std::string lpath;
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
!hasGroup(this->secCtx_->groups, meta.stat.st_gid))
mode &= ~S_ISGID;
- // TODO: update ACL, setAcl().
+ // Update the ACL
+ if (!meta.acl.empty()) {
+ for (size_t i = 0; i < meta.acl.size(); ++i) {
+ switch (meta.acl[i].type) {
+ case AclEntry::kUserObj:
+ meta.acl[i].perm = mode >> 6 & 07;
+ break;
+ case AclEntry::kGroupObj:
+ case AclEntry::kMask:
+ meta.acl[i].perm = mode >> 3 & 07;
+ break;
+ case AclEntry::kOther:
+ meta.acl[i].perm = mode & 07;
+ break;
+ default:
+ continue;
+ }
+ }
+ }
+
+ lpath = getLocalPath(path);
- vfsSetMode(path, getLocalPath(path), mode);
+ vfsSetMode(path, lpath, mode);
+ if (!meta.acl.empty())
+ vfsSetAcl(path, lpath, meta.acl);
}
{
ExtendedStat meta;
std::string lpath;
- char buf[10];
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
lpath = getLocalPath(path);
try {
- if (newUid != meta.stat.st_uid) {
- snprintf(buf, sizeof buf, "%u", newUid);
- vfsSetXattr(path, lpath, VFS_XATTR "owner", buf, ATTR_DONTFOLLOW);
- }
- if (newGid != meta.stat.st_gid) {
- snprintf(buf, sizeof buf, "%u", newGid);
- vfsSetXattr(path, lpath, VFS_XATTR "group", buf, ATTR_DONTFOLLOW);
- }
+ vfsSetOwner(path, lpath, meta, newUid, newGid, followSymLink);
// Update the ACL's if there is any
if (!meta.acl.empty()) {
for (size_t i = 0; i < meta.acl.size(); i++) {
- if (meta.acl[i].type == AclEntry::kUserObj)
- meta.acl[i].id = newUid;
- else if (meta.acl[i].type == AclEntry::kGroupObj)
- meta.acl[i].id = newGid;
+ switch (meta.acl[i].type) {
+ case AclEntry::kUserObj:
+ meta.acl[i].id = newUid;
+ break;
+ case AclEntry::kGroupObj:
+ meta.acl[i].id = newGid;
+ break;
+ default:
+ break;
+ }
}
- vfsSetXattr(path, lpath, VFS_XATTR "acl", buf, ATTR_DONTFOLLOW);
+ vfsSetXattr(path, lpath, VFS_XATTR "acl", meta.acl.serialize(), followSymLink ? 0 : ATTR_DONTFOLLOW);
}
} catch (DmException& e) {
// xattrs are not supported on symbolic links
void VfsCatalog::setAcl(const std::string& path, const Acl& acl) throw (DmException)
{
- throw DmException(EACCES, "Write mode not supported");
+ ExtendedStat meta;
+ Acl aclCopy(acl);
+ std::string lpath;
+
+ if (vfsCheckPermissions(path, S_IWRITE))
+ vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
+
+ meta = this->vfsExtendedStat(path);
+
+ // User has to be the owner, or root
+ if (getUid(this->secCtx_) != meta.stat.st_uid &&
+ getUid(this->secCtx_) != 0) {
+ vfsThrow(EACCES, "'%s' neither owner nor root, setting ACL of '%s' rejected", clientName.c_str(), path.c_str());
+ }
+
+ // Make sure the owner and group matches!
+ for (size_t i = 0; i < aclCopy.size(); ++i) {
+ switch (aclCopy[i].type) {
+ case AclEntry::kUserObj:
+ aclCopy[i].id = meta.stat.st_uid;
+ break;
+ case AclEntry::kGroupObj:
+ aclCopy[i].id = meta.stat.st_gid;
+ break;
+ default:
+ if (aclCopy[i].type & AclEntry::kDefault && !S_ISDIR(meta.stat.st_mode))
+ vfsThrow(EINVAL, "defaults can be only applied to directories");
+ break;
+ }
+ }
+
+ // Validate the ACL
+ aclCopy.validate();
+
+ // Update the file 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;
+ }
+ }
+
+ lpath = getLocalPath(path);
+
+ vfsSetMode(path, lpath, meta.stat.st_mode);
+ vfsSetAcl(path, lpath, aclCopy);
}
snprintf(buf, sizeof buf, "%04o", mode);
vfsSetXattr(path, lpath, VFS_XATTR "mode", buf, 0);
}
+
+
+
+void VfsCatalog::vfsSetOwner(const std::string& path, const std::string& lpath, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException) {
+ char buf[10];
+
+ if (newUid != (uid_t)-1) {
+ snprintf(buf, sizeof buf, "%u", newUid);
+ vfsSetXattr(path, lpath, VFS_XATTR "owner", buf, followSymLink ? 0 : ATTR_DONTFOLLOW);
+ }
+ if (newGid != (gid_t)-1) {
+ snprintf(buf, sizeof buf, "%u", newGid);
+ vfsSetXattr(path, lpath, VFS_XATTR "group", buf, followSymLink ? 0 : ATTR_DONTFOLLOW);
+ }
+}
+
+
+
+void VfsCatalog::vfsSetOwner(const std::string& path, const std::string& lpath, const ExtendedStat& meta, uid_t newUid, gid_t newGid, bool followSymLink) throw (DmException)
+{
+ vfsSetOwner(path, lpath, newUid != meta.stat.st_uid ? newUid : (uid_t)-1, newGid != meta.stat.st_gid ? newGid : (gid_t)-1, followSymLink);
+}
+
+
+
+void VfsCatalog::vfsSetAcl(const std::string& path, const std::string& lpath, Acl acl) throw (DmException) {
+ if (acl.empty())
+ vfsRemoveXattr(path, lpath, VFS_XATTR "acl", 0);
+ else
+ vfsSetXattr(path, lpath, VFS_XATTR "acl", acl.serialize(), 0);
+}