btrfs-progs: convert: Rework rollback
[platform/upstream/btrfs-progs.git] / cmds-receive.c
index 6f54c2e..6cf2263 100644 (file)
@@ -50,6 +50,7 @@
 #include "send-stream.h"
 #include "send-utils.h"
 #include "send-dump.h"
+#include "help.h"
 
 static int g_verbose = 0;
 
@@ -287,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;
        }
@@ -311,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;
@@ -320,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 {
                        /*
@@ -750,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;
                }
@@ -776,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);