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 void close_inode_for_write(struct btrfs_receive *r)
528 if(r->write_fd == -1)
533 r->write_path[0] = 0;
536 static int process_write(const char *path, const void *data, u64 offset,
540 struct btrfs_receive *r = user;
541 char *full_path = path_cat(r->full_subvol_path, path);
545 ret = open_inode_for_write(r, full_path);
550 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
554 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
555 path, strerror(-ret));
566 static int process_clone(const char *path, u64 offset, u64 len,
567 const u8 *clone_uuid, u64 clone_ctransid,
568 const char *clone_path, u64 clone_offset,
572 struct btrfs_receive *r = user;
573 struct btrfs_ioctl_clone_range_args clone_args;
574 struct subvol_info *si = NULL;
575 char *full_path = path_cat(r->full_subvol_path, path);
576 char *subvol_path = NULL;
577 char *full_clone_path = NULL;
580 ret = open_inode_for_write(r, full_path);
584 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
585 subvol_search_by_received_uuid);
587 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
588 BTRFS_UUID_SIZE) == 0) {
589 /* TODO check generation of extent */
590 subvol_path = strdup(r->cur_subvol->path);
593 fprintf(stderr, "ERROR: did not find source subvol.\n");
597 /*if (rs_args.ctransid > rs_args.rtransid) {
600 fprintf(stderr, "ERROR: subvolume %s was "
601 "modified after it was "
603 r->subvol_parent_name);
606 fprintf(stderr, "WARNING: subvolume %s was "
607 "modified after it was "
609 r->subvol_parent_name);
612 subvol_path = strdup(si->path);
615 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
617 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
620 fprintf(stderr, "ERROR: failed to open %s. %s\n",
621 full_clone_path, strerror(-ret));
625 clone_args.src_fd = clone_fd;
626 clone_args.src_offset = clone_offset;
627 clone_args.src_length = len;
628 clone_args.dest_offset = offset;
629 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
632 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
633 path, strerror(-ret));
643 free(full_clone_path);
651 static int process_set_xattr(const char *path, const char *name,
652 const void *data, int len, void *user)
655 struct btrfs_receive *r = user;
656 char *full_path = path_cat(r->full_subvol_path, path);
658 if (g_verbose >= 2) {
659 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
660 "data=%.*s\n", path, name, len,
664 ret = lsetxattr(full_path, name, data, len, 0);
667 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
668 path, name, len, (char*)data, strerror(-ret));
677 static int process_remove_xattr(const char *path, const char *name, void *user)
680 struct btrfs_receive *r = user;
681 char *full_path = path_cat(r->full_subvol_path, path);
683 if (g_verbose >= 2) {
684 fprintf(stderr, "remove_xattr %s - name=%s\n",
688 ret = lremovexattr(full_path, name);
691 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
692 path, name, strerror(-ret));
701 static int process_truncate(const char *path, u64 size, void *user)
704 struct btrfs_receive *r = user;
705 char *full_path = path_cat(r->full_subvol_path, path);
708 fprintf(stderr, "truncate %s size=%llu\n", path, size);
710 ret = truncate(full_path, size);
713 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
714 path, strerror(-ret));
723 static int process_chmod(const char *path, u64 mode, void *user)
726 struct btrfs_receive *r = user;
727 char *full_path = path_cat(r->full_subvol_path, path);
730 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
732 ret = chmod(full_path, mode);
735 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
736 path, strerror(-ret));
745 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
748 struct btrfs_receive *r = user;
749 char *full_path = path_cat(r->full_subvol_path, path);
752 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
755 ret = lchown(full_path, uid, gid);
758 fprintf(stderr, "ERROR: chown %s failed. %s\n",
759 path, strerror(-ret));
768 static int process_utimes(const char *path, struct timespec *at,
769 struct timespec *mt, struct timespec *ct,
773 struct btrfs_receive *r = user;
774 char *full_path = path_cat(r->full_subvol_path, path);
775 struct timespec tv[2];
778 fprintf(stderr, "utimes %s\n", path);
782 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
785 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
786 path, strerror(-ret));
796 static struct btrfs_send_ops send_ops = {
797 .subvol = process_subvol,
798 .snapshot = process_snapshot,
799 .mkfile = process_mkfile,
800 .mkdir = process_mkdir,
801 .mknod = process_mknod,
802 .mkfifo = process_mkfifo,
803 .mksock = process_mksock,
804 .symlink = process_symlink,
805 .rename = process_rename,
806 .link = process_link,
807 .unlink = process_unlink,
808 .rmdir = process_rmdir,
809 .write = process_write,
810 .clone = process_clone,
811 .set_xattr = process_set_xattr,
812 .remove_xattr = process_remove_xattr,
813 .truncate = process_truncate,
814 .chmod = process_chmod,
815 .chown = process_chown,
816 .utimes = process_utimes,
819 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
822 char *dest_dir_full_path;
825 dest_dir_full_path = realpath(tomnt, NULL);
826 if (!dest_dir_full_path) {
828 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
832 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
833 if (r->dest_dir_fd < 0) {
836 "ERROR: failed to open destination directory %s. %s\n",
837 dest_dir_full_path, strerror(-ret));
841 ret = find_mount_root(dest_dir_full_path, &r->root_path);
844 fprintf(stderr, "ERROR: failed to determine mount point "
845 "for %s\n", dest_dir_full_path);
848 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
851 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
857 * find_mount_root returns a root_path that is a subpath of
858 * dest_dir_full_path. Now get the other part of root_path,
859 * which is the destination dir relative to root_path.
861 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
862 while (r->dest_dir_path[0] == '/')
865 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
870 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
877 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 (check_argc_exact(argc - optind, 1))
948 usage(cmd_receive_usage);
950 tomnt = argv[optind];
953 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
954 if (receive_fd < 0) {
955 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
960 ret = do_receive(&r, tomnt, receive_fd);
965 const char * const cmd_receive_usage[] = {
966 "btrfs receive [-ve] [-f <infile>] <mount>",
967 "Receive subvolumes from stdin.",
968 "Receives one or more subvolumes that were previously ",
969 "sent with btrfs send. The received subvolumes are stored",
971 "btrfs receive will fail in case a receiving subvolume",
972 "already exists. It will also fail in case a previously",
973 "received subvolume was changed after it was received.",
974 "After receiving a subvolume, it is immediately set to",
976 "-v Enable verbose debug output. Each",
977 " occurrence of this option increases the",
978 " verbose level more.",
979 "-f <infile> By default, btrfs receive uses stdin",
980 " to receive the subvolumes. Use this",
981 " option to specify a file to use instead.",
982 "-e Terminate after receiving an <end cmd>",
983 " in the data stream. Without this option,",
984 " the receiver terminates only if an error",
985 " is recognized or on EOF.",