static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
			  void *user)
{
	int ret;
	struct btrfs_receive *r = user;
	struct btrfs_ioctl_vol_args args_v1;
	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];

	ret = finish_subvol(r);
	if (ret < 0)
		goto out;

	BUG_ON(r->cur_subvol.path);
	BUG_ON(r->cur_subvol_path[0]);

	if (*r->dest_dir_path == 0) {
		strncpy_null(r->cur_subvol_path, path);
	} else {
		ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
		if (ret < 0) {
			error("subvol: path invalid: %s\n", path);
			goto out;
		}
	}
	ret = path_cat3_out(r->full_subvol_path, r->root_path,
			r->dest_dir_path, path);
	if (ret < 0) {
		error("subvol: path invalid: %s", path);
		goto out;
	}

	fprintf(stderr, "At subvol %s\n", path);

	memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
	r->cur_subvol.stransid = ctransid;

	if (g_verbose) {
		uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
		fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
				path, uuid_str,
				r->cur_subvol.stransid);
	}

	memset(&args_v1, 0, sizeof(args_v1));
	strncpy_null(args_v1.name, path);
	ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
	if (ret < 0) {
		ret = -errno;
		error("creating subvolume %s failed: %s", path, strerror(-ret));
		goto out;
	}

out:
	return ret;
}
예제 #2
0
static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
			  void *user)
{
	int ret;
	struct btrfs_receive *r = user;
	struct btrfs_ioctl_vol_args args_v1;
	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];

	ret = finish_subvol(r);
	if (ret < 0)
		goto out;

	r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));

	if (strlen(r->dest_dir_path) == 0)
		r->cur_subvol->path = strdup(path);
	else
		r->cur_subvol->path = path_cat(r->dest_dir_path, path);
	free(r->full_subvol_path);
	r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);

	fprintf(stderr, "At subvol %s\n", path);

	memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
	r->cur_subvol->stransid = ctransid;

	if (g_verbose) {
		uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
		fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
				path, uuid_str,
				r->cur_subvol->stransid);
	}

	memset(&args_v1, 0, sizeof(args_v1));
	strncpy_null(args_v1.name, path);
	ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
	if (ret < 0) {
		ret = -errno;
		fprintf(stderr, "ERROR: creating subvolume %s failed. "
				"%s\n", path, strerror(-ret));
		goto out;
	}

out:
	return ret;
}
int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
{
	int ret;
	int end = 0;

	r->root_path = strdup(tomnt);
	r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
	if (r->mnt_fd < 0) {
		ret = -errno;
		fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
				strerror(-ret));
		goto out;
	}

	ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
	if (ret < 0)
		return ret;

	r->write_fd = -1;

	while (!end) {
		ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
		if (ret < 0)
			goto out;
		if (ret)
			end = 1;

		ret = close_inode_for_write(r);
		if (ret < 0)
			goto out;
		ret = finish_subvol(r);
		if (ret < 0)
			goto out;
	}
	ret = 0;

