Example #1
0
// .utimens
static int mhdd_utimens(const char *path, const struct timespec ts[2])
{
	mhdd_debug(MHDD_MSG, "mhdd_utimens: %s\n", path);
	int i, res, flag_found;

	for (i = flag_found = 0; i<mhdd.cdirs; i++) {
		char *object = create_path(mhdd.dirs[i], path);
		struct stat st;
		if (lstat(object, &st) != 0) {
			free(object);
			continue;
		}

		flag_found = 1;
		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;

		res = lutimes(object, tv);
		free(object);
		if (res == -1)
			return -errno;
	}
	if (flag_found)
		return 0;
	errno = ENOENT;
	return -errno;
}
Example #2
0
// write
static int mhdd_write(const char *path, const char *buf, size_t count,
		off_t offset, struct fuse_file_info *fi)
{
	ssize_t res;
	struct flist *info;
	mhdd_debug(MHDD_INFO, "mhdd_write: %s, handle = %lld\n", path, fi->fh);
	info = flist_item_by_id(fi->fh);

	if (!info) {
		errno = EBADF;
		return -errno;
	}

	res = pwrite(info->fh, buf, count, offset);
	if ((res == count) || (res == -1 && errno != ENOSPC)) {
		flist_unlock();
		if (res == -1) {
			mhdd_debug(MHDD_DEBUG,
				"mhdd_write: error write %s: %s\n",
				info->real_name, strerror(errno));
			return -errno;
		}
		return res;
	}

	// end free space
	if (move_file(info, offset + count) == 0) {
		res = pwrite(info->fh, buf, count, offset);
		flist_unlock();
		if (res == -1) {
			mhdd_debug(MHDD_DEBUG,
				"mhdd_write: error restart write: %s\n",
				strerror(errno));
			return -errno;
		}
		if (res < count) {
			mhdd_debug(MHDD_DEBUG,
				"mhdd_write: error (re)write file %s %s\n",
				info->real_name,
				strerror(ENOSPC));
		}
		return res;
	}
	errno = ENOSPC;
	flist_unlock();
	return -errno;
}
Example #3
0
// get diridx for maximum free space
int get_free_dir(void)
{
	int i, max, max_perc, max_perc_space = 0;
	struct statvfs stf;
	fsblkcnt_t max_space = 0;

	for (max = i = 0; i < mhdd.cdirs; i++) {

		if (statvfs(mhdd.dirs[i], &stf) != 0)
			continue;
		fsblkcnt_t space  = stf.f_bsize;
		space *= stf.f_bavail;

		if (mhdd.move_limit <= 100) {

			int perc;

			if (mhdd.move_limit != 100) {
				fsblkcnt_t perclimit = stf.f_blocks;

				if (mhdd.move_limit != 99) {
					perclimit *= mhdd.move_limit + 1;
					perclimit /= 100;
				}

				if (stf.f_bavail >= perclimit)
					return i;
			}

			perc = 100 * stf.f_bavail / stf.f_blocks;

			if (perc > max_perc_space) {
				max_perc_space = perc;
				max_perc = i;
			}
		} else {
			if (space >= mhdd.move_limit)
				return i;
		}

		if(space > max_space) {
			max_space = space;
			max = i;
		}
	}


	if (!max_space && !max_perc_space) {
		mhdd_debug(MHDD_INFO,
			"get_free_dir: Can't find freespace\n");
		return -1;
	}

	if (max_perc_space)
		return max_perc;
	return max;
}
Example #4
0
// close
static int mhdd_release(const char *path, struct fuse_file_info *fi)
{
	struct flist *del;
	int fh;

	mhdd_debug(MHDD_MSG, "mhdd_release: %s, handle = %lld\n", path, fi->fh);
	del = flist_item_by_id_wrlock(fi->fh);
	if (!del) {
		mhdd_debug(MHDD_INFO,
			"mhdd_release: unknown file number: %llu\n", fi->fh);
		errno = EBADF;
		return -errno;
	}

	fh = del->fh;
	flist_delete_wrlocked(del);
	close(fh);
	return 0;
}
Example #5
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 #6
0
// rmdir
static int mhdd_rmdir(const char * path)
{
	mhdd_debug(MHDD_MSG, "mhdd_rmdir: %s\n", path);
	char *dir;
	while((dir = find_path(path))) {
		int res = rmdir(dir);
		free(dir);
		if (res == -1) return -errno;
	}
	return 0;
}
Example #7
0
// unlink
static int mhdd_unlink(const char *path)
{
	mhdd_debug(MHDD_MSG, "mhdd_unlink: %s\n", path);
	char *file = find_path(path);
	if (!file) {
		errno = ENOENT;
		return -errno;
	}
	int res = unlink(file);
	free(file);
	if (res == -1) return -errno;
	return 0;
}
Example #8
0
// getattr
static int mhdd_stat(const char *file_name, struct stat *buf)
{
	mhdd_debug(MHDD_MSG, "mhdd_stat: %s\n", file_name);
	char *path = find_path(file_name);
	if (path) {
		int ret = lstat(path, buf);
		free(path);
		if (ret == -1) return -errno;
		return 0;
	}
	errno = ENOENT;
	return -errno;
}
Example #9
0
// readlink
static int mhdd_readlink(const char *path, char *buf, size_t size)
{
	mhdd_debug(MHDD_MSG, "mhdd_readlink: %s, size = %d\n", path, size);

	char *link = find_path(path);
	if (link) {
		memset(buf, 0, size);
		int res = readlink(link, buf, size);
		free(link);
		if (res >= 0)
			return 0;
	}
	return -1;
}
Example #10
0
// truncate
static int mhdd_truncate(const char *path, off_t size)
{
	char *file = find_path(path);
	mhdd_debug(MHDD_MSG, "mhdd_truncate: %s\n", path);
	if (file) {
		int res = truncate(file, size);
		free(file);
		if (res == -1)
			return -errno;
		return 0;
	}
	errno = ENOENT;
	return -errno;
}
Example #11
0
static int mhdd_getxattr(const char *path, const char *attrname, char *buf, size_t count)
{
        int size = 0;
	char * real_path = find_path(path);
	if (!real_path)
		return -ENOENT;

	mhdd_debug(MHDD_MSG,
		"mhdd_getxattr: path = %s name = %s bufsize = %d\n",
                real_path, attrname, count);
        size = getxattr(real_path, attrname, buf, count);
        free(real_path);
        if (size == -1) return -errno;
        return size;
}
Example #12
0
static int mhdd_removexattr(const char *path, const char *attrname)
{
	char * real_path = find_path(path);
	if (!real_path)
		return -ENOENT;

	mhdd_debug(MHDD_MSG,
		"mhdd_removexattr: path = %s name = %s\n",
                real_path, attrname);

        int res = removexattr(real_path, attrname);
        free(real_path);
        if (res == -1) return -errno;
        return 0;
}
Example #13
0
// access
static int mhdd_access(const char *path, int mask)
{
	mhdd_debug(MHDD_MSG, "mhdd_access: %s mode = %04X\n", path, mask);
	char *file = find_path(path);
	if (file) {
		int res = access(file, mask);
		free(file);
		if (res == -1)
			return -errno;
		return 0;
	}

	errno = ENOENT;
	return -errno;
}
Example #14
0
static int mhdd_setxattr(const char *path, const char *attrname,
                const char *attrval, size_t attrvalsize, int flags)
{
	char * real_path = find_path(path);
	if (!real_path)
		return -ENOENT;

	mhdd_debug(MHDD_MSG,
		"mhdd_setxattr: path = %s name = %s value = %s size = %d\n",
                real_path, attrname, attrval, attrvalsize);
        int res = setxattr(real_path, attrname, attrval, attrvalsize, flags);
        free(real_path);
        if (res == -1) return -errno;
        return 0;
}
Example #15
0
static int mhdd_listxattr(const char *path, char *buf, size_t count)
{
        int ret = 0;
	char * real_path = find_path(path);
	if (!real_path)
		return -ENOENT;

	mhdd_debug(MHDD_MSG,
		"mhdd_listxattr: path = %s bufsize = %d\n",
                real_path, count);

        ret=listxattr(real_path, buf, count);
        free(real_path);
        if (ret == -1) return -errno;
        return ret;
}
Example #16
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 #17
0
// ftrucate
static int mhdd_ftruncate(const char *path, off_t size,
		struct fuse_file_info *fi)
{
	int res;
	struct flist *info;
	mhdd_debug(MHDD_MSG,
		"mhdd_ftruncate: %s, handle = %lld\n", path, fi->fh);
	info = flist_item_by_id(fi->fh);

