Пример #1
0
/**
 * copy a directory between branches (includes all contents of the directory)
 */
int copy_directory(const char *path, int branch_ro, int branch_rw) {
	DBG_IN();

	/* create the directory on the destination branch */
	int res = path_create(path, branch_ro, branch_rw);
	if (res != 0) {
		return res;
	}

	/* determine path to source directory on read-only branch */
	char from[PATHLEN_MAX];
	if (BUILD_PATH(from, uopt.branches[branch_ro].path, path)) return 1;

	DIR *dp = opendir(from);
	if (dp == NULL) return 1;

	struct dirent *de;
	while ((de = readdir(dp)) != NULL) {
		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;

		char member[PATHLEN_MAX];
		if (BUILD_PATH(member, path, de->d_name)) return 1;
		res = cow_cp(member, branch_ro, branch_rw);
		if (res != 0) return res;
	}

	closedir(dp);
	return 0;
}
Пример #2
0
/**
 * Create a file or directory that hides path below root_rw
 */
static int do_create_whiteout(const char *path, int root_rw, enum whiteout mode) {
	char metapath[PATHLEN_MAX];
	int res = -1;

	to_root(); // whiteouts are root business

	if (BUILD_PATH(metapath, METADIR, path)) {
		syslog (LOG_WARNING, "%s(): Path too long\n", __func__);
		goto out;
	}

	// p MUST be without path to branch prefix here! 2 x root_rw is correct here!
	// this creates e.g. branch/.unionfs/some_directory
	path_create_cutlast(metapath, root_rw, root_rw);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.roots[root_rw].path, metapath, HIDETAG)) {
		syslog (LOG_WARNING, "%s(): Path too long\n", __func__);
		goto out;
	}

	if (mode == WHITEOUT_FILE) {
		res = open(p, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
		if (res == -1)
			goto out;
		res = close(res);
	} else
		res = mkdir(p, S_IRWXU);

out:
	to_user();
	return res;
}
Пример #3
0
/**
 * copy a directory between branches (includes all contents of the directory)
 */
int copy_directory(const char *path, int branch_ro, int branch_rw) {
	DBG("%s\n", path);

	/* create the directory on the destination branch */
	int res = path_create(path, branch_ro, branch_rw);
	if (res != 0) {
		RETURN(res);
	}

	/* determine path to source directory on read-only branch */
	char from[PATHLEN_MAX];
	if (BUILD_PATH(from, uopt.branches[branch_ro].path, path)) RETURN(1);

	DIR *dp = opendir(from);
	if (dp == NULL) RETURN(1);

	struct dirent *de;
	while ((de = readdir(dp)) != NULL) {
		if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) continue;

		char member[PATHLEN_MAX];
		if (BUILD_PATH(member, path, "/", de->d_name)) {
			res = 1;
			break;
		}
		res = cow_cp(member, branch_ro, branch_rw, true);               
		if (res != 0) break;
	}

	closedir(dp);
	struct stat  buf;
	lstat(from, &buf);
	setfile(from, &buf);
	RETURN(res);
}
Пример #4
0
/**
 * Create a file or directory that hides path below branch_rw
 */
static int do_create_whiteout(const char *path, int branch_rw, enum whiteout mode) {
	DBG("%s\n", path);

	char metapath[PATHLEN_MAX];

	if (BUILD_PATH(metapath, METADIR, path)) RETURN(-1);

	// p MUST be without path to branch prefix here! 2 x branch_rw is correct here!
	// this creates e.g. branch/.unionfs/some_directory
	path_create_cutlast(metapath, branch_rw, branch_rw);

	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[branch_rw].path, metapath)) RETURN(-1);
	strcat(p, HIDETAG); // TODO check length

	int res;
	if (mode == WHITEOUT_FILE) {
		res = open(p, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
		if (res == -1) RETURN(-1);
		res = close(res);
	} else {
		res = mkdir(p, S_IRWXU);
		if (res)
			USYSLOG(LOG_ERR, "Creating %s failed: %s\n", p, strerror(errno));
	}

	RETURN(res);
}
Пример #5
0
/**
 * initiate the cow-copy action
 */
