static int unionfs_chown(const char *path, uid_t uid, gid_t gid) {
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int res = lchown(p, uid, gid);
	if (res == -1) RETURN(-errno);

	RETURN(0);
}
static int unionfs_chmod(const char *path, mode_t mode) {
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int res = chmod(p, mode);
	if (res == -1) RETURN(-errno);

	RETURN(0);
}
static int unionfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) {
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int res = lsetxattr(p, name, value, size, flags);

	if (res == -1) RETURN(-errno);

	RETURN(res);
}
static int unionfs_truncate(const char *path, off_t size) {
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int res = truncate(p, size);

	if (res == -1) RETURN(-errno);

	RETURN(0);
}
static int unionfs_removexattr(const char *path, const char *name) {
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int res = lremovexattr(p, name);

	if (res == -1) RETURN(-errno);

	RETURN(res);
}
Esempio n. 6
0
static int unionfs_utimens(const char *path, const struct timespec ts[2]) {
	DBG("%s\n", path);

	if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) RETURN(0);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

	int res = utimensat(0, p, ts, AT_SYMLINK_NOFOLLOW);

	if (res == -1) RETURN(-errno);

	RETURN(0);
}
Esempio n. 7
0
static int unionfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags, uint32_t position) {
#else
static int unionfs_setxattr(const char *path, const char *name, const char *value, size_t size, int flags) {
#endif
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

#if __APPLE__
	int res = setxattr(p, name, value, size, position, flags | XATTR_NOFOLLOW);
#else
	int res = lsetxattr(p, name, value, size, flags);
#endif

	if (res == -1) RETURN(-errno);

	RETURN(res);
}
static int unionfs_link(const char *from, const char *to) {
	DBG("from %s to %s\n", from, to);

	// hardlinks do not work across different filesystems so we need a copy of from first
	int i = find_rw_branch_cow(from);
	if (i == -1) RETURN(-errno);

	int j = __find_rw_branch_cutlast(to, i);
	if (j == -1) RETURN(-errno);

	DBG("from branch: %d to branch: %d\n", i, j);

	char f[PATHLEN_MAX], t[PATHLEN_MAX];
	if (BUILD_PATH(f, uopt.branches[i].path, from)) RETURN(-ENAMETOOLONG);
	if (BUILD_PATH(t, uopt.branches[j].path, to)) RETURN(-ENAMETOOLONG);

	int res = link(f, t);
	if (res == -1) RETURN(-errno);

	// no need for set_owner(), since owner and permissions are copied over by link()

	remove_hidden(to, i); // remove hide file (if any)
	RETURN(0);
}
Esempio n. 9
0
static int unionfs_utimens(const char *path, const struct timespec ts[2]) {
	DBG("%s\n", path);

	int i = find_rw_branch_cow(path);
	if (i == -1) RETURN(-errno);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[i].path, path)) RETURN(-ENAMETOOLONG);

#ifdef UNIONFS_HAVE_AT
	int res = utimensat(0, p, ts, AT_SYMLINK_NOFOLLOW);
#else
	struct timeval tv[2];
	tv[0].tv_sec = ts[0].tv_sec;
	tv[0].tv_usec = ts[0].tv_nsec / 1000;
	tv[1].tv_sec = ts[1].tv_sec;
	tv[1].tv_usec = ts[1].tv_nsec / 1000;
	int res = utimes(p, tv);
#endif

	if (res == -1) RETURN(-errno);

	RETURN(0);
}
Esempio n. 10
0
/**
 * unionfs rename function
 * TODO: If we rename a directory on a read-only branch, we need to copy over
 *       all files to the renamed directory on the read-write branch.
 */
static int unionfs_rename(const char *from, const char *to) {
	DBG("from %s to %s\n", from, to);

	bool is_dir = false; // is 'from' a file or directory

	int j = find_rw_branch_cutlast(to);
	if (j == -1) RETURN(-errno);

	int i = find_rorw_branch(from);
	if (i == -1) RETURN(-errno);

	if (!uopt.branches[i].rw) {
		i = find_rw_branch_cow(from);
		if (i == -1) RETURN(-errno);
	}

	if (i != j) {
		USYSLOG(LOG_ERR, "%s: from and to are on different writable branches %d vs %d, which"
		       "is not supported yet.\n", __func__, i, j);
		RETURN(-EXDEV);
	}

	char f[PATHLEN_MAX], t[PATHLEN_MAX];
	if (BUILD_PATH(f, uopt.branches[i].path, from)) RETURN(-ENAMETOOLONG);
	if (BUILD_PATH(t, uopt.branches[i].path, to)) RETURN(-ENAMETOOLONG);

	filetype_t ftype = path_is_dir(f);
	if (ftype == NOT_EXISTING)
		RETURN(-ENOENT);
	else if (ftype == IS_DIR)
		is_dir = true;

	int res;
	if (!uopt.branches[i].rw) {
		// since original file is on a read-only branch, we copied the from file to a writable branch,
		// but since we will rename from, we also need to hide the from file on the read-only branch
		if (is_dir)
			res = hide_dir(from, i);
		else
			res = hide_file(from, i);
		if (res) RETURN(-errno);
	}

	res = rename(f, t);

	if (res == -1) {
		int err = errno; // unlink() might overwrite errno
		// if from was on a read-only branch we copied it, but now rename failed so we need to delete it
		if (!uopt.branches[i].rw) {
			if (unlink(f))
				USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
				       "also unlink()  failed\n", __func__, from);

			if (remove_hidden(from, i))
				USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now "
				       "also removing the whiteout  failed\n", __func__, from);
		}
		RETURN(-err);
	}

	if (uopt.branches[i].rw) {
		// A lower branch still *might* have a file called 'from', we need to delete this.
		// We only need to do this if we have been on a rw-branch, since we created
		// a whiteout for read-only branches anyway.
		if (is_dir)
			maybe_whiteout(from, i, WHITEOUT_DIR);
		else
			maybe_whiteout(from, i, WHITEOUT_FILE);
	}

	remove_hidden(to, i); // remove hide file (if any)
	RETURN(0);
}