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;
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;
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;
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(stderr, "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) {
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) {
256 fprintf(stderr, "ERROR: open %s failed. %s\n",
257 parent_subvol->path, strerror(-ret));
261 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
265 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
266 "failed. %s\n", parent_subvol->path,
267 path, strerror(-ret));
273 free(parent_subvol->path);
279 static int process_mkfile(const char *path, void *user)
282 struct btrfs_receive *r = user;
283 char *full_path = path_cat(r->full_subvol_path, path);
286 fprintf(stderr, "mkfile %s\n", path);
288 ret = creat(full_path, 0600);
291 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
303 static int process_mkdir(const char *path, void *user)
306 struct btrfs_receive *r = user;
307 char *full_path = path_cat(r->full_subvol_path, path);
310 fprintf(stderr, "mkdir %s\n", path);
312 ret = mkdir(full_path, 0700);
315 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
323 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
326 struct btrfs_receive *r = user;
327 char *full_path = path_cat(r->full_subvol_path, path);
330 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
333 ret = mknod(full_path, mode & S_IFMT, dev);
336 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
344 static int process_mkfifo(const char *path, void *user)
347 struct btrfs_receive *r = user;
348 char *full_path = path_cat(r->full_subvol_path, path);
351 fprintf(stderr, "mkfifo %s\n", path);
353 ret = mkfifo(full_path, 0600);
356 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
364 static int process_mksock(const char *path, void *user)
367 struct btrfs_receive *r = user;
368 char *full_path = path_cat(r->full_subvol_path, path);
371 fprintf(stderr, "mksock %s\n", path);
373 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
376 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
384 static int process_symlink(const char *path, const char *lnk, void *user)
387 struct btrfs_receive *r = user;
388 char *full_path = path_cat(r->full_subvol_path, path);
391 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
393 ret = symlink(lnk, full_path);
396 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
397 lnk, strerror(-ret));
404 static int process_rename(const char *from, const char *to, void *user)
407 struct btrfs_receive *r = user;
408 char *full_from = path_cat(r->full_subvol_path, from);
409 char *full_to = path_cat(r->full_subvol_path, to);
412 fprintf(stderr, "rename %s -> %s\n", from, to);
414 ret = rename(full_from, full_to);
417 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
426 static int process_link(const char *path, const char *lnk, void *user)
429 struct btrfs_receive *r = user;
430 char *full_path = path_cat(r->full_subvol_path, path);
431 char *full_link_path = path_cat(r->full_subvol_path, lnk);
434 fprintf(stderr, "link %s -> %s\n", path, lnk);
436 ret = link(full_link_path, full_path);
439 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
440 lnk, strerror(-ret));
444 free(full_link_path);
449 static int process_unlink(const char *path, void *user)
452 struct btrfs_receive *r = user;
453 char *full_path = path_cat(r->full_subvol_path, path);
456 fprintf(stderr, "unlink %s\n", path);
458 ret = unlink(full_path);
461 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
469 static int process_rmdir(const char *path, void *user)
472 struct btrfs_receive *r = user;
473 char *full_path = path_cat(r->full_subvol_path, path);
476 fprintf(stderr, "rmdir %s\n", path);
478 ret = rmdir(full_path);
481 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
490 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
494 if (r->write_fd != -1) {
495 if (strcmp(r->write_path, path) == 0)
501 r->write_fd = open(path, O_RDWR);
502 if (r->write_fd < 0) {
504 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
509 r->write_path = strdup(path);
515 static int close_inode_for_write(struct btrfs_receive *r)
519 if(r->write_fd == -1)
524 r->write_path[0] = 0;
530 static int process_write(const char *path, const void *data, u64 offset,
534 struct btrfs_receive *r = user;
535 char *full_path = path_cat(r->full_subvol_path, path);
539 ret = open_inode_for_write(r, full_path);
544 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
548 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
549 path, strerror(-ret));
560 static int process_clone(const char *path, u64 offset, u64 len,
561 const u8 *clone_uuid, u64 clone_ctransid,
562 const char *clone_path, u64 clone_offset,
566 struct btrfs_receive *r = user;
567 struct btrfs_ioctl_clone_range_args clone_args;
568 struct subvol_info *si = NULL;
569 char *full_path = path_cat(r->full_subvol_path, path);
570 char *subvol_path = NULL;
571 char *full_clone_path = NULL;
574 ret = open_inode_for_write(r, full_path);
578 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
579 subvol_search_by_received_uuid);
581 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
582 BTRFS_UUID_SIZE) == 0) {
583 /* TODO check generation of extent */
584 subvol_path = strdup(r->cur_subvol->path);
587 fprintf(stderr, "ERROR: did not find source subvol.\n");
591 /*if (rs_args.ctransid > rs_args.rtransid) {
594 fprintf(stderr, "ERROR: subvolume %s was "
595 "modified after it was "
597 r->subvol_parent_name);
600 fprintf(stderr, "WARNING: subvolume %s was "
601 "modified after it was "
603 r->subvol_parent_name);
606 subvol_path = strdup(si->path);
609 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
611 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
614 fprintf(stderr, "ERROR: failed to open %s. %s\n",
615 full_clone_path, strerror(-ret));
619 clone_args.src_fd = clone_fd;
620 clone_args.src_offset = clone_offset;
621 clone_args.src_length = len;
622 clone_args.dest_offset = offset;
623 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
626 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
627 path, strerror(-ret));
637 free(full_clone_path);
645 static int process_set_xattr(const char *path, const char *name,
646 const void *data, int len, void *user)
649 struct btrfs_receive *r = user;
650 char *full_path = path_cat(r->full_subvol_path, path);
652 if (g_verbose >= 2) {
653 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
654 "data=%.*s\n", path, name, len,
658 ret = lsetxattr(full_path, name, data, len, 0);
661 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
662 path, name, len, (char*)data, strerror(-ret));
671 static int process_remove_xattr(const char *path, const char *name, void *user)
674 struct btrfs_receive *r = user;
675 char *full_path = path_cat(r->full_subvol_path, path);
677 if (g_verbose >= 2) {
678 fprintf(stderr, "remove_xattr %s - name=%s\n",
682 ret = lremovexattr(full_path, name);
685 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
686 path, name, strerror(-ret));
695 static int process_truncate(const char *path, u64 size, void *user)
698 struct btrfs_receive *r = user;
699 char *full_path = path_cat(r->full_subvol_path, path);
702 fprintf(stderr, "truncate %s size=%llu\n", path, size);
704 ret = truncate(full_path, size);
707 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
708 path, strerror(-ret));
717 static int process_chmod(const char *path, u64 mode, void *user)
720 struct btrfs_receive *r = user;
721 char *full_path = path_cat(r->full_subvol_path, path);
724 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
726 ret = chmod(full_path, mode);
729 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
730 path, strerror(-ret));
739 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
742 struct btrfs_receive *r = user;
743 char *full_path = path_cat(r->full_subvol_path, path);
746 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
749 ret = lchown(full_path, uid, gid);
752 fprintf(stderr, "ERROR: chown %s failed. %s\n",
753 path, strerror(-ret));
762 static int process_utimes(const char *path, struct timespec *at,
763 struct timespec *mt, struct timespec *ct,
767 struct btrfs_receive *r = user;
768 char *full_path = path_cat(r->full_subvol_path, path);
769 struct timespec tv[2];
772 fprintf(stderr, "utimes %s\n", path);
776 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
779 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
780 path, strerror(-ret));
790 struct btrfs_send_ops send_ops = {
791 .subvol = process_subvol,
792 .snapshot = process_snapshot,
793 .mkfile = process_mkfile,
794 .mkdir = process_mkdir,
795 .mknod = process_mknod,
796 .mkfifo = process_mkfifo,
797 .mksock = process_mksock,
798 .symlink = process_symlink,
799 .rename = process_rename,
800 .link = process_link,
801 .unlink = process_unlink,
802 .rmdir = process_rmdir,
803 .write = process_write,
804 .clone = process_clone,
805 .set_xattr = process_set_xattr,
806 .remove_xattr = process_remove_xattr,
807 .truncate = process_truncate,
808 .chmod = process_chmod,
809 .chown = process_chown,
810 .utimes = process_utimes,
813 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
816 char *dest_dir_full_path;
819 dest_dir_full_path = realpath(tomnt, NULL);
820 if (!dest_dir_full_path) {
822 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
826 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
827 if (r->dest_dir_fd < 0) {
830 "ERROR: failed to open destination directory %s. %s\n",
831 dest_dir_full_path, strerror(-ret));
835 ret = find_mount_root(dest_dir_full_path, &r->root_path);
838 fprintf(stderr, "ERROR: failed to determine mount point "
839 "for %s\n", dest_dir_full_path);
842 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
845 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
851 * find_mount_root returns a root_path that is a subpath of
852 * dest_dir_full_path. Now get the other part of root_path,
853 * which is the destination dir relative to root_path.
855 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
856 while (r->dest_dir_path[0] == '/')
859 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
864 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
871 ret = close_inode_for_write(r);
874 ret = finish_subvol(r);
881 if (r->write_fd != -1) {
888 r->write_path = NULL;
889 free(r->full_subvol_path);
890 r->full_subvol_path = NULL;
891 r->dest_dir_path = NULL;
892 free(dest_dir_full_path);
894 free(r->cur_subvol->path);
896 r->cur_subvol = NULL;
898 subvol_uuid_search_finit(&r->sus);
899 if (r->mnt_fd != -1) {
903 if (r->dest_dir_fd != -1) {
904 close(r->dest_dir_fd);
910 static int do_cmd_receive(int argc, char **argv)
914 char *fromfile = NULL;
915 struct btrfs_receive r;
916 int receive_fd = fileno(stdin);
920 memset(&r, 0, sizeof(r));
925 while ((c = getopt(argc, argv, "evf:")) != -1) {
938 fprintf(stderr, "ERROR: receive args invalid.\n");
943 if (optind + 1 != argc) {
944 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
948 tomnt = argv[optind];
951 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
952 if (receive_fd < 0) {
953 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
958 ret = do_receive(&r, tomnt, receive_fd);
963 static const char * const receive_cmd_group_usage[] = {
964 "btrfs receive <command> <args>",
968 const char * const cmd_receive_usage[] = {
969 "btrfs receive [-ve] [-f <infile>] <mount>",
970 "Receive subvolumes from stdin.",
971 "Receives one or more subvolumes that were previously ",
972 "sent with btrfs send. The received subvolumes are stored",
974 "btrfs receive will fail in case a receiving subvolume",
975 "already exists. It will also fail in case a previously",
976 "received subvolume was changed after it was received.",
977 "After receiving a subvolume, it is immediately set to",
979 "-v Enable verbose debug output. Each",
980 " occurrence of this option increases the",
981 " verbose level more.",
982 "-f <infile> By default, btrfs receive uses stdin",
983 " to receive the subvolumes. Use this",
984 " option to specify a file to use instead.",
985 "-e Terminate after receiving an <end cmd>",
986 " in the data stream. Without this option,",
987 " the receiver terminates only if an error",
988 " is recognized or on EOF.",
992 const struct cmd_group receive_cmd_group = {
993 receive_cmd_group_usage, NULL, {
994 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
999 int cmd_receive(int argc, char **argv)
1001 return do_cmd_receive(argc, argv);