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;
65 struct subvol_info *cur_subvol;
67 struct subvol_uuid_search sus;
72 static int finish_subvol(struct btrfs_receive *r)
76 struct btrfs_ioctl_received_subvol_args rs_args;
77 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
80 if (r->cur_subvol == NULL)
83 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
84 O_RDONLY | O_NOATIME);
87 fprintf(stderr, "ERROR: open %s failed. %s\n",
88 r->cur_subvol->path, strerror(-ret));
92 memset(&rs_args, 0, sizeof(rs_args));
93 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
94 rs_args.stransid = r->cur_subvol->stransid;
97 uuid_unparse((u8*)rs_args.uuid, uuid_str);
98 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
99 "stransid=%llu\n", uuid_str, rs_args.stransid);
102 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
105 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
109 r->cur_subvol->rtransid = rs_args.rtransid;
111 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
114 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
119 flags |= BTRFS_SUBVOL_RDONLY;
121 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
124 fprintf(stderr, "ERROR: failed to make subvolume read only. "
125 "%s\n", strerror(-ret));
133 free(r->cur_subvol->path);
135 r->cur_subvol = NULL;
142 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
146 struct btrfs_receive *r = user;
147 struct btrfs_ioctl_vol_args args_v1;
148 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
150 ret = finish_subvol(r);
154 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
156 if (strlen(r->dest_dir_path) == 0)
157 r->cur_subvol->path = strdup(path);
159 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
160 free(r->full_subvol_path);
161 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
163 fprintf(stderr, "At subvol %s\n", path);
165 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
166 r->cur_subvol->stransid = ctransid;
169 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
170 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
172 r->cur_subvol->stransid);
175 memset(&args_v1, 0, sizeof(args_v1));
176 strncpy_null(args_v1.name, path);
177 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
180 fprintf(stderr, "ERROR: creating subvolume %s failed. "
181 "%s\n", path, strerror(-ret));
189 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
190 const u8 *parent_uuid, u64 parent_ctransid,
194 struct btrfs_receive *r = user;
195 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
196 struct btrfs_ioctl_vol_args_v2 args_v2;
197 struct subvol_info *parent_subvol = NULL;
199 ret = finish_subvol(r);
203 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
205 if (strlen(r->dest_dir_path) == 0)
206 r->cur_subvol->path = strdup(path);
208 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
209 free(r->full_subvol_path);
210 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
212 fprintf(stdout, "At snapshot %s\n", path);
214 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
215 r->cur_subvol->stransid = ctransid;
218 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
219 fprintf(stderr, "receiving snapshot %s uuid=%s, "
220 "ctransid=%llu ", path, uuid_str,
221 r->cur_subvol->stransid);
222 uuid_unparse(parent_uuid, uuid_str);
223 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
224 uuid_str, parent_ctransid);
227 memset(&args_v2, 0, sizeof(args_v2));
228 strncpy_null(args_v2.name, path);
230 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
231 parent_ctransid, NULL, subvol_search_by_received_uuid);
232 if (!parent_subvol) {
233 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
234 parent_ctransid, NULL, subvol_search_by_uuid);
236 if (!parent_subvol) {
238 fprintf(stderr, "ERROR: could not find parent subvolume\n");
242 /*if (rs_args.ctransid > rs_args.rtransid) {
245 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
248 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
252 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
253 O_RDONLY | O_NOATIME);
254 if (args_v2.fd < 0) {
257 fprintf(stderr, "ERROR: open %s failed. %s\n",
258 parent_subvol->path, strerror(-ret));
261 "It seems that you have changed your default "
262 "subvolume or you specify other subvolume to\n"
263 "mount btrfs, try to remount this btrfs filesystem "
264 "with fs tree, and run btrfs receive again!\n");
268 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
272 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
273 "failed. %s\n", parent_subvol->path,
274 path, strerror(-ret));
280 free(parent_subvol->path);
286 static int process_mkfile(const char *path, void *user)
289 struct btrfs_receive *r = user;
290 char *full_path = path_cat(r->full_subvol_path, path);
293 fprintf(stderr, "mkfile %s\n", path);
295 ret = creat(full_path, 0600);
298 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
310 static int process_mkdir(const char *path, void *user)
313 struct btrfs_receive *r = user;
314 char *full_path = path_cat(r->full_subvol_path, path);
317 fprintf(stderr, "mkdir %s\n", path);
319 ret = mkdir(full_path, 0700);
322 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
330 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
333 struct btrfs_receive *r = user;
334 char *full_path = path_cat(r->full_subvol_path, path);
337 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
340 ret = mknod(full_path, mode & S_IFMT, dev);
343 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
351 static int process_mkfifo(const char *path, void *user)
354 struct btrfs_receive *r = user;
355 char *full_path = path_cat(r->full_subvol_path, path);
358 fprintf(stderr, "mkfifo %s\n", path);
360 ret = mkfifo(full_path, 0600);
363 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
371 static int process_mksock(const char *path, void *user)
374 struct btrfs_receive *r = user;
375 char *full_path = path_cat(r->full_subvol_path, path);
378 fprintf(stderr, "mksock %s\n", path);
380 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
383 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
391 static int process_symlink(const char *path, const char *lnk, void *user)
394 struct btrfs_receive *r = user;
395 char *full_path = path_cat(r->full_subvol_path, path);
398 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
400 ret = symlink(lnk, full_path);
403 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
404 lnk, strerror(-ret));
411 static int process_rename(const char *from, const char *to, void *user)
414 struct btrfs_receive *r = user;
415 char *full_from = path_cat(r->full_subvol_path, from);
416 char *full_to = path_cat(r->full_subvol_path, to);
419 fprintf(stderr, "rename %s -> %s\n", from, to);
421 ret = rename(full_from, full_to);
424 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
433 static int process_link(const char *path, const char *lnk, void *user)
436 struct btrfs_receive *r = user;
437 char *full_path = path_cat(r->full_subvol_path, path);
438 char *full_link_path = path_cat(r->full_subvol_path, lnk);
441 fprintf(stderr, "link %s -> %s\n", path, lnk);
443 ret = link(full_link_path, full_path);
446 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
447 lnk, strerror(-ret));
451 free(full_link_path);
456 static int process_unlink(const char *path, void *user)
459 struct btrfs_receive *r = user;
460 char *full_path = path_cat(r->full_subvol_path, path);
463 fprintf(stderr, "unlink %s\n", path);
465 ret = unlink(full_path);
468 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
476 static int process_rmdir(const char *path, void *user)
479 struct btrfs_receive *r = user;
480 char *full_path = path_cat(r->full_subvol_path, path);
483 fprintf(stderr, "rmdir %s\n", path);
485 ret = rmdir(full_path);
488 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
497 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
501 if (r->write_fd != -1) {
502 if (strcmp(r->write_path, path) == 0)
508 r->write_fd = open(path, O_RDWR);
509 if (r->write_fd < 0) {
511 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
516 r->write_path = strdup(path);
522 static void close_inode_for_write(struct btrfs_receive *r)
524 if(r->write_fd == -1)
529 r->write_path[0] = 0;
532 static int process_write(const char *path, const void *data, u64 offset,
536 struct btrfs_receive *r = user;
537 char *full_path = path_cat(r->full_subvol_path, path);
541 ret = open_inode_for_write(r, full_path);
546 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
550 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
551 path, strerror(-ret));
562 static int process_clone(const char *path, u64 offset, u64 len,
563 const u8 *clone_uuid, u64 clone_ctransid,
564 const char *clone_path, u64 clone_offset,
568 struct btrfs_receive *r = user;
569 struct btrfs_ioctl_clone_range_args clone_args;
570 struct subvol_info *si = NULL;
571 char *full_path = path_cat(r->full_subvol_path, path);
572 char *subvol_path = NULL;
573 char *full_clone_path = NULL;
576 ret = open_inode_for_write(r, full_path);
580 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
581 subvol_search_by_received_uuid);
583 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
584 BTRFS_UUID_SIZE) == 0) {
585 /* TODO check generation of extent */
586 subvol_path = strdup(r->cur_subvol->path);
589 fprintf(stderr, "ERROR: did not find source subvol.\n");
593 /*if (rs_args.ctransid > rs_args.rtransid) {
596 fprintf(stderr, "ERROR: subvolume %s was "
597 "modified after it was "
599 r->subvol_parent_name);
602 fprintf(stderr, "WARNING: subvolume %s was "
603 "modified after it was "
605 r->subvol_parent_name);
608 subvol_path = strdup(si->path);
611 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
613 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
616 fprintf(stderr, "ERROR: failed to open %s. %s\n",
617 full_clone_path, strerror(-ret));
621 clone_args.src_fd = clone_fd;
622 clone_args.src_offset = clone_offset;
623 clone_args.src_length = len;
624 clone_args.dest_offset = offset;
625 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
628 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
629 path, strerror(-ret));
639 free(full_clone_path);
647 static int process_set_xattr(const char *path, const char *name,
648 const void *data, int len, void *user)
651 struct btrfs_receive *r = user;
652 char *full_path = path_cat(r->full_subvol_path, path);
654 if (g_verbose >= 2) {
655 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
656 "data=%.*s\n", path, name, len,
660 ret = lsetxattr(full_path, name, data, len, 0);
663 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
664 path, name, len, (char*)data, strerror(-ret));
673 static int process_remove_xattr(const char *path, const char *name, void *user)
676 struct btrfs_receive *r = user;
677 char *full_path = path_cat(r->full_subvol_path, path);
679 if (g_verbose >= 2) {
680 fprintf(stderr, "remove_xattr %s - name=%s\n",
684 ret = lremovexattr(full_path, name);
687 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
688 path, name, strerror(-ret));
697 static int process_truncate(const char *path, u64 size, void *user)
700 struct btrfs_receive *r = user;
701 char *full_path = path_cat(r->full_subvol_path, path);
704 fprintf(stderr, "truncate %s size=%llu\n", path, size);
706 ret = truncate(full_path, size);
709 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
710 path, strerror(-ret));
719 static int process_chmod(const char *path, u64 mode, void *user)
722 struct btrfs_receive *r = user;
723 char *full_path = path_cat(r->full_subvol_path, path);
726 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
728 ret = chmod(full_path, mode);
731 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
732 path, strerror(-ret));
741 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
744 struct btrfs_receive *r = user;
745 char *full_path = path_cat(r->full_subvol_path, path);
748 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
751 ret = lchown(full_path, uid, gid);
754 fprintf(stderr, "ERROR: chown %s failed. %s\n",
755 path, strerror(-ret));
764 static int process_utimes(const char *path, struct timespec *at,
765 struct timespec *mt, struct timespec *ct,
769 struct btrfs_receive *r = user;
770 char *full_path = path_cat(r->full_subvol_path, path);
771 struct timespec tv[2];
774 fprintf(stderr, "utimes %s\n", path);
778 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
781 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
782 path, strerror(-ret));
792 static struct btrfs_send_ops send_ops = {
793 .subvol = process_subvol,
794 .snapshot = process_snapshot,
795 .mkfile = process_mkfile,
796 .mkdir = process_mkdir,
797 .mknod = process_mknod,
798 .mkfifo = process_mkfifo,
799 .mksock = process_mksock,
800 .symlink = process_symlink,
801 .rename = process_rename,
802 .link = process_link,
803 .unlink = process_unlink,
804 .rmdir = process_rmdir,
805 .write = process_write,
806 .clone = process_clone,
807 .set_xattr = process_set_xattr,
808 .remove_xattr = process_remove_xattr,
809 .truncate = process_truncate,
810 .chmod = process_chmod,
811 .chown = process_chown,
812 .utimes = process_utimes,
815 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
819 char *dest_dir_full_path;
822 dest_dir_full_path = realpath(tomnt, NULL);
823 if (!dest_dir_full_path) {
825 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
829 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
830 if (r->dest_dir_fd < 0) {
833 "ERROR: failed to open destination directory %s. %s\n",
834 dest_dir_full_path, strerror(-ret));
838 ret = find_mount_root(dest_dir_full_path, &r->root_path);
841 "ERROR: failed to determine mount point for %s: %s\n",
842 dest_dir_full_path, strerror(-ret));
848 "ERROR: %s doesn't belong to btrfs mount point\n",
853 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
856 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
862 * find_mount_root returns a root_path that is a subpath of
863 * dest_dir_full_path. Now get the other part of root_path,
864 * which is the destination dir relative to root_path.
866 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
867 while (r->dest_dir_path[0] == '/')
870 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
875 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
883 close_inode_for_write(r);
884 ret = finish_subvol(r);
891 if (r->write_fd != -1) {
898 r->write_path = NULL;
899 free(r->full_subvol_path);
900 r->full_subvol_path = NULL;
901 r->dest_dir_path = NULL;
902 free(dest_dir_full_path);
904 free(r->cur_subvol->path);
906 r->cur_subvol = NULL;
908 subvol_uuid_search_finit(&r->sus);
909 if (r->mnt_fd != -1) {
913 if (r->dest_dir_fd != -1) {
914 close(r->dest_dir_fd);
920 int cmd_receive(int argc, char **argv)
923 char *fromfile = NULL;
924 struct btrfs_receive r;
925 int receive_fd = fileno(stdin);
929 memset(&r, 0, sizeof(r));
936 static const struct option long_opts[] = {
937 { "max-errors", 1, NULL, 'E' },
941 c = getopt_long(argc, argv, "evf:", long_opts, NULL);
956 max_errors = arg_strtou64(optarg);
960 fprintf(stderr, "ERROR: receive args invalid.\n");
965 if (check_argc_exact(argc - optind, 1))
966 usage(cmd_receive_usage);
968 tomnt = argv[optind];
971 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
972 if (receive_fd < 0) {
973 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
978 ret = do_receive(&r, tomnt, receive_fd, max_errors);
983 const char * const cmd_receive_usage[] = {
984 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
985 "Receive subvolumes from stdin.",
986 "Receives one or more subvolumes that were previously",
987 "sent with btrfs send. The received subvolumes are stored",
989 "btrfs receive will fail in case a receiving subvolume",
990 "already exists. It will also fail in case a previously",
991 "received subvolume was changed after it was received.",
992 "After receiving a subvolume, it is immediately set to",
994 "-v Enable verbose debug output. Each",
995 " occurrence of this option increases the",
996 " verbose level more.",
997 "-f <infile> By default, btrfs receive uses stdin",
998 " to receive the subvolumes. Use this",
999 " option to specify a file to use instead.",
1000 "-e Terminate after receiving an <end cmd>",
1001 " in the data stream. Without this option,",
1002 " the receiver terminates only if an error",
1003 " is recognized or on EOF.",
1004 "--max-errors <N> Terminate as soon as N errors happened while",
1005 " processing commands from the send stream.",
1006 " Default value is 1. A value of 0 means no limit.",