out:
	return ret;
}
static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
			    const u8 *parent_uuid, u64 parent_ctransid,
			    void *user)
{
	int ret;
	struct btrfs_receive *r = user;
	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
	struct btrfs_ioctl_vol_args_v2 args_v2;
	struct subvol_info *parent_subvol = NULL;

	ret = finish_subvol(r);
	if (ret < 0)
		goto out;

	BUG_ON(r->cur_subvol.path);
	BUG_ON(r->cur_subvol_path[0]);

	if (*r->dest_dir_path == 0) {
		strncpy_null(r->cur_subvol_path, path);
	} else {
		ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
		if (ret < 0) {
			error("snapshot: path invalid: %s", path);
			goto out;
		}
	}
	ret = path_cat3_out(r->full_subvol_path, r->root_path,
			r->dest_dir_path, path);
	if (ret < 0) {
		error("snapshot: path invalid: %s", path);
		goto out;
	}

	fprintf(stdout, "At snapshot %s\n", path);

	memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
	r->cur_subvol.stransid = ctransid;

	if (g_verbose) {
		uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
		fprintf(stderr, "receiving snapshot %s uuid=%s, "
				"ctransid=%llu ", path, uuid_str,
				r->cur_subvol.stransid);
		uuid_unparse(parent_uuid, uuid_str);
		fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
				uuid_str, parent_ctransid);
	}

	memset(&args_v2, 0, sizeof(args_v2));
	strncpy_null(args_v2.name, path);

	parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
			parent_ctransid, NULL, subvol_search_by_received_uuid);
	if (!parent_subvol) {
		parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
				parent_ctransid, NULL, subvol_search_by_uuid);
	}
	if (!parent_subvol) {
		ret = -ENOENT;
		error("cannot find parent subvolume");
		goto out;
	}

	/*
	 * The path is resolved from the root subvol, but we could be in some
	 * subvolume under the root subvolume, so try and adjust the path to be
	 * relative to our root path.
	 */
	if (r->full_root_path) {
		size_t root_len;
		size_t sub_len;

		root_len = strlen(r->full_root_path);
		sub_len = strlen(parent_subvol->path);

		/* First make sure the parent subvol is actually in our path */
		if (sub_len < root_len ||
		    strstr(parent_subvol->path, r->full_root_path) == NULL) {
			error(
		"parent subvol is not reachable from inside the root subvol");
			ret = -ENOENT;
			goto out;
		}

		if (sub_len == root_len) {
			parent_subvol->path[0] = '/';
			parent_subvol->path[1] = '\0';
		} else {
			/*
			 * root path is foo/bar
			 * subvol path is foo/bar/baz
			 *
			 * we need to have baz be the path, so we need to move
			 * the bit after foo/bar/, so path + root_len + 1, and
			 * move the part we care about, so sub_len - root_len -
			 * 1.
			 */
			memmove(parent_subvol->path,
				parent_subvol->path + root_len + 1,
				sub_len - root_len - 1);
			parent_subvol->path[sub_len - root_len - 1] = '\0';
		}
	}
	/*if (rs_args.ctransid > rs_args.rtransid) {
		if (!r->force) {
			ret = -EINVAL;
			fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
			goto out;
		} else {
			fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
		}
	}*/

	if (*parent_subvol->path == 0)
		args_v2.fd = dup(r->mnt_fd);
	else
		args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
				O_RDONLY | O_NOATIME);
	if (args_v2.fd < 0) {
		ret = -errno;
		if (errno != ENOENT)
			error("cannot open %s: %s",
					parent_subvol->path, strerror(-ret));
		else
			fprintf(stderr,
				"It seems that you have changed your default "
				"subvolume or you specify other subvolume to\n"
				"mount btrfs, try to remount this btrfs filesystem "
				"with fs tree, and run btrfs receive again!\n");
		goto out;
	}

	ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
	close(args_v2.fd);
	if (ret < 0) {
		ret = -errno;
		error("creating snapshot %s -> %s failed: %s",
				parent_subvol->path, path, strerror(-ret));
		goto out;
	}

out:
	if (parent_subvol) {
		free(parent_subvol->path);
		free(parent_subvol);
	}
	return ret;
}
static int do_receive(struct btrfs_receive *r, const char *tomnt,
		      char *realmnt, int r_fd, u64 max_errors)
{
	u64 subvol_id;
	int ret;
	char *dest_dir_full_path;
	char root_subvol_path[PATH_MAX];
	int end = 0;

	dest_dir_full_path = realpath(tomnt, NULL);
	if (!dest_dir_full_path) {
		ret = -errno;
		error("realpath(%s) failed: %s", tomnt, strerror(-ret));
		goto out;
	}
	r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
	if (r->dest_dir_fd < 0) {
		ret = -errno;
		error("cannot open destination directory %s: %s",
			dest_dir_full_path, strerror(-ret));
		goto out;
	}

	if (realmnt[0]) {
		r->root_path = realmnt;
	} else {
		ret = find_mount_root(dest_dir_full_path, &r->root_path);
		if (ret < 0) {
			error("failed to determine mount point for %s: %s",
				dest_dir_full_path, strerror(-ret));
			ret = -EINVAL;
			goto out;
		}
		if (ret > 0) {
			error("%s doesn't belong to btrfs mount point",
				dest_dir_full_path);
			ret = -EINVAL;
			goto out;
		}
	}
	r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
	if (r->mnt_fd < 0) {
		ret = -errno;
		error("cannot open %s: %s", r->root_path, strerror(-ret));
		goto out;
	}

	/*
	 * If we use -m or a default subvol we want to resolve the path to the
	 * subvolume we're sitting in so that we can adjust the paths of any
	 * subvols we want to receive in.
	 */
	ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
	if (ret) {
		error("cannot resolve our subvolid: %d",
			ret);
		goto out;
	}

	root_subvol_path[0] = 0;
	ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
				     PATH_MAX, subvol_id);
	if (ret) {
		error("cannot resolve our subvol path");
		goto out;
	}

	/*
	 * Ok we're inside of a subvol off of the root subvol, we need to
	 * actually set full_root_path.
	 */
	if (*root_subvol_path)
		r->full_root_path = root_subvol_path;

	if (r->dest_dir_chroot) {
		if (chroot(dest_dir_full_path)) {
			ret = -errno;
			error("failed to chroot to %s: %s",
				dest_dir_full_path, strerror(-ret));
			goto out;
		}
		if (chdir("/")) {
			ret = -errno;
			error("failed to chdir to / after chroot: %s",
				strerror(-ret));
			goto out;
		}
		fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
		r->root_path = strdup("/");
		r->dest_dir_path = r->root_path;
	} else {
		/*
		 * find_mount_root returns a root_path that is a subpath of
		 * dest_dir_full_path. Now get the other part of root_path,
		 * which is the destination dir relative to root_path.
		 */
		r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
		while (r->dest_dir_path[0] == '/')
			r->dest_dir_path++;
	}

	ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
	if (ret < 0)
		goto out;

	while (!end) {
		if (r->cached_capabilities_len) {
			if (g_verbose >= 3)
				fprintf(stderr, "clear cached capabilities\n");
			memset(r->cached_capabilities, 0,
					sizeof(r->cached_capabilities));
			r->cached_capabilities_len = 0;
		}

		ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
							 r->honor_end_cmd,
							 max_errors);
		if (ret < 0)
			goto out;
		if (ret)
			end = 1;

		close_inode_for_write(r);
		ret = finish_subvol(r);
		if (ret < 0)
			goto out;
	}
	ret = 0;

