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"
52 #include "send-dump.h"
54 static int g_verbose
= 0;
62 char write_path
[PATH_MAX
];
65 char *dest_dir_path
; /* relative to root_path */
66 char full_subvol_path
[PATH_MAX
];
70 struct subvol_info cur_subvol
;
72 * Substitute for cur_subvol::path which is a pointer and we cannot
73 * change it to an array as it's a public API.
75 char cur_subvol_path
[PATH_MAX
];
77 struct subvol_uuid_search sus
;
82 * Buffer to store capabilities from security.capabilities xattr,
83 * usually 20 bytes, but make same room for potentially larger
84 * encodings. Must be set only once per file, denoted by length > 0.
86 char cached_capabilities
[64];
87 int cached_capabilities_len
;
90 static int finish_subvol(struct btrfs_receive
*rctx
)
94 struct btrfs_ioctl_received_subvol_args rs_args
;
95 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
98 if (rctx
->cur_subvol_path
[0] == 0)
101 subvol_fd
= openat(rctx
->mnt_fd
, rctx
->cur_subvol_path
,
102 O_RDONLY
| O_NOATIME
);
105 error("cannot open %s: %s",
106 rctx
->cur_subvol_path
, strerror(-ret
));
110 memset(&rs_args
, 0, sizeof(rs_args
));
111 memcpy(rs_args
.uuid
, rctx
->cur_subvol
.received_uuid
, BTRFS_UUID_SIZE
);
112 rs_args
.stransid
= rctx
->cur_subvol
.stransid
;
114 if (g_verbose
>= 1) {
115 uuid_unparse((u8
*)rs_args
.uuid
, uuid_str
);
116 fprintf(stderr
, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
117 "stransid=%llu\n", uuid_str
, rs_args
.stransid
);
120 ret
= ioctl(subvol_fd
, BTRFS_IOC_SET_RECEIVED_SUBVOL
, &rs_args
);
123 error("ioctl BTRFS_IOC_SET_RECEIVED_SUBVOL failed: %s",
127 rctx
->cur_subvol
.rtransid
= rs_args
.rtransid
;
129 ret
= ioctl(subvol_fd
, BTRFS_IOC_SUBVOL_GETFLAGS
, &flags
);
132 error("ioctl BTRFS_IOC_SUBVOL_GETFLAGS failed: %s",
137 flags
|= BTRFS_SUBVOL_RDONLY
;
139 ret
= ioctl(subvol_fd
, BTRFS_IOC_SUBVOL_SETFLAGS
, &flags
);
142 error("failed to make subvolume read only: %s",
150 if (rctx
->cur_subvol_path
[0]) {
151 rctx
->cur_subvol_path
[0] = 0;
158 static int process_subvol(const char *path
, const u8
*uuid
, u64 ctransid
,
162 struct btrfs_receive
*rctx
= user
;
163 struct btrfs_ioctl_vol_args args_v1
;
164 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
166 ret
= finish_subvol(rctx
);
170 if (rctx
->cur_subvol
.path
) {
171 error("subvol: another one already started, path ptr: %s",
172 rctx
->cur_subvol
.path
);
176 if (rctx
->cur_subvol_path
[0]) {
177 error("subvol: another one already started, path buf: %s",
178 rctx
->cur_subvol
.path
);
183 if (*rctx
->dest_dir_path
== 0) {
184 strncpy_null(rctx
->cur_subvol_path
, path
);
186 ret
= path_cat_out(rctx
->cur_subvol_path
, rctx
->dest_dir_path
,
189 error("subvol: path invalid: %s", path
);
193 ret
= path_cat3_out(rctx
->full_subvol_path
, rctx
->root_path
,
194 rctx
->dest_dir_path
, path
);
196 error("subvol: path invalid: %s", path
);
200 fprintf(stderr
, "At subvol %s\n", path
);
202 memcpy(rctx
->cur_subvol
.received_uuid
, uuid
, BTRFS_UUID_SIZE
);
203 rctx
->cur_subvol
.stransid
= ctransid
;
206 uuid_unparse((u8
*)rctx
->cur_subvol
.received_uuid
, uuid_str
);
207 fprintf(stderr
, "receiving subvol %s uuid=%s, stransid=%llu\n",
209 rctx
->cur_subvol
.stransid
);
212 memset(&args_v1
, 0, sizeof(args_v1
));
213 strncpy_null(args_v1
.name
, path
);
214 ret
= ioctl(rctx
->dest_dir_fd
, BTRFS_IOC_SUBVOL_CREATE
, &args_v1
);
217 error("creating subvolume %s failed: %s", path
, strerror(-ret
));
225 static int process_snapshot(const char *path
, const u8
*uuid
, u64 ctransid
,
226 const u8
*parent_uuid
, u64 parent_ctransid
,
230 struct btrfs_receive
*rctx
= user
;
231 char uuid_str
[BTRFS_UUID_UNPARSED_SIZE
];
232 struct btrfs_ioctl_vol_args_v2 args_v2
;
233 struct subvol_info
*parent_subvol
= NULL
;
235 ret
= finish_subvol(rctx
);
239 if (rctx
->cur_subvol
.path
) {
240 error("snapshot: another one already started, path ptr: %s",
241 rctx
->cur_subvol
.path
);
245 if (rctx
->cur_subvol_path
[0]) {
246 error("snapshot: another one already started, path buf: %s",
247 rctx
->cur_subvol
.path
);
252 if (*rctx
->dest_dir_path
== 0) {
253 strncpy_null(rctx
->cur_subvol_path
, path
);
255 ret
= path_cat_out(rctx
->cur_subvol_path
, rctx
->dest_dir_path
,
258 error("snapshot: path invalid: %s", path
);
262 ret
= path_cat3_out(rctx
->full_subvol_path
, rctx
->root_path
,
263 rctx
->dest_dir_path
, path
);
265 error("snapshot: path invalid: %s", path
);
269 fprintf(stdout
, "At snapshot %s\n", path
);
271 memcpy(rctx
->cur_subvol
.received_uuid
, uuid
, BTRFS_UUID_SIZE
);
272 rctx
->cur_subvol
.stransid
= ctransid
;
275 uuid_unparse((u8
*)rctx
->cur_subvol
.received_uuid
, uuid_str
);
276 fprintf(stderr
, "receiving snapshot %s uuid=%s, "
277 "ctransid=%llu ", path
, uuid_str
,
278 rctx
->cur_subvol
.stransid
);
279 uuid_unparse(parent_uuid
, uuid_str
);
280 fprintf(stderr
, "parent_uuid=%s, parent_ctransid=%llu\n",
281 uuid_str
, parent_ctransid
);
284 memset(&args_v2
, 0, sizeof(args_v2
));
285 strncpy_null(args_v2
.name
, path
);
287 parent_subvol
= subvol_uuid_search(&rctx
->sus
, 0, parent_uuid
,
288 parent_ctransid
, NULL
,
289 subvol_search_by_received_uuid
);
290 if (IS_ERR_OR_NULL(parent_subvol
)) {
291 parent_subvol
= subvol_uuid_search(&rctx
->sus
, 0, parent_uuid
,
292 parent_ctransid
, NULL
,
293 subvol_search_by_uuid
);
295 if (IS_ERR_OR_NULL(parent_subvol
)) {
299 ret
= PTR_ERR(parent_subvol
);
300 error("cannot find parent subvolume");
305 * The path is resolved from the root subvol, but we could be in some
306 * subvolume under the root subvolume, so try and adjust the path to be
307 * relative to our root path.
309 if (rctx
->full_root_path
) {
313 root_len
= strlen(rctx
->full_root_path
);
314 sub_len
= strlen(parent_subvol
->path
);
316 /* First make sure the parent subvol is actually in our path */
317 if (sub_len
< root_len
||
318 strstr(parent_subvol
->path
, rctx
->full_root_path
) == NULL
) {
320 "parent subvol is not reachable from inside the root subvol");
325 if (sub_len
== root_len
) {
326 parent_subvol
->path
[0] = '/';
327 parent_subvol
->path
[1] = '\0';
330 * root path is foo/bar
331 * subvol path is foo/bar/baz
333 * we need to have baz be the path, so we need to move
334 * the bit after foo/bar/, so path + root_len + 1, and
335 * move the part we care about, so sub_len - root_len -
338 memmove(parent_subvol
->path
,
339 parent_subvol
->path
+ root_len
+ 1,
340 sub_len
- root_len
- 1);
341 parent_subvol
->path
[sub_len
- root_len
- 1] = '\0';
344 /*if (rs_args.ctransid > rs_args.rtransid) {
347 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
350 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
354 if (*parent_subvol
->path
== 0)
355 args_v2
.fd
= dup(rctx
->mnt_fd
);
357 args_v2
.fd
= openat(rctx
->mnt_fd
, parent_subvol
->path
,
358 O_RDONLY
| O_NOATIME
);
359 if (args_v2
.fd
< 0) {
362 error("cannot open %s: %s",
363 parent_subvol
->path
, strerror(-ret
));
366 "It seems that you have changed your default "
367 "subvolume or you specify other subvolume to\n"
368 "mount btrfs, try to remount this btrfs filesystem "
369 "with fs tree, and run btrfs receive again!\n");
373 ret
= ioctl(rctx
->dest_dir_fd
, BTRFS_IOC_SNAP_CREATE_V2
, &args_v2
);
377 error("creating snapshot %s -> %s failed: %s",
378 parent_subvol
->path
, path
, strerror(-ret
));
384 free(parent_subvol
->path
);
390 static int process_mkfile(const char *path
, void *user
)
393 struct btrfs_receive
*rctx
= user
;
394 char full_path
[PATH_MAX
];
396 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
398 error("mkfile: path invalid: %s", path
);
403 fprintf(stderr
, "mkfile %s\n", path
);
405 ret
= creat(full_path
, 0600);
408 error("mkfile %s failed: %s", path
, strerror(-ret
));
418 static int process_mkdir(const char *path
, void *user
)
421 struct btrfs_receive
*rctx
= user
;
422 char full_path
[PATH_MAX
];
424 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
426 error("mkdir: path invalid: %s", path
);
431 fprintf(stderr
, "mkdir %s\n", path
);
433 ret
= mkdir(full_path
, 0700);
436 error("mkdir %s failed: %s", path
, strerror(-ret
));
443 static int process_mknod(const char *path
, u64 mode
, u64 dev
, void *user
)
446 struct btrfs_receive
*rctx
= user
;
447 char full_path
[PATH_MAX
];
449 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
451 error("mknod: path invalid: %s", path
);
456 fprintf(stderr
, "mknod %s mode=%llu, dev=%llu\n",
459 ret
= mknod(full_path
, mode
& S_IFMT
, dev
);
462 error("mknod %s failed: %s", path
, strerror(-ret
));
469 static int process_mkfifo(const char *path
, void *user
)
472 struct btrfs_receive
*rctx
= user
;
473 char full_path
[PATH_MAX
];
475 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
477 error("mkfifo: path invalid: %s", path
);
482 fprintf(stderr
, "mkfifo %s\n", path
);
484 ret
= mkfifo(full_path
, 0600);
487 error("mkfifo %s failed: %s", path
, strerror(-ret
));
494 static int process_mksock(const char *path
, void *user
)
497 struct btrfs_receive
*rctx
= user
;
498 char full_path
[PATH_MAX
];
500 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
502 error("mksock: path invalid: %s", path
);
507 fprintf(stderr
, "mksock %s\n", path
);
509 ret
= mknod(full_path
, 0600 | S_IFSOCK
, 0);
512 error("mknod %s failed: %s", path
, strerror(-ret
));
519 static int process_symlink(const char *path
, const char *lnk
, void *user
)
522 struct btrfs_receive
*rctx
= user
;
523 char full_path
[PATH_MAX
];
525 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
527 error("symlink: path invalid: %s", path
);
532 fprintf(stderr
, "symlink %s -> %s\n", path
, lnk
);
534 ret
= symlink(lnk
, full_path
);
537 error("symlink %s -> %s failed: %s", path
,
538 lnk
, strerror(-ret
));
545 static int process_rename(const char *from
, const char *to
, void *user
)
548 struct btrfs_receive
*rctx
= user
;
549 char full_from
[PATH_MAX
];
550 char full_to
[PATH_MAX
];
552 ret
= path_cat_out(full_from
, rctx
->full_subvol_path
, from
);
554 error("rename: source path invalid: %s", from
);
558 ret
= path_cat_out(full_to
, rctx
->full_subvol_path
, to
);
560 error("rename: target path invalid: %s", to
);
565 fprintf(stderr
, "rename %s -> %s\n", from
, to
);
567 ret
= rename(full_from
, full_to
);
570 error("rename %s -> %s failed: %s", from
,
578 static int process_link(const char *path
, const char *lnk
, void *user
)
581 struct btrfs_receive
*rctx
= user
;
582 char full_path
[PATH_MAX
];
583 char full_link_path
[PATH_MAX
];
585 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
587 error("link: source path invalid: %s", full_path
);
591 ret
= path_cat_out(full_link_path
, rctx
->full_subvol_path
, lnk
);
593 error("link: target path invalid: %s", full_link_path
);
598 fprintf(stderr
, "link %s -> %s\n", path
, lnk
);
600 ret
= link(full_link_path
, full_path
);
603 error("link %s -> %s failed: %s", path
, lnk
, strerror(-ret
));
611 static int process_unlink(const char *path
, void *user
)
614 struct btrfs_receive
*rctx
= user
;
615 char full_path
[PATH_MAX
];
617 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
619 error("unlink: path invalid: %s", path
);
624 fprintf(stderr
, "unlink %s\n", path
);
626 ret
= unlink(full_path
);
629 error("unlink %s failed. %s", path
, strerror(-ret
));
636 static int process_rmdir(const char *path
, void *user
)
639 struct btrfs_receive
*rctx
= user
;
640 char full_path
[PATH_MAX
];
642 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
644 error("rmdir: path invalid: %s", path
);
649 fprintf(stderr
, "rmdir %s\n", path
);
651 ret
= rmdir(full_path
);
654 error("rmdir %s failed: %s", path
, strerror(-ret
));
661 static int open_inode_for_write(struct btrfs_receive
*rctx
, const char *path
)
665 if (rctx
->write_fd
!= -1) {
666 if (strcmp(rctx
->write_path
, path
) == 0)
668 close(rctx
->write_fd
);
672 rctx
->write_fd
= open(path
, O_RDWR
);
673 if (rctx
->write_fd
< 0) {
675 error("cannot open %s: %s", path
, strerror(-ret
));
678 strncpy_null(rctx
->write_path
, path
);
684 static void close_inode_for_write(struct btrfs_receive
*rctx
)
686 if(rctx
->write_fd
== -1)
689 close(rctx
->write_fd
);
691 rctx
->write_path
[0] = 0;
694 static int process_write(const char *path
, const void *data
, u64 offset
,
698 struct btrfs_receive
*rctx
= user
;
699 char full_path
[PATH_MAX
];
703 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
705 error("write: path invalid: %s", path
);
709 ret
= open_inode_for_write(rctx
, full_path
);
714 w
= pwrite(rctx
->write_fd
, (char*)data
+ pos
, len
- pos
,
718 error("writing to %s failed: %s",
719 path
, strerror(-ret
));
729 static int process_clone(const char *path
, u64 offset
, u64 len
,
730 const u8
*clone_uuid
, u64 clone_ctransid
,
731 const char *clone_path
, u64 clone_offset
,
735 struct btrfs_receive
*rctx
= user
;
736 struct btrfs_ioctl_clone_range_args clone_args
;
737 struct subvol_info
*si
= NULL
;
738 char full_path
[PATH_MAX
];
739 char *subvol_path
= NULL
;
740 char full_clone_path
[PATH_MAX
];
743 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
745 error("clone: source path invalid: %s", path
);
749 ret
= open_inode_for_write(rctx
, full_path
);
753 si
= subvol_uuid_search(&rctx
->sus
, 0, clone_uuid
, clone_ctransid
,
755 subvol_search_by_received_uuid
);
756 if (IS_ERR_OR_NULL(si
)) {
757 if (memcmp(clone_uuid
, rctx
->cur_subvol
.received_uuid
,
758 BTRFS_UUID_SIZE
) == 0) {
759 /* TODO check generation of extent */
760 subvol_path
= strdup(rctx
->cur_subvol_path
);
766 error("clone: did not find source subvol");
770 /*if (rs_args.ctransid > rs_args.rtransid) {
773 fprintf(stderr, "ERROR: subvolume %s was "
774 "modified after it was "
776 r->subvol_parent_name);
779 fprintf(stderr, "WARNING: subvolume %s was "
780 "modified after it was "
782 r->subvol_parent_name);
785 subvol_path
= strdup(si
->path
);
788 ret
= path_cat_out(full_clone_path
, subvol_path
, clone_path
);
790 error("clone: target path invalid: %s", clone_path
);
794 clone_fd
= openat(rctx
->mnt_fd
, full_clone_path
, O_RDONLY
| O_NOATIME
);
797 error("cannot open %s: %s", full_clone_path
, strerror(-ret
));
801 clone_args
.src_fd
= clone_fd
;
802 clone_args
.src_offset
= clone_offset
;
803 clone_args
.src_length
= len
;
804 clone_args
.dest_offset
= offset
;
805 ret
= ioctl(rctx
->write_fd
, BTRFS_IOC_CLONE_RANGE
, &clone_args
);
808 error("failed to clone extents to %s\n%s",
809 path
, strerror(-ret
));
825 static int process_set_xattr(const char *path
, const char *name
,
826 const void *data
, int len
, void *user
)
829 struct btrfs_receive
*rctx
= user
;
830 char full_path
[PATH_MAX
];
832 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
834 error("set_xattr: path invalid: %s", path
);
838 if (strcmp("security.capability", name
) == 0) {
840 fprintf(stderr
, "set_xattr: cache capabilities\n");
841 if (rctx
->cached_capabilities_len
)
842 warning("capabilities set multiple times per file: %s",
844 if (len
> sizeof(rctx
->cached_capabilities
)) {
845 error("capabilities encoded to %d bytes, buffer too small",
850 rctx
->cached_capabilities_len
= len
;
851 memcpy(rctx
->cached_capabilities
, data
, len
);
854 if (g_verbose
>= 2) {
855 fprintf(stderr
, "set_xattr %s - name=%s data_len=%d "
856 "data=%.*s\n", path
, name
, len
,
860 ret
= lsetxattr(full_path
, name
, data
, len
, 0);
863 error("lsetxattr %s %s=%.*s failed: %s",
864 path
, name
, len
, (char*)data
, strerror(-ret
));
872 static int process_remove_xattr(const char *path
, const char *name
, void *user
)
875 struct btrfs_receive
*rctx
= user
;
876 char full_path
[PATH_MAX
];
878 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
880 error("remove_xattr: path invalid: %s", path
);
884 if (g_verbose
>= 2) {
885 fprintf(stderr
, "remove_xattr %s - name=%s\n",
889 ret
= lremovexattr(full_path
, name
);
892 error("lremovexattr %s %s failed: %s",
893 path
, name
, strerror(-ret
));
901 static int process_truncate(const char *path
, u64 size
, void *user
)
904 struct btrfs_receive
*rctx
= user
;
905 char full_path
[PATH_MAX
];
907 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
909 error("truncate: path invalid: %s", path
);
914 fprintf(stderr
, "truncate %s size=%llu\n", path
, size
);
916 ret
= truncate(full_path
, size
);
919 error("truncate %s failed: %s", path
, strerror(-ret
));
927 static int process_chmod(const char *path
, u64 mode
, void *user
)
930 struct btrfs_receive
*rctx
= user
;
931 char full_path
[PATH_MAX
];
933 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
935 error("chmod: path invalid: %s", path
);
940 fprintf(stderr
, "chmod %s - mode=0%o\n", path
, (int)mode
);
942 ret
= chmod(full_path
, mode
);
945 error("chmod %s failed: %s", path
, strerror(-ret
));
953 static int process_chown(const char *path
, u64 uid
, u64 gid
, void *user
)
956 struct btrfs_receive
*rctx
= user
;
957 char full_path
[PATH_MAX
];
959 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
961 error("chown: path invalid: %s", path
);
966 fprintf(stderr
, "chown %s - uid=%llu, gid=%llu\n", path
,
969 ret
= lchown(full_path
, uid
, gid
);
972 error("chown %s failed: %s", path
, strerror(-ret
));
976 if (rctx
->cached_capabilities_len
) {
978 fprintf(stderr
, "chown: restore capabilities\n");
979 ret
= lsetxattr(full_path
, "security.capability",
980 rctx
->cached_capabilities
,
981 rctx
->cached_capabilities_len
, 0);
982 memset(rctx
->cached_capabilities
, 0,
983 sizeof(rctx
->cached_capabilities
));
984 rctx
->cached_capabilities_len
= 0;
987 error("restoring capabilities %s: %s",
988 path
, strerror(-ret
));
997 static int process_utimes(const char *path
, struct timespec
*at
,
998 struct timespec
*mt
, struct timespec
*ct
,
1002 struct btrfs_receive
*rctx
= user
;
1003 char full_path
[PATH_MAX
];
1004 struct timespec tv
[2];
1006 ret
= path_cat_out(full_path
, rctx
->full_subvol_path
, path
);
1008 error("utimes: path invalid: %s", path
);
1013 fprintf(stderr
, "utimes %s\n", path
);
1017 ret
= utimensat(AT_FDCWD
, full_path
, tv
, AT_SYMLINK_NOFOLLOW
);
1020 error("utimes %s failed: %s",
1021 path
, strerror(-ret
));
1029 static int process_update_extent(const char *path
, u64 offset
, u64 len
,
1033 fprintf(stderr
, "update_extent %s: offset=%llu, len=%llu\n",
1034 path
, (unsigned long long)offset
,
1035 (unsigned long long)len
);
1038 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1044 static struct btrfs_send_ops send_ops
= {
1045 .subvol
= process_subvol
,
1046 .snapshot
= process_snapshot
,
1047 .mkfile
= process_mkfile
,
1048 .mkdir
= process_mkdir
,
1049 .mknod
= process_mknod
,
1050 .mkfifo
= process_mkfifo
,
1051 .mksock
= process_mksock
,
1052 .symlink
= process_symlink
,
1053 .rename
= process_rename
,
1054 .link
= process_link
,
1055 .unlink
= process_unlink
,
1056 .rmdir
= process_rmdir
,
1057 .write
= process_write
,
1058 .clone
= process_clone
,
1059 .set_xattr
= process_set_xattr
,
1060 .remove_xattr
= process_remove_xattr
,
1061 .truncate
= process_truncate
,
1062 .chmod
= process_chmod
,
1063 .chown
= process_chown
,
1064 .utimes
= process_utimes
,
1065 .update_extent
= process_update_extent
,
1068 static int do_receive(struct btrfs_receive
*rctx
, const char *tomnt
,
1069 char *realmnt
, int r_fd
, u64 max_errors
)
1073 char *dest_dir_full_path
;
1074 char root_subvol_path
[PATH_MAX
];
1078 dest_dir_full_path
= realpath(tomnt
, NULL
);
1079 if (!dest_dir_full_path
) {
1081 error("realpath(%s) failed: %s", tomnt
, strerror(-ret
));
1084 rctx
->dest_dir_fd
= open(dest_dir_full_path
, O_RDONLY
| O_NOATIME
);
1085 if (rctx
->dest_dir_fd
< 0) {
1087 error("cannot open destination directory %s: %s",
1088 dest_dir_full_path
, strerror(-ret
));
1093 rctx
->root_path
= realmnt
;
1095 ret
= find_mount_root(dest_dir_full_path
, &rctx
->root_path
);
1097 error("failed to determine mount point for %s: %s",
1098 dest_dir_full_path
, strerror(-ret
));
1103 error("%s doesn't belong to btrfs mount point",
1104 dest_dir_full_path
);
1109 rctx
->mnt_fd
= open(rctx
->root_path
, O_RDONLY
| O_NOATIME
);
1110 if (rctx
->mnt_fd
< 0) {
1112 error("cannot open %s: %s", rctx
->root_path
, strerror(-ret
));
1117 * If we use -m or a default subvol we want to resolve the path to the
1118 * subvolume we're sitting in so that we can adjust the paths of any
1119 * subvols we want to receive in.
1121 ret
= btrfs_list_get_path_rootid(rctx
->mnt_fd
, &subvol_id
);
1125 root_subvol_path
[0] = 0;
1126 ret
= btrfs_subvolid_resolve(rctx
->mnt_fd
, root_subvol_path
,
1127 PATH_MAX
, subvol_id
);
1129 error("cannot resolve our subvol path");
1134 * Ok we're inside of a subvol off of the root subvol, we need to
1135 * actually set full_root_path.
1137 if (*root_subvol_path
)
1138 rctx
->full_root_path
= root_subvol_path
;
1140 if (rctx
->dest_dir_chroot
) {
1141 if (chroot(dest_dir_full_path
)) {
1143 error("failed to chroot to %s: %s",
1144 dest_dir_full_path
, strerror(-ret
));
1149 error("failed to chdir to / after chroot: %s",
1153 fprintf(stderr
, "Chroot to %s\n", dest_dir_full_path
);
1154 rctx
->root_path
= strdup("/");
1155 rctx
->dest_dir_path
= rctx
->root_path
;
1158 * find_mount_root returns a root_path that is a subpath of
1159 * dest_dir_full_path. Now get the other part of root_path,
1160 * which is the destination dir relative to root_path.
1162 rctx
->dest_dir_path
= dest_dir_full_path
+ strlen(rctx
->root_path
);
1163 while (rctx
->dest_dir_path
[0] == '/')
1164 rctx
->dest_dir_path
++;
1167 ret
= subvol_uuid_search_init(rctx
->mnt_fd
, &rctx
->sus
);
1173 if (rctx
->cached_capabilities_len
) {
1175 fprintf(stderr
, "clear cached capabilities\n");
1176 memset(rctx
->cached_capabilities
, 0,
1177 sizeof(rctx
->cached_capabilities
));
1178 rctx
->cached_capabilities_len
= 0;
1181 ret
= btrfs_read_and_process_send_stream(r_fd
, &send_ops
,
1183 rctx
->honor_end_cmd
,
1187 /* Empty stream is invalid */
1188 if (ret
&& count
== 0) {
1189 error("empty stream is not considered valid");
1197 close_inode_for_write(rctx
);
1198 ret
= finish_subvol(rctx
);
1205 if (rctx
->write_fd
!= -1) {
1206 close(rctx
->write_fd
);
1207 rctx
->write_fd
= -1;
1210 if (rctx
->root_path
!= realmnt
)
1211 free(rctx
->root_path
);
1212 rctx
->root_path
= NULL
;
1213 rctx
->dest_dir_path
= NULL
;
1214 free(dest_dir_full_path
);
1215 subvol_uuid_search_finit(&rctx
->sus
);
1216 if (rctx
->mnt_fd
!= -1) {
1217 close(rctx
->mnt_fd
);
1220 if (rctx
->dest_dir_fd
!= -1) {
1221 close(rctx
->dest_dir_fd
);
1222 rctx
->dest_dir_fd
= -1;
1228 int cmd_receive(int argc
, char **argv
)
1231 char fromfile
[PATH_MAX
];
1232 char realmnt
[PATH_MAX
];
1233 struct btrfs_receive rctx
;
1234 int receive_fd
= fileno(stdin
);
1239 memset(&rctx
, 0, sizeof(rctx
));
1242 rctx
.dest_dir_fd
= -1;
1243 rctx
.dest_dir_chroot
= 0;
1249 enum { GETOPT_VAL_DUMP
= 257 };
1250 static const struct option long_opts
[] = {
1251 { "max-errors", required_argument
, NULL
, 'E' },
1252 { "chroot", no_argument
, NULL
, 'C' },
1253 { "dump", no_argument
, NULL
, GETOPT_VAL_DUMP
},
1254 { NULL
, 0, NULL
, 0 }
1257 c
= getopt_long(argc
, argv
, "Cevf:m:", long_opts
, NULL
);
1266 if (arg_copy_path(fromfile
, optarg
, sizeof(fromfile
))) {
1267 error("input file path too long (%zu)",
1274 rctx
.honor_end_cmd
= 1;
1277 rctx
.dest_dir_chroot
= 1;
1280 max_errors
= arg_strtou64(optarg
);
1283 if (arg_copy_path(realmnt
, optarg
, sizeof(realmnt
))) {
1284 error("mount point path too long (%zu)",
1290 case GETOPT_VAL_DUMP
:
1295 error("receive args invalid");
1300 if (dump
&& check_argc_exact(argc
- optind
, 0))
1301 usage(cmd_receive_usage
);
1302 if (!dump
&& check_argc_exact(argc
- optind
, 1))
1303 usage(cmd_receive_usage
);
1305 tomnt
= argv
[optind
];
1308 receive_fd
= open(fromfile
, O_RDONLY
| O_NOATIME
);
1309 if (receive_fd
< 0) {
1310 error("cannot open %s: %s", fromfile
, strerror(errno
));
1316 struct btrfs_dump_send_args dump_args
;
1318 dump_args
.root_path
[0] = '.';
1319 dump_args
.root_path
[1] = '\0';
1320 dump_args
.full_subvol_path
[0] = '.';
1321 dump_args
.full_subvol_path
[1] = '\0';
1322 ret
= btrfs_read_and_process_send_stream(receive_fd
,
1323 &btrfs_print_send_ops
, &dump_args
, 0, 0);
1325 error("failed to dump the send stream: %s",
1328 ret
= do_receive(&rctx
, tomnt
, realmnt
, receive_fd
, max_errors
);
1331 if (receive_fd
!= fileno(stdin
))
1338 const char * const cmd_receive_usage
[] = {
1339 "btrfs receive [options] <mount>\n"
1340 "btrfs receive --dump [options]",
1341 "Receive subvolumes from a stream",
1342 "Receives one or more subvolumes that were previously",
1343 "sent with btrfs send. The received subvolumes are stored",
1345 "The receive will fail in case the receiving subvolume",
1346 "already exists. It will also fail in case a previously",
1347 "received subvolume has been changed after it was received.",
1348 "After receiving a subvolume, it is immediately set to",
1351 "-v increase verbosity about performed actions",
1352 "-f FILE read the stream from FILE instead of stdin",
1353 "-e terminate after receiving an <end cmd> marker in the stream.",
1354 " Without this option the receiver side terminates only in case",
1355 " of an error on end of file.",
1356 "-C|--chroot confine the process to <mount> using chroot",
1357 "-E|--max-errors NERR",
1358 " terminate as soon as NERR errors occur while",
1359 " stream processing commands from the stream.",
1360 " Default value is 1. A value of 0 means no limit.",
1361 "-m ROOTMOUNT the root mount point of the destination filesystem.",
1362 " If /proc is not accessible, use this to tell us where",
1363 " this file system is mounted.",
1364 "--dump dump stream metadata, one line per operation,",
1365 " does not require the MOUNT parameter",