2 * Copyright (C) 2012 Alexander Block. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public
6 * License v2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
19 #include "kerncompat.h"
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
36 #include <sys/types.h>
37 #include <sys/xattr.h>
38 #include <uuid/uuid.h>
45 #include "btrfs-list.h"
48 #include "send-stream.h"
49 #include "send-utils.h"
51 static int g_verbose = 0;
62 char *dest_dir_path; /* relative to root_path */
63 char *full_subvol_path;
67 struct subvol_info cur_subvol;
69 struct subvol_uuid_search sus;
74 * Buffer to store capabilities from security.capabilities xattr,
75 * usually 20 bytes, but make same room for potentially larger
76 * encodings. Must be set only once per file, denoted by length > 0.
78 char cached_capabilities[64];
79 int cached_capabilities_len;
82 static int finish_subvol(struct btrfs_receive *r)
86 struct btrfs_ioctl_received_subvol_args rs_args;
87 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
90 if (r->cur_subvol.path == NULL)
93 subvol_fd = openat(r->mnt_fd, r->cur_subvol.path,
94 O_RDONLY | O_NOATIME);
97 fprintf(stderr, "ERROR: open %s failed. %s\n",
98 r->cur_subvol.path, strerror(-ret));
102 memset(&rs_args, 0, sizeof(rs_args));
103 memcpy(rs_args.uuid, r->cur_subvol.received_uuid, BTRFS_UUID_SIZE);
104 rs_args.stransid = r->cur_subvol.stransid;
106 if (g_verbose >= 1) {
107 uuid_unparse((u8*)rs_args.uuid, uuid_str);
108 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
109 "stransid=%llu\n", uuid_str, rs_args.stransid);
112 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
115 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
119 r->cur_subvol.rtransid = rs_args.rtransid;
121 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
124 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
129 flags |= BTRFS_SUBVOL_RDONLY;
131 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
134 fprintf(stderr, "ERROR: failed to make subvolume read only. "
135 "%s\n", strerror(-ret));
142 if (r->cur_subvol.path) {
143 free(r->cur_subvol.path);
144 r->cur_subvol.path = NULL;
151 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
155 struct btrfs_receive *r = user;
156 struct btrfs_ioctl_vol_args args_v1;
157 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
159 ret = finish_subvol(r);
163 BUG_ON(r->cur_subvol.path);
165 if (strlen(r->dest_dir_path) == 0)
166 r->cur_subvol.path = strdup(path);
168 r->cur_subvol.path = path_cat(r->dest_dir_path, path);
169 free(r->full_subvol_path);
170 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
172 fprintf(stderr, "At subvol %s\n", path);
174 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
175 r->cur_subvol.stransid = ctransid;
178 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
179 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
181 r->cur_subvol.stransid);
184 memset(&args_v1, 0, sizeof(args_v1));
185 strncpy_null(args_v1.name, path);
186 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
189 fprintf(stderr, "ERROR: creating subvolume %s failed. "
190 "%s\n", path, strerror(-ret));
198 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
199 const u8 *parent_uuid, u64 parent_ctransid,
203 struct btrfs_receive *r = user;
204 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
205 struct btrfs_ioctl_vol_args_v2 args_v2;
206 struct subvol_info *parent_subvol = NULL;
208 ret = finish_subvol(r);
212 BUG_ON(r->cur_subvol.path);
214 if (strlen(r->dest_dir_path) == 0)
215 r->cur_subvol.path = strdup(path);
217 r->cur_subvol.path = path_cat(r->dest_dir_path, path);
218 free(r->full_subvol_path);
219 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
221 fprintf(stdout, "At snapshot %s\n", path);
223 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
224 r->cur_subvol.stransid = ctransid;
227 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
228 fprintf(stderr, "receiving snapshot %s uuid=%s, "
229 "ctransid=%llu ", path, uuid_str,
230 r->cur_subvol.stransid);
231 uuid_unparse(parent_uuid, uuid_str);
232 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
233 uuid_str, parent_ctransid);
236 memset(&args_v2, 0, sizeof(args_v2));
237 strncpy_null(args_v2.name, path);
239 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
240 parent_ctransid, NULL, subvol_search_by_received_uuid);
241 if (!parent_subvol) {
242 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
243 parent_ctransid, NULL, subvol_search_by_uuid);
245 if (!parent_subvol) {
247 fprintf(stderr, "ERROR: could not find parent subvolume\n");
252 * The path is resolved from the root subvol, but we could be in some
253 * subvolume under the root subvolume, so try and adjust the path to be
254 * relative to our root path.
256 if (r->full_root_path) {
260 root_len = strlen(r->full_root_path);
261 sub_len = strlen(parent_subvol->path);
263 /* First make sure the parent subvol is actually in our path */
264 if (sub_len < root_len ||
265 strstr(parent_subvol->path, r->full_root_path) == NULL) {
266 fprintf(stderr, "ERROR: parent subvol is not reachable"
267 " from inside the root subvol.\n");
272 if (sub_len == root_len) {
273 parent_subvol->path[0] = '/';
274 parent_subvol->path[1] = '\0';
277 * root path is foo/bar
278 * subvol path is foo/bar/baz
280 * we need to have baz be the path, so we need to move
281 * the bit after foo/bar/, so path + root_len + 1, and
282 * move the part we care about, so sub_len - root_len -
285 memmove(parent_subvol->path,
286 parent_subvol->path + root_len + 1,
287 sub_len - root_len - 1);
288 parent_subvol->path[sub_len - root_len - 1] = '\0';
291 /*if (rs_args.ctransid > rs_args.rtransid) {
294 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
297 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
301 if (strlen(parent_subvol->path) == 0)
302 args_v2.fd = dup(r->mnt_fd);
304 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
305 O_RDONLY | O_NOATIME);
306 if (args_v2.fd < 0) {
309 fprintf(stderr, "ERROR: open %s failed. %s\n",
310 parent_subvol->path, strerror(-ret));
313 "It seems that you have changed your default "
314 "subvolume or you specify other subvolume to\n"
315 "mount btrfs, try to remount this btrfs filesystem "
316 "with fs tree, and run btrfs receive again!\n");
320 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
324 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
325 "failed. %s\n", parent_subvol->path,
326 path, strerror(-ret));
332 free(parent_subvol->path);
338 static int process_mkfile(const char *path, void *user)
341 struct btrfs_receive *r = user;
342 char full_path[PATH_MAX];
344 ret = path_cat_out(full_path, r->full_subvol_path, path);
346 fprintf(stderr, "ERROR: mkfile: path invalid: %s\n", path);
351 fprintf(stderr, "mkfile %s\n", path);
353 ret = creat(full_path, 0600);
356 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
367 static int process_mkdir(const char *path, void *user)
370 struct btrfs_receive *r = user;
371 char full_path[PATH_MAX];
373 ret = path_cat_out(full_path, r->full_subvol_path, path);
375 fprintf(stderr, "ERROR: mkdir: path invalid: %s\n", path);
380 fprintf(stderr, "mkdir %s\n", path);
382 ret = mkdir(full_path, 0700);
385 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
393 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
396 struct btrfs_receive *r = user;
397 char full_path[PATH_MAX];
399 ret = path_cat_out(full_path, r->full_subvol_path, path);
401 fprintf(stderr, "ERROR: mknod: path invalid: %s\n", path);
406 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
409 ret = mknod(full_path, mode & S_IFMT, dev);
412 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
420 static int process_mkfifo(const char *path, void *user)
423 struct btrfs_receive *r = user;
424 char full_path[PATH_MAX];
426 ret = path_cat_out(full_path, r->full_subvol_path, path);
428 fprintf(stderr, "ERROR: mkfifo: path invalid: %s\n", path);
433 fprintf(stderr, "mkfifo %s\n", path);
435 ret = mkfifo(full_path, 0600);
438 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
446 static int process_mksock(const char *path, void *user)
449 struct btrfs_receive *r = user;
450 char full_path[PATH_MAX];
452 ret = path_cat_out(full_path, r->full_subvol_path, path);
454 fprintf(stderr, "ERROR: mksock: path invalid: %s\n", path);
459 fprintf(stderr, "mksock %s\n", path);
461 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
464 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
472 static int process_symlink(const char *path, const char *lnk, void *user)
475 struct btrfs_receive *r = user;
476 char full_path[PATH_MAX];
478 ret = path_cat_out(full_path, r->full_subvol_path, path);
480 fprintf(stderr, "ERROR: symlink: path invalid: %s\n", path);
485 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
487 ret = symlink(lnk, full_path);
490 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
491 lnk, strerror(-ret));
498 static int process_rename(const char *from, const char *to, void *user)
501 struct btrfs_receive *r = user;
502 char full_from[PATH_MAX];
503 char full_to[PATH_MAX];
505 ret = path_cat_out(full_from, r->full_subvol_path, from);
507 fprintf(stderr, "ERROR: rename: source path invalid: %s\n",
512 ret = path_cat_out(full_to, r->full_subvol_path, to);
514 fprintf(stderr, "ERROR: rename: target path invalid: %s\n",
520 fprintf(stderr, "rename %s -> %s\n", from, to);
522 ret = rename(full_from, full_to);
525 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
533 static int process_link(const char *path, const char *lnk, void *user)
536 struct btrfs_receive *r = user;
537 char full_path[PATH_MAX];
538 char full_link_path[PATH_MAX];
540 ret = path_cat_out(full_path, r->full_subvol_path, path);
542 fprintf(stderr, "ERROR: link: source path invalid: %s\n",
547 ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
549 fprintf(stderr, "ERROR: link: target path invalid: %s\n",
555 fprintf(stderr, "link %s -> %s\n", path, lnk);
557 ret = link(full_link_path, full_path);
560 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
561 lnk, strerror(-ret));
569 static int process_unlink(const char *path, void *user)
572 struct btrfs_receive *r = user;
573 char full_path[PATH_MAX];
575 ret = path_cat_out(full_path, r->full_subvol_path, path);
577 fprintf(stderr, "ERROR: unlink: path invalid: %s\n", path);
582 fprintf(stderr, "unlink %s\n", path);
584 ret = unlink(full_path);
587 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
595 static int process_rmdir(const char *path, void *user)
598 struct btrfs_receive *r = user;
599 char full_path[PATH_MAX];
601 ret = path_cat_out(full_path, r->full_subvol_path, path);
603 fprintf(stderr, "ERROR: rmdir: path invalid: %s\n", path);
608 fprintf(stderr, "rmdir %s\n", path);
610 ret = rmdir(full_path);
613 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
621 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
625 if (r->write_fd != -1) {
626 if (strcmp(r->write_path, path) == 0)
632 r->write_fd = open(path, O_RDWR);
633 if (r->write_fd < 0) {
635 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
640 r->write_path = strdup(path);
646 static void close_inode_for_write(struct btrfs_receive *r)
648 if(r->write_fd == -1)
653 r->write_path[0] = 0;
656 static int process_write(const char *path, const void *data, u64 offset,
660 struct btrfs_receive *r = user;
661 char full_path[PATH_MAX];
665 ret = path_cat_out(full_path, r->full_subvol_path, path);
667 fprintf(stderr, "ERROR: write: path invalid: %s\n", path);
671 ret = open_inode_for_write(r, full_path);
676 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
680 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
681 path, strerror(-ret));
691 static int process_clone(const char *path, u64 offset, u64 len,
692 const u8 *clone_uuid, u64 clone_ctransid,
693 const char *clone_path, u64 clone_offset,
697 struct btrfs_receive *r = user;
698 struct btrfs_ioctl_clone_range_args clone_args;
699 struct subvol_info *si = NULL;
700 char full_path[PATH_MAX];
701 char *subvol_path = NULL;
702 char full_clone_path[PATH_MAX];
705 ret = path_cat_out(full_path, r->full_subvol_path, path);
707 fprintf(stderr, "ERROR: clone: source path invalid: %s\n",
712 ret = open_inode_for_write(r, full_path);
716 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
717 subvol_search_by_received_uuid);
719 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
720 BTRFS_UUID_SIZE) == 0) {
721 /* TODO check generation of extent */
722 subvol_path = strdup(r->cur_subvol.path);
725 fprintf(stderr, "ERROR: did not find source subvol.\n");
729 /*if (rs_args.ctransid > rs_args.rtransid) {
732 fprintf(stderr, "ERROR: subvolume %s was "
733 "modified after it was "
735 r->subvol_parent_name);
738 fprintf(stderr, "WARNING: subvolume %s was "
739 "modified after it was "
741 r->subvol_parent_name);
744 subvol_path = strdup(si->path);
747 ret = path_cat_out(full_clone_path, subvol_path, clone_path);
749 fprintf(stderr, "ERROR: clone: target path invalid: %s\n",
754 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
757 fprintf(stderr, "ERROR: failed to open %s. %s\n",
758 full_clone_path, strerror(-ret));
762 clone_args.src_fd = clone_fd;
763 clone_args.src_offset = clone_offset;
764 clone_args.src_length = len;
765 clone_args.dest_offset = offset;
766 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
769 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
770 path, strerror(-ret));
786 static int process_set_xattr(const char *path, const char *name,
787 const void *data, int len, void *user)
790 struct btrfs_receive *r = user;
791 char full_path[PATH_MAX];
793 ret = path_cat_out(full_path, r->full_subvol_path, path);
795 fprintf(stderr, "ERROR: set_xattr: path invalid: %s\n", path);
799 if (strcmp("security.capability", name) == 0) {
801 fprintf(stderr, "set_xattr: cache capabilities\n");
802 if (r->cached_capabilities_len)
804 "WARNING: capabilities set multiple times per file: %s\n",
806 if (len > sizeof(r->cached_capabilities)) {
808 "ERROR: capabilities encoded to %d bytes, buffer too small\n",
813 r->cached_capabilities_len = len;
814 memcpy(r->cached_capabilities, data, len);
817 if (g_verbose >= 2) {
818 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
819 "data=%.*s\n", path, name, len,
823 ret = lsetxattr(full_path, name, data, len, 0);
826 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
827 path, name, len, (char*)data, strerror(-ret));
835 static int process_remove_xattr(const char *path, const char *name, void *user)
838 struct btrfs_receive *r = user;
839 char full_path[PATH_MAX];
841 ret = path_cat_out(full_path, r->full_subvol_path, path);
843 fprintf(stderr, "ERROR: remove_xattr: path invalid: %s\n",
848 if (g_verbose >= 2) {
849 fprintf(stderr, "remove_xattr %s - name=%s\n",
853 ret = lremovexattr(full_path, name);
856 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
857 path, name, strerror(-ret));
865 static int process_truncate(const char *path, u64 size, void *user)
868 struct btrfs_receive *r = user;
869 char full_path[PATH_MAX];
871 ret = path_cat_out(full_path, r->full_subvol_path, path);
873 fprintf(stderr, "ERROR: truncate: path invalid: %s\n", path);
878 fprintf(stderr, "truncate %s size=%llu\n", path, size);
880 ret = truncate(full_path, size);
883 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
884 path, strerror(-ret));
892 static int process_chmod(const char *path, u64 mode, void *user)
895 struct btrfs_receive *r = user;
896 char full_path[PATH_MAX];
898 ret = path_cat_out(full_path, r->full_subvol_path, path);
900 fprintf(stderr, "ERROR: chmod: path invalid: %s\n", path);
905 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
907 ret = chmod(full_path, mode);
910 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
911 path, strerror(-ret));
919 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
922 struct btrfs_receive *r = user;
923 char full_path[PATH_MAX];
925 ret = path_cat_out(full_path, r->full_subvol_path, path);
927 fprintf(stderr, "ERROR: chown: path invalid: %s\n", path);
932 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
935 ret = lchown(full_path, uid, gid);
938 fprintf(stderr, "ERROR: chown %s failed. %s\n",
939 path, strerror(-ret));
943 if (r->cached_capabilities_len) {
945 fprintf(stderr, "chown: restore capabilities\n");
946 ret = lsetxattr(full_path, "security.capability",
947 r->cached_capabilities,
948 r->cached_capabilities_len, 0);
949 memset(r->cached_capabilities, 0,
950 sizeof(r->cached_capabilities));
951 r->cached_capabilities_len = 0;
954 fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
955 path, strerror(-ret));
964 static int process_utimes(const char *path, struct timespec *at,
965 struct timespec *mt, struct timespec *ct,
969 struct btrfs_receive *r = user;
970 char full_path[PATH_MAX];
971 struct timespec tv[2];
973 ret = path_cat_out(full_path, r->full_subvol_path, path);
975 fprintf(stderr, "ERROR: utimes: path invalid: %s\n", path);
980 fprintf(stderr, "utimes %s\n", path);
984 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
987 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
988 path, strerror(-ret));
996 static int process_update_extent(const char *path, u64 offset, u64 len,
1000 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
1001 path, (unsigned long long)offset,
1002 (unsigned long long)len);
1005 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1011 static struct btrfs_send_ops send_ops = {
1012 .subvol = process_subvol,
1013 .snapshot = process_snapshot,
1014 .mkfile = process_mkfile,
1015 .mkdir = process_mkdir,
1016 .mknod = process_mknod,
1017 .mkfifo = process_mkfifo,
1018 .mksock = process_mksock,
1019 .symlink = process_symlink,
1020 .rename = process_rename,
1021 .link = process_link,
1022 .unlink = process_unlink,
1023 .rmdir = process_rmdir,
1024 .write = process_write,
1025 .clone = process_clone,
1026 .set_xattr = process_set_xattr,
1027 .remove_xattr = process_remove_xattr,
1028 .truncate = process_truncate,
1029 .chmod = process_chmod,
1030 .chown = process_chown,
1031 .utimes = process_utimes,
1032 .update_extent = process_update_extent,
1035 static int do_receive(struct btrfs_receive *r, const char *tomnt,
1036 char *realmnt, int r_fd, u64 max_errors)
1040 char *dest_dir_full_path;
1041 char *root_subvol_path;
1044 dest_dir_full_path = realpath(tomnt, NULL);
1045 if (!dest_dir_full_path) {
1047 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
1051 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
1052 if (r->dest_dir_fd < 0) {
1055 "ERROR: failed to open destination directory %s. %s\n",
1056 dest_dir_full_path, strerror(-ret));
1061 r->root_path = realmnt;
1063 ret = find_mount_root(dest_dir_full_path, &r->root_path);
1066 "ERROR: failed to determine mount point for %s: %s\n",
1067 dest_dir_full_path, strerror(-ret));
1073 "ERROR: %s doesn't belong to btrfs mount point\n",
1074 dest_dir_full_path);
1079 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
1080 if (r->mnt_fd < 0) {
1082 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
1088 * If we use -m or a default subvol we want to resolve the path to the
1089 * subvolume we're sitting in so that we can adjust the paths of any
1090 * subvols we want to receive in.
1092 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
1094 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
1099 root_subvol_path = malloc(PATH_MAX);
1100 if (!root_subvol_path) {
1102 fprintf(stderr, "ERROR: couldn't allocate buffer for the root "
1107 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
1108 PATH_MAX, subvol_id);
1110 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
1115 * Ok we're inside of a subvol off of the root subvol, we need to
1116 * actually set full_root_path.
1118 if (strlen(root_subvol_path))
1119 r->full_root_path = root_subvol_path;
1121 free(root_subvol_path);
1123 if (r->dest_dir_chroot) {
1124 if (chroot(dest_dir_full_path)) {
1127 "ERROR: failed to chroot to %s, %s\n",
1135 "ERROR: failed to chdir to /, %s\n",
1139 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1140 r->root_path = strdup("/");
1141 r->dest_dir_path = r->root_path;
1144 * find_mount_root returns a root_path that is a subpath of
1145 * dest_dir_full_path. Now get the other part of root_path,
1146 * which is the destination dir relative to root_path.
1148 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1149 while (r->dest_dir_path[0] == '/')
1153 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1158 if (r->cached_capabilities_len) {
1160 fprintf(stderr, "clear cached capabilities\n");
1161 memset(r->cached_capabilities, 0,
1162 sizeof(r->cached_capabilities));
1163 r->cached_capabilities_len = 0;
1166 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1174 close_inode_for_write(r);
1175 ret = finish_subvol(r);
1182 if (r->write_fd != -1) {
1187 r->root_path = NULL;
1188 free(r->write_path);
1189 r->write_path = NULL;
1190 free(r->full_subvol_path);
1191 r->full_subvol_path = NULL;
1192 r->dest_dir_path = NULL;
1193 free(dest_dir_full_path);
1194 if (r->cur_subvol.path) {
1195 free(r->cur_subvol.path);
1196 r->cur_subvol.path = NULL;
1198 subvol_uuid_search_finit(&r->sus);
1199 if (r->mnt_fd != -1) {
1203 if (r->dest_dir_fd != -1) {
1204 close(r->dest_dir_fd);
1205 r->dest_dir_fd = -1;
1207 if (r->full_root_path) {
1208 free(r->full_root_path);
1209 r->full_root_path = NULL;
1214 int cmd_receive(int argc, char **argv)
1217 char fromfile[PATH_MAX];
1218 char realmnt[PATH_MAX];
1219 struct btrfs_receive r;
1220 int receive_fd = fileno(stdin);
1224 memset(&r, 0, sizeof(r));
1228 r.dest_dir_chroot = 0;
1234 static const struct option long_opts[] = {
1235 { "max-errors", required_argument, NULL, 'E' },
1236 { "chroot", no_argument, NULL, 'C' },
1237 { NULL, 0, NULL, 0 }
1240 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1249 if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
1251 "ERROR: input file path too long (%zu)\n",
1258 r.honor_end_cmd = 1;
1261 r.dest_dir_chroot = 1;
1264 max_errors = arg_strtou64(optarg);
1267 if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
1269 "ERROR: mount point path too long (%zu)\n",
1277 fprintf(stderr, "ERROR: receive args invalid.\n");
1282 if (check_argc_exact(argc - optind, 1))
1283 usage(cmd_receive_usage);
1285 tomnt = argv[optind];
1288 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1289 if (receive_fd < 0) {
1290 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1295 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1302 const char * const cmd_receive_usage[] = {
1303 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1304 "Receive subvolumes from stdin.",
1305 "Receives one or more subvolumes that were previously",
1306 "sent with btrfs send. The received subvolumes are stored",
1308 "btrfs receive will fail in case a receiving subvolume",
1309 "already exists. It will also fail in case a previously",
1310 "received subvolume was changed after it was received.",
1311 "After receiving a subvolume, it is immediately set to",
1313 "-v Enable verbose debug output. Each",
1314 " occurrence of this option increases the",
1315 " verbose level more.",
1316 "-f <infile> By default, btrfs receive uses stdin",
1317 " to receive the subvolumes. Use this",
1318 " option to specify a file to use instead.",
1319 "-e Terminate after receiving an <end cmd>",
1320 " in the data stream. Without this option,",
1321 " the receiver terminates only if an error",
1322 " is recognized or on EOF.",
1323 "-C|--chroot confine the process to <mount> using chroot",
1324 "--max-errors <N> Terminate as soon as N errors happened while",
1325 " processing commands from the send stream.",
1326 " Default value is 1. A value of 0 means no limit.",
1327 "-m <mountpoint> The root mount point of the destination fs.",
1328 " If you do not have /proc use this to tell us where ",
1329 " this file system is mounted.",