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;
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 ret = btrfs_list_get_path_rootid(subvol_fd, &r->cur_subvol->root_id);
131 subvol_uuid_search_add(&r->sus, r->cur_subvol);
132 r->cur_subvol = NULL;
141 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
145 struct btrfs_receive *r = user;
146 struct btrfs_ioctl_vol_args args_v1;
149 ret = finish_subvol(r);
153 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
155 r->cur_subvol->path = strdup(path);
156 free(r->full_subvol_path);
157 r->full_subvol_path = path_cat(r->root_path, path);
159 fprintf(stderr, "At subvol %s\n", path);
161 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
162 r->cur_subvol->stransid = ctransid;
165 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
166 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
168 r->cur_subvol->stransid);
171 memset(&args_v1, 0, sizeof(args_v1));
172 strncpy_null(args_v1.name, path);
173 ret = ioctl(r->mnt_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
176 fprintf(stderr, "ERROR: creating subvolume %s failed. "
177 "%s\n", path, strerror(-ret));
185 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
186 const u8 *parent_uuid, u64 parent_ctransid,
190 struct btrfs_receive *r = user;
192 struct btrfs_ioctl_vol_args_v2 args_v2;
193 struct subvol_info *parent_subvol;
195 ret = finish_subvol(r);
199 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
201 r->cur_subvol->path = strdup(path);
202 free(r->full_subvol_path);
203 r->full_subvol_path = path_cat(r->root_path, path);
205 fprintf(stderr, "At snapshot %s\n", path);
207 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
208 r->cur_subvol->stransid = ctransid;
211 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
212 fprintf(stderr, "receiving snapshot %s uuid=%s, "
213 "ctransid=%llu ", path, uuid_str,
214 r->cur_subvol->stransid);
215 uuid_unparse(parent_uuid, uuid_str);
216 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
217 uuid_str, parent_ctransid);
220 memset(&args_v2, 0, sizeof(args_v2));
221 strncpy_null(args_v2.name, path);
223 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
224 parent_ctransid, NULL, subvol_search_by_received_uuid);
225 if (!parent_subvol) {
227 fprintf(stderr, "ERROR: could not find parent subvolume\n");
231 /*if (rs_args.ctransid > rs_args.rtransid) {
234 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
237 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
241 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
242 O_RDONLY | O_NOATIME);
243 if (args_v2.fd < 0) {
245 fprintf(stderr, "ERROR: open %s failed. %s\n",
246 parent_subvol->path, strerror(-ret));
250 ret = ioctl(r->mnt_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
254 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
255 "failed. %s\n", parent_subvol->path,
256 path, strerror(-ret));
264 static int process_mkfile(const char *path, void *user)
267 struct btrfs_receive *r = user;
268 char *full_path = path_cat(r->full_subvol_path, path);
271 fprintf(stderr, "mkfile %s\n", path);
273 ret = creat(full_path, 0600);
276 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
288 static int process_mkdir(const char *path, void *user)
291 struct btrfs_receive *r = user;
292 char *full_path = path_cat(r->full_subvol_path, path);
295 fprintf(stderr, "mkdir %s\n", path);
297 ret = mkdir(full_path, 0700);
300 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
308 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
311 struct btrfs_receive *r = user;
312 char *full_path = path_cat(r->full_subvol_path, path);
315 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
318 ret = mknod(full_path, mode & S_IFMT, dev);
321 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
329 static int process_mkfifo(const char *path, void *user)
332 struct btrfs_receive *r = user;
333 char *full_path = path_cat(r->full_subvol_path, path);
336 fprintf(stderr, "mkfifo %s\n", path);
338 ret = mkfifo(full_path, 0600);
341 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
349 static int process_mksock(const char *path, void *user)
352 struct btrfs_receive *r = user;
353 char *full_path = path_cat(r->full_subvol_path, path);
356 fprintf(stderr, "mksock %s\n", path);
358 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
361 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
369 static int process_symlink(const char *path, const char *lnk, void *user)
372 struct btrfs_receive *r = user;
373 char *full_path = path_cat(r->full_subvol_path, path);
376 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
378 ret = symlink(lnk, full_path);
381 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
382 lnk, strerror(-ret));
389 static int process_rename(const char *from, const char *to, void *user)
392 struct btrfs_receive *r = user;
393 char *full_from = path_cat(r->full_subvol_path, from);
394 char *full_to = path_cat(r->full_subvol_path, to);
397 fprintf(stderr, "rename %s -> %s\n", from, to);
399 ret = rename(full_from, full_to);
402 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
411 static int process_link(const char *path, const char *lnk, void *user)
414 struct btrfs_receive *r = user;
415 char *full_path = path_cat(r->full_subvol_path, path);
416 char *full_link_path = path_cat(r->full_subvol_path, lnk);
419 fprintf(stderr, "link %s -> %s\n", path, lnk);
421 ret = link(full_link_path, full_path);
424 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
425 lnk, strerror(-ret));
429 free(full_link_path);
434 static int process_unlink(const char *path, void *user)
437 struct btrfs_receive *r = user;
438 char *full_path = path_cat(r->full_subvol_path, path);
441 fprintf(stderr, "unlink %s\n", path);
443 ret = unlink(full_path);
446 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
454 static int process_rmdir(const char *path, void *user)
457 struct btrfs_receive *r = user;
458 char *full_path = path_cat(r->full_subvol_path, path);
461 fprintf(stderr, "rmdir %s\n", path);
463 ret = rmdir(full_path);
466 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
475 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
479 if (r->write_fd != -1) {
480 if (strcmp(r->write_path, path) == 0)
486 r->write_fd = open(path, O_RDWR);
487 if (r->write_fd < 0) {
489 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
494 r->write_path = strdup(path);
500 static int close_inode_for_write(struct btrfs_receive *r)
504 if(r->write_fd == -1)
509 r->write_path[0] = 0;
515 static int process_write(const char *path, const void *data, u64 offset,
519 struct btrfs_receive *r = user;
520 char *full_path = path_cat(r->full_subvol_path, path);
524 ret = open_inode_for_write(r, full_path);
529 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
533 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
534 path, strerror(-ret));
545 static int process_clone(const char *path, u64 offset, u64 len,
546 const u8 *clone_uuid, u64 clone_ctransid,
547 const char *clone_path, u64 clone_offset,
551 struct btrfs_receive *r = user;
552 struct btrfs_ioctl_clone_range_args clone_args;
553 struct subvol_info *si = NULL;
554 char *full_path = path_cat(r->full_subvol_path, path);
555 char *subvol_path = NULL;
556 char *full_clone_path = NULL;
559 ret = open_inode_for_write(r, full_path);
563 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
564 subvol_search_by_received_uuid);
566 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
567 BTRFS_FSID_SIZE) == 0) {
568 /* TODO check generation of extent */
569 subvol_path = strdup(r->cur_subvol->path);
572 fprintf(stderr, "ERROR: did not find source subvol.\n");
576 /*if (rs_args.ctransid > rs_args.rtransid) {
579 fprintf(stderr, "ERROR: subvolume %s was "
580 "modified after it was "
582 r->subvol_parent_name);
585 fprintf(stderr, "WARNING: subvolume %s was "
586 "modified after it was "
588 r->subvol_parent_name);
591 subvol_path = strdup(si->path);
594 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
596 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
599 fprintf(stderr, "ERROR: failed to open %s. %s\n",
600 full_clone_path, strerror(-ret));
604 clone_args.src_fd = clone_fd;
605 clone_args.src_offset = clone_offset;
606 clone_args.src_length = len;
607 clone_args.dest_offset = offset;
608 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
611 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
612 path, strerror(-ret));
618 free(full_clone_path);
626 static int process_set_xattr(const char *path, const char *name,
627 const void *data, int len, void *user)
630 struct btrfs_receive *r = user;
631 char *full_path = path_cat(r->full_subvol_path, path);
633 if (g_verbose >= 2) {
634 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
635 "data=%.*s\n", path, name, len,
639 ret = lsetxattr(full_path, name, data, len, 0);
642 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
643 path, name, len, (char*)data, strerror(-ret));
652 static int process_remove_xattr(const char *path, const char *name, 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, "remove_xattr %s - name=%s\n",
663 ret = lremovexattr(full_path, name);
666 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
667 path, name, strerror(-ret));
676 static int process_truncate(const char *path, u64 size, void *user)
679 struct btrfs_receive *r = user;
680 char *full_path = path_cat(r->full_subvol_path, path);
683 fprintf(stderr, "truncate %s size=%llu\n", path, size);
685 ret = truncate(full_path, size);
688 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
689 path, strerror(-ret));
698 static int process_chmod(const char *path, u64 mode, void *user)
701 struct btrfs_receive *r = user;
702 char *full_path = path_cat(r->full_subvol_path, path);
705 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
707 ret = chmod(full_path, mode);
710 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
711 path, strerror(-ret));
720 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
723 struct btrfs_receive *r = user;
724 char *full_path = path_cat(r->full_subvol_path, path);
727 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
730 ret = lchown(full_path, uid, gid);
733 fprintf(stderr, "ERROR: chown %s failed. %s\n",
734 path, strerror(-ret));
743 static int process_utimes(const char *path, struct timespec *at,
744 struct timespec *mt, struct timespec *ct,
748 struct btrfs_receive *r = user;
749 char *full_path = path_cat(r->full_subvol_path, path);
750 struct timespec tv[2];
753 fprintf(stderr, "utimes %s\n", path);
757 ret = utimensat(-1, full_path, tv, AT_SYMLINK_NOFOLLOW);
760 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
761 path, strerror(-ret));
771 struct btrfs_send_ops send_ops = {
772 .subvol = process_subvol,
773 .snapshot = process_snapshot,
774 .mkfile = process_mkfile,
775 .mkdir = process_mkdir,
776 .mknod = process_mknod,
777 .mkfifo = process_mkfifo,
778 .mksock = process_mksock,
779 .symlink = process_symlink,
780 .rename = process_rename,
781 .link = process_link,
782 .unlink = process_unlink,
783 .rmdir = process_rmdir,
784 .write = process_write,
785 .clone = process_clone,
786 .set_xattr = process_set_xattr,
787 .remove_xattr = process_remove_xattr,
788 .truncate = process_truncate,
789 .chmod = process_chmod,
790 .chown = process_chown,
791 .utimes = process_utimes,
794 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
799 r->root_path = strdup(tomnt);
800 r->mnt_fd = open(tomnt, O_RDONLY | O_NOATIME);
803 fprintf(stderr, "ERROR: failed to open %s. %s\n", tomnt,
808 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
813 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r);
819 ret = close_inode_for_write(r);
822 ret = finish_subvol(r);
829 if (r->write_fd != -1) {
836 r->write_path = NULL;
837 free(r->full_subvol_path);
838 r->full_subvol_path = NULL;
840 free(r->cur_subvol->path);
842 r->cur_subvol = NULL;
844 subvol_uuid_search_finit(&r->sus);
845 if (r->mnt_fd != -1) {
852 static int do_cmd_receive(int argc, char **argv)
856 char *fromfile = NULL;
857 struct btrfs_receive r;
858 int receive_fd = fileno(stdin);
862 memset(&r, 0, sizeof(r));
866 while ((c = getopt(argc, argv, "vf:")) != -1) {
876 fprintf(stderr, "ERROR: receive args invalid.\n");
881 if (optind + 1 != argc) {
882 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
886 tomnt = argv[optind];
889 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
890 if (receive_fd < 0) {
891 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
896 ret = do_receive(&r, tomnt, receive_fd);
901 static const char * const receive_cmd_group_usage[] = {
902 "btrfs receive <command> <args>",
906 const char * const cmd_receive_usage[] = {
907 "btrfs receive [-v] [-f <infile>] <mount>",
908 "Receive subvolumes from stdin.",
909 "Receives one or more subvolumes that were previously ",
910 "sent with btrfs send. The received subvolumes are stored",
912 "btrfs receive will fail in case a receiving subvolume",
913 "already exists. It will also fail in case a previously",
914 "received subvolume was changed after it was received.",
915 "After receiving a subvolume, it is immediately set to",
917 "-v Enable verbose debug output. Each",
918 " occurrence of this option increases the",
919 " verbose level more.",
920 "-f <infile> By default, btrfs receive uses stdin",
921 " to receive the subvolumes. Use this",
922 " option to specify a file to use instead.",
926 const struct cmd_group receive_cmd_group = {
927 receive_cmd_group_usage, NULL, {
928 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
933 int cmd_receive(int argc, char **argv)
935 return do_cmd_receive(argc, argv);