X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=cmds-receive.c;h=68123a31cc5cf5afe2eed69f5fad956c2ffb6253;hb=992aa558397e519d2251cdc6c4d3a9e019b240a0;hp=85a6eea5f784f740c81ddb385a2a1589bba75e3c;hpb=b62565093327d1c9a3e4b91b8ff53030638e4080;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/cmds-receive.c b/cmds-receive.c index 85a6eea..68123a3 100644 --- a/cmds-receive.c +++ b/cmds-receive.c @@ -49,6 +49,8 @@ #include "send.h" #include "send-stream.h" #include "send-utils.h" +#include "send-dump.h" +#include "help.h" static int g_verbose = 0; @@ -286,13 +288,16 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid, parent_subvol = subvol_uuid_search(&rctx->sus, 0, parent_uuid, parent_ctransid, NULL, subvol_search_by_received_uuid); - if (!parent_subvol) { + if (IS_ERR_OR_NULL(parent_subvol)) { parent_subvol = subvol_uuid_search(&rctx->sus, 0, parent_uuid, parent_ctransid, NULL, subvol_search_by_uuid); } - if (!parent_subvol) { - ret = -ENOENT; + if (IS_ERR_OR_NULL(parent_subvol)) { + if (!parent_subvol) + ret = -ENOENT; + else + ret = PTR_ERR(parent_subvol); error("cannot find parent subvolume"); goto out; } @@ -310,8 +315,8 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid, 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, rctx->full_root_path) == NULL) { + if (strstr(parent_subvol->path, rctx->full_root_path) != parent_subvol->path || + (sub_len > root_len && parent_subvol->path[root_len] != '/')) { error( "parent subvol is not reachable from inside the root subvol"); ret = -ENOENT; @@ -319,7 +324,7 @@ static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid, } if (sub_len == root_len) { - parent_subvol->path[0] = '/'; + parent_subvol->path[0] = '.'; parent_subvol->path[1] = '\0'; } else { /* @@ -749,13 +754,16 @@ static int process_clone(const char *path, u64 offset, u64 len, si = subvol_uuid_search(&rctx->sus, 0, clone_uuid, clone_ctransid, NULL, subvol_search_by_received_uuid); - if (!si) { + if (IS_ERR_OR_NULL(si)) { if (memcmp(clone_uuid, rctx->cur_subvol.received_uuid, BTRFS_UUID_SIZE) == 0) { /* TODO check generation of extent */ subvol_path = strdup(rctx->cur_subvol_path); } else { - ret = -ENOENT; + if (!si) + ret = -ENOENT; + else + ret = PTR_ERR(si); error("clone: did not find source subvol"); goto out; } @@ -775,7 +783,24 @@ static int process_clone(const char *path, u64 offset, u64 len, r->subvol_parent_name); } }*/ - subvol_path = strdup(si->path); + + /* strip the subvolume that we are receiving to from the start of subvol_path */ + if (rctx->full_root_path) { + size_t root_len = strlen(rctx->full_root_path); + size_t sub_len = strlen(si->path); + + if (sub_len > root_len && + strstr(si->path, rctx->full_root_path) == si->path && + si->path[root_len] == '/') { + subvol_path = strdup(si->path + root_len + 1); + } else { + error("clone: source subvol path %s unreachable from %s", + si->path, rctx->full_root_path); + goto out; + } + } else { + subvol_path = strdup(si->path); + } } ret = path_cat_out(full_clone_path, subvol_path, clone_path); @@ -1066,7 +1091,7 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt, char *dest_dir_full_path; char root_subvol_path[PATH_MAX]; int end = 0; - int count; + int iterations = 0; dest_dir_full_path = realpath(tomnt, NULL); if (!dest_dir_full_path) { @@ -1161,7 +1186,6 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt, if (ret < 0) goto out; - count = 0; while (!end) { if (rctx->cached_capabilities_len) { if (g_verbose >= 3) @@ -1175,22 +1199,28 @@ static int do_receive(struct btrfs_receive *rctx, const char *tomnt, rctx, rctx->honor_end_cmd, max_errors); - if (ret < 0) - goto out; - /* Empty stream is invalid */ - if (ret && count == 0) { - error("empty stream is not considered valid"); - ret = -EINVAL; - goto out; + if (ret < 0) { + if (ret != -ENODATA) + goto out; + + /* Empty stream is invalid */ + if (iterations == 0) { + error("empty stream is not considered valid"); + ret = -EINVAL; + goto out; + } + + ret = 1; } - count++; - if (ret) + if (ret > 0) end = 1; close_inode_for_write(rctx); ret = finish_subvol(rctx); if (ret < 0) goto out; + + iterations++; } ret = 0; @@ -1226,6 +1256,7 @@ int cmd_receive(int argc, char **argv) struct btrfs_receive rctx; int receive_fd = fileno(stdin); u64 max_errors = 1; + int dump = 0; int ret = 0; memset(&rctx, 0, sizeof(rctx)); @@ -1238,13 +1269,15 @@ int cmd_receive(int argc, char **argv) while (1) { int c; + enum { GETOPT_VAL_DUMP = 257 }; static const struct option long_opts[] = { { "max-errors", required_argument, NULL, 'E' }, { "chroot", no_argument, NULL, 'C' }, + { "dump", no_argument, NULL, GETOPT_VAL_DUMP }, { NULL, 0, NULL, 0 } }; - c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL); + c = getopt_long(argc, argv, "Cevf:m:E:", long_opts, NULL); if (c < 0) break; @@ -1277,6 +1310,9 @@ int cmd_receive(int argc, char **argv) goto out; } break; + case GETOPT_VAL_DUMP: + dump = 1; + break; case '?': default: error("receive args invalid"); @@ -1284,7 +1320,9 @@ int cmd_receive(int argc, char **argv) } } - if (check_argc_exact(argc - optind, 1)) + if (dump && check_argc_exact(argc - optind, 0)) + usage(cmd_receive_usage); + if (!dump && check_argc_exact(argc - optind, 1)) usage(cmd_receive_usage); tomnt = argv[optind]; @@ -1292,47 +1330,61 @@ int cmd_receive(int argc, char **argv) if (fromfile[0]) { receive_fd = open(fromfile, O_RDONLY | O_NOATIME); if (receive_fd < 0) { - error("cannot open %s: %s", fromfile, strerror(errno)); + error("cannot open %s: %m", fromfile); goto out; } } - ret = do_receive(&rctx, tomnt, realmnt, receive_fd, max_errors); + if (dump) { + struct btrfs_dump_send_args dump_args; + + dump_args.root_path[0] = '.'; + dump_args.root_path[1] = '\0'; + dump_args.full_subvol_path[0] = '.'; + dump_args.full_subvol_path[1] = '\0'; + ret = btrfs_read_and_process_send_stream(receive_fd, + &btrfs_print_send_ops, &dump_args, 0, 0); + if (ret < 0) + error("failed to dump the send stream: %s", + strerror(-ret)); + } else { + ret = do_receive(&rctx, tomnt, realmnt, receive_fd, max_errors); + } + if (receive_fd != fileno(stdin)) close(receive_fd); - out: return !!ret; } const char * const cmd_receive_usage[] = { - "btrfs receive [-ve] [-f ] [--max-errors ] ", - "Receive subvolumes from stdin.", + "btrfs receive [options] \n" + "btrfs receive --dump [options]", + "Receive subvolumes from a stream", "Receives one or more subvolumes that were previously", "sent with btrfs send. The received subvolumes are stored", - "into .", - "btrfs receive will fail in case a receiving subvolume", + "into MOUNT.", + "The receive will fail in case the receiving subvolume", "already exists. It will also fail in case a previously", - "received subvolume was changed after it was received.", + "received subvolume has been changed after it was received.", "After receiving a subvolume, it is immediately set to", - "read only.\n", - "-v Enable verbose debug output. Each", - " occurrence of this option increases the", - " verbose level more.", - "-f By default, btrfs receive uses stdin", - " to receive the subvolumes. Use this", - " option to specify a file to use instead.", - "-e Terminate after receiving an ", - " in the data stream. Without this option,", - " the receiver terminates only if an error", - " is recognized or on EOF.", + "read-only.", + "", + "-v increase verbosity about performed actions", + "-f FILE read the stream from FILE instead of stdin", + "-e terminate after receiving an marker in the stream.", + " Without this option the receiver side terminates only in case", + " of an error on end of file.", "-C|--chroot confine the process to using chroot", - "--max-errors Terminate as soon as N errors happened while", - " processing commands from the send stream.", + "-E|--max-errors NERR", + " terminate as soon as NERR errors occur while", + " stream processing commands from the stream.", " Default value is 1. A value of 0 means no limit.", - "-m The root mount point of the destination fs.", - " If you do not have /proc use this to tell us where ", + "-m ROOTMOUNT the root mount point of the destination filesystem.", + " If /proc is not accessible, use this to tell us where", " this file system is mounted.", + "--dump dump stream metadata, one line per operation,", + " does not require the MOUNT parameter", NULL };