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"
20 #include "androidcompat.h"
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <sys/xattr.h>
40 #include <uuid/uuid.h>
47 #include "btrfs-list.h"
50 #include "send-stream.h"
51 #include "send-utils.h"
53 static int g_verbose = 0;
61 char write_path[PATH_MAX];
64 char *dest_dir_path; /* relative to root_path */
65 char full_subvol_path[PATH_MAX];
69 struct subvol_info cur_subvol;
71 * Substitute for cur_subvol::path which is a pointer and we cannot
72 * change it to an array as it's a public API.
74 char cur_subvol_path[PATH_MAX];
76 struct subvol_uuid_search sus;
81 * Buffer to store capabilities from security.capabilities xattr,
82 * usually 20 bytes, but make same room for potentially larger
83 * encodings. Must be set only once per file, denoted by length > 0.
85 char cached_capabilities[64];
86 int cached_capabilities_len;
89 static int finish_subvol(struct btrfs_receive *r)
93 struct btrfs_ioctl_received_subvol_args rs_args;
94 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
97 if (r->cur_subvol_path[0] == 0)
100 subvol_fd = openat(r->mnt_fd, r->cur_subvol_path,
101 O_RDONLY | O_NOATIME);
104 error("cannot open %s: %s\n",
105 r->cur_subvol_path, strerror(-ret));
109 memset(&rs_args, 0, sizeof(rs_args));
110 memcpy(rs_args.uuid, r->cur_subvol.received_uuid, BTRFS_UUID_SIZE);
111 rs_args.stransid = r->cur_subvol.stransid;
113 if (g_verbose >= 1) {
114 uuid_unparse((u8*)rs_args.uuid, uuid_str);
115 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
116 "stransid=%llu\n", uuid_str, rs_args.stransid);
119 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
122 error("ioctl BTRFS_IOC_SET_RECEIVED_SUBVOL failed: %s",
126 r->cur_subvol.rtransid = rs_args.rtransid;
128 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
131 error("ioctl BTRFS_IOC_SUBVOL_GETFLAGS failed: %s",
136 flags |= BTRFS_SUBVOL_RDONLY;
138 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
141 error("failed to make subvolume read only: %s",
149 if (r->cur_subvol_path[0]) {
150 r->cur_subvol_path[0] = 0;
157 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
161 struct btrfs_receive *r = user;
162 struct btrfs_ioctl_vol_args args_v1;
163 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
165 ret = finish_subvol(r);
169 if (r->cur_subvol.path) {
170 error("subvol: another one already started, path ptr: %s",
175 if (r->cur_subvol_path[0]) {
176 error("subvol: another one already started, path buf: %s",
182 if (*r->dest_dir_path == 0) {
183 strncpy_null(r->cur_subvol_path, path);
185 ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
187 error("subvol: path invalid: %s\n", path);
191 ret = path_cat3_out(r->full_subvol_path, r->root_path,
192 r->dest_dir_path, path);
194 error("subvol: path invalid: %s", path);
198 fprintf(stderr, "At subvol %s\n", path);
200 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
201 r->cur_subvol.stransid = ctransid;
204 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
205 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
207 r->cur_subvol.stransid);
210 memset(&args_v1, 0, sizeof(args_v1));
211 strncpy_null(args_v1.name, path);
212 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
215 error("creating subvolume %s failed: %s", path, strerror(-ret));
223 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
224 const u8 *parent_uuid, u64 parent_ctransid,
228 struct btrfs_receive *r = user;
229 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
230 struct btrfs_ioctl_vol_args_v2 args_v2;
231 struct subvol_info *parent_subvol = NULL;
233 ret = finish_subvol(r);
237 if (r->cur_subvol.path) {
238 error("snapshot: another one already started, path ptr: %s",
243 if (r->cur_subvol_path[0]) {
244 error("snapshot: another one already started, path buf: %s",
250 if (*r->dest_dir_path == 0) {
251 strncpy_null(r->cur_subvol_path, path);
253 ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
255 error("snapshot: path invalid: %s", path);
259 ret = path_cat3_out(r->full_subvol_path, r->root_path,
260 r->dest_dir_path, path);
262 error("snapshot: path invalid: %s", path);
266 fprintf(stdout, "At snapshot %s\n", path);
268 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
269 r->cur_subvol.stransid = ctransid;
272 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
273 fprintf(stderr, "receiving snapshot %s uuid=%s, "
274 "ctransid=%llu ", path, uuid_str,
275 r->cur_subvol.stransid);
276 uuid_unparse(parent_uuid, uuid_str);
277 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
278 uuid_str, parent_ctransid);
281 memset(&args_v2, 0, sizeof(args_v2));
282 strncpy_null(args_v2.name, path);
284 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
285 parent_ctransid, NULL, subvol_search_by_received_uuid);
286 if (!parent_subvol) {
287 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
288 parent_ctransid, NULL, subvol_search_by_uuid);
290 if (!parent_subvol) {
292 error("cannot find parent subvolume");
297 * The path is resolved from the root subvol, but we could be in some
298 * subvolume under the root subvolume, so try and adjust the path to be
299 * relative to our root path.
301 if (r->full_root_path) {
305 root_len = strlen(r->full_root_path);
306 sub_len = strlen(parent_subvol->path);
308 /* First make sure the parent subvol is actually in our path */
309 if (sub_len < root_len ||
310 strstr(parent_subvol->path, r->full_root_path) == NULL) {
312 "parent subvol is not reachable from inside the root subvol");
317 if (sub_len == root_len) {
318 parent_subvol->path[0] = '/';
319 parent_subvol->path[1] = '\0';
322 * root path is foo/bar
323 * subvol path is foo/bar/baz
325 * we need to have baz be the path, so we need to move
326 * the bit after foo/bar/, so path + root_len + 1, and
327 * move the part we care about, so sub_len - root_len -
330 memmove(parent_subvol->path,
331 parent_subvol->path + root_len + 1,
332 sub_len - root_len - 1);
333 parent_subvol->path[sub_len - root_len - 1] = '\0';
336 /*if (rs_args.ctransid > rs_args.rtransid) {
339 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
342 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
346 if (*parent_subvol->path == 0)
347 args_v2.fd = dup(r->mnt_fd);
349 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
350 O_RDONLY | O_NOATIME);
351 if (args_v2.fd < 0) {
354 error("cannot open %s: %s",
355 parent_subvol->path, strerror(-ret));
358 "It seems that you have changed your default "
359 "subvolume or you specify other subvolume to\n"
360 "mount btrfs, try to remount this btrfs filesystem "
361 "with fs tree, and run btrfs receive again!\n");
365 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
369 error("creating snapshot %s -> %s failed: %s",
370 parent_subvol->path, path, strerror(-ret));
376 free(parent_subvol->path);
382 static int process_mkfile(const char *path, void *user)
385 struct btrfs_receive *r = user;
386 char full_path[PATH_MAX];
388 ret = path_cat_out(full_path, r->full_subvol_path, path);
390 error("mkfile: path invalid: %s", path);
395 fprintf(stderr, "mkfile %s\n", path);
397 ret = creat(full_path, 0600);
400 error("mkfile %s failed: %s", path, strerror(-ret));
410 static int process_mkdir(const char *path, void *user)
413 struct btrfs_receive *r = user;
414 char full_path[PATH_MAX];
416 ret = path_cat_out(full_path, r->full_subvol_path, path);
418 error("mkdir: path invalid: %s", path);
423 fprintf(stderr, "mkdir %s\n", path);
425 ret = mkdir(full_path, 0700);
428 error("mkdir %s failed: %s", path, strerror(-ret));
435 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
438 struct btrfs_receive *r = user;
439 char full_path[PATH_MAX];
441 ret = path_cat_out(full_path, r->full_subvol_path, path);
443 error("mknod: path invalid: %s", path);
448 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
451 ret = mknod(full_path, mode & S_IFMT, dev);
454 error("mknod %s failed: %s", path, strerror(-ret));
461 static int process_mkfifo(const char *path, void *user)
464 struct btrfs_receive *r = user;
465 char full_path[PATH_MAX];
467 ret = path_cat_out(full_path, r->full_subvol_path, path);
469 error("mkfifo: path invalid: %s", path);
474 fprintf(stderr, "mkfifo %s\n", path);
476 ret = mkfifo(full_path, 0600);
479 error("mkfifo %s failed: %s", path, strerror(-ret));
486 static int process_mksock(const char *path, void *user)
489 struct btrfs_receive *r = user;
490 char full_path[PATH_MAX];
492 ret = path_cat_out(full_path, r->full_subvol_path, path);
494 error("mksock: path invalid: %s", path);
499 fprintf(stderr, "mksock %s\n", path);
501 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
504 error("mknod %s failed: %s", path, strerror(-ret));
511 static int process_symlink(const char *path, const char *lnk, void *user)
514 struct btrfs_receive *r = user;
515 char full_path[PATH_MAX];
517 ret = path_cat_out(full_path, r->full_subvol_path, path);
519 error("symlink: path invalid: %s", path);
524 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
526 ret = symlink(lnk, full_path);
529 error("symlink %s -> %s failed: %s", path,
530 lnk, strerror(-ret));
537 static int process_rename(const char *from, const char *to, void *user)
540 struct btrfs_receive *r = user;
541 char full_from[PATH_MAX];
542 char full_to[PATH_MAX];
544 ret = path_cat_out(full_from, r->full_subvol_path, from);
546 error("rename: source path invalid: %s", from);
550 ret = path_cat_out(full_to, r->full_subvol_path, to);
552 error("rename: target path invalid: %s", to);
557 fprintf(stderr, "rename %s -> %s\n", from, to);
559 ret = rename(full_from, full_to);
562 error("rename %s -> %s failed: %s", from,
570 static int process_link(const char *path, const char *lnk, void *user)
573 struct btrfs_receive *r = user;
574 char full_path[PATH_MAX];
575 char full_link_path[PATH_MAX];
577 ret = path_cat_out(full_path, r->full_subvol_path, path);
579 error("link: source path invalid: %s", full_path);
583 ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
585 error("link: target path invalid: %s", full_link_path);
590 fprintf(stderr, "link %s -> %s\n", path, lnk);
592 ret = link(full_link_path, full_path);
595 error("link %s -> %s failed: %s", path, lnk, strerror(-ret));
603 static int process_unlink(const char *path, void *user)
606 struct btrfs_receive *r = user;
607 char full_path[PATH_MAX];
609 ret = path_cat_out(full_path, r->full_subvol_path, path);
611 error("unlink: path invalid: %s", path);
616 fprintf(stderr, "unlink %s\n", path);
618 ret = unlink(full_path);
621 error("unlink %s failed. %s", path, strerror(-ret));
628 static int process_rmdir(const char *path, void *user)
631 struct btrfs_receive *r = user;
632 char full_path[PATH_MAX];
634 ret = path_cat_out(full_path, r->full_subvol_path, path);
636 error("rmdir: path invalid: %s", path);
641 fprintf(stderr, "rmdir %s\n", path);
643 ret = rmdir(full_path);
646 error("rmdir %s failed: %s", path, strerror(-ret));
653 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
657 if (r->write_fd != -1) {
658 if (strcmp(r->write_path, path) == 0)
664 r->write_fd = open(path, O_RDWR);
665 if (r->write_fd < 0) {
667 error("cannot open %s: %s", path, strerror(-ret));
670 strncpy_null(r->write_path, path);
676 static void close_inode_for_write(struct btrfs_receive *r)
678 if(r->write_fd == -1)
683 r->write_path[0] = 0;
686 static int process_write(const char *path, const void *data, u64 offset,
690 struct btrfs_receive *r = user;
691 char full_path[PATH_MAX];
695 ret = path_cat_out(full_path, r->full_subvol_path, path);
697 error("write: path invalid: %s", path);
701 ret = open_inode_for_write(r, full_path);
706 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
710 error("writing to %s failed: %s\n",
711 path, strerror(-ret));
721 static int process_clone(const char *path, u64 offset, u64 len,
722 const u8 *clone_uuid, u64 clone_ctransid,
723 const char *clone_path, u64 clone_offset,
727 struct btrfs_receive *r = user;
728 struct btrfs_ioctl_clone_range_args clone_args;
729 struct subvol_info *si = NULL;
730 char full_path[PATH_MAX];
731 char *subvol_path = NULL;
732 char full_clone_path[PATH_MAX];
735 ret = path_cat_out(full_path, r->full_subvol_path, path);
737 error("clone: source path invalid: %s", path);
741 ret = open_inode_for_write(r, full_path);
745 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
746 subvol_search_by_received_uuid);
748 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
749 BTRFS_UUID_SIZE) == 0) {
750 /* TODO check generation of extent */
751 subvol_path = strdup(r->cur_subvol_path);
754 error("clone: did not find source subvol");
758 /*if (rs_args.ctransid > rs_args.rtransid) {
761 fprintf(stderr, "ERROR: subvolume %s was "
762 "modified after it was "
764 r->subvol_parent_name);
767 fprintf(stderr, "WARNING: subvolume %s was "
768 "modified after it was "
770 r->subvol_parent_name);
773 subvol_path = strdup(si->path);
776 ret = path_cat_out(full_clone_path, subvol_path, clone_path);
778 error("clone: target path invalid: %s", clone_path);
782 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
785 error("cannot open %s: %s", full_clone_path, strerror(-ret));
789 clone_args.src_fd = clone_fd;
790 clone_args.src_offset = clone_offset;
791 clone_args.src_length = len;
792 clone_args.dest_offset = offset;
793 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
796 error("failed to clone extents to %s\n%s\n",
797 path, strerror(-ret));
813 static int process_set_xattr(const char *path, const char *name,
814 const void *data, int len, void *user)
817 struct btrfs_receive *r = user;
818 char full_path[PATH_MAX];
820 ret = path_cat_out(full_path, r->full_subvol_path, path);
822 error("set_xattr: path invalid: %s", path);
826 if (strcmp("security.capability", name) == 0) {
828 fprintf(stderr, "set_xattr: cache capabilities\n");
829 if (r->cached_capabilities_len)
830 warning("capabilities set multiple times per file: %s",
832 if (len > sizeof(r->cached_capabilities)) {
833 error("capabilities encoded to %d bytes, buffer too small",
838 r->cached_capabilities_len = len;
839 memcpy(r->cached_capabilities, data, len);
842 if (g_verbose >= 2) {
843 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
844 "data=%.*s\n", path, name, len,
848 ret = lsetxattr(full_path, name, data, len, 0);
851 error("lsetxattr %s %s=%.*s failed: %s",
852 path, name, len, (char*)data, strerror(-ret));
860 static int process_remove_xattr(const char *path, const char *name, void *user)
863 struct btrfs_receive *r = user;
864 char full_path[PATH_MAX];
866 ret = path_cat_out(full_path, r->full_subvol_path, path);
868 error("remove_xattr: path invalid: %s", path);
872 if (g_verbose >= 2) {
873 fprintf(stderr, "remove_xattr %s - name=%s\n",
877 ret = lremovexattr(full_path, name);
880 error("lremovexattr %s %s failed: %s",
881 path, name, strerror(-ret));
889 static int process_truncate(const char *path, u64 size, void *user)
892 struct btrfs_receive *r = user;
893 char full_path[PATH_MAX];
895 ret = path_cat_out(full_path, r->full_subvol_path, path);
897 error("truncate: path invalid: %s", path);
902 fprintf(stderr, "truncate %s size=%llu\n", path, size);
904 ret = truncate(full_path, size);
907 error("truncate %s failed: %s", path, strerror(-ret));
915 static int process_chmod(const char *path, u64 mode, void *user)
918 struct btrfs_receive *r = user;
919 char full_path[PATH_MAX];
921 ret = path_cat_out(full_path, r->full_subvol_path, path);
923 error("chmod: path invalid: %s", path);
928 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
930 ret = chmod(full_path, mode);
933 error("chmod %s failed: %s", path, strerror(-ret));
941 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
944 struct btrfs_receive *r = user;
945 char full_path[PATH_MAX];
947 ret = path_cat_out(full_path, r->full_subvol_path, path);
949 error("chown: path invalid: %s", path);
954 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
957 ret = lchown(full_path, uid, gid);
960 error("chown %s failed: %s", path, strerror(-ret));
964 if (r->cached_capabilities_len) {
966 fprintf(stderr, "chown: restore capabilities\n");
967 ret = lsetxattr(full_path, "security.capability",
968 r->cached_capabilities,
969 r->cached_capabilities_len, 0);
970 memset(r->cached_capabilities, 0,
971 sizeof(r->cached_capabilities));
972 r->cached_capabilities_len = 0;
975 error("restoring capabilities %s: %s",
976 path, strerror(-ret));
985 static int process_utimes(const char *path, struct timespec *at,
986 struct timespec *mt, struct timespec *ct,
990 struct btrfs_receive *r = user;
991 char full_path[PATH_MAX];
992 struct timespec tv[2];
994 ret = path_cat_out(full_path, r->full_subvol_path, path);
996 error("utimes: path invalid: %s", path);
1001 fprintf(stderr, "utimes %s\n", path);
1005 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
1008 error("utimes %s failed: %s",
1009 path, strerror(-ret));
1017 static int process_update_extent(const char *path, u64 offset, u64 len,
1021 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
1022 path, (unsigned long long)offset,
1023 (unsigned long long)len);
1026 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1032 static struct btrfs_send_ops send_ops = {
1033 .subvol = process_subvol,
1034 .snapshot = process_snapshot,
1035 .mkfile = process_mkfile,
1036 .mkdir = process_mkdir,
1037 .mknod = process_mknod,
1038 .mkfifo = process_mkfifo,
1039 .mksock = process_mksock,
1040 .symlink = process_symlink,
1041 .rename = process_rename,
1042 .link = process_link,
1043 .unlink = process_unlink,
1044 .rmdir = process_rmdir,
1045 .write = process_write,
1046 .clone = process_clone,
1047 .set_xattr = process_set_xattr,
1048 .remove_xattr = process_remove_xattr,
1049 .truncate = process_truncate,
1050 .chmod = process_chmod,
1051 .chown = process_chown,
1052 .utimes = process_utimes,
1053 .update_extent = process_update_extent,
1056 static int do_receive(struct btrfs_receive *r, const char *tomnt,
1057 char *realmnt, int r_fd, u64 max_errors)
1061 char *dest_dir_full_path;
1062 char root_subvol_path[PATH_MAX];
1065 dest_dir_full_path = realpath(tomnt, NULL);
1066 if (!dest_dir_full_path) {
1068 error("realpath(%s) failed: %s", tomnt, strerror(-ret));
1071 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
1072 if (r->dest_dir_fd < 0) {
1074 error("cannot open destination directory %s: %s",
1075 dest_dir_full_path, strerror(-ret));
1080 r->root_path = realmnt;
1082 ret = find_mount_root(dest_dir_full_path, &r->root_path);
1084 error("failed to determine mount point for %s: %s",
1085 dest_dir_full_path, strerror(-ret));
1090 error("%s doesn't belong to btrfs mount point",
1091 dest_dir_full_path);
1096 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
1097 if (r->mnt_fd < 0) {
1099 error("cannot open %s: %s", r->root_path, strerror(-ret));
1104 * If we use -m or a default subvol we want to resolve the path to the
1105 * subvolume we're sitting in so that we can adjust the paths of any
1106 * subvols we want to receive in.
1108 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
1110 error("cannot resolve our subvolid: %d",
1115 root_subvol_path[0] = 0;
1116 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
1117 PATH_MAX, subvol_id);
1119 error("cannot resolve our subvol path");
1124 * Ok we're inside of a subvol off of the root subvol, we need to
1125 * actually set full_root_path.
1127 if (*root_subvol_path)
1128 r->full_root_path = root_subvol_path;
1130 if (r->dest_dir_chroot) {
1131 if (chroot(dest_dir_full_path)) {
1133 error("failed to chroot to %s: %s",
1134 dest_dir_full_path, strerror(-ret));
1139 error("failed to chdir to / after chroot: %s",
1143 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1144 r->root_path = strdup("/");
1145 r->dest_dir_path = r->root_path;
1148 * find_mount_root returns a root_path that is a subpath of
1149 * dest_dir_full_path. Now get the other part of root_path,
1150 * which is the destination dir relative to root_path.
1152 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1153 while (r->dest_dir_path[0] == '/')
1157 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1162 if (r->cached_capabilities_len) {
1164 fprintf(stderr, "clear cached capabilities\n");
1165 memset(r->cached_capabilities, 0,
1166 sizeof(r->cached_capabilities));
1167 r->cached_capabilities_len = 0;
1170 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1178 close_inode_for_write(r);
1179 ret = finish_subvol(r);
1186 if (r->write_fd != -1) {
1191 if (r->root_path != realmnt)
1193 r->root_path = NULL;
1194 r->dest_dir_path = NULL;
1195 free(dest_dir_full_path);
1196 subvol_uuid_search_finit(&r->sus);
1197 if (r->mnt_fd != -1) {
1201 if (r->dest_dir_fd != -1) {
1202 close(r->dest_dir_fd);
1203 r->dest_dir_fd = -1;
1209 int cmd_receive(int argc, char **argv)
1212 char fromfile[PATH_MAX];
1213 char realmnt[PATH_MAX];
1214 struct btrfs_receive r;
1215 int receive_fd = fileno(stdin);
1219 memset(&r, 0, sizeof(r));
1223 r.dest_dir_chroot = 0;
1229 static const struct option long_opts[] = {
1230 { "max-errors", required_argument, NULL, 'E' },
1231 { "chroot", no_argument, NULL, 'C' },
1232 { NULL, 0, NULL, 0 }
1235 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1244 if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
1245 error("input file path too long (%zu)",
1252 r.honor_end_cmd = 1;
1255 r.dest_dir_chroot = 1;
1258 max_errors = arg_strtou64(optarg);
1261 if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
1262 error("mount point path too long (%zu)",
1270 error("receive args invalid");
1275 if (check_argc_exact(argc - optind, 1))
1276 usage(cmd_receive_usage);
1278 tomnt = argv[optind];
1281 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1282 if (receive_fd < 0) {
1283 error("cannot open %s: %s", fromfile, strerror(errno));
1288 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1289 if (receive_fd != fileno(stdin))
1297 const char * const cmd_receive_usage[] = {
1298 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1299 "Receive subvolumes from stdin.",
1300 "Receives one or more subvolumes that were previously",
1301 "sent with btrfs send. The received subvolumes are stored",
1303 "btrfs receive will fail in case a receiving subvolume",
1304 "already exists. It will also fail in case a previously",
1305 "received subvolume was changed after it was received.",
1306 "After receiving a subvolume, it is immediately set to",
1308 "-v Enable verbose debug output. Each",
1309 " occurrence of this option increases the",
1310 " verbose level more.",
1311 "-f <infile> By default, btrfs receive uses stdin",
1312 " to receive the subvolumes. Use this",
1313 " option to specify a file to use instead.",
1314 "-e Terminate after receiving an <end cmd>",
1315 " in the data stream. Without this option,",
1316 " the receiver terminates only if an error",
1317 " is recognized or on EOF.",
1318 "-C|--chroot confine the process to <mount> using chroot",
1319 "--max-errors <N> Terminate as soon as N errors happened while",
1320 " processing commands from the send stream.",
1321 " Default value is 1. A value of 0 means no limit.",
1322 "-m <mountpoint> The root mount point of the destination fs.",
1323 " If you do not have /proc use this to tell us where ",
1324 " this file system is mounted.",