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;
64 char *full_subvol_path;
66 struct subvol_info *cur_subvol;
67 struct subvol_info *parent_subvol;
69 struct subvol_uuid_search sus;
72 static int finish_subvol(struct btrfs_receive *r)
76 struct btrfs_ioctl_received_subvol_args rs_args;
80 if (r->cur_subvol == NULL)
83 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
84 O_RDONLY | O_NOATIME);
87 fprintf(stderr, "ERROR: open %s failed. %s\n",
88 r->cur_subvol->path, strerror(-ret));
92 memset(&rs_args, 0, sizeof(rs_args));
93 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
94 rs_args.stransid = r->cur_subvol->stransid;
97 uuid_unparse((u8*)rs_args.uuid, uuid_str);
98 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
99 "stransid=%llu\n", uuid_str, rs_args.stransid);
102 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
105 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
109 r->cur_subvol->rtransid = rs_args.rtransid;
111 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
114 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
119 flags |= BTRFS_SUBVOL_RDONLY;
121 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
124 fprintf(stderr, "ERROR: failed to make subvolume read only. "
125 "%s\n", strerror(-ret));
129 ret = btrfs_list_get_path_rootid(subvol_fd, &r->cur_subvol->root_id);
132 subvol_uuid_search_add(&r->sus, r->cur_subvol);
133 r->cur_subvol = NULL;
142 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
146 struct btrfs_receive *r = user;
147 struct btrfs_ioctl_vol_args args_v1;
150 ret = finish_subvol(r);
154 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
155 r->parent_subvol = NULL;
157 r->cur_subvol->path = strdup(path);
158 free(r->full_subvol_path);
159 r->full_subvol_path = path_cat(r->root_path, path);
161 fprintf(stderr, "At subvol %s\n", path);
163 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
164 r->cur_subvol->stransid = ctransid;
167 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
168 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
170 r->cur_subvol->stransid);
173 memset(&args_v1, 0, sizeof(args_v1));
174 strncpy_null(args_v1.name, path);
175 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
178 fprintf(stderr, "ERROR: creating subvolume %s failed. "
179 "%s\n", path, strerror(-ret));
187 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
188 const u8 *parent_uuid, u64 parent_ctransid,
192 struct btrfs_receive *r = user;
194 struct btrfs_ioctl_vol_args_v2 args_v2;
196 ret = finish_subvol(r);
200 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
201 r->parent_subvol = NULL;
203 r->cur_subvol->path = strdup(path);
204 free(r->full_subvol_path);
205 r->full_subvol_path = path_cat(r->root_path, path);
207 fprintf(stderr, "At snapshot %s\n", path);
209 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
210 r->cur_subvol->stransid = ctransid;
213 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
214 fprintf(stderr, "receiving snapshot %s uuid=%s, "
215 "ctransid=%llu ", path, uuid_str,
216 r->cur_subvol->stransid);
217 uuid_unparse(parent_uuid, uuid_str);
218 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
219 uuid_str, parent_ctransid);
222 memset(&args_v2, 0, sizeof(args_v2));
223 strncpy_null(args_v2.name, path);
225 r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
226 parent_ctransid, NULL, subvol_search_by_received_uuid);
227 if (!r->parent_subvol) {
229 fprintf(stderr, "ERROR: could not find parent subvolume\n");
233 /*if (rs_args.ctransid > rs_args.rtransid) {
236 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
239 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
243 args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
244 O_RDONLY | O_NOATIME);
245 if (args_v2.fd < 0) {
247 fprintf(stderr, "ERROR: open %s failed. %s\n",
248 r->parent_subvol->path, strerror(-ret));
252 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
256 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
257 "failed. %s\n", r->parent_subvol->path,
258 path, strerror(-ret));
266 static int process_mkfile(const char *path, void *user)
269 struct btrfs_receive *r = user;
270 char *full_path = path_cat(r->full_subvol_path, path);
273 fprintf(stderr, "mkfile %s\n", path);
275 ret = creat(full_path, 0600);
278 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
290 static int process_mkdir(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, "mkdir %s\n", path);
299 ret = mkdir(full_path, 0700);
302 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
310 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
313 struct btrfs_receive *r = user;
314 char *full_path = path_cat(r->full_subvol_path, path);
317 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
320 ret = mknod(full_path, mode & S_IFMT, dev);
323 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
331 static int process_mkfifo(const char *path, void *user)
334 struct btrfs_receive *r = user;
335 char *full_path = path_cat(r->full_subvol_path, path);
338 fprintf(stderr, "mkfifo %s\n", path);
340 ret = mkfifo(full_path, 0600);
343 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
351 static int process_mksock(const char *path, void *user)
354 struct btrfs_receive *r = user;
355 char *full_path = path_cat(r->full_subvol_path, path);
358 fprintf(stderr, "mksock %s\n", path);
360 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
363 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
371 static int process_symlink(const char *path, const char *lnk, void *user)
374 struct btrfs_receive *r = user;
375 char *full_path = path_cat(r->full_subvol_path, path);
378 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
380 ret = symlink(lnk, full_path);
383 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
384 lnk, strerror(-ret));
391 static int process_rename(const char *from, const char *to, void *user)
394 struct btrfs_receive *r = user;
395 char *full_from = path_cat(r->full_subvol_path, from);
396 char *full_to = path_cat(r->full_subvol_path, to);
399 fprintf(stderr, "rename %s -> %s\n", from, to);
401 ret = rename(full_from, full_to);
404 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
413 static int process_link(const char *path, const char *lnk, void *user)
416 struct btrfs_receive *r = user;
417 char *full_path = path_cat(r->full_subvol_path, path);
418 char *full_link_path = path_cat(r->full_subvol_path, lnk);
421 fprintf(stderr, "link %s -> %s\n", path, lnk);
423 ret = link(full_link_path, full_path);
426 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
427 lnk, strerror(-ret));
431 free(full_link_path);
436 static int process_unlink(const char *path, void *user)
439 struct btrfs_receive *r = user;
440 char *full_path = path_cat(r->full_subvol_path, path);
443 fprintf(stderr, "unlink %s\n", path);
445 ret = unlink(full_path);
448 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
456 static int process_rmdir(const char *path, void *user)
459 struct btrfs_receive *r = user;
460 char *full_path = path_cat(r->full_subvol_path, path);
463 fprintf(stderr, "rmdir %s\n", path);
465 ret = rmdir(full_path);
468 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
477 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
481 if (r->write_fd != -1) {
482 if (strcmp(r->write_path, path) == 0)
488 r->write_fd = open(path, O_RDWR);
489 if (r->write_fd < 0) {
491 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
496 r->write_path = strdup(path);
502 static int close_inode_for_write(struct btrfs_receive *r)
506 if(r->write_fd == -1)
511 r->write_path[0] = 0;
517 static int process_write(const char *path, const void *data, u64 offset,
521 struct btrfs_receive *r = user;
522 char *full_path = path_cat(r->full_subvol_path, path);
526 ret = open_inode_for_write(r, full_path);
531 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
535 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
536 path, strerror(-ret));
547 static int process_clone(const char *path, u64 offset, u64 len,
548 const u8 *clone_uuid, u64 clone_ctransid,
549 const char *clone_path, u64 clone_offset,
553 struct btrfs_receive *r = user;
554 struct btrfs_ioctl_clone_range_args clone_args;
555 struct subvol_info *si = NULL;
556 char *full_path = path_cat(r->full_subvol_path, path);
557 char *subvol_path = NULL;
558 char *full_clone_path = NULL;
561 ret = open_inode_for_write(r, full_path);
565 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
566 subvol_search_by_received_uuid);
568 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
569 BTRFS_FSID_SIZE) == 0) {
570 /* TODO check generation of extent */
571 subvol_path = strdup(r->cur_subvol->path);
574 fprintf(stderr, "ERROR: did not find source subvol.\n");
578 /*if (rs_args.ctransid > rs_args.rtransid) {
581 fprintf(stderr, "ERROR: subvolume %s was "
582 "modified after it was "
584 r->subvol_parent_name);
587 fprintf(stderr, "WARNING: subvolume %s was "
588 "modified after it was "
590 r->subvol_parent_name);
593 subvol_path = strdup(si->path);
596 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
598 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
601 fprintf(stderr, "ERROR: failed to open %s. %s\n",
602 full_clone_path, strerror(-ret));
606 clone_args.src_fd = clone_fd;
607 clone_args.src_offset = clone_offset;
608 clone_args.src_length = len;
609 clone_args.dest_offset = offset;
610 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
613 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
614 path, strerror(-ret));
620 free(full_clone_path);
628 static int process_set_xattr(const char *path, const char *name,
629 const void *data, int len, void *user)
632 struct btrfs_receive *r = user;
633 char *full_path = path_cat(r->full_subvol_path, path);
635 if (g_verbose >= 2) {
636 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
637 "data=%.*s\n", path, name, len,
641 ret = lsetxattr(full_path, name, data, len, 0);
644 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
645 path, name, len, (char*)data, strerror(-ret));
654 static int process_remove_xattr(const char *path, const char *name, void *user)
657 struct btrfs_receive *r = user;
658 char *full_path = path_cat(r->full_subvol_path, path);
660 if (g_verbose >= 2) {
661 fprintf(stderr, "remove_xattr %s - name=%s\n",
665 ret = lremovexattr(full_path, name);
668 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
669 path, name, strerror(-ret));
678 static int process_truncate(const char *path, u64 size, void *user)
681 struct btrfs_receive *r = user;
682 char *full_path = path_cat(r->full_subvol_path, path);
685 fprintf(stderr, "truncate %s size=%llu\n", path, size);
687 ret = truncate(full_path, size);
690 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
691 path, strerror(-ret));
700 static int process_chmod(const char *path, u64 mode, void *user)
703 struct btrfs_receive *r = user;
704 char *full_path = path_cat(r->full_subvol_path, path);
707 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
709 ret = chmod(full_path, mode);
712 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
713 path, strerror(-ret));
722 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
725 struct btrfs_receive *r = user;
726 char *full_path = path_cat(r->full_subvol_path, path);
729 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
732 ret = lchown(full_path, uid, gid);
735 fprintf(stderr, "ERROR: chown %s failed. %s\n",
736 path, strerror(-ret));
745 static int process_utimes(const char *path, struct timespec *at,
746 struct timespec *mt, struct timespec *ct,
750 struct btrfs_receive *r = user;
751 char *full_path = path_cat(r->full_subvol_path, path);
752 struct timespec tv[2];
755 fprintf(stderr, "utimes %s\n", path);
759 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
762 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
763 path, strerror(-ret));
773 struct btrfs_send_ops send_ops = {
774 .subvol = process_subvol,
775 .snapshot = process_snapshot,
776 .mkfile = process_mkfile,
777 .mkdir = process_mkdir,
778 .mknod = process_mknod,
779 .mkfifo = process_mkfifo,
780 .mksock = process_mksock,
781 .symlink = process_symlink,
782 .rename = process_rename,
783 .link = process_link,
784 .unlink = process_unlink,
785 .rmdir = process_rmdir,
786 .write = process_write,
787 .clone = process_clone,
788 .set_xattr = process_set_xattr,
789 .remove_xattr = process_remove_xattr,
790 .truncate = process_truncate,
791 .chmod = process_chmod,
792 .chown = process_chown,
793 .utimes = process_utimes,
796 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
801 r->root_path = strdup(tomnt);
802 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
805 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
810 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
815 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
821 ret = close_inode_for_write(r);
824 ret = finish_subvol(r);
831 if (r->write_fd != -1) {
838 r->write_path = NULL;
839 free(r->full_subvol_path);
840 r->full_subvol_path = NULL;
842 free(r->cur_subvol->path);
844 r->cur_subvol = NULL;
846 subvol_uuid_search_finit(&r->sus);
847 if (r->mnt_fd != -1) {
854 static int do_cmd_receive(int argc, char **argv)
858 char *fromfile = NULL;
859 struct btrfs_receive r;
860 int receive_fd = fileno(stdin);
864 memset(&r, 0, sizeof(r));
868 while ((c = getopt(argc, argv, "vf:")) != -1) {
878 fprintf(stderr, "ERROR: receive args invalid.\n");
883 if (optind + 1 != argc) {
884 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
888 tomnt = argv[optind];
891 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
892 if (receive_fd < 0) {
893 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
898 ret = do_receive(&r, tomnt, receive_fd);
903 static const char * const receive_cmd_group_usage[] = {
904 "btrfs receive <command> <args>",
908 const char * const cmd_receive_usage[] = {
909 "btrfs receive [-v] [-f <infile>] <mount>",
910 "Receive subvolumes from stdin.",
911 "Receives one or more subvolumes that were previously ",
912 "sent with btrfs send. The received subvolumes are stored",
914 "btrfs receive will fail in case a receiving subvolume",
915 "already exists. It will also fail in case a previously",
916 "received subvolume was changed after it was received.",
917 "After receiving a subvolume, it is immediately set to",
919 "-v Enable verbose debug output. Each",
920 " occurrence of this option increases the",
921 " verbose level more.",
922 "-f <infile> By default, btrfs receive uses stdin",
923 " to receive the subvolumes. Use this",
924 " option to specify a file to use instead.",
928 const struct cmd_group receive_cmd_group = {
929 receive_cmd_group_usage, NULL, {
930 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
935 int cmd_receive(int argc, char **argv)
937 return do_cmd_receive(argc, argv);