static int init_root_path(struct btrfs_send *s, const char *subvol) { int ret = 0; if (s->root_path) goto out; ret = find_mount_root(subvol, &s->root_path); if (ret < 0) { ret = -EINVAL; fprintf(stderr, "ERROR: failed to determine mount point " "for %s\n", subvol); goto out; } s->mnt_fd = open(s->root_path, O_RDONLY | O_NOATIME); if (s->mnt_fd < 0) { ret = -errno; fprintf(stderr, "ERROR: can't open '%s': %s\n", s->root_path, strerror(-ret)); goto out; } ret = subvol_uuid_search_init(s->mnt_fd, &s->sus); if (ret < 0) { fprintf(stderr, "ERROR: failed to initialize subvol search. " "%s\n", 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 init_root_path(struct btrfs_send *sctx, const char *subvol) { int ret = 0; if (sctx->root_path) goto out; ret = find_mount_root(subvol, &sctx->root_path); if (ret < 0) { error("failed to determine mount point for %s: %s", subvol, strerror(-ret)); ret = -EINVAL; goto out; } if (ret > 0) { error("%s doesn't belong to btrfs mount point", subvol); ret = -EINVAL; goto out; } sctx->mnt_fd = open(sctx->root_path, O_RDONLY | O_NOATIME); if (sctx->mnt_fd < 0) { ret = -errno; error("cannot open '%s': %s", sctx->root_path, strerror(-ret)); goto out; } ret = subvol_uuid_search_init(sctx->mnt_fd, &sctx->sus); if (ret < 0) { error("failed to initialize subvol search: %s", strerror(-ret)); goto out; } out: 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; }
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; }