int cow_cp(const char *path, int branch_ro, int branch_rw, bool copy_dir) {
	DBG("%s\n", path);

	// create the path to the file
	path_create_cutlast(path, branch_ro, branch_rw);

	char from[PATHLEN_MAX], to[PATHLEN_MAX];
	if (BUILD_PATH(from, uopt.branches[branch_ro].path, path))
	       RETURN(-ENAMETOOLONG);
	if (BUILD_PATH(to, uopt.branches[branch_rw].path, path))
	       RETURN(-ENAMETOOLONG);

	setlocale(LC_ALL, "");

	struct cow cow;

	cow.uid = getuid();

	// Copy the umask for explicit mode setting.
	cow.umask = umask(0);
	umask(cow.umask);

	cow.from_path = from;
	cow.to_path = to;

	struct stat buf;
	lstat(cow.from_path, &buf);
	cow.stat = &buf;

	int res;
	switch (buf.st_mode & S_IFMT) {
	       case S_IFLNK:
		       res = copy_link(&cow);
		       break;
	       case S_IFDIR:
		       if (copy_dir) {
			       res = copy_directory(path, branch_ro, branch_rw);
		       } else {
			      res = path_create(path, branch_ro, branch_rw);
		       }
		       break;
	       case S_IFBLK:
	       case S_IFCHR:
		       res = copy_special(&cow);
		       break;
	       case S_IFIFO:
		       res = copy_fifo(&cow);
		       break;
	       case S_IFSOCK:
		       USYSLOG(LOG_WARNING, "COW of sockets not supported: %s\n", cow.from_path);
		       RETURN(1);
	       default:
		       res = copy_file(&cow);
	}

	RETURN(res);
}
Пример #6
0
/**
 * unionfs implementation of the create call
 * libfuse will call this to create regular files
 */
static int unionfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) {
	DBG("%s\n", path);

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

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

	// NOTE: We should do:
	//       Create the file with mode=0 first, otherwise we might create
	//       a file as root + x-bit + suid bit set, which might be used for
	//       security racing!
	int res = open(p, fi->flags, 0);
	if (res == -1) RETURN(-errno);

	set_owner(p); // no error check, since creating the file succeeded

	// NOW, that the file has the proper owner we may set the requested mode
	fchmod(res, mode);

	fi->fh = res;
	remove_hidden(path, i);

	DBG("fd = %" PRIx64 "\n", fi->fh);
	RETURN(0);
}
Пример #7
0
static int unionfs_open(const char *path, struct fuse_file_info *fi) {
	DBG("%s\n", path);

	int i;
	if (fi->flags & (O_WRONLY | O_RDWR)) {
		i = find_rw_branch_cutlast(path);
	} else {
		i = find_rorw_branch(path);
	}

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

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

	int fd = open(p, fi->flags);
	if (fd == -1) RETURN(-errno);

	if (fi->flags & (O_WRONLY | O_RDWR)) {
		// There might have been a hide file, but since we successfully
		// wrote to the real file, a hide file must not exist anymore
		remove_hidden(path, i);
	}

	// This makes exec() fail
	//fi->direct_io = 1;
	fi->fh = (unsigned long)fd;

	DBG("fd = %"PRIx64"\n", fi->fh);
	RETURN(0);
}
Пример #8
0
/**
 * l_nbranch (lower nbranch than nbranch) is write protected, create the dir path on
 * nbranch for an other COW operation.
 */
int path_create(const char *path, int nbranch_ro, int nbranch_rw) {
	DBG("%s\n", path);

	if (!uopt.cow_enabled) RETURN(0);

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

	struct stat st;
	if (!stat(p, &st)) {
		// path does already exists, no need to create it
		RETURN(0);
	}

	char *walk = (char *)path;

	// first slashes, e.g. we have path = /dir1/dir2/, will set walk = dir1/dir2/
	while (*walk == '/') walk++;

	do {
		// walk over the directory name, walk will now be /dir2
		while (*walk != '\0' && *walk != '/') walk++;

		// +1 due to \0, which gets added automatically
		snprintf(p, (walk - path) + 1, "%s", path); // walk - path = strlen(/dir1)
		int res = do_create(p, nbranch_ro, nbranch_rw);
		if (res) RETURN(res); // creating the directory failed

		// as above the do loop, walk over the next slashes, walk = dir2/
		while (*walk == '/') walk++;
	} while (*walk != '\0');

	RETURN(0);
}
Пример #9
0
/**
 * Remove a hide-file in all roots up to maxroot
 * If maxroot == -1, try to delete it in all roots.
 */
int remove_hidden(const char *path, int maxroot) {
	if (!uopt.cow_enabled) return 0;

	if (maxroot == -1) maxroot = uopt.nroots;

	int i;
	for (i = 0; i <= maxroot; i++) {
		char p[PATHLEN_MAX];
		if (BUILD_PATH(p, uopt.roots[i].path, METADIR, path, HIDETAG)) {
			syslog(LOG_WARNING, "%s: Path too long\n", __func__);
			return 1;
		}

		struct stat buf;
		int res = lstat(p, &buf);
		if (res == -1) continue;

		switch (buf.st_mode & S_IFMT) {
			case S_IFDIR: rmdir(p); break;
			default: unlink(p); break;
		}
	}

	return 0;
}
Пример #10
0
/**
 * check if any dir or file within path is hidden
 */