out:
	if (r->write_fd != -1) {
		close(r->write_fd);
		r->write_fd = -1;
	}

	if (r->root_path != realmnt)
		free(r->root_path);
	r->root_path = NULL;
	r->dest_dir_path = NULL;
	free(dest_dir_full_path);
	subvol_uuid_search_finit(&r->sus);
	if (r->mnt_fd != -1) {
		close(r->mnt_fd);
		r->mnt_fd = -1;
	}
	if (r->dest_dir_fd != -1) {
		close(r->dest_dir_fd);
		r->dest_dir_fd = -1;
	}

	return ret;
}
예제 #6
0
static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
		      u64 max_errors)
{
	int ret;
	char *dest_dir_full_path;
	int end = 0;

	dest_dir_full_path = realpath(tomnt, NULL);
	if (!dest_dir_full_path) {
		ret = -errno;
		fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
			strerror(-ret));
		goto out;
	}
	r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
	if (r->dest_dir_fd < 0) {
		ret = -errno;
		fprintf(stderr,
			"ERROR: failed to open destination directory %s. %s\n",
			dest_dir_full_path, strerror(-ret));
		goto out;
	}

	ret = find_mount_root(dest_dir_full_path, &r->root_path);
	if (ret < 0) {
		fprintf(stderr,
			"ERROR: failed to determine mount point for %s: %s\n",
			dest_dir_full_path, strerror(-ret));
		ret = -EINVAL;
		goto out;
	}
	if (ret > 0) {
		fprintf(stderr,
			"ERROR: %s doesn't belong to btrfs mount point\n",
			dest_dir_full_path);
		ret = -EINVAL;
		goto out;
	}
	r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
	if (r->mnt_fd < 0) {
		ret = -errno;
		fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
			strerror(-ret));
		goto out;
	}

	/*
	 * find_mount_root returns a root_path that is a subpath of
	 * dest_dir_full_path. Now get the other part of root_path,
	 * which is the destination dir relative to root_path.
	 */
	r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
	while (r->dest_dir_path[0] == '/')
		r->dest_dir_path++;

	ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
	if (ret < 0)
		goto out;

	while (!end) {
		ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
							 r->honor_end_cmd,
							 max_errors);
		if (ret < 0)
			goto out;
		if (ret)
			end = 1;

		close_inode_for_write(r);
		ret = finish_subvol(r);
		if (ret < 0)
			goto out;
	}
	ret = 0;

