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(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) {
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) {
260 fprintf(stderr, "ERROR: open %s failed. %s\n",
261 parent_subvol->path, strerror(-ret));
265 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
269 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
270 "failed. %s\n", parent_subvol->path,
271 path, strerror(-ret));
277 free(parent_subvol->path);
283 static int process_mkfile(const char *path, void *user)
286 struct btrfs_receive *r = user;
287 char *full_path = path_cat(r->full_subvol_path, path);
290 fprintf(stderr, "mkfile %s\n", path);
292 ret = creat(full_path, 0600);
295 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
307 static int process_mkdir(const char *path, void *user)
310 struct btrfs_receive *r = user;
311 char *full_path = path_cat(r->full_subvol_path, path);
314 fprintf(stderr, "mkdir %s\n", path);
316 ret = mkdir(full_path, 0700);
319 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
327 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
330 struct btrfs_receive *r = user;
331 char *full_path = path_cat(r->full_subvol_path, path);
334 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
337 ret = mknod(full_path, mode & S_IFMT, dev);
340 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
348 static int process_mkfifo(const char *path, void *user)
351 struct btrfs_receive *r = user;
352 char *full_path = path_cat(r->full_subvol_path, path);
355 fprintf(stderr, "mkfifo %s\n", path);
357 ret = mkfifo(full_path, 0600);
360 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
368 static int process_mksock(const char *path, void *user)
371 struct btrfs_receive *r = user;
372 char *full_path = path_cat(r->full_subvol_path, path);
375 fprintf(stderr, "mksock %s\n", path);
377 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
380 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
388 static int process_symlink(const char *path, const char *lnk, void *user)
391 struct btrfs_receive *r = user;
392 char *full_path = path_cat(r->full_subvol_path, path);
395 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
397 ret = symlink(lnk, full_path);
400 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
401 lnk, strerror(-ret));
408 static int process_rename(const char *from, const char *to, void *user)
411 struct btrfs_receive *r = user;
412 char *full_from = path_cat(r->full_subvol_path, from);
413 char *full_to = path_cat(r->full_subvol_path, to);
416 fprintf(stderr, "rename %s -> %s\n", from, to);
418 ret = rename(full_from, full_to);
421 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
430 static int process_link(const char *path, const char *lnk, void *user)
433 struct btrfs_receive *r = user;
434 char *full_path = path_cat(r->full_subvol_path, path);
435 char *full_link_path = path_cat(r->full_subvol_path, lnk);
438 fprintf(stderr, "link %s -> %s\n", path, lnk);
440 ret = link(full_link_path, full_path);
443 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
444 lnk, strerror(-ret));
448 free(full_link_path);
453 static int process_unlink(const char *path, void *user)
456 struct btrfs_receive *r = user;
457 char *full_path = path_cat(r->full_subvol_path, path);
460 fprintf(stderr, "unlink %s\n", path);
462 ret = unlink(full_path);
465 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
473 static int process_rmdir(const char *path, void *user)
476 struct btrfs_receive *r = user;
477 char *full_path = path_cat(r->full_subvol_path, path);
480 fprintf(stderr, "rmdir %s\n", path);
482 ret = rmdir(full_path);
485 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
494 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
498 if (r->write_fd != -1) {
499 if (strcmp(r->write_path, path) == 0)
505 r->write_fd = open(path, O_RDWR);
506 if (r->write_fd < 0) {
508 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
513 r->write_path = strdup(path);
519 static int close_inode_for_write(struct btrfs_receive *r)
523 if(r->write_fd == -1)
528 r->write_path[0] = 0;
534 static int process_write(const char *path, const void *data, u64 offset,
538 struct btrfs_receive *r = user;
539 char *full_path = path_cat(r->full_subvol_path, path);
543 ret = open_inode_for_write(r, full_path);
548 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
552 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
553 path, strerror(-ret));
564 static int process_clone(const char *path, u64 offset, u64 len,
565 const u8 *clone_uuid, u64 clone_ctransid,
566 const char *clone_path, u64 clone_offset,
570 struct btrfs_receive *r = user;
571 struct btrfs_ioctl_clone_range_args clone_args;
572 struct subvol_info *si = NULL;
573 char *full_path = path_cat(r->full_subvol_path, path);
574 char *subvol_path = NULL;
575 char *full_clone_path = NULL;
578 ret = open_inode_for_write(r, full_path);
582 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
583 subvol_search_by_received_uuid);
585 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
586 BTRFS_UUID_SIZE) == 0) {
587 /* TODO check generation of extent */
588 subvol_path = strdup(r->cur_subvol->path);
591 fprintf(stderr, "ERROR: did not find source subvol.\n");
595 /*if (rs_args.ctransid > rs_args.rtransid) {
598 fprintf(stderr, "ERROR: subvolume %s was "
599 "modified after it was "
601 r->subvol_parent_name);
604 fprintf(stderr, "WARNING: subvolume %s was "
605 "modified after it was "
607 r->subvol_parent_name);
610 subvol_path = strdup(si->path);
613 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
615 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
618 fprintf(stderr, "ERROR: failed to open %s. %s\n",
619 full_clone_path, strerror(-ret));
623 clone_args.src_fd = clone_fd;
624 clone_args.src_offset = clone_offset;
625 clone_args.src_length = len;
626 clone_args.dest_offset = offset;
627 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
630 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
631 path, strerror(-ret));
641 free(full_clone_path);
649 static int process_set_xattr(const char *path, const char *name,
650 const void *data, int len, void *user)
653 struct btrfs_receive *r = user;
654 char *full_path = path_cat(r->full_subvol_path, path);
656 if (g_verbose >= 2) {
657 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
658 "data=%.*s\n", path, name, len,
662 ret = lsetxattr(full_path, name, data, len, 0);
665 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
666 path, name, len, (char*)data, strerror(-ret));
675 static int process_remove_xattr(const char *path, const char *name, void *user)
678 struct btrfs_receive *r = user;
679 char *full_path = path_cat(r->full_subvol_path, path);
681 if (g_verbose >= 2) {
682 fprintf(stderr, "remove_xattr %s - name=%s\n",
686 ret = lremovexattr(full_path, name);
689 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
690 path, name, strerror(-ret));
699 static int process_truncate(const char *path, u64 size, void *user)
702 struct btrfs_receive *r = user;
703 char *full_path = path_cat(r->full_subvol_path, path);
706 fprintf(stderr, "truncate %s size=%llu\n", path, size);
708 ret = truncate(full_path, size);
711 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
712 path, strerror(-ret));
721 static int process_chmod(const char *path, u64 mode, void *user)
724 struct btrfs_receive *r = user;
725 char *full_path = path_cat(r->full_subvol_path, path);
728 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
730 ret = chmod(full_path, mode);
733 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
734 path, strerror(-ret));
743 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
746 struct btrfs_receive *r = user;
747 char *full_path = path_cat(r->full_subvol_path, path);
750 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
753 ret = lchown(full_path, uid, gid);
756 fprintf(stderr, "ERROR: chown %s failed. %s\n",
757 path, strerror(-ret));
766 static int process_utimes(const char *path, struct timespec *at,
767 struct timespec *mt, struct timespec *ct,
771 struct btrfs_receive *r = user;
772 char *full_path = path_cat(r->full_subvol_path, path);
773 struct timespec tv[2];
776 fprintf(stderr, "utimes %s\n", path);
780 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
783 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
784 path, strerror(-ret));
794 static struct btrfs_send_ops send_ops = {
795 .subvol = process_subvol,
796 .snapshot = process_snapshot,
797 .mkfile = process_mkfile,
798 .mkdir = process_mkdir,
799 .mknod = process_mknod,
800 .mkfifo = process_mkfifo,
801 .mksock = process_mksock,
802 .symlink = process_symlink,
803 .rename = process_rename,
804 .link = process_link,
805 .unlink = process_unlink,
806 .rmdir = process_rmdir,
807 .write = process_write,
808 .clone = process_clone,
809 .set_xattr = process_set_xattr,
810 .remove_xattr = process_remove_xattr,
811 .truncate = process_truncate,
812 .chmod = process_chmod,
813 .chown = process_chown,
814 .utimes = process_utimes,
817 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
820 char *dest_dir_full_path;
823 dest_dir_full_path = realpath(tomnt, NULL);
824 if (!dest_dir_full_path) {
826 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
830 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
831 if (r->dest_dir_fd < 0) {
834 "ERROR: failed to open destination directory %s. %s\n",
835 dest_dir_full_path, strerror(-ret));
839 ret = find_mount_root(dest_dir_full_path, &r->root_path);
842 fprintf(stderr, "ERROR: failed to determine mount point "
843 "for %s\n", dest_dir_full_path);
846 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
849 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
855 * find_mount_root returns a root_path that is a subpath of
856 * dest_dir_full_path. Now get the other part of root_path,
857 * which is the destination dir relative to root_path.
859 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
860 while (r->dest_dir_path[0] == '/')
863 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
868 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
875 ret = close_inode_for_write(r);
878 ret = finish_subvol(r);
885 if (r->write_fd != -1) {
892 r->write_path = NULL;
893 free(r->full_subvol_path);
894 r->full_subvol_path = NULL;
895 r->dest_dir_path = NULL;
896 free(dest_dir_full_path);
898 free(r->cur_subvol->path);
900 r->cur_subvol = NULL;
902 subvol_uuid_search_finit(&r->sus);
903 if (r->mnt_fd != -1) {
907 if (r->dest_dir_fd != -1) {
908 close(r->dest_dir_fd);
914 int cmd_receive(int argc, char **argv)
918 char *fromfile = NULL;
919 struct btrfs_receive r;
920 int receive_fd = fileno(stdin);
924 memset(&r, 0, sizeof(r));
929 while ((c = getopt(argc, argv, "evf:")) != -1) {
942 fprintf(stderr, "ERROR: receive args invalid.\n");
947 if (optind + 1 != argc) {
948 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
952 tomnt = argv[optind];
955 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
956 if (receive_fd < 0) {
957 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
962 ret = do_receive(&r, tomnt, receive_fd);
967 const char * const cmd_receive_usage[] = {
968 "btrfs receive [-ve] [-f <infile>] <mount>",
969 "Receive subvolumes from stdin.",
970 "Receives one or more subvolumes that were previously ",
971 "sent with btrfs send. The received subvolumes are stored",
973 "btrfs receive will fail in case a receiving subvolume",
974 "already exists. It will also fail in case a previously",
975 "received subvolume was changed after it was received.",
976 "After receiving a subvolume, it is immediately set to",
978 "-v Enable verbose debug output. Each",
979 " occurrence of this option increases the",
980 " verbose level more.",
981 "-f <infile> By default, btrfs receive uses stdin",
982 " to receive the subvolumes. Use this",
983 " option to specify a file to use instead.",
984 "-e Terminate after receiving an <end cmd>",
985 " in the data stream. Without this option,",
986 " the receiver terminates only if an error",
987 " is recognized or on EOF.",