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>
49 #include "send-stream.h"
50 #include "send-utils.h"
52 static int g_verbose = 0;
62 char *full_subvol_path;
64 struct subvol_info *cur_subvol;
65 struct subvol_info *parent_subvol;
67 struct subvol_uuid_search sus;
70 static int finish_subvol(struct btrfs_receive *r)
74 struct btrfs_ioctl_received_subvol_args rs_args;
78 if (r->cur_subvol == NULL)
81 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
82 O_RDONLY | O_NOATIME);
85 fprintf(stderr, "ERROR: open %s failed. %s\n",
86 r->cur_subvol->path, strerror(-ret));
90 memset(&rs_args, 0, sizeof(rs_args));
91 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
92 rs_args.stransid = r->cur_subvol->stransid;
95 uuid_unparse((u8*)rs_args.uuid, uuid_str);
96 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
97 "stransid=%llu\n", uuid_str, rs_args.stransid);
100 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
103 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
107 r->cur_subvol->rtransid = rs_args.rtransid;
109 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
112 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
117 flags |= BTRFS_SUBVOL_RDONLY;
119 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
122 fprintf(stderr, "ERROR: failed to make subvolume read only. "
123 "%s\n", strerror(-ret));
127 subvol_uuid_search_add(&r->sus, r->cur_subvol);
128 r->cur_subvol = NULL;
137 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
141 struct btrfs_receive *r = user;
142 struct btrfs_ioctl_vol_args args_v1;
145 ret = finish_subvol(r);
149 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
150 r->parent_subvol = NULL;
152 r->cur_subvol->path = strdup(path);
153 r->full_subvol_path = path_cat(r->root_path, path);
155 fprintf(stderr, "At subvol %s\n", path);
157 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
158 r->cur_subvol->stransid = ctransid;
161 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
162 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
164 r->cur_subvol->stransid);
167 memset(&args_v1, 0, sizeof(args_v1));
168 strcpy(args_v1.name, path);
169 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
172 fprintf(stderr, "ERROR: creating subvolume %s failed. "
173 "%s\n", path, strerror(-ret));
181 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
182 const u8 *parent_uuid, u64 parent_ctransid,
186 struct btrfs_receive *r = user;
188 struct btrfs_ioctl_vol_args_v2 args_v2;
190 ret = finish_subvol(r);
194 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
195 r->parent_subvol = NULL;
197 r->cur_subvol->path = strdup(path);
198 r->full_subvol_path = path_cat(r->root_path, path);
200 fprintf(stderr, "At snapshot %s\n", path);
202 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
203 r->cur_subvol->stransid = ctransid;
206 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
207 fprintf(stderr, "receiving snapshot %s uuid=%s, "
208 "ctransid=%llu ", path, uuid_str,
209 r->cur_subvol->stransid);
210 uuid_unparse(parent_uuid, uuid_str);
211 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
212 uuid_str, parent_ctransid);
215 memset(&args_v2, 0, sizeof(args_v2));
216 strcpy(args_v2.name, path);
218 r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
219 parent_ctransid, NULL, subvol_search_by_received_uuid);
220 if (!r->parent_subvol) {
222 fprintf(stderr, "ERROR: could not find parent subvolume\n");
226 /*if (rs_args.ctransid > rs_args.rtransid) {
229 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
232 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
236 args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
237 O_RDONLY | O_NOATIME);
238 if (args_v2.fd < 0) {
240 fprintf(stderr, "ERROR: open %s failed. %s\n",
241 r->parent_subvol->path, strerror(-ret));
245 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
249 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
250 "failed. %s\n", r->parent_subvol->path,
251 path, strerror(-ret));
259 static int process_mkfile(const char *path, void *user)
262 struct btrfs_receive *r = user;
263 char *full_path = path_cat(r->full_subvol_path, path);
266 fprintf(stderr, "mkfile %s\n", path);
268 ret = creat(full_path, 0600);
271 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
283 static int process_mkdir(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, "mkdir %s\n", path);
292 ret = mkdir(full_path, 0700);
295 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
303 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
306 struct btrfs_receive *r = user;
307 char *full_path = path_cat(r->full_subvol_path, path);
310 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
313 ret = mknod(full_path, mode & S_IFMT, dev);
316 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
324 static int process_mkfifo(const char *path, void *user)
327 struct btrfs_receive *r = user;
328 char *full_path = path_cat(r->full_subvol_path, path);
331 fprintf(stderr, "mkfifo %s\n", path);
333 ret = mkfifo(full_path, 0600);
336 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
344 static int process_mksock(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, "mksock %s\n", path);
353 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
356 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
364 static int process_symlink(const char *path, const char *lnk, void *user)
367 struct btrfs_receive *r = user;
368 char *full_path = path_cat(r->full_subvol_path, path);
371 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
373 ret = symlink(lnk, full_path);
376 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
377 lnk, strerror(-ret));
384 static int process_rename(const char *from, const char *to, void *user)
387 struct btrfs_receive *r = user;
388 char *full_from = path_cat(r->full_subvol_path, from);
389 char *full_to = path_cat(r->full_subvol_path, to);
392 fprintf(stderr, "rename %s -> %s\n", from, to);
394 ret = rename(full_from, full_to);
397 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
406 static int process_link(const char *path, const char *lnk, void *user)
409 struct btrfs_receive *r = user;
410 char *full_path = path_cat(r->full_subvol_path, path);
411 char *full_link_path = path_cat(r->full_subvol_path, lnk);
414 fprintf(stderr, "link %s -> %s\n", path, lnk);
416 ret = link(full_link_path, full_path);
419 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
420 lnk, strerror(-ret));
424 free(full_link_path);
429 static int process_unlink(const char *path, void *user)
432 struct btrfs_receive *r = user;
433 char *full_path = path_cat(r->full_subvol_path, path);
436 fprintf(stderr, "unlink %s\n", path);
438 ret = unlink(full_path);
441 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
449 static int process_rmdir(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, "rmdir %s\n", path);
458 ret = rmdir(full_path);
461 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
470 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
474 if (r->write_fd != -1) {
475 if (strcmp(r->write_path, path) == 0)
481 r->write_fd = open(path, O_RDWR);
482 if (r->write_fd < 0) {
484 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
489 r->write_path = strdup(path);
495 static int close_inode_for_write(struct btrfs_receive *r)
499 if(r->write_fd == -1)
504 r->write_path[0] = 0;
510 static int process_write(const char *path, const void *data, u64 offset,
514 struct btrfs_receive *r = user;
515 char *full_path = path_cat(r->full_subvol_path, path);
519 ret = open_inode_for_write(r, full_path);
524 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
528 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
529 path, strerror(-ret));
540 static int process_clone(const char *path, u64 offset, u64 len,
541 const u8 *clone_uuid, u64 clone_ctransid,
542 const char *clone_path, u64 clone_offset,
546 struct btrfs_receive *r = user;
547 struct btrfs_ioctl_clone_range_args clone_args;
548 struct subvol_info *si = NULL;
549 char *full_path = path_cat(r->full_subvol_path, path);
550 char *subvol_path = NULL;
551 char *full_clone_path = NULL;
554 ret = open_inode_for_write(r, full_path);
558 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
559 subvol_search_by_received_uuid);
561 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
562 BTRFS_FSID_SIZE) == 0) {
563 /* TODO check generation of extent */
564 subvol_path = strdup(r->cur_subvol->path);
567 fprintf(stderr, "ERROR: did not find source subvol.\n");
571 /*if (rs_args.ctransid > rs_args.rtransid) {
574 fprintf(stderr, "ERROR: subvolume %s was "
575 "modified after it was "
577 r->subvol_parent_name);
580 fprintf(stderr, "WARNING: subvolume %s was "
581 "modified after it was "
583 r->subvol_parent_name);
586 subvol_path = strdup(si->path);
589 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
591 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
594 fprintf(stderr, "ERROR: failed to open %s. %s\n",
595 full_clone_path, strerror(-ret));
599 clone_args.src_fd = clone_fd;
600 clone_args.src_offset = clone_offset;
601 clone_args.src_length = len;
602 clone_args.dest_offset = offset;
603 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
606 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
607 path, strerror(-ret));
613 free(full_clone_path);
621 static int process_set_xattr(const char *path, const char *name,
622 const void *data, int len, void *user)
625 struct btrfs_receive *r = user;
626 char *full_path = path_cat(r->full_subvol_path, path);
628 if (g_verbose >= 1) {
629 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
630 "data=%.*s\n", path, name, len,
634 ret = lsetxattr(full_path, name, data, len, 0);
637 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
638 path, name, len, (char*)data, strerror(-ret));
647 static int process_remove_xattr(const char *path, const char *name, void *user)
650 struct btrfs_receive *r = user;
651 char *full_path = path_cat(r->full_subvol_path, path);
653 if (g_verbose >= 1) {
654 fprintf(stderr, "remove_xattr %s - name=%s\n",
658 ret = lremovexattr(full_path, name);
661 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
662 path, name, strerror(-ret));
671 static int process_truncate(const char *path, u64 size, void *user)
674 struct btrfs_receive *r = user;
675 char *full_path = path_cat(r->full_subvol_path, path);
678 fprintf(stderr, "truncate %s size=%llu\n", path, size);
680 ret = truncate(full_path, size);
683 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
684 path, strerror(-ret));
693 static int process_chmod(const char *path, u64 mode, void *user)
696 struct btrfs_receive *r = user;
697 char *full_path = path_cat(r->full_subvol_path, path);
700 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
702 ret = chmod(full_path, mode);
705 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
706 path, strerror(-ret));
715 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
718 struct btrfs_receive *r = user;
719 char *full_path = path_cat(r->full_subvol_path, path);
722 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
725 ret = lchown(full_path, uid, gid);
728 fprintf(stderr, "ERROR: chown %s failed. %s\n",
729 path, strerror(-ret));
738 static int process_utimes(const char *path, struct timespec *at,
739 struct timespec *mt, struct timespec *ct,
743 struct btrfs_receive *r = user;
744 char *full_path = path_cat(r->full_subvol_path, path);
745 struct timespec tv[2];
748 fprintf(stderr, "utimes %s\n", path);
752 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
755 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
756 path, strerror(-ret));
766 struct btrfs_send_ops send_ops = {
767 .subvol = process_subvol,
768 .snapshot = process_snapshot,
769 .mkfile = process_mkfile,
770 .mkdir = process_mkdir,
771 .mknod = process_mknod,
772 .mkfifo = process_mkfifo,
773 .mksock = process_mksock,
774 .symlink = process_symlink,
775 .rename = process_rename,
776 .link = process_link,
777 .unlink = process_unlink,
778 .rmdir = process_rmdir,
779 .write = process_write,
780 .clone = process_clone,
781 .set_xattr = process_set_xattr,
782 .remove_xattr = process_remove_xattr,
783 .truncate = process_truncate,
784 .chmod = process_chmod,
785 .chown = process_chown,
786 .utimes = process_utimes,
789 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
794 r->root_path = strdup(tomnt);
795 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
798 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
803 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
810 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
816 ret = close_inode_for_write(r);
819 ret = finish_subvol(r);
829 static int do_cmd_receive(int argc, char **argv)
833 char *fromfile = NULL;
834 struct btrfs_receive r;
835 int receive_fd = fileno(stdin);
839 memset(&r, 0, sizeof(r));
841 while ((c = getopt(argc, argv, "vf:")) != -1) {
851 fprintf(stderr, "ERROR: receive args invalid.\n");
856 if (optind + 1 != argc) {
857 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
861 tomnt = argv[optind];
864 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
865 if (receive_fd < 0) {
866 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
871 ret = do_receive(&r, tomnt, receive_fd);
876 static const char * const receive_cmd_group_usage[] = {
877 "btrfs receive <command> <args>",
881 const char * const cmd_receive_usage[] = {
882 "btrfs receive [-v] [-f <infile>] <mount>",
883 "Receive subvolumes from stdin.",
884 "Receives one or more subvolumes that were previously ",
885 "sent with btrfs send. The received subvolumes are stored",
887 "btrfs receive will fail in case a receiving subvolume",
888 "already exists. It will also fail in case a previously",
889 "received subvolume was changed after it was received.",
890 "After receiving a subvolume, it is immediately set to",
892 "-v Enable verbose debug output. Each",
893 " occurrence of this option increases the",
894 " verbose level more.",
895 "-f <infile> By default, btrfs receive uses stdin",
896 " to receive the subvolumes. Use this",
897 " option to specify a file to use instead.",
901 const struct cmd_group receive_cmd_group = {
902 receive_cmd_group_usage, NULL, {
903 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
908 int cmd_receive(int argc, char **argv)
910 return do_cmd_receive(argc, argv);