	if (!info) {
		errno = EBADF;
		return -errno;
	}

	int fh = info->fh;
	res = ftruncate(fh, size);
	flist_unlock();
	if (res == -1)
		return -errno;
	return 0;
}
Example #18
0
// read
static int mhdd_read(const char *path, char *buf, size_t count, off_t offset,
		struct fuse_file_info *fi)
{
	ssize_t res;
	struct flist * info;
	mhdd_debug(MHDD_INFO, "mhdd_read: %s, offset = %lld, count = %lld\n",
			path,
			(long long)offset,
			(long long)count
		  );
	info = flist_item_by_id(fi->fh);
	if (!info) {
		errno = EBADF;
		return -errno;
	}
	res = pread(info->fh, buf, count, offset);
	flist_unlock();
	if (res == -1)
		return -errno;
	return res;
}
Example #19
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 #20
0
// .chmod
static int mhdd_chmod(const char *path, mode_t mode)
{
	mhdd_debug(MHDD_MSG, "mhdd_chmod: mode = 0x%03X %s\n", mode, path);
	int i, res, flag_found;

	for (i = flag_found = 0; i<mhdd.cdirs; i++) {
		char *object = create_path(mhdd.dirs[i], path);
		struct stat st;
		if (lstat(object, &st) != 0) {
			free(object);
			continue;
		}

		flag_found = 1;
		res = chmod(object, mode);
		free(object);
		if (res == -1)
			return -errno;
	}
	if (flag_found)
		return 0;
	errno = ENOENT;
	return -errno;
}
Example #21
0
int move_file(struct flist * file, off_t wsize)
{
	char *from, *to, *buf;
	off_t size;
	FILE *input, *output;
	int ret, dir_id;
	struct utimbuf ftime = {0};
	struct statvfs svf;
	fsblkcnt_t space;
	struct stat st;

	mhdd_debug(MHDD_MSG, "move_file: %s\n", file->real_name);

	/* TODO: it would be nice to contrive something alter */
	flist_wrlock_locked();
	from=file->real_name;

	/* We need to check if already moved */
	if (statvfs(from, &svf) != 0)
		return -errno;
	space = svf.f_bsize;
	space *= svf.f_bavail;

	/* get file size */
	if (fstat(file->fh, &st) != 0) {
		mhdd_debug(MHDD_MSG, "move_file: error stat %s: %s\n",
			from, strerror(errno));
		return -errno;
	}

        /* Hard link support is limited to a single device, and files with
           >1 hardlinks cannot be moved between devices since this would
           (a) result in partial files on the source device (b) not free
           the space from the source device during unlink. */
	if (st.st_nlink > 1) {
		mhdd_debug(MHDD_MSG, "move_file: cannot move "
			"files with >1 hardlinks\n");
		return -ENOTSUP;
	}

	size = st.st_size;
	if (size < wsize) size=wsize;

	if (space > size) {
		mhdd_debug(MHDD_MSG, "move_file: we have enough space\n");
		return 0;
	}

	if ((dir_id=find_free_space(size)) == -1) {
		mhdd_debug(MHDD_MSG, "move_file: can not find space\n");
		return -1;
	}

	if (!(input = fopen(from, "r")))
		return -errno;

	create_parent_dirs(dir_id, file->name);

	to = create_path(mhdd.dirs[dir_id], file->name);
	if (!(output = fopen(to, "w+"))) {
		ret = -errno;
		mhdd_debug(MHDD_MSG, "move_file: error create %s: %s\n",
				to, strerror(errno));
		free(to);
		fclose(input);
		return(ret);
	}

	mhdd_debug(MHDD_MSG, "move_file: move %s to %s\n", from, to);

	// move data
	buf=(char *)calloc(sizeof(char), MOVE_BLOCK_SIZE);
	while((size = fread(buf, sizeof(char), MOVE_BLOCK_SIZE, input))) {
		if (size != fwrite(buf, sizeof(char), size, output)) {
			mhdd_debug(MHDD_MSG,
				"move_file: error move data to %s: %s\n",
				to, strerror(errno));
			fclose(output);
			fclose(input);
			free(buf);
			unlink(to);
			free(to);
			return -1;
		}
	}
	free(buf);

	mhdd_debug(MHDD_MSG, "move_file: done move data\n");
	fclose(input);

	// owner/group/permissions
	fchmod(fileno(output), st.st_mode);
	fchown(fileno(output), st.st_uid, st.st_gid);
	fclose(output);

	// time
	ftime.actime = st.st_atime;
	ftime.modtime = st.st_mtime;
	utime(to, &ftime);

#ifndef WITHOUT_XATTR
        // extended attributes
        if (copy_xattrs(from, to) == -1)
            mhdd_debug(MHDD_MSG,
                    "copy_xattrs: error copying xattrs from %s to %s\n",
                    from, to);
#endif


	from = strdup(from);
	if ((ret = reopen_files(file, to)) == 0)
		unlink(from);
	else
		unlink(to);

	mhdd_debug(MHDD_MSG, "move_file: %s -> %s: done, code=%d\n",
		from, to, ret);
	free(to);
	free(from);
	return ret;
}
Example #22
0
int copy_xattrs(const char *from, const char *to)
{
        int listsize=0, attrvalsize=0;
        char *listbuf=NULL, *attrvalbuf=NULL,
                *name_begin=NULL, *name_end=NULL;

        // if not xattrs on source, then do nothing
        if ((listsize=listxattr(from, NULL, 0)) == 0)
                return 0;

        // get all extended attributes
        listbuf=(char *)calloc(sizeof(char), listsize);
        if (listxattr(from, listbuf, listsize) == -1)
        {
                mhdd_debug(MHDD_MSG,
                        "listxattr: error listing xattrs on %s : %s\n",
                        from, strerror(errno));
                return -1;
        }

        // loop through each xattr
        for(name_begin=listbuf, name_end=listbuf+1;
                name_end < (listbuf + listsize); name_end++)
        {
                // skip the loop if we're not at the end of an attribute name
                if (*name_end != '\0')
                        continue;

                // get the size of the extended attribute
                attrvalsize = getxattr(from, name_begin, NULL, 0);
                if (attrvalsize < 0)
                {
                        mhdd_debug(MHDD_MSG,
                                "getxattr: error getting xattr size on %s name %s : %s\n",
                                from, name_begin, strerror(errno));
                        return -1;
                }

                // get the value of the extended attribute
                attrvalbuf=(char *)calloc(sizeof(char), attrvalsize);
                if (getxattr(from, name_begin, attrvalbuf, attrvalsize) < 0)
                {
                        mhdd_debug(MHDD_MSG,
                                "getxattr: error getting xattr value on %s name %s : %s\n",
                                from, name_begin, strerror(errno));
                        return -1;
                }

                // set the value of the extended attribute on dest file
                if (setxattr(to, name_begin, attrvalbuf, attrvalsize, 0) < 0)
                {
                        mhdd_debug(MHDD_MSG,
                                "setxattr: error setting xattr value on %s name %s : %s\n",
                                from, name_begin, strerror(errno));
                        return -1;
                }

                free(attrvalbuf);

                // point the pointer to the start of the attr name to the start
                // of the next attr
                name_begin=name_end+1;
                name_end++;
        }

        free(listbuf);
        return 0;
}
Example #23
0
static int reopen_files(struct flist * file, const char *new_name)
{
	int i;
	struct flist ** rlist;
	int error = 0;

	mhdd_debug(MHDD_INFO, "reopen_files: %s -> %s\n",
			file->real_name, new_name);
	rlist = flist_items_by_eq_name(file);
	if (!rlist)
		return 0;

	for (i = 0; rlist[i]; i++) {
		struct flist * next = rlist[i];

		off_t seek = lseek(next->fh, 0, SEEK_CUR);
		int flags = next->flags;
		int fh;

		flags &= ~(O_EXCL|O_TRUNC);

		// open
		if ((fh = open(new_name, flags)) == -1) {
			mhdd_debug(MHDD_INFO,
				"reopen_files: error reopen: %s\n",
				strerror(errno));
			if (!i) {
				error = errno;
				break;
			}
			close(next->fh);
		}
		else
		{
			// seek
			if (seek != lseek(fh, seek, SEEK_SET)) {
				mhdd_debug(MHDD_INFO,
					"reopen_files: error seek %s\n",
					strerror(errno));
				close(fh);
				if (!i) {
					error = errno;
					break;
				}
			}

			// filehandle
			if (dup2(fh, next->fh) != next->fh) {
				mhdd_debug(MHDD_INFO,
					"reopen_files: error dup2 %s\n",
					strerror(errno));
				close(fh);
				if (!i) {
					error = errno;
					break;
				}
			}
			// close temporary filehandle
			mhdd_debug(MHDD_MSG,
				"reopen_files: reopened %s (to %s) old h=%x "
				"new h=%x seek=%lld\n",
				next->real_name, new_name, next->fh, fh, seek);
			close(fh);
		}
	}

	if (error) {
		free(rlist);
		return -error;
	}

	/* change real_name */
	for (i = 0; rlist[i]; i++) {
		free(rlist[i]->real_name);
		rlist[i]->real_name = strdup(new_name);
	}
	free(rlist);
	return 0;
}
Example #24
0
static int mhdd_readdir(
		const char *dirname,
		void *buf,
		fuse_fill_dir_t filler,
		off_t offset,
		struct fuse_file_info * fi)
{
	int i, j, found;

