}
-VfsCatalog::VfsCatalog(const std::string& host, const std::string &allow, const std::string &deny) throw (DmException): Catalog(),
- hostName_(host)
+VfsCatalog::VfsCatalog(const std::string& host, const std::string& prefix, const std::string &allow, const std::string &deny) throw (DmException): Catalog(),
+ hostName_(host), prefix_(prefix)
{
regex_t regex;
int ret;
vfsThrow(EINVAL, "invalid regular expresion for 'Deny': %s", buf);
this->denyRegex = new regex_t(regex);
}
+
+ if (prefix.empty()) this->prefix_ = "";
}
void VfsCatalog::changeDir(const std::string& path) throw (DmException)
{
ExtendedStat meta;
+ std::string lpath;
meta = this->extendedStat(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());
- wrapCall(chdir(path.c_str()));
- syslog(LOG_DEBUG, "%s: changed to '%s'", __func__, path.c_str());
+ lpath = getLocalPath(path);
+ wrapCall(chdir(lpath.c_str()));
+ syslog(LOG_DEBUG, "%s: changed to '%s'", __func__, lpath.c_str());
}
std::string VfsCatalog::getWorkingDir(void) throw (DmException)
{
char buffer[1024];
+ size_t len;
+
wrapCall(getcwd(buffer, sizeof(buffer)));
- return std::string(buffer);
+ len = strlen(buffer);
+
+ // working directory out of namespace prefix ==> "/"
+ if (this->prefix_.size() >= len || this->prefix_.compare(0, len, buffer, this->prefix_.size()) != 0 || buffer[this->prefix_.size()] != '/')
+ return std::string("/");
+
+ // strip the prefix
+ return std::string(buffer + this->prefix_.size());
}
else dir = this->getWorkingDir() + "/" + path;
components = Url::splitPath(dir);
- dir = "";
+ dir = this->prefix_;
for (unsigned int i = 0; i < components.size() - 1; i++) {
+ // the first component always '/', let's use it as separator
if (i < 2) dir += components[i];
else dir = dir + "/" + components[i];
vfsThrow(EACCES, "not enough permissions for '%s' to list '%s'", clientName.c_str(), meta.name.c_str());
}
- meta = vfsExtendedStat(components.back(), path, follow);
+ meta = vfsExtendedStat(components.back(), getLocalPath(path), follow);
// not require working xattrs
try {
- xattrs = vfsGetXattrs(path, follow);
+ xattrs = vfsGetXattrs(path, getLocalPath(path), follow);
meta.copy(xattrs);
} catch (DmException e) {
if (e.code() != ENOTSUP) throw;
if (checkPermissions(this->secCtx_, meta.acl, meta.stat, perm) != 0) return false;
- if (::access(path.c_str(), mode) == -1) {
+ if (::access(getLocalPath(path).c_str(), mode) == -1) {
if (errno == ENOENT) {
// stat() performed OK, but access() failed with ENOENT
vfsThrowErrno("access() failed with ENOENT on '" + path + "' (dangling symlink?)");
bool VfsCatalog::accessReplica(const std::string& replica, int mode) throw (DmException)
{
- return access(replica, mode);
+ return this->access(replica, mode);
}
if (checkPermissions(this->secCtx_, parent.acl, parent.stat, S_IWRITE | S_IEXEC) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), parentPath.c_str());
- wrapCall(::symlink(oldPath.c_str(), newPath.c_str()));
+ wrapCall(::symlink(getLocalPath(oldPath).c_str(), getLocalPath(newPath).c_str()));
}
vfsThrow(EACCES, "not enough permissions for '%s' on '%s'", clientName.c_str(), path.c_str());
memset(buf, 0, sizeof(buf));
- wrapCall(readlink(path.c_str(), buf, sizeof(buf) - 1));
+ wrapCall(readlink(getLocalPath(path).c_str(), buf, sizeof(buf) - 1));
return buf;
}
}
}
- wrapCall(::unlink(path.c_str()));
+ wrapCall(::unlink(getLocalPath(path).c_str()));
}
void VfsCatalog::create(const std::string& path, mode_t mode) throw (DmException)
{
FILE *f;
- std::string parentPath, name;
+ std::string parentPath, name, lpath;
int code = DMLITE_SUCCESS;
ExtendedStat file;
}
#endif
+ lpath = getLocalPath(path);
if (code == ENOENT) {
// Create new
- wrapCall(f = fopen(path.c_str(), "w"));
+ wrapCall(f = fopen(lpath.c_str(), "w"));
wrapCall(fclose(f));
} else {
// Truncate
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());
}
- wrapCall(truncate(path.c_str(), 0));
+ wrapCall(truncate(lpath.c_str(), 0));
}
setMode(path, mode);
// TODO: buildin resets S_ISGID if not in the group
// TODO: update ACL (kUserObj, kGroupObj/kMask, kOther)
- wrapCall(chmod(path.c_str(), mode));
+ wrapCall(chmod(getLocalPath(path).c_str(), mode));
}
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());
}
- wrapCall(truncate(path.c_str(), newSize));
+ wrapCall(truncate(getLocalPath(path).c_str(), newSize));
}
vfsThrow(EACCES, "not enough permissions for '%s' to modify the time of '%s'", clientName.c_str(), path.c_str());
}
- wrapCall(::utime(path.c_str(), buf));
+ wrapCall(::utime(getLocalPath(path).c_str(), buf));
}
Extensible oldXattrs, newXattrs;
Extensible::const_iterator it;
std::string key, value, oldvalue;
+ std::string lpath;
meta = this->extendedStat(path, true);
if (checkPermissions(this->secCtx_, meta.acl, meta.stat, S_IWRITE) != 0)
vfsThrow(EACCES, "not enough permissions for '%s' to change attributes on '%s'", clientName.c_str(), path.c_str());
- oldXattrs = vfsGetXattrs(path, true);
+ lpath = getLocalPath(path);
+
+ oldXattrs = vfsGetXattrs(path, lpath, true);
newXattrs.copy(attr);
for (it = newXattrs.begin(); it != newXattrs.end(); it++) {
if (oldXattrs.hasField(key)) {
oldvalue = Extensible::anyToString(oldXattrs[key]);
if (oldvalue != value) {
- syslog(LOG_DEBUG, "%s: replacing '%s' from '%s' to '%s' on '%s'", __func__, key.c_str(), oldvalue.c_str(), value.c_str(), path.c_str());
- wrapCall(attr_set(path.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_REPLACE), "could not replace extended attribute '%s' on '%s'", key.c_str(), path.c_str());
+ syslog(LOG_DEBUG, "%s: replacing '%s' from '%s' to '%s' on '%s'", __func__, key.c_str(), oldvalue.c_str(), value.c_str(), lpath.c_str());
+ wrapCall(attr_set(lpath.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_REPLACE), "could not replace extended attribute '%s' on '%s'", key.c_str(), path.c_str());
}
oldXattrs.erase(key);
} else {
- syslog(LOG_DEBUG, "%s: creating '%s' = '%s' on '%s'", __func__, key.c_str(), value.c_str(), path.c_str());
- wrapCall(attr_set(path.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_CREATE), "could not create extended attribute '%s' on '%s'", key.c_str(), path.c_str());
+ syslog(LOG_DEBUG, "%s: creating '%s' = '%s' on '%s'", __func__, key.c_str(), value.c_str(), lpath.c_str());
+ wrapCall(attr_set(lpath.c_str(), key.c_str(), value.c_str(), value.size(), ATTR_CREATE), "could not create extended attribute '%s' on '%s'", key.c_str(), path.c_str());
}
}
for (it = oldXattrs.begin(); it != oldXattrs.end(); it++) {
key = it->first;
value = Extensible::anyToString(it->second);
- syslog(LOG_DEBUG, "%s: removing '%s' = '%s' from '%s'", __func__, key.c_str(), value.c_str(), path.c_str());
- wrapCall(attr_remove(path.c_str(), key.c_str(), 0), "could not remove '%s' on '%s'", key.c_str(), path.c_str());
+ syslog(LOG_DEBUG, "%s: removing '%s' = '%s' from '%s'", __func__, 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());
}
}
-PrivateDir* VfsCatalog::vfsOpenDir(const std::string& path) throw (DmException)
+PrivateDir* VfsCatalog::vfsOpenDir(const std::string& lpath, const std::string& path) throw (DmException)
{
PrivateDir *privateDir;
privateDir = new PrivateDir();
try {
privateDir->path = path;
- privateDir->dir = opendir(path.c_str());
+ privateDir->lpath = lpath;
+ privateDir->dir = opendir(lpath.c_str());
if (privateDir->dir == NULL)
vfsThrowErrno("error opening directory '%s'", path.c_str());
} catch (...) {
{
PrivateDir *privateDir;
ExtendedStat meta;
+ std::string lpath;
meta = this->extendedStat(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());
- privateDir = vfsOpenDir(path);
+ lpath = getLocalPath(path);
+ privateDir = vfsOpenDir(lpath, path);
- syslog(LOG_DEBUG, "%s: directory '%s' opened", __func__, path.c_str());
+ syslog(LOG_DEBUG, "%s: directory '%s' opened", __func__, lpath.c_str());
return privateDir;
}
int r;
PrivateDir *privateDir = dynamic_cast<PrivateDir*>(dir);
std::string path = privateDir->path;
+ std::string lpath = privateDir->lpath;
if (privateDir == NULL)
throw DmException(DMLITE_SYSERR(EFAULT),
r = closedir(privateDir->dir);
delete privateDir;
- wrapCall(r);
- syslog(LOG_DEBUG, "%s: directory '%s' closed", __func__, path.c_str());
+ wrapCall(r, "error closing directory '%s'", path.c_str());
+ syslog(LOG_DEBUG, "%s: directory '%s' closed", __func__, lpath.c_str());
}
struct stat fstat;
- wrapCall(fstatat(dirfd(privateDir->dir), ent->d_name,
- &fstat, AT_SYMLINK_NOFOLLOW));
+ wrapCall(
+ fstatat(dirfd(privateDir->dir), ent->d_name, &fstat, AT_SYMLINK_NOFOLLOW),
+ "can't stat '%s' at '%s'", ent->d_name, privateDir->path.c_str());
privateDir->stat.stat = fstat;
privateDir->stat.name = ent->d_name;
mode &= ~S_IFMT;
// TODO: S_ISGID
// TODO: inherit default ACL
- wrapCall(mkdir(path.c_str(), mode));
+ wrapCall(mkdir(getLocalPath(path).c_str(), mode));
}
vfsThrow(EINVAL, "not the source, neither the destination, can be '/'");
ExtendedStat oldParent = this->getParent(oldPath, &oldParentPath, &oldName);
- ExtendedStat newParent = this->getParent(newPath, &oldParentPath, &newName);
+ ExtendedStat newParent = this->getParent(newPath, &newParentPath, &newName);
if (checkPermissions(this->secCtx_, oldParent.acl, oldParent.stat, S_IWRITE) != 0)
- vfsThrow(EACCES, "Not enough permissions for '%s' on origin '%s'", clientName.c_str(), oldPath.c_str());
+ vfsThrow(EACCES, "not enough permissions for '%s' on origin '%s'", clientName.c_str(), oldPath.c_str());
if (checkPermissions(this->secCtx_, newParent.acl, newParent.stat, S_IWRITE) != 0)
- vfsThrow(EACCES, "Not enough permissions for '%s' on destination '%s'", clientName.c_str(), newPath.c_str());
+ vfsThrow(EACCES, "not enough permissions for '%s' on destination '%s'", clientName.c_str(), newPath.c_str());
// Check sticky
if (oldParent.stat.st_mode & S_ISVTX) {
// XXX: test-rename should probably accept both ENOTEMPTY and EEXIST instead
// of changing it here?
try {
- wrapCall(::rename(oldPath.c_str(), newPath.c_str()));
+ wrapCall(::rename(getLocalPath(oldPath).c_str(), getLocalPath(newPath).c_str()));
} catch (DmException e) {
if (e.code() == ENOTEMPTY) e = DmException(EEXIST, e.what());
throw e;
}
::chdir(cwd);
// OK, we can try to remove
- wrapCall(rmdir(path.c_str()));
+ wrapCall(rmdir(getLocalPath(path).c_str()));
} catch (...) {
if (cwd) ::chdir(cwd);
free(cwd);
Replica replica;
struct stat fstat;
- wrapCall(stat(rfn.c_str(), &fstat));
+ wrapCall(stat(getLocalPath(rfn).c_str(), &fstat));
replica.atime = fstat.st_atime;
replica.fileid = fstat.st_ino;
+const std::string VfsCatalog::getLocalPath(const std::string &path) {
+ if (path.empty() || path[0] != '/') return path;
+ return this->prefix_ + path;
+}
+
+
+
int VfsCatalog::checkPermissions(const SecurityContext *context, const Acl &acl, const struct stat &stat, mode_t mode) {
//fprintf(stderr, "VfsCatalog::checkPermissions(inode %lu, %04o)\n", stat.st_ino, mode);
return this->allowCurrent ? 0 : 1;
}
-Extensible VfsCatalog::vfsGetXattrs(const std::string& path, bool follow) throw (DmException) {
+Extensible VfsCatalog::vfsGetXattrs(const std::string& path, const std::string& lpath, bool follow) throw (DmException) {
int len;
std::string attrValue;
Extensible xattrs;
list = (attrlist_t *)this->xattrBuffer;
memset(&attr_cursor, 0, sizeof attr_cursor);
do {
- wrapCall(attr_list(path.c_str(), this->xattrBuffer, sizeof this->xattrBuffer, follow ? 0 : ATTR_DONTFOLLOW, &attr_cursor), "could not get list of extended attributes on '%s'", path.c_str());
+ wrapCall(attr_list(lpath.c_str(), this->xattrBuffer, sizeof this->xattrBuffer, 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->xattrBuffer, i);
// "selinux" is returned in the list, but failing to get the value
//syslog(LOG_DEBUG, "%s: skipping attribute '%s'", __func__, entry->a_name);
} else {
len = sizeof this->xattrValue;
- wrapCall(attr_get(path.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());
+ 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());
syslog(LOG_DEBUG, "%s: '%s' = '%.*s'", __func__, entry->a_name, len, this->xattrValue);
attrValue.assign(this->xattrValue, len);
xattrs[entry->a_name] = attrValue;