if (vfsCheckPermissions(path, S_IEXEC | S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- meta = this->extendedStat(path);
+ meta = this->vfsExtendedStat(path);
if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IEXEC | S_IREAD) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), meta.name.c_str());
{
ExtendedStat meta;
Extensible xattrs;
+ std::string key;
+ Extensible::const_iterator it;
if (vfsCheckPermissions(path, S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
meta = vfsExtendedStat(path, follow);
- // not require working xattrs
- try {
- xattrs = vfsGetXattrs(path, getLocalPath(path), follow);
- meta.copy(xattrs);
- } catch (DmException e) {
- if (e.code() != ENOTSUP) throw;
+ //
+ // 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);
+
+ // copy attributes
+ for (it = xattrs.begin(); it != xattrs.end(); it++) {
+ key = it->first;
+ meta[key] = xattrs[key];
}
meta["pool"] = std::string("vfs");
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
try {
- meta = this->extendedStat(path);
+ meta = this->vfsExtendedStat(path);
perm = 0;
if (mode & R_OK) perm = S_IREAD;
if (vfsCheckPermissions(path, S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- xStat = this->extendedStat(path, true);
+ xStat = this->vfsExtendedStat(path, 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());
void VfsCatalog::unlink(const std::string& path) throw (DmException)
{
- std::string parentPath, name;
+ std::string parentPath, name, lpath;
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
if (checkPermissions(this->secCtx_, parent.acl, parent.stat, S_IWRITE) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' on '%s' to unlink '%s'", clientName.c_str(), parentPath.c_str(), path.c_str());
+ lpath = getLocalPath(path);
+
// Sticky bit set ==> only directory or file owner can delete
if ((parent.stat.st_mode & S_ISVTX) == S_ISVTX) {
- ExtendedStat file = this->extendedStat(path);
+ // not follow symlinks (remove them instead)
+ ExtendedStat file = this->vfsSimpleStat(name, path, lpath, false);
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());
}
}
- wrapCall(::unlink(getLocalPath(path).c_str()));
+ wrapCall(::unlink(lpath.c_str()));
}
if (checkPermissions(this->secCtx_, parent.acl, parent.stat, S_IWRITE) != 0)
vfsThrow(EACCES, "need write access for '%s' on '%s' to create '%s'", clientName.c_str(), parentPath.c_str(), path.c_str());
+ lpath = getLocalPath(path);
+
try {
- file = this->extendedStat(path);
+ // follow symlinks
+ file = this->vfsSimpleStat(name, path, lpath, true);
} catch (DmException e) {
code = DMLITE_ERRNO(e.code());
if (code != ENOENT) throw;
}
#endif
- lpath = getLocalPath(path);
if (code == ENOENT) {
// Create new
wrapCall(f = fopen(lpath.c_str(), "w"));
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- meta = this->vfsExtendedStat(path, true);
+ meta = this->vfsExtendedStat(path);
// User has to be the owner, or root
if (getUid(this->secCtx_) != meta.stat.st_uid &&
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- file = this->extendedStat(path);
+ file = this->vfsExtendedStat(path);
if (S_ISDIR(file.stat.st_mode))
vfsThrow(EISDIR, "'%s' is directory, can not truncate", path.c_str());
if (getUid(this->secCtx_) != file.stat.st_uid &&
if (vfsCheckPermissions(path, S_IWRITE))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- meta = this->extendedStat(path);
+ meta = this->vfsExtendedStat(path);
if (getUid(this->secCtx_) != meta.stat.st_uid &&
checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IWRITE) != 0) {
vfsThrow(EACCES, "not enough permissions for '%s' to modify the time of '%s'", clientName.c_str(), path.c_str());
lpath = getLocalPath(path);
- oldXattrs = vfsGetXattrs(path, lpath, true);
+ oldXattrs = meta;
newXattrs.copy(attr);
+ oldXattrs.erase("pool");
+ newXattrs.erase("pool");
for (it = newXattrs.begin(); it != newXattrs.end(); it++) {
key = it->first;
// OK, it's working now :-)
value = Extensible::anyToString(it->second);
+ // reconcile
if (oldXattrs.hasField(key)) {
oldvalue = Extensible::anyToString(oldXattrs[key]);
if (oldvalue != value)
vfsSetXattr(path, lpath, key, value, ATTR_CREATE);
}
}
+
for (it = oldXattrs.begin(); it != oldXattrs.end(); it++) {
key = it->first;
+
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());
if (vfsCheckPermissions(path, S_IREAD))
vfsThrow(EACCES, "not enough permissions for '%s'", clientName.c_str());
- meta = this->extendedStat(path);
+ meta = this->vfsExtendedStat(path);
if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IREAD) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' to read '%s'", clientName.c_str(), path.c_str());
// Check sticky
if (oldParent.stat.st_mode & S_ISVTX) {
- ExtendedStat old = this->extendedStat(oldPath);
+ ExtendedStat old = this->vfsExtendedStat(oldPath);
if (getUid(this->secCtx_) != oldParent.stat.st_uid &&
getUid(this->secCtx_) != old.stat.st_uid &&
checkPermissions(this->secCtx_, old.acl, old.stat, S_IWRITE) != 0)
vfsThrow(EINVAL, "can not remove '/'");
ExtendedStat parent = this->getParent(path, &parentPath, &name);
- ExtendedStat entry = this->extendedStat(path);
+ ExtendedStat entry = this->vfsExtendedStat(path);
if ((parent.stat.st_mode & S_ISVTX) == S_ISVTX) {
// Sticky bit set
if (getUid(this->secCtx_) != entry.stat.st_uid &&
// Get the files now
if (!parentPath->empty()) {
- return this->extendedStat(*parentPath);
+ return this->vfsExtendedStat(*parentPath);
} else {
- return this->extendedStat(this->getWorkingDir());
+ return this->vfsExtendedStat(this->getWorkingDir());
}
}
+///
+/// Get extended attributes.
+///
+/// @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) {
int len;
std::string attrValue;