int path_hidden(const char *path, int branch) {
	DBG("%s\n", path);

	if (!uopt.cow_enabled) RETURN(false);

	char whiteoutpath[PATHLEN_MAX];
	if (BUILD_PATH(whiteoutpath, uopt.branches[branch].path, METADIR, path)) RETURN(false);

	// -1 as we MUST not end on the next path element
	char *walk = whiteoutpath + uopt.branches[branch].path_len + strlen(METADIR) - 1;

	// first slashes, e.g. we have path = /dir1/dir2/, will set walk = dir1/dir2/
	while (*walk == '/') walk++;

	do {
		// walk over the directory name, walk will now be /dir2
		while (*walk != '\0' && *walk != '/') walk++;

		// +1 due to \0, which gets added automatically
		char p[PATHLEN_MAX];
		// walk - path = strlen(/dir1)
		snprintf(p, (walk - whiteoutpath) + 1, "%s", whiteoutpath);
		int res = filedir_hidden(p);
		if (res) RETURN(res); // path is hidden or error

		// as above the do loop, walk over the next slashes, walk = dir2/
		while (*walk == '/') walk++;
	} while (*walk != '\0');

	RETURN(0);
}
Пример #11
0
static int unionfs_getattr(const char *path, struct stat *stbuf) {
	DBG("%s\n", path);

	if (uopt.stats_enabled && strcmp(path, STATS_FILENAME) == 0) {
		memset(stbuf, 0, sizeof(stbuf));
		stbuf->st_mode = S_IFREG | 0444;
		stbuf->st_nlink = 1;
		stbuf->st_size = STATS_SIZE;
		RETURN(0);
	}
	
	int i = find_rorw_branch(path);
	if (i == -1) RETURN(-errno);

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

	int res = lstat(p, stbuf);
	if (res == -1) RETURN(-errno);

	/* This is a workaround for broken gnu find implementations. Actually,
	 * n_links is not defined at all for directories by posix. However, it
	 * seems to be common for filesystems to set it to one if the actual value
	 * is unknown. Since nlink_t is unsigned and since these broken implementations
	 * always substract 2 (for . and ..) this will cause an underflow, setting
	 * it to max(nlink_t).
	 */
	if (S_ISDIR(stbuf->st_mode)) stbuf->st_nlink = 1;

	RETURN(0);
}
Пример #12
0
/**
  * This method is to post-process options once we know all of them
  */
void unionfs_post_opts(void) {
	// chdir to the given chroot, we
	if (uopt.chroot) {
		int res = chdir(uopt.chroot);
		if (res) {
			fprintf(stderr, "Chdir to %s failed: %s ! Aborting!\n",
				  uopt.chroot, strerror(errno));
			exit(1);
		}
	}

	// Make the pathes absolute and add trailing slashes
	int i;
	for (i = 0; i<uopt.nbranches; i++) {
		// if -ochroot= is specified, the path has to be given absolute
		// or relative to the chroot, so no need to make it absolute
		// also won't work, since we are not yet in the chroot here
		if (!uopt.chroot) {
			uopt.branches[i].path = make_absolute(uopt.branches[i].path);
		}
		uopt.branches[i].path = add_trailing_slash(uopt.branches[i].path);

		// Prevent accidental umounts. Especially system shutdown scripts tend
		// to umount everything they can. If we don't have an open file descriptor,
		// this might cause unexpected behaviour.
		char path[PATHLEN_MAX];

		if (!uopt.chroot) {
			BUILD_PATH(path, uopt.branches[i].path);
		} else {
			BUILD_PATH(path, uopt.chroot, uopt.branches[i].path);
		}

		int fd = open(path, O_RDONLY);
		if (fd == -1) {
			fprintf(stderr, "\nFailed to open %s: %s. Aborting!\n\n",
				path, strerror(errno));
			exit(1);
		}
		uopt.branches[i].fd = fd;
		uopt.branches[i].path_len = strlen(path);
	}
}
Пример #13
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);
}
Пример #14
0
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);
}
Пример #15
0
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);
}
Пример #16
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);
}
Пример #17
0
static int unionfs_listxattr(const char *path, char *list, size_t size) {
	DBG("%s\n", path);

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

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

	int res = llistxattr(p, list, size);

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

	RETURN(res);
}
Пример #18
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);
}
Пример #19
0
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);
}
Пример #20
0
static int unionfs_symlink(const char *from, const char *to) {
	DBG("from %s to %s\n", from, to);

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

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

	int res = symlink(from, t);
	if (res == -1) RETURN(-errno);

	set_owner(t); // no error check, since creating the file succeeded

	remove_hidden(to, i); // remove hide file (if any)
	RETURN(0);
}
Пример #21
0
static int unionfs_readlink(const char *path, char *buf, size_t size) {
	DBG("%s\n", path);

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

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

	int res = readlink(p, buf, size - 1);

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

	buf[res] = '\0';

	RETURN(0);
}
Пример #22
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);
}
Пример #23
0
/**
 * unionfs mkdir() implementation
 *
 * NOTE: Never delete whiteouts directories here, since this will just
 *       make already hidden sub-branches visible again.
 */
