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>
50 #include "send-stream.h"
51 #include "send-utils.h"
53 static int g_verbose = 0;
63 char *full_subvol_path;
65 struct subvol_info *cur_subvol;
66 struct subvol_info *parent_subvol;
68 struct subvol_uuid_search sus;
71 static int finish_subvol(struct btrfs_receive *r)
75 struct btrfs_ioctl_received_subvol_args rs_args;
79 if (r->cur_subvol == NULL)
82 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
83 O_RDONLY | O_NOATIME);
86 fprintf(stderr, "ERROR: open %s failed. %s\n",
87 r->cur_subvol->path, strerror(-ret));
91 memset(&rs_args, 0, sizeof(rs_args));
92 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
93 rs_args.stransid = r->cur_subvol->stransid;
96 uuid_unparse((u8*)rs_args.uuid, uuid_str);
97 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
98 "stransid=%llu\n", uuid_str, rs_args.stransid);
101 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
104 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
108 r->cur_subvol->rtransid = rs_args.rtransid;
110 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
113 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
118 flags |= BTRFS_SUBVOL_RDONLY;
120 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
123 fprintf(stderr, "ERROR: failed to make subvolume read only. "
124 "%s\n", strerror(-ret));
128 subvol_uuid_search_add(&r->sus, r->cur_subvol);
129 r->cur_subvol = NULL;
138 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
142 struct btrfs_receive *r = user;
143 struct btrfs_ioctl_vol_args args_v1;
146 ret = finish_subvol(r);
150 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
151 r->parent_subvol = NULL;
153 r->cur_subvol->path = strdup(path);
154 r->full_subvol_path = path_cat(r->root_path, path);
156 fprintf(stderr, "At subvol %s\n", path);
158 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
159 r->cur_subvol->stransid = ctransid;
162 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
163 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
165 r->cur_subvol->stransid);
168 memset(&args_v1, 0, sizeof(args_v1));
169 strncpy_null(args_v1.name, path);
170 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
173 fprintf(stderr, "ERROR: creating subvolume %s failed. "
174 "%s\n", path, strerror(-ret));
182 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
183 const u8 *parent_uuid, u64 parent_ctransid,
187 struct btrfs_receive *r = user;
189 struct btrfs_ioctl_vol_args_v2 args_v2;
191 ret = finish_subvol(r);
195 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
196 r->parent_subvol = NULL;
198 r->cur_subvol->path = strdup(path);
199 r->full_subvol_path = path_cat(r->root_path, path);
201 fprintf(stderr, "At snapshot %s\n", path);
203 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
204 r->cur_subvol->stransid = ctransid;
207 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
208 fprintf(stderr, "receiving snapshot %s uuid=%s, "
209 "ctransid=%llu ", path, uuid_str,
210 r->cur_subvol->stransid);
211 uuid_unparse(parent_uuid, uuid_str);
212 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
213 uuid_str, parent_ctransid);
216 memset(&args_v2, 0, sizeof(args_v2));
217 strncpy_null(args_v2.name, path);
219 r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
220 parent_ctransid, NULL, subvol_search_by_received_uuid);
221 if (!r->parent_subvol) {
223 fprintf(stderr, "ERROR: could not find parent subvolume\n");
227 /*if (rs_args.ctransid > rs_args.rtransid) {
230 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
233 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
237 args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
238 O_RDONLY | O_NOATIME);
239 if (args_v2.fd < 0) {
241 fprintf(stderr, "ERROR: open %s failed. %s\n",
242 r->parent_subvol->path, strerror(-ret));
246 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
250 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
251 "failed. %s\n", r->parent_subvol->path,
252 path, strerror(-ret));
260 static int process_mkfile(const char *path, void *user)
263 struct btrfs_receive *r = user;
264 char *full_path = path_cat(r->full_subvol_path, path);
267 fprintf(stderr, "mkfile %s\n", path);
269 ret = creat(full_path, 0600);
272 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
284 static int process_mkdir(const char *path, void *user)
287 struct btrfs_receive *r = user;
288 char *full_path = path_cat(r->full_subvol_path, path);
291 fprintf(stderr, "mkdir %s\n", path);
293 ret = mkdir(full_path, 0700);
296 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
304 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
307 struct btrfs_receive *r = user;
308 char *full_path = path_cat(r->full_subvol_path, path);
311 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
314 ret = mknod(full_path, mode & S_IFMT, dev);
317 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
325 static int process_mkfifo(const char *path, void *user)
328 struct btrfs_receive *r = user;
329 char *full_path = path_cat(r->full_subvol_path, path);
332 fprintf(stderr, "mkfifo %s\n", path);
334 ret = mkfifo(full_path, 0600);
337 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
345 static int process_mksock(const char *path, void *user)
348 struct btrfs_receive *r = user;
349 char *full_path = path_cat(r->full_subvol_path, path);
352 fprintf(stderr, "mksock %s\n", path);
354 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
357 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
365 static int process_symlink(const char *path, const char *lnk, void *user)
368 struct btrfs_receive *r = user;
369 char *full_path = path_cat(r->full_subvol_path, path);
372 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
374 ret = symlink(lnk, full_path);
377 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
378 lnk, strerror(-ret));
385 static int process_rename(const char *from, const char *to, void *user)
388 struct btrfs_receive *r = user;
389 char *full_from = path_cat(r->full_subvol_path, from);
390 char *full_to = path_cat(r->full_subvol_path, to);
393 fprintf(stderr, "rename %s -> %s\n", from, to);
395 ret = rename(full_from, full_to);
398 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
407 static int process_link(const char *path, const char *lnk, void *user)
410 struct btrfs_receive *r = user;
411 char *full_path = path_cat(r->full_subvol_path, path);
412 char *full_link_path = path_cat(r->full_subvol_path, lnk);
415 fprintf(stderr, "link %s -> %s\n", path, lnk);
417 ret = link(full_link_path, full_path);
420 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
421 lnk, strerror(-ret));
425 free(full_link_path);
430 static int process_unlink(const char *path, void *user)
433 struct btrfs_receive *r = user;
434 char *full_path = path_cat(r->full_subvol_path, path);
437 fprintf(stderr, "unlink %s\n", path);
439 ret = unlink(full_path);
442 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
450 static int process_rmdir(const char *path, void *user)
453 struct btrfs_receive *r = user;
454 char *full_path = path_cat(r->full_subvol_path, path);
457 fprintf(stderr, "rmdir %s\n", path);
459 ret = rmdir(full_path);
462 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
471 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
475 if (r->write_fd != -1) {
476 if (strcmp(r->write_path, path) == 0)
482 r->write_fd = open(path, O_RDWR);
483 if (r->write_fd < 0) {
485 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
490 r->write_path = strdup(path);
496 static int close_inode_for_write(struct btrfs_receive *r)
500 if(r->write_fd == -1)
505 r->write_path[0] = 0;
511 static int process_write(const char *path, const void *data, u64 offset,
515 struct btrfs_receive *r = user;
516 char *full_path = path_cat(r->full_subvol_path, path);
520 ret = open_inode_for_write(r, full_path);
525 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
529 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
530 path, strerror(-ret));
541 static int process_clone(const char *path, u64 offset, u64 len,
542 const u8 *clone_uuid, u64 clone_ctransid,
543 const char *clone_path, u64 clone_offset,
547 struct btrfs_receive *r = user;
548 struct btrfs_ioctl_clone_range_args clone_args;
549 struct subvol_info *si = NULL;
550 char *full_path = path_cat(r->full_subvol_path, path);
551 char *subvol_path = NULL;
552 char *full_clone_path = NULL;
555 ret = open_inode_for_write(r, full_path);
559 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
560 subvol_search_by_received_uuid);
562 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
563 BTRFS_FSID_SIZE) == 0) {
564 /* TODO check generation of extent */
565 subvol_path = strdup(r->cur_subvol->path);
568 fprintf(stderr, "ERROR: did not find source subvol.\n");
572 /*if (rs_args.ctransid > rs_args.rtransid) {
575 fprintf(stderr, "ERROR: subvolume %s was "
576 "modified after it was "
578 r->subvol_parent_name);
581 fprintf(stderr, "WARNING: subvolume %s was "
582 "modified after it was "
584 r->subvol_parent_name);
587 subvol_path = strdup(si->path);
590 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
592 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
595 fprintf(stderr, "ERROR: failed to open %s. %s\n",
596 full_clone_path, strerror(-ret));
600 clone_args.src_fd = clone_fd;
601 clone_args.src_offset = clone_offset;
602 clone_args.src_length = len;
603 clone_args.dest_offset = offset;
604 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
607 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
608 path, strerror(-ret));
614 free(full_clone_path);
622 static int process_set_xattr(const char *path, const char *name,
623 const void *data, int len, void *user)
626 struct btrfs_receive *r = user;
627 char *full_path = path_cat(r->full_subvol_path, path);
629 if (g_verbose >= 1) {
630 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
631 "data=%.*s\n", path, name, len,
635 ret = lsetxattr(full_path, name, data, len, 0);
638 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
639 path, name, len, (char*)data, strerror(-ret));
648 static int process_remove_xattr(const char *path, const char *name, void *user)
651 struct btrfs_receive *r = user;
652 char *full_path = path_cat(r->full_subvol_path, path);
654 if (g_verbose >= 1) {
655 fprintf(stderr, "remove_xattr %s - name=%s\n",
659 ret = lremovexattr(full_path, name);
662 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
663 path, name, strerror(-ret));
672 static int process_truncate(const char *path, u64 size, void *user)
675 struct btrfs_receive *r = user;
676 char *full_path = path_cat(r->full_subvol_path, path);
679 fprintf(stderr, "truncate %s size=%llu\n", path, size);
681 ret = truncate(full_path, size);
684 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
685 path, strerror(-ret));
694 static int process_chmod(const char *path, u64 mode, void *user)
697 struct btrfs_receive *r = user;
698 char *full_path = path_cat(r->full_subvol_path, path);
701 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
703 ret = chmod(full_path, mode);
706 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
707 path, strerror(-ret));
716 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
719 struct btrfs_receive *r = user;
720 char *full_path = path_cat(r->full_subvol_path, path);
723 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
726 ret = lchown(full_path, uid, gid);
729 fprintf(stderr, "ERROR: chown %s failed. %s\n",
730 path, strerror(-ret));
739 static int process_utimes(const char *path, struct timespec *at,
740 struct timespec *mt, struct timespec *ct,
744 struct btrfs_receive *r = user;
745 char *full_path = path_cat(r->full_subvol_path, path);
746 struct timespec tv[2];
749 fprintf(stderr, "utimes %s\n", path);
753 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
756 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
757 path, strerror(-ret));
767 struct btrfs_send_ops send_ops = {
768 .subvol = process_subvol,
769 .snapshot = process_snapshot,
770 .mkfile = process_mkfile,
771 .mkdir = process_mkdir,
772 .mknod = process_mknod,
773 .mkfifo = process_mkfifo,
774 .mksock = process_mksock,
775 .symlink = process_symlink,
776 .rename = process_rename,
777 .link = process_link,
778 .unlink = process_unlink,
779 .rmdir = process_rmdir,
780 .write = process_write,
781 .clone = process_clone,
782 .set_xattr = process_set_xattr,
783 .remove_xattr = process_remove_xattr,
784 .truncate = process_truncate,
785 .chmod = process_chmod,
786 .chown = process_chown,
787 .utimes = process_utimes,
790 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
795 r->root_path = strdup(tomnt);
796 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
799 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
804 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
811 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
817 ret = close_inode_for_write(r);
820 ret = finish_subvol(r);
830 static int do_cmd_receive(int argc, char **argv)
834 char *fromfile = NULL;
835 struct btrfs_receive r;
836 int receive_fd = fileno(stdin);
840 memset(&r, 0, sizeof(r));
842 while ((c = getopt(argc, argv, "vf:")) != -1) {
852 fprintf(stderr, "ERROR: receive args invalid.\n");
857 if (optind + 1 != argc) {
858 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
862 tomnt = argv[optind];
865 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
866 if (receive_fd < 0) {
867 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
872 ret = do_receive(&r, tomnt, receive_fd);
877 static const char * const receive_cmd_group_usage[] = {
878 "btrfs receive <command> <args>",
882 const char * const cmd_receive_usage[] = {
883 "btrfs receive [-v] [-f <infile>] <mount>",
884 "Receive subvolumes from stdin.",
885 "Receives one or more subvolumes that were previously ",
886 "sent with btrfs send. The received subvolumes are stored",
888 "btrfs receive will fail in case a receiving subvolume",
889 "already exists. It will also fail in case a previously",
890 "received subvolume was changed after it was received.",
891 "After receiving a subvolume, it is immediately set to",
893 "-v Enable verbose debug output. Each",
894 " occurrence of this option increases the",
895 " verbose level more.",
896 "-f <infile> By default, btrfs receive uses stdin",
897 " to receive the subvolumes. Use this",
898 " option to specify a file to use instead.",
902 const struct cmd_group receive_cmd_group = {
903 receive_cmd_group_usage, NULL, {
904 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
909 int cmd_receive(int argc, char **argv)
911 return do_cmd_receive(argc, argv);