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"
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
40 #include <sys/types.h>
41 #include <sys/xattr.h>
42 #include <uuid/uuid.h>
49 #include "btrfs-list.h"
52 #include "send-stream.h"
53 #include "send-utils.h"
55 static int g_verbose = 0;
66 char *dest_dir_path; /* relative to root_path */
67 char *full_subvol_path;
69 struct subvol_info *cur_subvol;
71 struct subvol_uuid_search sus;
76 static int finish_subvol(struct btrfs_receive *r)
80 struct btrfs_ioctl_received_subvol_args rs_args;
81 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
84 if (r->cur_subvol == NULL)
87 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
88 O_RDONLY | O_NOATIME);
91 fprintf(stderr, "ERROR: open %s failed. %s\n",
92 r->cur_subvol->path, strerror(-ret));
96 memset(&rs_args, 0, sizeof(rs_args));
97 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
98 rs_args.stransid = r->cur_subvol->stransid;
100 if (g_verbose >= 1) {
101 uuid_unparse((u8*)rs_args.uuid, uuid_str);
102 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
103 "stransid=%llu\n", uuid_str, rs_args.stransid);
106 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
109 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
113 r->cur_subvol->rtransid = rs_args.rtransid;
115 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
118 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
123 flags |= BTRFS_SUBVOL_RDONLY;
125 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
128 fprintf(stderr, "ERROR: failed to make subvolume read only. "
129 "%s\n", strerror(-ret));
137 free(r->cur_subvol->path);
139 r->cur_subvol = NULL;
146 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
150 struct btrfs_receive *r = user;
151 struct btrfs_ioctl_vol_args args_v1;
152 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
154 ret = finish_subvol(r);
158 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
160 if (strlen(r->dest_dir_path) == 0)
161 r->cur_subvol->path = strdup(path);
163 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
164 free(r->full_subvol_path);
165 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
167 fprintf(stderr, "At subvol %s\n", path);
169 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
170 r->cur_subvol->stransid = ctransid;
173 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
174 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
176 r->cur_subvol->stransid);
179 memset(&args_v1, 0, sizeof(args_v1));
180 strncpy_null(args_v1.name, path);
181 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
184 fprintf(stderr, "ERROR: creating subvolume %s failed. "
185 "%s\n", path, strerror(-ret));
193 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
194 const u8 *parent_uuid, u64 parent_ctransid,
198 struct btrfs_receive *r = user;
199 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
200 struct btrfs_ioctl_vol_args_v2 args_v2;
201 struct subvol_info *parent_subvol = NULL;
203 ret = finish_subvol(r);
207 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
209 if (strlen(r->dest_dir_path) == 0)
210 r->cur_subvol->path = strdup(path);
212 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
213 free(r->full_subvol_path);
214 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
216 fprintf(stdout, "At snapshot %s\n", path);
218 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
219 r->cur_subvol->stransid = ctransid;
222 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
223 fprintf(stderr, "receiving snapshot %s uuid=%s, "
224 "ctransid=%llu ", path, uuid_str,
225 r->cur_subvol->stransid);
226 uuid_unparse(parent_uuid, uuid_str);
227 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
228 uuid_str, parent_ctransid);
231 memset(&args_v2, 0, sizeof(args_v2));
232 strncpy_null(args_v2.name, path);
234 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
235 parent_ctransid, NULL, subvol_search_by_received_uuid);
236 if (!parent_subvol) {
237 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
238 parent_ctransid, NULL, subvol_search_by_uuid);
240 if (!parent_subvol) {
242 fprintf(stderr, "ERROR: could not find parent subvolume\n");
246 /*if (rs_args.ctransid > rs_args.rtransid) {
249 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
252 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
256 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
257 O_RDONLY | O_NOATIME);
258 if (args_v2.fd < 0) {
261 fprintf(stderr, "ERROR: open %s failed. %s\n",
262 parent_subvol->path, strerror(-ret));
265 "It seems that you have changed your default "
266 "subvolume or you specify other subvolume to\n"
267 "mount btrfs, try to remount this btrfs filesystem "
268 "with fs tree, and run btrfs receive again!\n");
272 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
276 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
277 "failed. %s\n", parent_subvol->path,
278 path, strerror(-ret));
284 free(parent_subvol->path);
290 static int process_mkfile(const char *path, void *user)
293 struct btrfs_receive *r = user;
294 char *full_path = path_cat(r->full_subvol_path, path);
297 fprintf(stderr, "mkfile %s\n", path);
299 ret = creat(full_path, 0600);
302 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
314 static int process_mkdir(const char *path, void *user)
317 struct btrfs_receive *r = user;
318 char *full_path = path_cat(r->full_subvol_path, path);
321 fprintf(stderr, "mkdir %s\n", path);
323 ret = mkdir(full_path, 0700);
326 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
334 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
337 struct btrfs_receive *r = user;
338 char *full_path = path_cat(r->full_subvol_path, path);
341 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
344 ret = mknod(full_path, mode & S_IFMT, dev);
347 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
355 static int process_mkfifo(const char *path, void *user)
358 struct btrfs_receive *r = user;
359 char *full_path = path_cat(r->full_subvol_path, path);
362 fprintf(stderr, "mkfifo %s\n", path);
364 ret = mkfifo(full_path, 0600);
367 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
375 static int process_mksock(const char *path, void *user)
378 struct btrfs_receive *r = user;
379 char *full_path = path_cat(r->full_subvol_path, path);
382 fprintf(stderr, "mksock %s\n", path);
384 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
387 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
395 static int process_symlink(const char *path, const char *lnk, void *user)
398 struct btrfs_receive *r = user;
399 char *full_path = path_cat(r->full_subvol_path, path);
402 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
404 ret = symlink(lnk, full_path);
407 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
408 lnk, strerror(-ret));
415 static int process_rename(const char *from, const char *to, void *user)
418 struct btrfs_receive *r = user;
419 char *full_from = path_cat(r->full_subvol_path, from);
420 char *full_to = path_cat(r->full_subvol_path, to);
423 fprintf(stderr, "rename %s -> %s\n", from, to);
425 ret = rename(full_from, full_to);
428 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
437 static int process_link(const char *path, const char *lnk, void *user)
440 struct btrfs_receive *r = user;
441 char *full_path = path_cat(r->full_subvol_path, path);
442 char *full_link_path = path_cat(r->full_subvol_path, lnk);
445 fprintf(stderr, "link %s -> %s\n", path, lnk);
447 ret = link(full_link_path, full_path);
450 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
451 lnk, strerror(-ret));
455 free(full_link_path);
460 static int process_unlink(const char *path, void *user)
463 struct btrfs_receive *r = user;
464 char *full_path = path_cat(r->full_subvol_path, path);
467 fprintf(stderr, "unlink %s\n", path);
469 ret = unlink(full_path);
472 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
480 static int process_rmdir(const char *path, void *user)
483 struct btrfs_receive *r = user;
484 char *full_path = path_cat(r->full_subvol_path, path);
487 fprintf(stderr, "rmdir %s\n", path);
489 ret = rmdir(full_path);
492 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
501 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
505 if (r->write_fd != -1) {
506 if (strcmp(r->write_path, path) == 0)
512 r->write_fd = open(path, O_RDWR);
513 if (r->write_fd < 0) {
515 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
520 r->write_path = strdup(path);
526 static int close_inode_for_write(struct btrfs_receive *r)
530 if(r->write_fd == -1)
535 r->write_path[0] = 0;
541 static int process_write(const char *path, const void *data, u64 offset,
545 struct btrfs_receive *r = user;
546 char *full_path = path_cat(r->full_subvol_path, path);
550 ret = open_inode_for_write(r, full_path);
555 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
559 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
560 path, strerror(-ret));
571 static int process_clone(const char *path, u64 offset, u64 len,
572 const u8 *clone_uuid, u64 clone_ctransid,
573 const char *clone_path, u64 clone_offset,
577 struct btrfs_receive *r = user;
578 struct btrfs_ioctl_clone_range_args clone_args;
579 struct subvol_info *si = NULL;
580 char *full_path = path_cat(r->full_subvol_path, path);
581 char *subvol_path = NULL;
582 char *full_clone_path = NULL;
585 ret = open_inode_for_write(r, full_path);
589 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
590 subvol_search_by_received_uuid);
592 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
593 BTRFS_UUID_SIZE) == 0) {
594 /* TODO check generation of extent */
595 subvol_path = strdup(r->cur_subvol->path);
598 fprintf(stderr, "ERROR: did not find source subvol.\n");
602 /*if (rs_args.ctransid > rs_args.rtransid) {
605 fprintf(stderr, "ERROR: subvolume %s was "
606 "modified after it was "
608 r->subvol_parent_name);
611 fprintf(stderr, "WARNING: subvolume %s was "
612 "modified after it was "
614 r->subvol_parent_name);
617 subvol_path = strdup(si->path);
620 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
622 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
625 fprintf(stderr, "ERROR: failed to open %s. %s\n",
626 full_clone_path, strerror(-ret));
630 clone_args.src_fd = clone_fd;
631 clone_args.src_offset = clone_offset;
632 clone_args.src_length = len;
633 clone_args.dest_offset = offset;
634 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
637 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
638 path, strerror(-ret));
648 free(full_clone_path);
656 static int process_set_xattr(const char *path, const char *name,
657 const void *data, int len, void *user)
660 struct btrfs_receive *r = user;
661 char *full_path = path_cat(r->full_subvol_path, path);
663 if (g_verbose >= 2) {
664 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
665 "data=%.*s\n", path, name, len,
669 ret = lsetxattr(full_path, name, data, len, 0);
672 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
673 path, name, len, (char*)data, strerror(-ret));
682 static int process_remove_xattr(const char *path, const char *name, void *user)
685 struct btrfs_receive *r = user;
686 char *full_path = path_cat(r->full_subvol_path, path);
688 if (g_verbose >= 2) {
689 fprintf(stderr, "remove_xattr %s - name=%s\n",
693 ret = lremovexattr(full_path, name);
696 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
697 path, name, strerror(-ret));
706 static int process_truncate(const char *path, u64 size, void *user)
709 struct btrfs_receive *r = user;
710 char *full_path = path_cat(r->full_subvol_path, path);
713 fprintf(stderr, "truncate %s size=%llu\n", path, size);
715 ret = truncate(full_path, size);
718 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
719 path, strerror(-ret));
728 static int process_chmod(const char *path, u64 mode, void *user)
731 struct btrfs_receive *r = user;
732 char *full_path = path_cat(r->full_subvol_path, path);
735 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
737 ret = chmod(full_path, mode);
740 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
741 path, strerror(-ret));
750 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
753 struct btrfs_receive *r = user;
754 char *full_path = path_cat(r->full_subvol_path, path);
757 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
760 ret = lchown(full_path, uid, gid);
763 fprintf(stderr, "ERROR: chown %s failed. %s\n",
764 path, strerror(-ret));
773 static int process_utimes(const char *path, struct timespec *at,
774 struct timespec *mt, struct timespec *ct,
778 struct btrfs_receive *r = user;
779 char *full_path = path_cat(r->full_subvol_path, path);
780 struct timespec tv[2];
783 fprintf(stderr, "utimes %s\n", path);
787 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
790 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
791 path, strerror(-ret));
801 static struct btrfs_send_ops send_ops = {
802 .subvol = process_subvol,
803 .snapshot = process_snapshot,
804 .mkfile = process_mkfile,
805 .mkdir = process_mkdir,
806 .mknod = process_mknod,
807 .mkfifo = process_mkfifo,
808 .mksock = process_mksock,
809 .symlink = process_symlink,
810 .rename = process_rename,
811 .link = process_link,
812 .unlink = process_unlink,
813 .rmdir = process_rmdir,
814 .write = process_write,
815 .clone = process_clone,
816 .set_xattr = process_set_xattr,
817 .remove_xattr = process_remove_xattr,
818 .truncate = process_truncate,
819 .chmod = process_chmod,
820 .chown = process_chown,
821 .utimes = process_utimes,
824 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
827 char *dest_dir_full_path;
830 dest_dir_full_path = realpath(tomnt, NULL);
831 if (!dest_dir_full_path) {
833 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
837 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
838 if (r->dest_dir_fd < 0) {
841 "ERROR: failed to open destination directory %s. %s\n",
842 dest_dir_full_path, strerror(-ret));
846 ret = find_mount_root(dest_dir_full_path, &r->root_path);
849 fprintf(stderr, "ERROR: failed to determine mount point "
850 "for %s\n", dest_dir_full_path);
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,
882 ret = close_inode_for_write(r);
885 ret = finish_subvol(r);
892 if (r->write_fd != -1) {
899 r->write_path = NULL;
900 free(r->full_subvol_path);
901 r->full_subvol_path = NULL;
902 r->dest_dir_path = NULL;
903 free(dest_dir_full_path);
905 free(r->cur_subvol->path);
907 r->cur_subvol = NULL;
909 subvol_uuid_search_finit(&r->sus);
910 if (r->mnt_fd != -1) {
914 if (r->dest_dir_fd != -1) {
915 close(r->dest_dir_fd);
921 int cmd_receive(int argc, char **argv)
925 char *fromfile = NULL;
926 struct btrfs_receive r;
927 int receive_fd = fileno(stdin);
931 memset(&r, 0, sizeof(r));
936 while ((c = getopt(argc, argv, "evf:")) != -1) {
949 fprintf(stderr, "ERROR: receive args invalid.\n");
954 if (check_argc_exact(argc - optind, 1))
955 usage(cmd_receive_usage);
957 tomnt = argv[optind];
960 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
961 if (receive_fd < 0) {
962 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
967 ret = do_receive(&r, tomnt, receive_fd);
972 const char * const cmd_receive_usage[] = {
973 "btrfs receive [-ve] [-f <infile>] <mount>",
974 "Receive subvolumes from stdin.",
975 "Receives one or more subvolumes that were previously ",
976 "sent with btrfs send. The received subvolumes are stored",
978 "btrfs receive will fail in case a receiving subvolume",
979 "already exists. It will also fail in case a previously",
980 "received subvolume was changed after it was received.",
981 "After receiving a subvolume, it is immediately set to",
983 "-v Enable verbose debug output. Each",
984 " occurrence of this option increases the",
985 " verbose level more.",
986 "-f <infile> By default, btrfs receive uses stdin",
987 " to receive the subvolumes. Use this",
988 " option to specify a file to use instead.",
989 "-e Terminate after receiving an <end cmd>",
990 " in the data stream. Without this option,",
991 " the receiver terminates only if an error",
992 " is recognized or on EOF.",