static int unionfs_mkdir(const char *path, mode_t mode) {
	DBG("%s\n", path);

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

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

	int res = mkdir(p, 0);
	if (res == -1) RETURN(-errno);

	set_owner(p); // no error check, since creating the file succeeded
        // NOW, that the file has the proper owner we may set the requested mode
        chmod(p, mode);

	RETURN(0);
}
Пример #24
0
/**
 * l_nbranch (lower nbranch than nbranch) is write protected, create the dir path on
 * nbranch for an other COW operation.
 */
int path_create(const char *path, int nbranch_ro, int nbranch_rw) {
	DBG("%s\n", path);

	if (!uopt.cow_enabled) RETURN(0);
	
	char p[PATHLEN_MAX];
	if (BUILD_PATH(p, uopt.branches[nbranch_rw].path, path)) RETURN(-ENAMETOOLONG);

	struct stat st;
	if (!stat(p, &st)) {
		// path does already exists, no need to create it
		RETURN(0);
	}

	char *walk = (char *)path;
	
	int res = path_create_by_step(path, walk,  nbranch_ro, nbranch_rw);
	RETURN(res);
}
Пример #25
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);
}
Пример #26
0
/**
 * Remove a hide-file in all branches up to maxbranch
 * If maxbranch == -1, try to delete it in all branches.
 */
int remove_hidden(const char *path, int maxbranch) {
	DBG("%s\n", path);

	if (!uopt.cow_enabled) RETURN(0);

	if (maxbranch == -1) maxbranch = uopt.nbranches;

	int i;
	for (i = 0; i <= maxbranch; i++) {
		char p[PATHLEN_MAX];
		if (BUILD_PATH(p, uopt.branches[i].path, METADIR, path)) RETURN(-ENAMETOOLONG);
		if (strlen(p) + strlen(HIDETAG) > PATHLEN_MAX) RETURN(-ENAMETOOLONG);
		strcat(p, HIDETAG); // TODO check length

		switch (path_is_dir(p)) {
			case IS_FILE: unlink(p); break;
			case IS_DIR: rmdir(p); break;
			case NOT_EXISTING: continue;
		}
	}

	RETURN(0);
}
Пример #27
0
static int unionfs_mknod(const char *path, mode_t mode, dev_t rdev) {
	DBG("%s\n", path);

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

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

	int file_type = mode & S_IFMT;
	int file_perm = mode & (S_PROT_MASK);

	int res = -1;
	if ((file_type) == S_IFREG) {
		// under FreeBSD, only the super-user can create ordinary files using mknod
		// Actually this workaround should not be required any more
		// since we now have the unionfs_create() method
		// So can we remove it?

		USYSLOG (LOG_INFO, "deprecated mknod workaround, tell the unionfs-fuse authors if you see this!\n");

		res = creat(p, 0);
		if (res > 0 && close(res) == -1) USYSLOG(LOG_WARNING, "Warning, cannot close file\n");
	} else {
		res = mknod(p, file_type, rdev);
	}

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

	set_owner(p); // no error check, since creating the file succeeded
	// NOW, that the file has the proper owner we may set the requested mode
	chmod(p, file_perm);

	remove_hidden(path, i);

	RETURN(0);
}
Пример #28
0
/**
 * check if any dir or file within path is hidden
 */
bool path_hidden(const char *path, int branch) {
	if (!uopt.cow_enabled) return false;

	char whiteoutpath[PATHLEN_MAX];
	if (BUILD_PATH(whiteoutpath, uopt.roots[branch].path, METADIR, path)) {
		syslog (LOG_WARNING, "%s(): Path too long\n", __func__);
		return false;
	}

	char *walk = whiteoutpath;

	// first slashes, e.g. we have path = /dir1/dir2/, will set walk = dir1/dir2/
	while (*walk != '\0' && *walk == '/') walk++;

	bool first = true;
	do {
		// walk over the directory name, walk will now be /dir2
		while (*walk != '\0' && *walk != '/') walk++;
	
		if (first) {
			// first dir in path is our branch, no need to check if it is hidden
			first = false;
			continue;
		}
		// +1 due to \0, which gets added automatically
		char p[PATHLEN_MAX];
		snprintf(p, (walk - whiteoutpath) + 1, "%s", whiteoutpath); // walk - path = strlen(/dir1)
		bool res = filedir_hidden(p);
		if (res) return res; // path is hidden

		// as above the do loop, walk over the next slashes, walk = dir2/
		while (*walk != '\0' && *walk == '/') walk++;
	} while (*walk != '\0');

	return 0;
}
Пример #29
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);
}
Пример #30
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_common(from, true);
		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);
}