	mhdd_debug(MHDD_MSG, "mhdd_readdir: %s\n", dirname);
	char **dirs = (char **) calloc(mhdd.cdirs+1, sizeof(char *));

	struct stat st;

	typedef struct dir_item {
		char            *name;
		struct stat     *st;
	} dir_item;


	// find all dirs
	for(i = j = found = 0; i<mhdd.cdirs; i++) {
		char *path = create_path(mhdd.dirs[i], dirname);
		if (stat(path, &st) == 0) {
			found++;
			if (S_ISDIR(st.st_mode)) {
				dirs[j] = path;
				j++;
				continue;
			}
		}
		free(path);
	}

	// dirs not found
	if (dirs[0] == 0) {
		errno = ENOENT;
		if (found) errno = ENOTDIR;
		free(dirs);
		return -errno;
	}

	GHashTable* hash = g_hash_table_new(g_str_hash, g_str_equal);

	// read directories
	for (i = 0; dirs[i]; i++) {
		struct dirent *de;
		DIR * dh = opendir(dirs[i]);
		if (!dh)
			continue;

		while((de = readdir(dh))) {
			// find dups
			
			if(g_hash_table_lookup(hash, de->d_name))
			{
				continue;
			}

			// add item
			char *object_name = create_path(dirs[i], de->d_name);
			struct dir_item *new_item =	calloc(1, sizeof(struct dir_item));

			new_item->name = strdup(de->d_name);
			new_item->st = calloc(1, sizeof(struct stat));
			lstat(object_name, new_item->st);

			g_hash_table_insert(hash, new_item->name, new_item);
			free(object_name);
		}

		closedir(dh);
	}

