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.
20 #define _POSIX_C_SOURCE 200809
21 #define _XOPEN_SOURCE 700
24 #include "kerncompat.h"
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
41 #include <sys/types.h>
42 #include <sys/xattr.h>
43 #include <uuid/uuid.h>
50 #include "btrfs-list.h"
53 #include "send-stream.h"
54 #include "send-utils.h"
56 static int g_verbose = 0;
67 char *dest_dir_path; /* relative to root_path */
68 char *full_subvol_path;
70 struct subvol_info *cur_subvol;
72 struct subvol_uuid_search sus;
77 static int finish_subvol(struct btrfs_receive *r)
81 struct btrfs_ioctl_received_subvol_args rs_args;
82 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
85 if (r->cur_subvol == NULL)
88 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
89 O_RDONLY | O_NOATIME);
92 fprintf(stderr, "ERROR: open %s failed. %s\n",
93 r->cur_subvol->path, strerror(-ret));
97 memset(&rs_args, 0, sizeof(rs_args));
98 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
99 rs_args.stransid = r->cur_subvol->stransid;
101 if (g_verbose >= 1) {
102 uuid_unparse((u8*)rs_args.uuid, uuid_str);
103 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
104 "stransid=%llu\n", uuid_str, rs_args.stransid);
107 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
110 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
114 r->cur_subvol->rtransid = rs_args.rtransid;
116 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
119 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
124 flags |= BTRFS_SUBVOL_RDONLY;
126 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
129 fprintf(stderr, "ERROR: failed to make subvolume read only. "
130 "%s\n", strerror(-ret));
138 free(r->cur_subvol->path);
140 r->cur_subvol = NULL;
147 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
151 struct btrfs_receive *r = user;
152 struct btrfs_ioctl_vol_args args_v1;
153 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
155 ret = finish_subvol(r);
159 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
161 if (strlen(r->dest_dir_path) == 0)
162 r->cur_subvol->path = strdup(path);
164 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
165 free(r->full_subvol_path);
166 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
168 fprintf(stderr, "At subvol %s\n", path);
170 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
171 r->cur_subvol->stransid = ctransid;
174 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
175 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
177 r->cur_subvol->stransid);
180 memset(&args_v1, 0, sizeof(args_v1));
181 strncpy_null(args_v1.name, path);
182 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
185 fprintf(stderr, "ERROR: creating subvolume %s failed. "
186 "%s\n", path, strerror(-ret));
194 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
195 const u8 *parent_uuid, u64 parent_ctransid,
199 struct btrfs_receive *r = user;
200 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
201 struct btrfs_ioctl_vol_args_v2 args_v2;
202 struct subvol_info *parent_subvol = NULL;
204 ret = finish_subvol(r);
208 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
210 if (strlen(r->dest_dir_path) == 0)
211 r->cur_subvol->path = strdup(path);
213 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
214 free(r->full_subvol_path);
215 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
217 fprintf(stdout, "At snapshot %s\n", path);
219 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
220 r->cur_subvol->stransid = ctransid;
223 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
224 fprintf(stderr, "receiving snapshot %s uuid=%s, "
225 "ctransid=%llu ", path, uuid_str,
226 r->cur_subvol->stransid);
227 uuid_unparse(parent_uuid, uuid_str);
228 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
229 uuid_str, parent_ctransid);
232 memset(&args_v2, 0, sizeof(args_v2));
233 strncpy_null(args_v2.name, path);
235 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
236 parent_ctransid, NULL, subvol_search_by_received_uuid);
237 if (!parent_subvol) {
238 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
239 parent_ctransid, NULL, subvol_search_by_uuid);
241 if (!parent_subvol) {
243 fprintf(stderr, "ERROR: could not find parent subvolume\n");
247 /*if (rs_args.ctransid > rs_args.rtransid) {
250 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
253 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
257 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
258 O_RDONLY | O_NOATIME);
259 if (args_v2.fd < 0) {
262 fprintf(stderr, "ERROR: open %s failed. %s\n",
263 parent_subvol->path, strerror(-ret));
266 "It seems that you have changed your default "
267 "subvolume or you specify other subvolume to\n"
268 "mount btrfs, try to remount this btrfs filesystem "
269 "with fs tree, and run btrfs receive again!\n");
273 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
277 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
278 "failed. %s\n", parent_subvol->path,
279 path, strerror(-ret));
285 free(parent_subvol->path);
291 static int process_mkfile(const char *path, void *user)
294 struct btrfs_receive *r = user;
295 char *full_path = path_cat(r->full_subvol_path, path);
298 fprintf(stderr, "mkfile %s\n", path);
300 ret = creat(full_path, 0600);
303 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
315 static int process_mkdir(const char *path, void *user)
318 struct btrfs_receive *r = user;
319 char *full_path = path_cat(r->full_subvol_path, path);
322 fprintf(stderr, "mkdir %s\n", path);
324 ret = mkdir(full_path, 0700);
327 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
335 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
338 struct btrfs_receive *r = user;
339 char *full_path = path_cat(r->full_subvol_path, path);
342 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
345 ret = mknod(full_path, mode & S_IFMT, dev);
348 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
356 static int process_mkfifo(const char *path, void *user)
359 struct btrfs_receive *r = user;
360 char *full_path = path_cat(r->full_subvol_path, path);
363 fprintf(stderr, "mkfifo %s\n", path);
365 ret = mkfifo(full_path, 0600);
368 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
376 static int process_mksock(const char *path, void *user)
379 struct btrfs_receive *r = user;
380 char *full_path = path_cat(r->full_subvol_path, path);
383 fprintf(stderr, "mksock %s\n", path);
385 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
388 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
396 static int process_symlink(const char *path, const char *lnk, void *user)
399 struct btrfs_receive *r = user;
400 char *full_path = path_cat(r->full_subvol_path, path);
403 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
405 ret = symlink(lnk, full_path);
408 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
409 lnk, strerror(-ret));
416 static int process_rename(const char *from, const char *to, void *user)
419 struct btrfs_receive *r = user;
420 char *full_from = path_cat(r->full_subvol_path, from);
421 char *full_to = path_cat(r->full_subvol_path, to);
424 fprintf(stderr, "rename %s -> %s\n", from, to);
426 ret = rename(full_from, full_to);
429 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
438 static int process_link(const char *path, const char *lnk, void *user)
441 struct btrfs_receive *r = user;
442 char *full_path = path_cat(r->full_subvol_path, path);
443 char *full_link_path = path_cat(r->full_subvol_path, lnk);
446 fprintf(stderr, "link %s -> %s\n", path, lnk);
448 ret = link(full_link_path, full_path);
451 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
452 lnk, strerror(-ret));
456 free(full_link_path);
461 static int process_unlink(const char *path, void *user)
464 struct btrfs_receive *r = user;
465 char *full_path = path_cat(r->full_subvol_path, path);
468 fprintf(stderr, "unlink %s\n", path);
470 ret = unlink(full_path);
473 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
481 static int process_rmdir(const char *path, void *user)
484 struct btrfs_receive *r = user;
485 char *full_path = path_cat(r->full_subvol_path, path);
488 fprintf(stderr, "rmdir %s\n", path);
490 ret = rmdir(full_path);
493 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
502 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
506 if (r->write_fd != -1) {
507 if (strcmp(r->write_path, path) == 0)
513 r->write_fd = open(path, O_RDWR);
514 if (r->write_fd < 0) {
516 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
521 r->write_path = strdup(path);
527 static void close_inode_for_write(struct btrfs_receive *r)
529 if(r->write_fd == -1)
534 r->write_path[0] = 0;
537 static int process_write(const char *path, const void *data, u64 offset,
541 struct btrfs_receive *r = user;
542 char *full_path = path_cat(r->full_subvol_path, path);
546 ret = open_inode_for_write(r, full_path);
551 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
555 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
556 path, strerror(-ret));
567 static int process_clone(const char *path, u64 offset, u64 len,
568 const u8 *clone_uuid, u64 clone_ctransid,
569 const char *clone_path, u64 clone_offset,
573 struct btrfs_receive *r = user;
574 struct btrfs_ioctl_clone_range_args clone_args;
575 struct subvol_info *si = NULL;
576 char *full_path = path_cat(r->full_subvol_path, path);
577 char *subvol_path = NULL;
578 char *full_clone_path = NULL;
581 ret = open_inode_for_write(r, full_path);
585 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
586 subvol_search_by_received_uuid);
588 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
589 BTRFS_UUID_SIZE) == 0) {
590 /* TODO check generation of extent */
591 subvol_path = strdup(r->cur_subvol->path);
594 fprintf(stderr, "ERROR: did not find source subvol.\n");
598 /*if (rs_args.ctransid > rs_args.rtransid) {
601 fprintf(stderr, "ERROR: subvolume %s was "
602 "modified after it was "
604 r->subvol_parent_name);
607 fprintf(stderr, "WARNING: subvolume %s was "
608 "modified after it was "
610 r->subvol_parent_name);
613 subvol_path = strdup(si->path);
616 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
618 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
621 fprintf(stderr, "ERROR: failed to open %s. %s\n",
622 full_clone_path, strerror(-ret));
626 clone_args.src_fd = clone_fd;
627 clone_args.src_offset = clone_offset;
628 clone_args.src_length = len;
629 clone_args.dest_offset = offset;
630 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
633 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
634 path, strerror(-ret));
644 free(full_clone_path);
652 static int process_set_xattr(const char *path, const char *name,
653 const void *data, int len, void *user)
656 struct btrfs_receive *r = user;
657 char *full_path = path_cat(r->full_subvol_path, path);
659 if (g_verbose >= 2) {
660 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
661 "data=%.*s\n", path, name, len,
665 ret = lsetxattr(full_path, name, data, len, 0);
668 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
669 path, name, len, (char*)data, strerror(-ret));
678 static int process_remove_xattr(const char *path, const char *name, void *user)
681 struct btrfs_receive *r = user;
682 char *full_path = path_cat(r->full_subvol_path, path);
684 if (g_verbose >= 2) {
685 fprintf(stderr, "remove_xattr %s - name=%s\n",
689 ret = lremovexattr(full_path, name);
692 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
693 path, name, strerror(-ret));
702 static int process_truncate(const char *path, u64 size, void *user)
705 struct btrfs_receive *r = user;
706 char *full_path = path_cat(r->full_subvol_path, path);
709 fprintf(stderr, "truncate %s size=%llu\n", path, size);
711 ret = truncate(full_path, size);
714 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
715 path, strerror(-ret));
724 static int process_chmod(const char *path, u64 mode, void *user)
727 struct btrfs_receive *r = user;
728 char *full_path = path_cat(r->full_subvol_path, path);
731 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
733 ret = chmod(full_path, mode);
736 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
737 path, strerror(-ret));
746 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
749 struct btrfs_receive *r = user;
750 char *full_path = path_cat(r->full_subvol_path, path);
753 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
756 ret = lchown(full_path, uid, gid);
759 fprintf(stderr, "ERROR: chown %s failed. %s\n",
760 path, strerror(-ret));
769 static int process_utimes(const char *path, struct timespec *at,
770 struct timespec *mt, struct timespec *ct,
774 struct btrfs_receive *r = user;
775 char *full_path = path_cat(r->full_subvol_path, path);
776 struct timespec tv[2];
779 fprintf(stderr, "utimes %s\n", path);
783 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
786 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
787 path, strerror(-ret));
797 static struct btrfs_send_ops send_ops = {
798 .subvol = process_subvol,
799 .snapshot = process_snapshot,
800 .mkfile = process_mkfile,
801 .mkdir = process_mkdir,
802 .mknod = process_mknod,
803 .mkfifo = process_mkfifo,
804 .mksock = process_mksock,
805 .symlink = process_symlink,
806 .rename = process_rename,
807 .link = process_link,
808 .unlink = process_unlink,
809 .rmdir = process_rmdir,
810 .write = process_write,
811 .clone = process_clone,
812 .set_xattr = process_set_xattr,
813 .remove_xattr = process_remove_xattr,
814 .truncate = process_truncate,
815 .chmod = process_chmod,
816 .chown = process_chown,
817 .utimes = process_utimes,
820 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
824 char *dest_dir_full_path;
827 dest_dir_full_path = realpath(tomnt, NULL);
828 if (!dest_dir_full_path) {
830 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
834 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
835 if (r->dest_dir_fd < 0) {
838 "ERROR: failed to open destination directory %s. %s\n",
839 dest_dir_full_path, strerror(-ret));
843 ret = find_mount_root(dest_dir_full_path, &r->root_path);
846 "ERROR: failed to determine mount point for %s: %s\n",
847 dest_dir_full_path, strerror(-ret));
853 "ERROR: %s doesn't belong to btrfs mount point\n",
858 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
861 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
867 * find_mount_root returns a root_path that is a subpath of
868 * dest_dir_full_path. Now get the other part of root_path,
869 * which is the destination dir relative to root_path.
871 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
872 while (r->dest_dir_path[0] == '/')
875 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
880 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
888 close_inode_for_write(r);
889 ret = finish_subvol(r);
896 if (r->write_fd != -1) {
903 r->write_path = NULL;
904 free(r->full_subvol_path);
905 r->full_subvol_path = NULL;
906 r->dest_dir_path = NULL;
907 free(dest_dir_full_path);
909 free(r->cur_subvol->path);
911 r->cur_subvol = NULL;
913 subvol_uuid_search_finit(&r->sus);
914 if (r->mnt_fd != -1) {
918 if (r->dest_dir_fd != -1) {
919 close(r->dest_dir_fd);
925 static const struct option long_opts[] = {
926 { "max-errors", 1, NULL, 'E' },
930 int cmd_receive(int argc, char **argv)
934 char *fromfile = NULL;
935 struct btrfs_receive r;
936 int receive_fd = fileno(stdin);
940 memset(&r, 0, sizeof(r));
945 while ((c = getopt_long(argc, argv, "evf:", long_opts, NULL)) != -1) {
957 max_errors = arg_strtou64(optarg);
961 fprintf(stderr, "ERROR: receive args invalid.\n");
966 if (check_argc_exact(argc - optind, 1))
967 usage(cmd_receive_usage);
969 tomnt = argv[optind];
972 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
973 if (receive_fd < 0) {
974 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
979 ret = do_receive(&r, tomnt, receive_fd, max_errors);
984 const char * const cmd_receive_usage[] = {
985 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
986 "Receive subvolumes from stdin.",
987 "Receives one or more subvolumes that were previously",
988 "sent with btrfs send. The received subvolumes are stored",
990 "btrfs receive will fail in case a receiving subvolume",
991 "already exists. It will also fail in case a previously",
992 "received subvolume was changed after it was received.",
993 "After receiving a subvolume, it is immediately set to",
995 "-v Enable verbose debug output. Each",
996 " occurrence of this option increases the",
997 " verbose level more.",
998 "-f <infile> By default, btrfs receive uses stdin",
999 " to receive the subvolumes. Use this",
1000 " option to specify a file to use instead.",
1001 "-e Terminate after receiving an <end cmd>",
1002 " in the data stream. Without this option,",
1003 " the receiver terminates only if an error",
1004 " is recognized or on EOF.",
1005 "--max-errors <N> Terminate as soon as N errors happened while",
1006 " processing commands from the send stream.",
1007 " Default value is 1. A value of 0 means no limit.",