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"
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/xattr.h>
41 #include <uuid/uuid.h>
48 #include "btrfs-list.h"
51 #include "send-stream.h"
52 #include "send-utils.h"
54 static int g_verbose = 0;
65 char *dest_dir_path; /* relative to root_path */
66 char *full_subvol_path;
68 struct subvol_info *cur_subvol;
70 struct subvol_uuid_search sus;
75 static int finish_subvol(struct btrfs_receive *r)
79 struct btrfs_ioctl_received_subvol_args rs_args;
83 if (r->cur_subvol == NULL)
86 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
87 O_RDONLY | O_NOATIME);
90 fprintf(stderr, "ERROR: open %s failed. %s\n",
91 r->cur_subvol->path, strerror(-ret));
95 memset(&rs_args, 0, sizeof(rs_args));
96 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
97 rs_args.stransid = r->cur_subvol->stransid;
100 uuid_unparse((u8*)rs_args.uuid, uuid_str);
101 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
102 "stransid=%llu\n", uuid_str, rs_args.stransid);
105 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
108 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
112 r->cur_subvol->rtransid = rs_args.rtransid;
114 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
117 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
122 flags |= BTRFS_SUBVOL_RDONLY;
124 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
127 fprintf(stderr, "ERROR: failed to make subvolume read only. "
128 "%s\n", strerror(-ret));
132 ret = btrfs_list_get_path_rootid(subvol_fd, &r->cur_subvol->root_id);
135 subvol_uuid_search_add(&r->sus, r->cur_subvol);
136 r->cur_subvol = NULL;
145 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
149 struct btrfs_receive *r = user;
150 struct btrfs_ioctl_vol_args args_v1;
153 ret = finish_subvol(r);
157 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
159 if (strlen(r->dest_dir_path) == 0)
160 r->cur_subvol->path = strdup(path);
162 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
163 free(r->full_subvol_path);
164 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
166 fprintf(stderr, "At subvol %s\n", path);
168 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
169 r->cur_subvol->stransid = ctransid;
172 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
173 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
175 r->cur_subvol->stransid);
178 memset(&args_v1, 0, sizeof(args_v1));
179 strncpy_null(args_v1.name, path);
180 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
183 fprintf(stderr, "ERROR: creating subvolume %s failed. "
184 "%s\n", path, strerror(-ret));
192 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
193 const u8 *parent_uuid, u64 parent_ctransid,
197 struct btrfs_receive *r = user;
199 struct btrfs_ioctl_vol_args_v2 args_v2;
200 struct subvol_info *parent_subvol;
202 ret = finish_subvol(r);
206 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
208 if (strlen(r->dest_dir_path) == 0)
209 r->cur_subvol->path = strdup(path);
211 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
212 free(r->full_subvol_path);
213 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
215 fprintf(stderr, "At snapshot %s\n", path);
217 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
218 r->cur_subvol->stransid = ctransid;
221 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
222 fprintf(stderr, "receiving snapshot %s uuid=%s, "
223 "ctransid=%llu ", path, uuid_str,
224 r->cur_subvol->stransid);
225 uuid_unparse(parent_uuid, uuid_str);
226 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
227 uuid_str, parent_ctransid);
230 memset(&args_v2, 0, sizeof(args_v2));
231 strncpy_null(args_v2.name, path);
233 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
234 parent_ctransid, NULL, subvol_search_by_received_uuid);
235 if (!parent_subvol) {
237 fprintf(stderr, "ERROR: could not find parent subvolume\n");
241 /*if (rs_args.ctransid > rs_args.rtransid) {
244 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
247 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
251 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
252 O_RDONLY | O_NOATIME);
253 if (args_v2.fd < 0) {
255 fprintf(stderr, "ERROR: open %s failed. %s\n",
256 parent_subvol->path, strerror(-ret));
260 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
264 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
265 "failed. %s\n", parent_subvol->path,
266 path, strerror(-ret));
274 static int process_mkfile(const char *path, void *user)
277 struct btrfs_receive *r = user;
278 char *full_path = path_cat(r->full_subvol_path, path);
281 fprintf(stderr, "mkfile %s\n", path);
283 ret = creat(full_path, 0600);
286 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
298 static int process_mkdir(const char *path, void *user)
301 struct btrfs_receive *r = user;
302 char *full_path = path_cat(r->full_subvol_path, path);
305 fprintf(stderr, "mkdir %s\n", path);
307 ret = mkdir(full_path, 0700);
310 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
318 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
321 struct btrfs_receive *r = user;
322 char *full_path = path_cat(r->full_subvol_path, path);
325 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
328 ret = mknod(full_path, mode & S_IFMT, dev);
331 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
339 static int process_mkfifo(const char *path, void *user)
342 struct btrfs_receive *r = user;
343 char *full_path = path_cat(r->full_subvol_path, path);
346 fprintf(stderr, "mkfifo %s\n", path);
348 ret = mkfifo(full_path, 0600);
351 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
359 static int process_mksock(const char *path, void *user)
362 struct btrfs_receive *r = user;
363 char *full_path = path_cat(r->full_subvol_path, path);
366 fprintf(stderr, "mksock %s\n", path);
368 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
371 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
379 static int process_symlink(const char *path, const char *lnk, void *user)
382 struct btrfs_receive *r = user;
383 char *full_path = path_cat(r->full_subvol_path, path);
386 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
388 ret = symlink(lnk, full_path);
391 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
392 lnk, strerror(-ret));
399 static int process_rename(const char *from, const char *to, void *user)
402 struct btrfs_receive *r = user;
403 char *full_from = path_cat(r->full_subvol_path, from);
404 char *full_to = path_cat(r->full_subvol_path, to);
407 fprintf(stderr, "rename %s -> %s\n", from, to);
409 ret = rename(full_from, full_to);
412 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
421 static int process_link(const char *path, const char *lnk, void *user)
424 struct btrfs_receive *r = user;
425 char *full_path = path_cat(r->full_subvol_path, path);
426 char *full_link_path = path_cat(r->full_subvol_path, lnk);
429 fprintf(stderr, "link %s -> %s\n", path, lnk);
431 ret = link(full_link_path, full_path);
434 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
435 lnk, strerror(-ret));
439 free(full_link_path);
444 static int process_unlink(const char *path, void *user)
447 struct btrfs_receive *r = user;
448 char *full_path = path_cat(r->full_subvol_path, path);
451 fprintf(stderr, "unlink %s\n", path);
453 ret = unlink(full_path);
456 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
464 static int process_rmdir(const char *path, void *user)
467 struct btrfs_receive *r = user;
468 char *full_path = path_cat(r->full_subvol_path, path);
471 fprintf(stderr, "rmdir %s\n", path);
473 ret = rmdir(full_path);
476 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
485 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
489 if (r->write_fd != -1) {
490 if (strcmp(r->write_path, path) == 0)
496 r->write_fd = open(path, O_RDWR);
497 if (r->write_fd < 0) {
499 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
504 r->write_path = strdup(path);
510 static int close_inode_for_write(struct btrfs_receive *r)
514 if(r->write_fd == -1)
519 r->write_path[0] = 0;
525 static int process_write(const char *path, const void *data, u64 offset,
529 struct btrfs_receive *r = user;
530 char *full_path = path_cat(r->full_subvol_path, path);
534 ret = open_inode_for_write(r, full_path);
539 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
543 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
544 path, strerror(-ret));
555 static int process_clone(const char *path, u64 offset, u64 len,
556 const u8 *clone_uuid, u64 clone_ctransid,
557 const char *clone_path, u64 clone_offset,
561 struct btrfs_receive *r = user;
562 struct btrfs_ioctl_clone_range_args clone_args;
563 struct subvol_info *si = NULL;
564 char *full_path = path_cat(r->full_subvol_path, path);
565 char *subvol_path = NULL;
566 char *full_clone_path = NULL;
569 ret = open_inode_for_write(r, full_path);
573 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
574 subvol_search_by_received_uuid);
576 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
577 BTRFS_UUID_SIZE) == 0) {
578 /* TODO check generation of extent */
579 subvol_path = strdup(r->cur_subvol->path);
582 fprintf(stderr, "ERROR: did not find source subvol.\n");
586 /*if (rs_args.ctransid > rs_args.rtransid) {
589 fprintf(stderr, "ERROR: subvolume %s was "
590 "modified after it was "
592 r->subvol_parent_name);
595 fprintf(stderr, "WARNING: subvolume %s was "
596 "modified after it was "
598 r->subvol_parent_name);
601 subvol_path = strdup(si->path);
604 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
606 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
609 fprintf(stderr, "ERROR: failed to open %s. %s\n",
610 full_clone_path, strerror(-ret));
614 clone_args.src_fd = clone_fd;
615 clone_args.src_offset = clone_offset;
616 clone_args.src_length = len;
617 clone_args.dest_offset = offset;
618 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
621 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
622 path, strerror(-ret));
628 free(full_clone_path);
636 static int process_set_xattr(const char *path, const char *name,
637 const void *data, int len, void *user)
640 struct btrfs_receive *r = user;
641 char *full_path = path_cat(r->full_subvol_path, path);
643 if (g_verbose >= 2) {
644 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
645 "data=%.*s\n", path, name, len,
649 ret = lsetxattr(full_path, name, data, len, 0);
652 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
653 path, name, len, (char*)data, strerror(-ret));
662 static int process_remove_xattr(const char *path, const char *name, void *user)
665 struct btrfs_receive *r = user;
666 char *full_path = path_cat(r->full_subvol_path, path);
668 if (g_verbose >= 2) {
669 fprintf(stderr, "remove_xattr %s - name=%s\n",
673 ret = lremovexattr(full_path, name);
676 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
677 path, name, strerror(-ret));
686 static int process_truncate(const char *path, u64 size, void *user)
689 struct btrfs_receive *r = user;
690 char *full_path = path_cat(r->full_subvol_path, path);
693 fprintf(stderr, "truncate %s size=%llu\n", path, size);
695 ret = truncate(full_path, size);
698 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
699 path, strerror(-ret));
708 static int process_chmod(const char *path, u64 mode, void *user)
711 struct btrfs_receive *r = user;
712 char *full_path = path_cat(r->full_subvol_path, path);
715 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
717 ret = chmod(full_path, mode);
720 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
721 path, strerror(-ret));
730 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
733 struct btrfs_receive *r = user;
734 char *full_path = path_cat(r->full_subvol_path, path);
737 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
740 ret = lchown(full_path, uid, gid);
743 fprintf(stderr, "ERROR: chown %s failed. %s\n",
744 path, strerror(-ret));
753 static int process_utimes(const char *path, struct timespec *at,
754 struct timespec *mt, struct timespec *ct,
758 struct btrfs_receive *r = user;
759 char *full_path = path_cat(r->full_subvol_path, path);
760 struct timespec tv[2];
763 fprintf(stderr, "utimes %s\n", path);
767 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
770 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
771 path, strerror(-ret));
781 struct btrfs_send_ops send_ops = {
782 .subvol = process_subvol,
783 .snapshot = process_snapshot,
784 .mkfile = process_mkfile,
785 .mkdir = process_mkdir,
786 .mknod = process_mknod,
787 .mkfifo = process_mkfifo,
788 .mksock = process_mksock,
789 .symlink = process_symlink,
790 .rename = process_rename,
791 .link = process_link,
792 .unlink = process_unlink,
793 .rmdir = process_rmdir,
794 .write = process_write,
795 .clone = process_clone,
796 .set_xattr = process_set_xattr,
797 .remove_xattr = process_remove_xattr,
798 .truncate = process_truncate,
799 .chmod = process_chmod,
800 .chown = process_chown,
801 .utimes = process_utimes,
804 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
807 char *dest_dir_full_path;
810 dest_dir_full_path = realpath(tomnt, NULL);
811 if (!dest_dir_full_path) {
813 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
817 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
818 if (r->dest_dir_fd < 0) {
821 "ERROR: failed to open destination directory %s. %s\n",
822 dest_dir_full_path, strerror(-ret));
826 ret = find_mount_root(dest_dir_full_path, &r->root_path);
829 fprintf(stderr, "ERROR: failed to determine mount point "
830 "for %s\n", dest_dir_full_path);
833 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
836 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
842 * find_mount_root returns a root_path that is a subpath of
843 * dest_dir_full_path. Now get the other part of root_path,
844 * which is the destination dir relative to root_path.
846 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
847 while (r->dest_dir_path[0] == '/')
850 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
855 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
862 ret = close_inode_for_write(r);
865 ret = finish_subvol(r);
872 if (r->write_fd != -1) {
879 r->write_path = NULL;
880 free(r->full_subvol_path);
881 r->full_subvol_path = NULL;
882 r->dest_dir_path = NULL;
883 free(dest_dir_full_path);
885 free(r->cur_subvol->path);
887 r->cur_subvol = NULL;
889 subvol_uuid_search_finit(&r->sus);
890 if (r->mnt_fd != -1) {
894 if (r->dest_dir_fd != -1) {
895 close(r->dest_dir_fd);
901 static int do_cmd_receive(int argc, char **argv)
905 char *fromfile = NULL;
906 struct btrfs_receive r;
907 int receive_fd = fileno(stdin);
911 memset(&r, 0, sizeof(r));
916 while ((c = getopt(argc, argv, "evf:")) != -1) {
929 fprintf(stderr, "ERROR: receive args invalid.\n");
934 if (optind + 1 != argc) {
935 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
939 tomnt = argv[optind];
942 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
943 if (receive_fd < 0) {
944 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
949 ret = do_receive(&r, tomnt, receive_fd);
954 static const char * const receive_cmd_group_usage[] = {
955 "btrfs receive <command> <args>",
959 const char * const cmd_receive_usage[] = {
960 "btrfs receive [-ve] [-f <infile>] <mount>",
961 "Receive subvolumes from stdin.",
962 "Receives one or more subvolumes that were previously ",
963 "sent with btrfs send. The received subvolumes are stored",
965 "btrfs receive will fail in case a receiving subvolume",
966 "already exists. It will also fail in case a previously",
967 "received subvolume was changed after it was received.",
968 "After receiving a subvolume, it is immediately set to",
970 "-v Enable verbose debug output. Each",
971 " occurrence of this option increases the",
972 " verbose level more.",
973 "-f <infile> By default, btrfs receive uses stdin",
974 " to receive the subvolumes. Use this",
975 " option to specify a file to use instead.",
976 "-e Terminate after receiving an <end cmd>",
977 " in the data stream. Without this option,",
978 " the receiver terminates only if an error",
979 " is recognized or on EOF.",
983 const struct cmd_group receive_cmd_group = {
984 receive_cmd_group_usage, NULL, {
985 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
990 int cmd_receive(int argc, char **argv)
992 return do_cmd_receive(argc, argv);