	dir_item *item;

	gpointer key, value;	
	GHashTableIter iter;
	g_hash_table_iter_init(&iter, hash);

	while(g_hash_table_iter_next (&iter, &key, &value))
	{
		item = (dir_item*) value;
		int result = filler(buf, item->name, item->st, 0);
		free(item->name);
		free(item->st);
		free(item);
		if(result) break;
	}

	g_hash_table_destroy(hash);

	for (i = 0; dirs[i]; i++)
		free(dirs[i]);
	free(dirs);
	return 0;
}
Example #25
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 #26
0
//statvfs
static int mhdd_statfs(const char *path, struct statvfs *buf)
{
	int i, j;
	struct statvfs * stats;
	struct stat st;
	dev_t * devices;

	mhdd_debug(MHDD_MSG, "mhdd_statfs: %s\n", path);

	stats = calloc(mhdd.cdirs, sizeof(struct statvfs));
	devices = calloc(mhdd.cdirs, sizeof(dev_t));

	for (i = 0; i < mhdd.cdirs; i++) {
		int ret = statvfs(mhdd.dirs[i], stats+i);
		if (ret != 0) {
			free(stats);
			free(devices);
			return -errno;
		}

		ret = stat(mhdd.dirs[i], &st);
		if (ret != 0) {
			free(stats);
			free(devices);
			return -errno;
		}
		devices[i] = st.st_dev;
	}

	unsigned long
		min_block = stats[0].f_bsize,
		min_frame = stats[0].f_frsize;

	for (i = 1; i<mhdd.cdirs; i++) {
		if (min_block>stats[i].f_bsize) min_block = stats[i].f_bsize;
		if (min_frame>stats[i].f_frsize) min_frame = stats[i].f_frsize;
	}

	if (!min_block)
		min_block = 512;
	if (!min_frame)
		min_frame = 512;

	for (i = 0; i < mhdd.cdirs; i++) {
		if (stats[i].f_bsize>min_block) {
			stats[i].f_bfree    *=  stats[i].f_bsize/min_block;
			stats[i].f_bavail   *=  stats[i].f_bsize/min_block;
			stats[i].f_bsize    =   min_block;
		}
		if (stats[i].f_frsize>min_frame) {
			stats[i].f_blocks   *=  stats[i].f_frsize/min_frame;
			stats[i].f_frsize   =   min_frame;
		}
	}

	memcpy(buf, stats, sizeof(struct statvfs));

	for (i = 1; i<mhdd.cdirs; i++) {

		/* if the device already processed, skip it */
		if (devices[i]) {
			int dup_found = 0;
			for (j = 0; j < i; j++) {
				if (devices[j] == devices[i]) {
					dup_found = 1;
					break;
				}
			}

			if (dup_found)
				continue;
		}

		if (buf->f_namemax<stats[i].f_namemax) {
			buf->f_namemax = stats[i].f_namemax;
		}
		buf->f_ffree  +=  stats[i].f_ffree;
		buf->f_files  +=  stats[i].f_files;
		buf->f_favail +=  stats[i].f_favail;
		buf->f_bavail +=  stats[i].f_bavail;
		buf->f_bfree  +=  stats[i].f_bfree;
		buf->f_blocks +=  stats[i].f_blocks;
	}

	free(stats);
	free(devices);
	return 0;
}
Example #27
0
static int mhdd_readdir(
		const char *dirname,
		void *buf,
		fuse_fill_dir_t filler,
		off_t offset,
		struct fuse_file_info * fi)
{
	int i, j, found;

