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 free(r->full_subvol_path);
155 r->full_subvol_path = path_cat(r->root_path, path);
157 fprintf(stderr, "At subvol %s\n", path);
159 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
160 r->cur_subvol->stransid = ctransid;
163 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
164 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
166 r->cur_subvol->stransid);
169 memset(&args_v1, 0, sizeof(args_v1));
170 strncpy_null(args_v1.name, path);
171 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
174 fprintf(stderr, "ERROR: creating subvolume %s failed. "
175 "%s\n", path, strerror(-ret));
183 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
184 const u8 *parent_uuid, u64 parent_ctransid,
188 struct btrfs_receive *r = user;
190 struct btrfs_ioctl_vol_args_v2 args_v2;
192 ret = finish_subvol(r);
196 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
197 r->parent_subvol = NULL;
199 r->cur_subvol->path = strdup(path);
200 free(r->full_subvol_path);
201 r->full_subvol_path = path_cat(r->root_path, path);
203 fprintf(stderr, "At snapshot %s\n", path);
205 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
206 r->cur_subvol->stransid = ctransid;
209 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
210 fprintf(stderr, "receiving snapshot %s uuid=%s, "
211 "ctransid=%llu ", path, uuid_str,
212 r->cur_subvol->stransid);
213 uuid_unparse(parent_uuid, uuid_str);
214 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
215 uuid_str, parent_ctransid);
218 memset(&args_v2, 0, sizeof(args_v2));
219 strncpy_null(args_v2.name, path);
221 r->parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
222 parent_ctransid, NULL, subvol_search_by_received_uuid);
223 if (!r->parent_subvol) {
225 fprintf(stderr, "ERROR: could not find parent subvolume\n");
229 /*if (rs_args.ctransid > rs_args.rtransid) {
232 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
235 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
239 args_v2.fd = openat(r->mnt_fd, r->parent_subvol->path,
240 O_RDONLY | O_NOATIME);
241 if (args_v2.fd < 0) {
243 fprintf(stderr, "ERROR: open %s failed. %s\n",
244 r->parent_subvol->path, strerror(-ret));
248 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
252 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
253 "failed. %s\n", r->parent_subvol->path,
254 path, strerror(-ret));
262 static int process_mkfile(const char *path, void *user)
265 struct btrfs_receive *r = user;
266 char *full_path = path_cat(r->full_subvol_path, path);
269 fprintf(stderr, "mkfile %s\n", path);
271 ret = creat(full_path, 0600);
274 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
286 static int process_mkdir(const char *path, void *user)
289 struct btrfs_receive *r = user;
290 char *full_path = path_cat(r->full_subvol_path, path);
293 fprintf(stderr, "mkdir %s\n", path);
295 ret = mkdir(full_path, 0700);
298 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
306 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
309 struct btrfs_receive *r = user;
310 char *full_path = path_cat(r->full_subvol_path, path);
313 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
316 ret = mknod(full_path, mode & S_IFMT, dev);
319 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
327 static int process_mkfifo(const char *path, void *user)
330 struct btrfs_receive *r = user;
331 char *full_path = path_cat(r->full_subvol_path, path);
334 fprintf(stderr, "mkfifo %s\n", path);
336 ret = mkfifo(full_path, 0600);
339 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
347 static int process_mksock(const char *path, void *user)
350 struct btrfs_receive *r = user;
351 char *full_path = path_cat(r->full_subvol_path, path);
354 fprintf(stderr, "mksock %s\n", path);
356 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
359 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
367 static int process_symlink(const char *path, const char *lnk, void *user)
370 struct btrfs_receive *r = user;
371 char *full_path = path_cat(r->full_subvol_path, path);
374 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
376 ret = symlink(lnk, full_path);
379 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
380 lnk, strerror(-ret));
387 static int process_rename(const char *from, const char *to, void *user)
390 struct btrfs_receive *r = user;
391 char *full_from = path_cat(r->full_subvol_path, from);
392 char *full_to = path_cat(r->full_subvol_path, to);
395 fprintf(stderr, "rename %s -> %s\n", from, to);
397 ret = rename(full_from, full_to);
400 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
409 static int process_link(const char *path, const char *lnk, void *user)
412 struct btrfs_receive *r = user;
413 char *full_path = path_cat(r->full_subvol_path, path);
414 char *full_link_path = path_cat(r->full_subvol_path, lnk);
417 fprintf(stderr, "link %s -> %s\n", path, lnk);
419 ret = link(full_link_path, full_path);
422 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
423 lnk, strerror(-ret));
427 free(full_link_path);
432 static int process_unlink(const char *path, void *user)
435 struct btrfs_receive *r = user;
436 char *full_path = path_cat(r->full_subvol_path, path);
439 fprintf(stderr, "unlink %s\n", path);
441 ret = unlink(full_path);
444 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
452 static int process_rmdir(const char *path, void *user)
455 struct btrfs_receive *r = user;
456 char *full_path = path_cat(r->full_subvol_path, path);
459 fprintf(stderr, "rmdir %s\n", path);
461 ret = rmdir(full_path);
464 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
473 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
477 if (r->write_fd != -1) {
478 if (strcmp(r->write_path, path) == 0)
484 r->write_fd = open(path, O_RDWR);
485 if (r->write_fd < 0) {
487 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
492 r->write_path = strdup(path);
498 static int close_inode_for_write(struct btrfs_receive *r)
502 if(r->write_fd == -1)
507 r->write_path[0] = 0;
513 static int process_write(const char *path, const void *data, u64 offset,
517 struct btrfs_receive *r = user;
518 char *full_path = path_cat(r->full_subvol_path, path);
522 ret = open_inode_for_write(r, full_path);
527 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
531 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
532 path, strerror(-ret));
543 static int process_clone(const char *path, u64 offset, u64 len,
544 const u8 *clone_uuid, u64 clone_ctransid,
545 const char *clone_path, u64 clone_offset,
549 struct btrfs_receive *r = user;
550 struct btrfs_ioctl_clone_range_args clone_args;
551 struct subvol_info *si = NULL;
552 char *full_path = path_cat(r->full_subvol_path, path);
553 char *subvol_path = NULL;
554 char *full_clone_path = NULL;
557 ret = open_inode_for_write(r, full_path);
561 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
562 subvol_search_by_received_uuid);
564 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
565 BTRFS_FSID_SIZE) == 0) {
566 /* TODO check generation of extent */
567 subvol_path = strdup(r->cur_subvol->path);
570 fprintf(stderr, "ERROR: did not find source subvol.\n");
574 /*if (rs_args.ctransid > rs_args.rtransid) {
577 fprintf(stderr, "ERROR: subvolume %s was "
578 "modified after it was "
580 r->subvol_parent_name);
583 fprintf(stderr, "WARNING: subvolume %s was "
584 "modified after it was "
586 r->subvol_parent_name);
589 subvol_path = strdup(si->path);
592 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
594 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
597 fprintf(stderr, "ERROR: failed to open %s. %s\n",
598 full_clone_path, strerror(-ret));
602 clone_args.src_fd = clone_fd;
603 clone_args.src_offset = clone_offset;
604 clone_args.src_length = len;
605 clone_args.dest_offset = offset;
606 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
609 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
610 path, strerror(-ret));
616 free(full_clone_path);
624 static int process_set_xattr(const char *path, const char *name,
625 const void *data, int len, void *user)
628 struct btrfs_receive *r = user;
629 char *full_path = path_cat(r->full_subvol_path, path);
631 if (g_verbose >= 2) {
632 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
633 "data=%.*s\n", path, name, len,
637 ret = lsetxattr(full_path, name, data, len, 0);
640 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
641 path, name, len, (char*)data, strerror(-ret));
650 static int process_remove_xattr(const char *path, const char *name, 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, "remove_xattr %s - name=%s\n",
661 ret = lremovexattr(full_path, name);
664 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
665 path, name, strerror(-ret));
674 static int process_truncate(const char *path, u64 size, void *user)
677 struct btrfs_receive *r = user;
678 char *full_path = path_cat(r->full_subvol_path, path);
681 fprintf(stderr, "truncate %s size=%llu\n", path, size);
683 ret = truncate(full_path, size);
686 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
687 path, strerror(-ret));
696 static int process_chmod(const char *path, u64 mode, void *user)
699 struct btrfs_receive *r = user;
700 char *full_path = path_cat(r->full_subvol_path, path);
703 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
705 ret = chmod(full_path, mode);
708 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
709 path, strerror(-ret));
718 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
721 struct btrfs_receive *r = user;
722 char *full_path = path_cat(r->full_subvol_path, path);
725 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
728 ret = lchown(full_path, uid, gid);
731 fprintf(stderr, "ERROR: chown %s failed. %s\n",
732 path, strerror(-ret));
741 static int process_utimes(const char *path, struct timespec *at,
742 struct timespec *mt, struct timespec *ct,
746 struct btrfs_receive *r = user;
747 char *full_path = path_cat(r->full_subvol_path, path);
748 struct timespec tv[2];
751 fprintf(stderr, "utimes %s\n", path);
755 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
758 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
759 path, strerror(-ret));
769 struct btrfs_send_ops send_ops = {
770 .subvol = process_subvol,
771 .snapshot = process_snapshot,
772 .mkfile = process_mkfile,
773 .mkdir = process_mkdir,
774 .mknod = process_mknod,
775 .mkfifo = process_mkfifo,
776 .mksock = process_mksock,
777 .symlink = process_symlink,
778 .rename = process_rename,
779 .link = process_link,
780 .unlink = process_unlink,
781 .rmdir = process_rmdir,
782 .write = process_write,
783 .clone = process_clone,
784 .set_xattr = process_set_xattr,
785 .remove_xattr = process_remove_xattr,
786 .truncate = process_truncate,
787 .chmod = process_chmod,
788 .chown = process_chown,
789 .utimes = process_utimes,
792 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
797 r->root_path = strdup(tomnt);
798 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
801 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
806 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);
827 if (r->write_fd != -1) {
834 r->write_path = NULL;
835 free(r->full_subvol_path);
836 r->full_subvol_path = NULL;
838 free(r->cur_subvol->path);
840 r->cur_subvol = NULL;
842 subvol_uuid_search_finit(&r->sus);
843 if (r->mnt_fd != -1) {
850 static int do_cmd_receive(int argc, char **argv)
854 char *fromfile = NULL;
855 struct btrfs_receive r;
856 int receive_fd = fileno(stdin);
860 memset(&r, 0, sizeof(r));
864 while ((c = getopt(argc, argv, "vf:")) != -1) {
874 fprintf(stderr, "ERROR: receive args invalid.\n");
879 if (optind + 1 != argc) {
880 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
884 tomnt = argv[optind];
887 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
888 if (receive_fd < 0) {
889 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
894 ret = do_receive(&r, tomnt, receive_fd);
899 static const char * const receive_cmd_group_usage[] = {
900 "btrfs receive <command> <args>",
904 const char * const cmd_receive_usage[] = {
905 "btrfs receive [-v] [-f <infile>] <mount>",
906 "Receive subvolumes from stdin.",
907 "Receives one or more subvolumes that were previously ",
908 "sent with btrfs send. The received subvolumes are stored",
910 "btrfs receive will fail in case a receiving subvolume",
911 "already exists. It will also fail in case a previously",
912 "received subvolume was changed after it was received.",
913 "After receiving a subvolume, it is immediately set to",
915 "-v Enable verbose debug output. Each",
916 " occurrence of this option increases the",
917 " verbose level more.",
918 "-f <infile> By default, btrfs receive uses stdin",
919 " to receive the subvolumes. Use this",
920 " option to specify a file to use instead.",
924 const struct cmd_group receive_cmd_group = {
925 receive_cmd_group_usage, NULL, {
926 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
931 int cmd_receive(int argc, char **argv)
933 return do_cmd_receive(argc, argv);