out:
	if (r->write_fd != -1) {
		close(r->write_fd);
		r->write_fd = -1;
	}
	free(r->root_path);
	r->root_path = NULL;
	free(r->write_path);
	r->write_path = NULL;
	free(r->full_subvol_path);
	r->full_subvol_path = NULL;
	r->dest_dir_path = NULL;
	free(dest_dir_full_path);
	if (r->cur_subvol) {
		free(r->cur_subvol->path);
		free(r->cur_subvol);
		r->cur_subvol = NULL;
	}
	subvol_uuid_search_finit(&r->sus);
	if (r->mnt_fd != -1) {
		close(r->mnt_fd);
		r->mnt_fd = -1;
	}
	if (r->dest_dir_fd != -1) {
		close(r->dest_dir_fd);
		r->dest_dir_fd = -1;
	}
	return ret;
}
예제 #7
0
static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
			    const u8 *parent_uuid, u64 parent_ctransid,
			    void *user)
{
	int ret;
	struct btrfs_receive *r = user;
	char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
	struct btrfs_ioctl_vol_args_v2 args_v2;
	struct subvol_info *parent_subvol = NULL;

	ret = finish_subvol(r);
	if (ret < 0)
		goto out;

	r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));

	if (strlen(r->dest_dir_path) == 0)
		r->cur_subvol->path = strdup(path);
	else
		r->cur_subvol->path = path_cat(r->dest_dir_path, path);
	free(r->full_subvol_path);
	r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);

	fprintf(stdout, "At snapshot %s\n", path);

	memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
	r->cur_subvol->stransid = ctransid;

	if (g_verbose) {
		uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
		fprintf(stderr, "receiving snapshot %s uuid=%s, "
				"ctransid=%llu ", path, uuid_str,
				r->cur_subvol->stransid);
		uuid_unparse(parent_uuid, uuid_str);
		fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
				uuid_str, parent_ctransid);
	}

	memset(&args_v2, 0, sizeof(args_v2));
	strncpy_null(args_v2.name, path);

	parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
			parent_ctransid, NULL, subvol_search_by_received_uuid);
	if (!parent_subvol) {
		parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
				parent_ctransid, NULL, subvol_search_by_uuid);
	}
	if (!parent_subvol) {
		ret = -ENOENT;
		fprintf(stderr, "ERROR: could not find parent subvolume\n");
		goto out;
	}

	/*if (rs_args.ctransid > rs_args.rtransid) {
		if (!r->force) {
			ret = -EINVAL;
			fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
			goto out;
		} else {
			fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
		}
	}*/

	args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
			O_RDONLY | O_NOATIME);
	if (args_v2.fd < 0) {
		ret = -errno;
		if (errno != ENOENT)
			fprintf(stderr, "ERROR: open %s failed. %s\n",
					parent_subvol->path, strerror(-ret));
		else
			fprintf(stderr,
				"It seems that you have changed your default "
				"subvolume or you specify other subvolume to\n"
				"mount btrfs, try to remount this btrfs filesystem "
				"with fs tree, and run btrfs receive again!\n");
		goto out;
	}

	ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
	close(args_v2.fd);
	if (ret < 0) {
		ret = -errno;
		fprintf(stderr, "ERROR: creating snapshot %s -> %s "
				"failed. %s\n", parent_subvol->path,
				path, strerror(-ret));
		goto out;
	}

out:
	if (parent_subvol) {
		free(parent_subvol->path);
		free(parent_subvol);
	}
	return ret;
}
static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
			    const u8 *parent_uuid, u64 parent_ctransid,
			    void *user)
{
	int ret;
	struct btrfs_receive *r = user;
	char uuid_str[128];
	struct btrfs_ioctl_vol_args_v2 args_v2;

	ret = finish_subvol(r);
	if (ret < 0)
		goto out;

	r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
	r->parent_subvol = NULL;

	r->cur_subvol->path = strdup(path);
	r->full_subvol_path = path_cat(r->root_path, path);

	fprintf(stderr, "At snapshot %s\n", path);

	memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
	r->cur_subvol->stransid = ctransid;

	if (g_verbose) {
		uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
		fprintf(stderr, "receiving snapshot %s uuid=%s, "
				"ctransid=%llu ", path, uuid_str,
				r->cur_subvol->stransid);
		uuid_unparse(parent_uuid, uuid_str);
		fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
				uuid_str, parent_ctransid);
	}

	memset(&args_v2, 0, sizeof(args_v2));
	strcpy(args_v2.name, path);

	r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
			parent_ctransid, NULL, subvol_search_by_received_uuid);
	if (!r->parent_subvol) {
		ret = -ENOENT;
		fprintf(stderr, "ERROR: could not find parent subvolume\n");
		goto out;
	}

	/*if (rs_args.ctransid > rs_args.rtransid) {
		if (!r->force) {
			ret = -EINVAL;
			fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
			goto out;
		} else {
			fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
		}
	}*/

	args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
			O_RDONLY | O_NOATIME);
	if (args_v2.fd < 0) {
		ret = -errno;
		fprintf(stderr, "ERROR: open %s failed. %s\n",
				r->parent_subvol->path, strerror(-ret));
		goto out;
	}

	ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
	close(args_v2.fd);
	if (ret < 0) {
		ret = -errno;
		fprintf(stderr, "ERROR: creating snapshot %s -> %s "
				"failed. %s\n", r->parent_subvol->path,
				path, strerror(-ret));
		goto out;
	}

out:
	return ret;
}