	mhdd_debug(MHDD_MSG, "mhdd_readdir: %s\n", dirname);
	char **dirs = (char **) calloc(mhdd.cdirs+1, sizeof(char *));

	typedef struct dir_item {
		char            *name;
		struct stat     *st;
		UT_hash_handle   hh;
	} dir_item;

	dir_item * items_ht = NULL;


	struct stat st;

	// find all dirs
	for(i = j = found = 0; i<mhdd.cdirs; i++) {
		char *path = create_path(mhdd.dirs[i], dirname);
		if (stat(path, &st) == 0) {
			found++;
			if (S_ISDIR(st.st_mode)) {
				dirs[j] = path;
				j++;
				continue;
			}
		}
		free(path);
	}

	// dirs not found
	if (dirs[0] == 0) {
		errno = ENOENT;
		if (found) errno = ENOTDIR;
		free(dirs);
		return -errno;
	}

	// read directories
	for (i = 0; dirs[i]; i++) {
		struct dirent *de;
		DIR * dh = opendir(dirs[i]);
		if (!dh)
			continue;

		while((de = readdir(dh))) {
			// find dups
			
			struct dir_item *prev;

			HASH_FIND_STR(items_ht, de->d_name, prev);

			if (prev) {
				continue;
			}

			// add item
			char *object_name = create_path(dirs[i], de->d_name);
			struct dir_item *new_item =
				calloc(1, sizeof(struct dir_item));

			new_item->name = strdup(de->d_name);
			new_item->st = calloc(1, sizeof(struct stat));
			lstat(object_name, new_item->st);

			HASH_ADD_KEYPTR(
				hh,
				items_ht,
				new_item->name,
				strlen(new_item->name),
				new_item
			);
			free(object_name);
		}

		closedir(dh);
	}

