示例#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;
}
gboolean
rb_uri_create_parent_dirs (const char *uri, GError **error)
{
	GFile *file;
	GFile *parent;
	gboolean ret;
#if !GLIB_CHECK_VERSION(2,17,1)
	GError *l_error = NULL;
#endif

	file = g_file_new_for_uri (uri);
	parent = g_file_get_parent (file);
	g_object_unref (file);
	if (parent == NULL) {
		/* now what? */
		return TRUE;
	}

#if GLIB_CHECK_VERSION(2,17,1)
	ret = check_file_is_directory (parent, error);
	if (ret == FALSE && *error == NULL) {
		ret = g_file_make_directory_with_parents (parent, NULL, error);
	}
#else
	ret = create_parent_dirs (parent, &l_error);

	if (l_error != NULL) {
		g_propagate_error (error, l_error);
	}
#endif
	g_object_unref (parent);
	return ret;
}
示例#3
0
// create or open
static int mhdd_internal_open(const char *file,
		mode_t mode, struct fuse_file_info *fi, int what)
{
	mhdd_debug(MHDD_INFO, "mhdd_internal_open: %s, flags = 0x%X\n",
		file, fi->flags);
	int dir_id, fd;

	char *path = find_path(file);

	if (path) {
		if (what == CREATE_FUNCTION)
			fd = open(path, fi->flags, mode);
		else
			fd = open(path, fi->flags);
		if (fd == -1) {
			free(path);
			return -errno;
		}
		struct flist *add = flist_create(file, path, fi->flags, fd);
		fi->fh = add->id;
		flist_unlock();
		free(path);
		return 0;
	}

	mhdd_debug(MHDD_INFO, "mhdd_internal_open: new file %s\n", file);

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

	create_parent_dirs(dir_id, file);
	path = create_path(mhdd.dirs[dir_id], file);

	if (what == CREATE_FUNCTION)
		fd = open(path, fi->flags, mode);
	else
		fd = open(path, fi->flags);

	if (fd == -1) {
		free(path);
		return -errno;
	}

	if (getuid() == 0) {
		struct stat st;
		gid_t gid = fuse_get_context()->gid;
		if (fstat(fd, &st) == 0) {
			/* parent directory is SGID'ed */
			if (st.st_gid != getgid()) gid = st.st_gid;
		}
		fchown(fd, fuse_get_context()->uid, gid);
	}
	struct flist *add = flist_create(file, path, fi->flags, fd);
	fi->fh = add->id;
	flist_unlock();
	free(path);
	return 0;
}
示例#4
0
文件: stats.c 项目: dgivone/ccache
/* write out a stats file */
void
stats_write(const char *path, struct counters *counters)
{
	size_t i;
	char *tmp_file;
	FILE *f;

	tmp_file = format("%s.tmp.%s", path, tmp_string());
	f = fopen(tmp_file, "wb");
	if (!f && errno == ENOENT) {
		if (create_parent_dirs(path) == 0) {
			f = fopen(tmp_file, "wb");
		}
	}
	if (!f) {
		cc_log("Failed to open %s", tmp_file);
		goto end;
	}
	for (i = 0; i < counters->size; i++) {
		if (fprintf(f, "%u\n", counters->data[i]) < 0) {
			fatal("Failed to write to %s", tmp_file);
		}
	}
	fclose(f);
	x_rename(tmp_file, path);

end:
	free(tmp_file);
}
示例#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;
}
示例#6
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;
}
static gboolean
create_parent_dirs (GFile *file, GError **error)
{
	gboolean ret;
	GFile *parent;

	ret = check_file_is_directory (file, error);
	if (ret == TRUE || *error != NULL) {
		return ret;
	}

	parent = g_file_get_parent (file);
	ret = create_parent_dirs (parent, error);
	g_object_unref (parent);
	if (ret == FALSE) {
		return FALSE;
	}

	return g_file_make_directory (file, NULL, error);
}
示例#8
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;
}
示例#9
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;
}
示例#10
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;
}
示例#11
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;
}
示例#12
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;
}
示例#13
0
文件: lockfile.c 项目: jjuran/ccache
/*
 * This function acquires a lockfile for the given path. Returns true if the
 * lock was acquired, otherwise false. If the lock has been considered stale
 * for the number of microseconds specified by staleness_limit, the function
 * will (if possible) break the lock and then try to acquire it again. The
 * staleness limit should be reasonably larger than the longest time the lock
 * can be expected to be held, and the updates of the locked path should
 * probably be made with an atomic rename(2) to avoid corruption in the rare
 * case that the lock is broken by another process.
 */
