Example #1
0
// link
static int mhdd_link(const char *from, const char *to)
{
	mhdd_debug(MHDD_MSG, "mhdd_link: from = %s to = %s\n", from, to);

	int dir_id = find_path_id(from);

	if (dir_id == -1) {
		errno = ENOENT;
		return -errno;
	}

	int res = create_parent_dirs(dir_id, to);
	if (res != 0) {
		return res;
	}

	char *path_from = create_path(mhdd.dirs[dir_id], from);
	char *path_to = create_path(mhdd.dirs[dir_id], to);

	res = link(path_from, path_to);
	free(path_from);
	free(path_to);

	if (res == 0)
		return 0;
	return -errno;
}
Example #2
0
// mkdir
static int mhdd_mkdir(const char * path, mode_t mode)
{
	mhdd_debug(MHDD_MSG, "mhdd_mkdir: %s mode = %04X\n", path, mode);

	if (find_path_id(path) != -1) {
		errno = EEXIST;
		return -errno;
	}

	char *parent = get_parent_path(path);
	if (!parent) {
		errno = EFAULT;
		return -errno;
	}

	if (find_path_id(parent) == -1) {
		free(parent);
		errno = EFAULT;
		return -errno;
	}
	free(parent);

	int dir_id = get_free_dir();
	if (dir_id<0) {
		errno = ENOSPC;
		return -errno;
	}

	create_parent_dirs(dir_id, path);
	char *name = create_path(mhdd.dirs[dir_id], path);
	if (mkdir(name, mode) == 0) {
		if (getuid() == 0) {
			struct stat st;
			gid_t gid = fuse_get_context()->gid;
			if (lstat(name, &st) == 0) {
				/* parent directory is SGID'ed */
				if (st.st_gid != getgid())
					gid = st.st_gid;
			}
			chown(name, fuse_get_context()->uid, gid);
		}
		free(name);
		return 0;
	}
	free(name);
	return -errno;
}
Example #3
0
// mknod
static int mhdd_mknod(const char *path, mode_t mode, dev_t rdev)
{
	mhdd_debug(MHDD_MSG, "mhdd_mknod: path = %s mode = %X\n", path, mode);
	int res, i;
	char *nod;

	char *parent = get_parent_path(path);
	if (!parent) {
		errno = ENOENT;
		return -errno;
	}

	int dir_id = find_path_id(parent);
	free(parent);

	if (dir_id == -1) {
		errno = ENOENT;
		return -errno;
	}

	for (i = 0; i < 2; i++) {
		if (i) {
			if ((dir_id = get_free_dir())<0) {
				errno = ENOSPC;
				return -errno;
			}
			create_parent_dirs(dir_id, path);
		}
		nod = create_path(mhdd.dirs[dir_id], path);

		if (S_ISREG(mode)) {
			res = open(nod, O_CREAT | O_EXCL | O_WRONLY, mode);
			if (res >= 0)
				res = close(res);
		} else if (S_ISFIFO(mode))
			res = mkfifo(nod, mode);
		else
			res = mknod(nod, mode, rdev);

		if (res != -1) {
			if (getuid() == 0) {
				struct fuse_context * fcontext =
					fuse_get_context();
				chown(nod, fcontext->uid, fcontext->gid);
			}
			free(nod);
			return 0;
		}
		free(nod);
		if (errno != ENOSPC)
			return -errno;
	}
	return -errno;
}
Example #4
0
// symlink
static int mhdd_symlink(const char *from, const char *to)
{
	mhdd_debug(MHDD_MSG, "mhdd_symlink: from = %s to = %s\n", from, to);
	int i, res;
	char *parent = get_parent_path(to);
	if (!parent) {
		errno = ENOENT;
		return -errno;
	}

	int dir_id = find_path_id(parent);
	free(parent);

	if (dir_id == -1) {
		errno = ENOENT;
		return -errno;
	}

	for (i = 0; i < 2; i++) {
		if (i) {
			if ((dir_id = get_free_dir()) < 0) {
				errno = ENOSPC;
				return -errno;
			}

			create_parent_dirs(dir_id, to);
		}

		char *path_to = create_path(mhdd.dirs[dir_id], to);

		res = symlink(from, path_to);
		free(path_to);
		if (res == 0)
			return 0;
		if (errno != ENOSPC)
			return -errno;
	}
	return -errno;
}
Example #5
0
// rename
static int mhdd_rename(const char *from, const char *to)
{
	mhdd_debug(MHDD_MSG, "mhdd_rename: from = %s to = %s\n", from, to);

	int i, res;
	struct stat sto, sfrom;
	char *obj_from, *obj_to;
	int from_is_dir = 0, to_is_dir = 0, from_is_file = 0, to_is_file = 0;
	int to_dir_is_empty = 1, to_is_link = 0;

	if (strcmp(from, to) == 0)
		return 0;

	/* seek for possible errors */
	for (i = 0; i < mhdd.cdirs; i++) {
		obj_to   = create_path(mhdd.dirs[i], to);
		obj_from = create_path(mhdd.dirs[i], from);
		if (stat(obj_to, &sto) == 0) {
			if (S_ISDIR(sto.st_mode)) {
				to_is_dir++;
				if (!dir_is_empty(obj_to))
					to_dir_is_empty = 0;
			}
			else
				to_is_file++;
			if (lstat(obj_to, &sto) == 0) {
				if ((sto.st_mode & S_IFMT) == S_IFLNK)
					to_is_link++;
			}
		}
		if (stat(obj_from, &sfrom) == 0) {
			if (S_ISDIR (sfrom.st_mode))
				from_is_dir++;
			else
				from_is_file++;
		}
		free(obj_from);
		free(obj_to);

		if (to_is_file && from_is_dir)
			return -ENOTDIR;
		if (to_is_file && to_is_dir)
			return -ENOTEMPTY;
		if (from_is_dir && !to_dir_is_empty && !to_is_link)
			return -ENOTEMPTY;
	}

	/* parent 'to' path doesn't exists */
	char *pto = get_parent_path (to);
	if (find_path_id(pto) == -1) {
		free (pto);
		return -ENOENT;
	}
	free (pto);

	/* rename cycle */
	for (i = 0; i < mhdd.cdirs; i++) {
		obj_to   = create_path(mhdd.dirs[i], to);
		obj_from = create_path(mhdd.dirs[i], from);
		if (lstat(obj_from, &sfrom) == 0) {
			/* if from is dir and at the same time file,
			   we only rename dir, using lstat because we
			   should handle symlinks here as well */
			if (from_is_dir && from_is_file) {
				if (!S_ISDIR(sfrom.st_mode)) {
					free(obj_from);
					free(obj_to);
					continue;
				}
			}

			create_parent_dirs(i, to);

			mhdd_debug(MHDD_MSG, "mhdd_rename: rename %s -> %s\n",
				obj_from, obj_to);
			res = rename(obj_from, obj_to);
			if (res == -1) {
				free(obj_from);
				free(obj_to);
				return -errno;
			}
		} else {
			/* from and to are files, so we must remove to files */
			if (from_is_file && to_is_file && !from_is_dir) {
				if (stat(obj_to, &sto) == 0) {
					mhdd_debug(MHDD_MSG,
						"mhdd_rename: unlink %s\n",
						obj_to);
					if (unlink(obj_to) == -1) {
						free(obj_from);
						free(obj_to);
						return -errno;
					}
				}
			}
		}

		free(obj_from);
		free(obj_to);
	}

	return 0;
}
Example #6
0
// rename
static int mhdd_rename(const char *from, const char *to)
{
	mhdd_debug(MHDD_MSG, "mhdd_rename: from = %s to = %s\n", from, to);

	int i, res;
	struct stat sto, sfrom;
	char *obj_from, *obj_to;
	int from_is_dir = 0, to_is_dir = 0, from_is_file = 0, to_is_file = 0;
	int to_dir_is_empty = 1;

	if (strcmp(from, to) == 0)
		return 0;

	/* seek for possible errors */
	for (i = 0; i < mhdd.cdirs; i++) {
		obj_to   = create_path(mhdd.dirs[i], to);
		obj_from = create_path(mhdd.dirs[i], from);
		if (stat(obj_to, &sto) == 0) {
			if (S_ISDIR(sto.st_mode)) {
				to_is_dir++;
				if (!dir_is_empty(obj_to))
					to_dir_is_empty = 0;
			}
			else
				to_is_file++;
		}
		if (stat(obj_from, &sfrom) == 0) {
			if (S_ISDIR (sfrom.st_mode))
				from_is_dir++;
			else
				from_is_file++;
		}
		free(obj_from);
		free(obj_to);

		if (to_is_file && from_is_dir)
			return -ENOTDIR;
		if (to_is_file && to_is_dir)
			return -ENOTEMPTY;
		if (from_is_dir && !to_dir_is_empty)
			return -ENOTEMPTY;
	}

	/* parent 'to' path doesn't exists */
	char *pto = get_parent_path (to);
	if (find_path_id(pto) == -1) {
		free (pto);
		return -ENOENT;
	}
	free (pto);

	int *renamed_on = calloc(mhdd.cdirs, sizeof(int));
	if (!renamed_on)
		return -ENOMEM;

	/* rename first, then unlink, so we never see a nonexistent file */
	for (i = 0; i < mhdd.cdirs; i++) {
		obj_to   = create_path(mhdd.dirs[i], to);
		obj_from = create_path(mhdd.dirs[i], from);
		if (stat(obj_from, &sfrom) == 0) {
			/* if from is dir and at the same time file,
			   we only rename dir */
			if (from_is_dir && from_is_file) {
				if (!S_ISDIR(sfrom.st_mode)) {
					free(obj_from);
					free(obj_to);
					continue;
				}
			}

			create_parent_dirs(i, to);

			mhdd_debug(MHDD_MSG, "mhdd_rename: rename %s -> %s\n",
				obj_from, obj_to);
			res = rename(obj_from, obj_to);
			if (res == -1) {
				free(obj_from);
				free(obj_to);
				free(renamed_on);
				return -errno;
			}
			renamed_on[i] = 1;
		}
		free(obj_from);
		free(obj_to);
	}

	/* now unlink */
	for (i = 0; i < mhdd.cdirs; i++) {
		/* don't delete if we already renamed. */
		if (renamed_on[i])
			continue;

		obj_to   = create_path(mhdd.dirs[i], to);
		obj_from = create_path(mhdd.dirs[i], from);
		if (stat(obj_from, &sfrom) != 0) {
			/* from and to are files, so we must remove to files */
			if (from_is_file && to_is_file && !from_is_dir) {
				if (stat(obj_to, &sto) == 0) {
					mhdd_debug(MHDD_MSG,
						"mhdd_rename: unlink %s\n",
						obj_to);
					if (unlink(obj_to) == -1) {
						free(obj_from);
						free(obj_to);
						return -errno;
					}
				}
			}
		}
		free(obj_from);
		free(obj_to);
	}

	free(renamed_on);
	return 0;
}