	dir_item *item, *tmp;

	// fill list
	HASH_ITER(hh, items_ht, item, tmp) {
		if (filler(buf, item->name, item->st, 0))
			break;
	}

	// free memory
	HASH_ITER(hh, items_ht, item, tmp) {
		free(item->name);
		free(item->st);
		free(item);
	}
Example #28
0
int create_parent_dirs(int dir_id, const char *path)
{
	mhdd_debug(MHDD_DEBUG,
		"create_parent_dirs: dir_id=%d, path=%s\n", dir_id, path);
	char *parent=get_parent_path(path);
	if (!parent) return 0;

	char *exists=find_path(parent);
	if (!exists) { free(parent); errno=EFAULT; return -errno; }


	char *path_parent=create_path(mhdd.dirs[dir_id], parent);
	struct stat st;

	// already exists
	if (stat(path_parent, &st)==0)
	{
		free(exists);
		free(path_parent);
		free(parent);
		return 0;
	}

	// create parent dirs
	int res=create_parent_dirs(dir_id, parent);

	if (res!=0)
	{
		free(path_parent);
		free(parent);
		free(exists);
		return res;
	}

	// get stat from exists dir
	if (stat(exists, &st)!=0)
	{
		free(exists);
		free(path_parent);
		free(parent);
		return -errno;
	}
	res=mkdir(path_parent, st.st_mode);
	if (res==0)
	{
		chown(path_parent, st.st_uid, st.st_gid);
		chmod(path_parent, st.st_mode);
	}
	else
	{
		res=-errno;
		mhdd_debug(MHDD_DEBUG,
			"create_parent_dirs: can not create dir %s: %s\n",
			path_parent,
			strerror(errno));
	}

#ifndef WITHOUT_XATTR
        // copy extended attributes of parent dir
        if (copy_xattrs(exists, path_parent) == -1)
            mhdd_debug(MHDD_MSG,
                    "copy_xattrs: error copying xattrs from %s to %s\n",
                    exists, path_parent);
#endif

	free(exists);
	free(path_parent);
	free(parent);
	return res;
}
Example #29
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;
}