bool
lockfile_acquire(const char *path, unsigned staleness_limit)
{
	char *lockfile = format("%s.lock", path);
	char *my_content = NULL, *content = NULL, *initial_content = NULL;
	const char *hostname = get_hostname();
	bool acquired = false;
#ifdef _WIN32
	const size_t bufsize = 1024;
	int fd, len;
#else
	int ret;
#endif
	unsigned to_sleep = 1000, slept = 0; /* Microseconds. */

	while (1) {
		free(my_content);
		my_content = format("%s:%d:%d", hostname, (int)getpid(), (int)time(NULL));

#ifdef _WIN32
		fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0666);
		if (fd == -1) {
			cc_log("lockfile_acquire: open WRONLY %s: %s", lockfile, strerror(errno));
			if (errno == ENOENT) {
				/* Directory doesn't exist? */
				if (create_parent_dirs(lockfile) == 0) {
					/* OK. Retry. */
					continue;
				}
			}
			if (errno != EEXIST) {
				/* Directory doesn't exist or isn't writable? */
				goto out;
			}
			/* Someone else has the lock. */
			fd = open(lockfile, O_RDONLY|O_BINARY);
			if (fd == -1) {
				if (errno == ENOENT) {
					/*
					 * The file was removed after the open() call above, so retry
					 * acquiring it.
					 */
					continue;
				} else {
					cc_log("lockfile_acquire: open RDONLY %s: %s",
					       lockfile, strerror(errno));
					goto out;
				}
			}
			free(content);
			content = x_malloc(bufsize);
			if ((len = read(fd, content, bufsize - 1)) == -1) {
				cc_log("lockfile_acquire: read %s: %s", lockfile, strerror(errno));
				close(fd);
				goto out;
			}
			close(fd);
			content[len] = '\0';
		} else {
			/* We got the lock. */
			if (write(fd, my_content, strlen(my_content)) == -1) {
				cc_log("lockfile_acquire: write %s: %s", lockfile, strerror(errno));
				close(fd);
				x_unlink(lockfile);
				goto out;
			}
			close(fd);
			acquired = true;
			goto out;
		}
#else
		ret = symlink(my_content, lockfile);
		if (ret == 0) {
			/* We got the lock. */
			acquired = true;
			goto out;
		}
		cc_log("lockfile_acquire: symlink %s: %s", lockfile, strerror(errno));
		if (errno == ENOENT) {
			/* Directory doesn't exist? */
			if (create_parent_dirs(lockfile) == 0) {
				/* OK. Retry. */
				continue;
			}
		}
		if (errno != EEXIST) {
			/* Directory doesn't exist or isn't writable? */
			goto out;
		}
		free(content);
		content = x_readlink(lockfile);
		if (!content) {
			if (errno == ENOENT) {
				/*
				 * The symlink was removed after the symlink() call above, so retry
				 * acquiring it.
				 */
				continue;
			} else {
				cc_log("lockfile_acquire: readlink %s: %s", lockfile, strerror(errno));
				goto out;
			}
		}
#endif

		if (str_eq(content, my_content)) {
			/* Lost NFS reply? */
			cc_log("lockfile_acquire: symlink %s failed but we got the lock anyway",
			       lockfile);
			acquired = true;
			goto out;
		}
		/*
		 * A possible improvement here would be to check if the process holding the
		 * lock is still alive and break the lock early if it isn't.
		 */
		cc_log("lockfile_acquire: lock info for %s: %s", lockfile, content);
		if (!initial_content) {
			initial_content = x_strdup(content);
		}
		if (slept > staleness_limit) {
			if (str_eq(content, initial_content)) {
				/* The lock seems to be stale -- break it. */
				cc_log("lockfile_acquire: breaking %s", lockfile);
				if (lockfile_acquire(lockfile, staleness_limit)) {
					lockfile_release(path);
					lockfile_release(lockfile);
					to_sleep = 1000;
					slept = 0;
					continue;
				}
			}
			cc_log("lockfile_acquire: gave up acquiring %s", lockfile);
			goto out;
		}
		cc_log("lockfile_acquire: failed to acquire %s; sleeping %u microseconds",
		       lockfile, to_sleep);
		usleep(to_sleep);
		slept += to_sleep;
		to_sleep *= 2;
	}

out:
	if (acquired) {
		cc_log("Acquired lock %s", lockfile);
	} else {
		cc_log("Failed to acquire lock %s", lockfile);
	}
	free(lockfile);
	free(my_content);
	free(initial_content);
	free(content);
	return acquired;
}