btrfs-progs: fix wrong data ratio for raid56 in btrfs-file-usage
[btrfs-progs-unstable/devel.git] / cmds-receive.c
blob358df1f4d91101260818c3160ffd5f2b44872164
1 /*
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.
19 #define _GNU_SOURCE
20 #define _POSIX_C_SOURCE 200809
21 #define _XOPEN_SOURCE 700
22 #define _BSD_SOURCE
24 #include "kerncompat.h"
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include <pthread.h>
31 #include <math.h>
32 #include <ftw.h>
33 #include <wait.h>
34 #include <assert.h>
35 #include <getopt.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <sys/ioctl.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/xattr.h>
43 #include <uuid/uuid.h>
45 #include "ctree.h"
46 #include "ioctl.h"
47 #include "commands.h"
48 #include "utils.h"
49 #include "list.h"
50 #include "btrfs-list.h"
52 #include "send.h"
53 #include "send-stream.h"
54 #include "send-utils.h"
56 static int g_verbose = 0;
58 struct btrfs_receive
60 int mnt_fd;
61 int dest_dir_fd;
63 int write_fd;
64 char *write_path;
66 char *root_path;
67 char *dest_dir_path; /* relative to root_path */
68 char *full_subvol_path;
70 struct subvol_info *cur_subvol;
72 struct subvol_uuid_search sus;
74 int honor_end_cmd;
77 static int finish_subvol(struct btrfs_receive *r)
79 int ret;
80 int subvol_fd = -1;
81 struct btrfs_ioctl_received_subvol_args rs_args;
82 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
83 u64 flags;
85 if (r->cur_subvol == NULL)
86 return 0;
88 subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
89 O_RDONLY | O_NOATIME);
90 if (subvol_fd < 0) {
91 ret = -errno;
92 fprintf(stderr, "ERROR: open %s failed. %s\n",
93 r->cur_subvol->path, strerror(-ret));
94 goto out;
97 memset(&rs_args, 0, sizeof(rs_args));
98 memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
99 rs_args.stransid = r->cur_subvol->stransid;
101 if (g_verbose >= 1) {
102 uuid_unparse((u8*)rs_args.uuid, uuid_str);
103 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
104 "stransid=%llu\n", uuid_str, rs_args.stransid);
107 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
108 if (ret < 0) {
109 ret = -errno;
110 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
111 strerror(-ret));
112 goto out;
114 r->cur_subvol->rtransid = rs_args.rtransid;
116 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
117 if (ret < 0) {
118 ret = -errno;
119 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
120 strerror(-ret));
121 goto out;
124 flags |= BTRFS_SUBVOL_RDONLY;
126 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
127 if (ret < 0) {
128 ret = -errno;
129 fprintf(stderr, "ERROR: failed to make subvolume read only. "
130 "%s\n", strerror(-ret));
131 goto out;
134 ret = 0;
136 out:
137 if (r->cur_subvol) {
138 free(r->cur_subvol->path);
139 free(r->cur_subvol);
140 r->cur_subvol = NULL;
142 if (subvol_fd != -1)
143 close(subvol_fd);
144 return ret;
147 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
148 void *user)
150 int ret;
151 struct btrfs_receive *r = user;
152 struct btrfs_ioctl_vol_args args_v1;
153 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
155 ret = finish_subvol(r);
156 if (ret < 0)
157 goto out;
159 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
161 if (strlen(r->dest_dir_path) == 0)
162 r->cur_subvol->path = strdup(path);
163 else
164 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
165 free(r->full_subvol_path);
166 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
168 fprintf(stderr, "At subvol %s\n", path);
170 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
171 r->cur_subvol->stransid = ctransid;
173 if (g_verbose) {
174 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
175 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
176 path, uuid_str,
177 r->cur_subvol->stransid);
180 memset(&args_v1, 0, sizeof(args_v1));
181 strncpy_null(args_v1.name, path);
182 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
183 if (ret < 0) {
184 ret = -errno;
185 fprintf(stderr, "ERROR: creating subvolume %s failed. "
186 "%s\n", path, strerror(-ret));
187 goto out;
190 out:
191 return ret;
194 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
195 const u8 *parent_uuid, u64 parent_ctransid,
196 void *user)
198 int ret;
199 struct btrfs_receive *r = user;
200 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
201 struct btrfs_ioctl_vol_args_v2 args_v2;
202 struct subvol_info *parent_subvol = NULL;
204 ret = finish_subvol(r);
205 if (ret < 0)
206 goto out;
208 r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
210 if (strlen(r->dest_dir_path) == 0)
211 r->cur_subvol->path = strdup(path);
212 else
213 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
214 free(r->full_subvol_path);
215 r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
217 fprintf(stdout, "At snapshot %s\n", path);
219 memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
220 r->cur_subvol->stransid = ctransid;
222 if (g_verbose) {
223 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
224 fprintf(stderr, "receiving snapshot %s uuid=%s, "
225 "ctransid=%llu ", path, uuid_str,
226 r->cur_subvol->stransid);
227 uuid_unparse(parent_uuid, uuid_str);
228 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
229 uuid_str, parent_ctransid);
232 memset(&args_v2, 0, sizeof(args_v2));
233 strncpy_null(args_v2.name, path);
235 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
236 parent_ctransid, NULL, subvol_search_by_received_uuid);
237 if (!parent_subvol) {
238 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
239 parent_ctransid, NULL, subvol_search_by_uuid);
241 if (!parent_subvol) {
242 ret = -ENOENT;
243 fprintf(stderr, "ERROR: could not find parent subvolume\n");
244 goto out;
247 /*if (rs_args.ctransid > rs_args.rtransid) {
248 if (!r->force) {
249 ret = -EINVAL;
250 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
251 goto out;
252 } else {
253 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
257 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
258 O_RDONLY | O_NOATIME);
259 if (args_v2.fd < 0) {
260 ret = -errno;
261 if (errno != ENOENT)
262 fprintf(stderr, "ERROR: open %s failed. %s\n",
263 parent_subvol->path, strerror(-ret));
264 else
265 fprintf(stderr,
266 "It seems that you have changed your default "
267 "subvolume or you specify other subvolume to\n"
268 "mount btrfs, try to remount this btrfs filesystem "
269 "with fs tree, and run btrfs receive again!\n");
270 goto out;
273 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
274 close(args_v2.fd);
275 if (ret < 0) {
276 ret = -errno;
277 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
278 "failed. %s\n", parent_subvol->path,
279 path, strerror(-ret));
280 goto out;
283 out:
284 if (parent_subvol) {
285 free(parent_subvol->path);
286 free(parent_subvol);
288 return ret;
291 static int process_mkfile(const char *path, void *user)
293 int ret;
294 struct btrfs_receive *r = user;
295 char *full_path = path_cat(r->full_subvol_path, path);
297 if (g_verbose >= 2)
298 fprintf(stderr, "mkfile %s\n", path);
300 ret = creat(full_path, 0600);
301 if (ret < 0) {
302 ret = -errno;
303 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
304 strerror(-ret));
305 goto out;
307 close(ret);
308 ret = 0;
310 out:
311 free(full_path);
312 return ret;
315 static int process_mkdir(const char *path, void *user)
317 int ret;
318 struct btrfs_receive *r = user;
319 char *full_path = path_cat(r->full_subvol_path, path);
321 if (g_verbose >= 2)
322 fprintf(stderr, "mkdir %s\n", path);
324 ret = mkdir(full_path, 0700);
325 if (ret < 0) {
326 ret = -errno;
327 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
328 strerror(-ret));
331 free(full_path);
332 return ret;
335 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
337 int ret;
338 struct btrfs_receive *r = user;
339 char *full_path = path_cat(r->full_subvol_path, path);
341 if (g_verbose >= 2)
342 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
343 path, mode, dev);
345 ret = mknod(full_path, mode & S_IFMT, dev);
346 if (ret < 0) {
347 ret = -errno;
348 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
349 strerror(-ret));
352 free(full_path);
353 return ret;
356 static int process_mkfifo(const char *path, void *user)
358 int ret;
359 struct btrfs_receive *r = user;
360 char *full_path = path_cat(r->full_subvol_path, path);
362 if (g_verbose >= 2)
363 fprintf(stderr, "mkfifo %s\n", path);
365 ret = mkfifo(full_path, 0600);
366 if (ret < 0) {
367 ret = -errno;
368 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
369 strerror(-ret));
372 free(full_path);
373 return ret;
376 static int process_mksock(const char *path, void *user)
378 int ret;
379 struct btrfs_receive *r = user;
380 char *full_path = path_cat(r->full_subvol_path, path);
382 if (g_verbose >= 2)
383 fprintf(stderr, "mksock %s\n", path);
385 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
386 if (ret < 0) {
387 ret = -errno;
388 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
389 strerror(-ret));
392 free(full_path);
393 return ret;
396 static int process_symlink(const char *path, const char *lnk, void *user)
398 int ret;
399 struct btrfs_receive *r = user;
400 char *full_path = path_cat(r->full_subvol_path, path);
402 if (g_verbose >= 2)
403 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
405 ret = symlink(lnk, full_path);
406 if (ret < 0) {
407 ret = -errno;
408 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
409 lnk, strerror(-ret));
412 free(full_path);
413 return ret;
416 static int process_rename(const char *from, const char *to, void *user)
418 int ret;
419 struct btrfs_receive *r = user;
420 char *full_from = path_cat(r->full_subvol_path, from);
421 char *full_to = path_cat(r->full_subvol_path, to);
423 if (g_verbose >= 2)
424 fprintf(stderr, "rename %s -> %s\n", from, to);
426 ret = rename(full_from, full_to);
427 if (ret < 0) {
428 ret = -errno;
429 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
430 to, strerror(-ret));
433 free(full_from);
434 free(full_to);
435 return ret;
438 static int process_link(const char *path, const char *lnk, void *user)
440 int ret;
441 struct btrfs_receive *r = user;
442 char *full_path = path_cat(r->full_subvol_path, path);
443 char *full_link_path = path_cat(r->full_subvol_path, lnk);
445 if (g_verbose >= 2)
446 fprintf(stderr, "link %s -> %s\n", path, lnk);
448 ret = link(full_link_path, full_path);
449 if (ret < 0) {
450 ret = -errno;
451 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
452 lnk, strerror(-ret));
455 free(full_path);
456 free(full_link_path);
457 return ret;
461 static int process_unlink(const char *path, void *user)
463 int ret;
464 struct btrfs_receive *r = user;
465 char *full_path = path_cat(r->full_subvol_path, path);
467 if (g_verbose >= 2)
468 fprintf(stderr, "unlink %s\n", path);
470 ret = unlink(full_path);
471 if (ret < 0) {
472 ret = -errno;
473 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
474 strerror(-ret));
477 free(full_path);
478 return ret;
481 static int process_rmdir(const char *path, void *user)
483 int ret;
484 struct btrfs_receive *r = user;
485 char *full_path = path_cat(r->full_subvol_path, path);
487 if (g_verbose >= 2)
488 fprintf(stderr, "rmdir %s\n", path);
490 ret = rmdir(full_path);
491 if (ret < 0) {
492 ret = -errno;
493 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
494 strerror(-ret));
497 free(full_path);
498 return ret;
502 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
504 int ret = 0;
506 if (r->write_fd != -1) {
507 if (strcmp(r->write_path, path) == 0)
508 goto out;
509 close(r->write_fd);
510 r->write_fd = -1;
513 r->write_fd = open(path, O_RDWR);
514 if (r->write_fd < 0) {
515 ret = -errno;
516 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
517 strerror(-ret));
518 goto out;
520 free(r->write_path);
521 r->write_path = strdup(path);
523 out:
524 return ret;
527 static void close_inode_for_write(struct btrfs_receive *r)
529 if(r->write_fd == -1)
530 return;
532 close(r->write_fd);
533 r->write_fd = -1;
534 r->write_path[0] = 0;
537 static int process_write(const char *path, const void *data, u64 offset,
538 u64 len, void *user)
540 int ret = 0;
541 struct btrfs_receive *r = user;
542 char *full_path = path_cat(r->full_subvol_path, path);
543 u64 pos = 0;
544 int w;
546 ret = open_inode_for_write(r, full_path);
547 if (ret < 0)
548 goto out;
550 while (pos < len) {
551 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
552 offset + pos);
553 if (w < 0) {
554 ret = -errno;
555 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
556 path, strerror(-ret));
557 goto out;
559 pos += w;
562 out:
563 free(full_path);
564 return ret;
567 static int process_clone(const char *path, u64 offset, u64 len,
568 const u8 *clone_uuid, u64 clone_ctransid,
569 const char *clone_path, u64 clone_offset,
570 void *user)
572 int ret;
573 struct btrfs_receive *r = user;
574 struct btrfs_ioctl_clone_range_args clone_args;
575 struct subvol_info *si = NULL;
576 char *full_path = path_cat(r->full_subvol_path, path);
577 char *subvol_path = NULL;
578 char *full_clone_path = NULL;
579 int clone_fd = -1;
581 ret = open_inode_for_write(r, full_path);
582 if (ret < 0)
583 goto out;
585 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
586 subvol_search_by_received_uuid);
587 if (!si) {
588 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
589 BTRFS_UUID_SIZE) == 0) {
590 /* TODO check generation of extent */
591 subvol_path = strdup(r->cur_subvol->path);
592 } else {
593 ret = -ENOENT;
594 fprintf(stderr, "ERROR: did not find source subvol.\n");
595 goto out;
597 } else {
598 /*if (rs_args.ctransid > rs_args.rtransid) {
599 if (!r->force) {
600 ret = -EINVAL;
601 fprintf(stderr, "ERROR: subvolume %s was "
602 "modified after it was "
603 "received.\n",
604 r->subvol_parent_name);
605 goto out;
606 } else {
607 fprintf(stderr, "WARNING: subvolume %s was "
608 "modified after it was "
609 "received.\n",
610 r->subvol_parent_name);
613 subvol_path = strdup(si->path);
616 full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
618 clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
619 if (clone_fd < 0) {
620 ret = -errno;
621 fprintf(stderr, "ERROR: failed to open %s. %s\n",
622 full_clone_path, strerror(-ret));
623 goto out;
626 clone_args.src_fd = clone_fd;
627 clone_args.src_offset = clone_offset;
628 clone_args.src_length = len;
629 clone_args.dest_offset = offset;
630 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
631 if (ret) {
632 ret = -errno;
633 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
634 path, strerror(-ret));
635 goto out;
638 out:
639 if (si) {
640 free(si->path);
641 free(si);
643 free(full_path);
644 free(full_clone_path);
645 free(subvol_path);
646 if (clone_fd != -1)
647 close(clone_fd);
648 return ret;
652 static int process_set_xattr(const char *path, const char *name,
653 const void *data, int len, void *user)
655 int ret = 0;
656 struct btrfs_receive *r = user;
657 char *full_path = path_cat(r->full_subvol_path, path);
659 if (g_verbose >= 2) {
660 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
661 "data=%.*s\n", path, name, len,
662 len, (char*)data);
665 ret = lsetxattr(full_path, name, data, len, 0);
666 if (ret < 0) {
667 ret = -errno;
668 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
669 path, name, len, (char*)data, strerror(-ret));
670 goto out;
673 out:
674 free(full_path);
675 return ret;
678 static int process_remove_xattr(const char *path, const char *name, void *user)
680 int ret = 0;
681 struct btrfs_receive *r = user;
682 char *full_path = path_cat(r->full_subvol_path, path);
684 if (g_verbose >= 2) {
685 fprintf(stderr, "remove_xattr %s - name=%s\n",
686 path, name);
689 ret = lremovexattr(full_path, name);
690 if (ret < 0) {
691 ret = -errno;
692 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
693 path, name, strerror(-ret));
694 goto out;
697 out:
698 free(full_path);
699 return ret;
702 static int process_truncate(const char *path, u64 size, void *user)
704 int ret = 0;
705 struct btrfs_receive *r = user;
706 char *full_path = path_cat(r->full_subvol_path, path);
708 if (g_verbose >= 2)
709 fprintf(stderr, "truncate %s size=%llu\n", path, size);
711 ret = truncate(full_path, size);
712 if (ret < 0) {
713 ret = -errno;
714 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
715 path, strerror(-ret));
716 goto out;
719 out:
720 free(full_path);
721 return ret;
724 static int process_chmod(const char *path, u64 mode, void *user)
726 int ret = 0;
727 struct btrfs_receive *r = user;
728 char *full_path = path_cat(r->full_subvol_path, path);
730 if (g_verbose >= 2)
731 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
733 ret = chmod(full_path, mode);
734 if (ret < 0) {
735 ret = -errno;
736 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
737 path, strerror(-ret));
738 goto out;
741 out:
742 free(full_path);
743 return ret;
746 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
748 int ret = 0;
749 struct btrfs_receive *r = user;
750 char *full_path = path_cat(r->full_subvol_path, path);
752 if (g_verbose >= 2)
753 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
754 uid, gid);
756 ret = lchown(full_path, uid, gid);
757 if (ret < 0) {
758 ret = -errno;
759 fprintf(stderr, "ERROR: chown %s failed. %s\n",
760 path, strerror(-ret));
761 goto out;
764 out:
765 free(full_path);
766 return ret;
769 static int process_utimes(const char *path, struct timespec *at,
770 struct timespec *mt, struct timespec *ct,
771 void *user)
773 int ret = 0;
774 struct btrfs_receive *r = user;
775 char *full_path = path_cat(r->full_subvol_path, path);
776 struct timespec tv[2];
778 if (g_verbose >= 2)
779 fprintf(stderr, "utimes %s\n", path);
781 tv[0] = *at;
782 tv[1] = *mt;
783 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
784 if (ret < 0) {
785 ret = -errno;
786 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
787 path, strerror(-ret));
788 goto out;
791 out:
792 free(full_path);
793 return ret;
797 static struct btrfs_send_ops send_ops = {
798 .subvol = process_subvol,
799 .snapshot = process_snapshot,
800 .mkfile = process_mkfile,
801 .mkdir = process_mkdir,
802 .mknod = process_mknod,
803 .mkfifo = process_mkfifo,
804 .mksock = process_mksock,
805 .symlink = process_symlink,
806 .rename = process_rename,
807 .link = process_link,
808 .unlink = process_unlink,
809 .rmdir = process_rmdir,
810 .write = process_write,
811 .clone = process_clone,
812 .set_xattr = process_set_xattr,
813 .remove_xattr = process_remove_xattr,
814 .truncate = process_truncate,
815 .chmod = process_chmod,
816 .chown = process_chown,
817 .utimes = process_utimes,
820 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd,
821 u64 max_errors)
823 int ret;
824 char *dest_dir_full_path;
825 int end = 0;
827 dest_dir_full_path = realpath(tomnt, NULL);
828 if (!dest_dir_full_path) {
829 ret = -errno;
830 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
831 strerror(-ret));
832 goto out;
834 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
835 if (r->dest_dir_fd < 0) {
836 ret = -errno;
837 fprintf(stderr,
838 "ERROR: failed to open destination directory %s. %s\n",
839 dest_dir_full_path, strerror(-ret));
840 goto out;
843 ret = find_mount_root(dest_dir_full_path, &r->root_path);
844 if (ret < 0) {
845 fprintf(stderr,
846 "ERROR: failed to determine mount point for %s: %s\n",
847 dest_dir_full_path, strerror(-ret));
848 ret = -EINVAL;
849 goto out;
851 if (ret > 0) {
852 fprintf(stderr,
853 "ERROR: %s doesn't belong to btrfs mount point\n",
854 dest_dir_full_path);
855 ret = -EINVAL;
856 goto out;
858 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
859 if (r->mnt_fd < 0) {
860 ret = -errno;
861 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
862 strerror(-ret));
863 goto out;
867 * find_mount_root returns a root_path that is a subpath of
868 * dest_dir_full_path. Now get the other part of root_path,
869 * which is the destination dir relative to root_path.
871 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
872 while (r->dest_dir_path[0] == '/')
873 r->dest_dir_path++;
875 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
876 if (ret < 0)
877 goto out;
879 while (!end) {
880 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
881 r->honor_end_cmd,
882 max_errors);
883 if (ret < 0)
884 goto out;
885 if (ret)
886 end = 1;
888 close_inode_for_write(r);
889 ret = finish_subvol(r);
890 if (ret < 0)
891 goto out;
893 ret = 0;
895 out:
896 if (r->write_fd != -1) {
897 close(r->write_fd);
898 r->write_fd = -1;
900 free(r->root_path);
901 r->root_path = NULL;
902 free(r->write_path);
903 r->write_path = NULL;
904 free(r->full_subvol_path);
905 r->full_subvol_path = NULL;
906 r->dest_dir_path = NULL;
907 free(dest_dir_full_path);
908 if (r->cur_subvol) {
909 free(r->cur_subvol->path);
910 free(r->cur_subvol);
911 r->cur_subvol = NULL;
913 subvol_uuid_search_finit(&r->sus);
914 if (r->mnt_fd != -1) {
915 close(r->mnt_fd);
916 r->mnt_fd = -1;
918 if (r->dest_dir_fd != -1) {
919 close(r->dest_dir_fd);
920 r->dest_dir_fd = -1;
922 return ret;
925 static const struct option long_opts[] = {
926 { "max-errors", 1, NULL, 'E' },
927 { NULL, 0, NULL, 0 }
930 int cmd_receive(int argc, char **argv)
932 int c;
933 char *tomnt = NULL;
934 char *fromfile = NULL;
935 struct btrfs_receive r;
936 int receive_fd = fileno(stdin);
937 u64 max_errors = 1;
938 int ret;
940 memset(&r, 0, sizeof(r));
941 r.mnt_fd = -1;
942 r.write_fd = -1;
943 r.dest_dir_fd = -1;
945 while ((c = getopt_long(argc, argv, "evf:", long_opts, NULL)) != -1) {
946 switch (c) {
947 case 'v':
948 g_verbose++;
949 break;
950 case 'f':
951 fromfile = optarg;
952 break;
953 case 'e':
954 r.honor_end_cmd = 1;
955 break;
956 case 'E':
957 max_errors = arg_strtou64(optarg);
958 break;
959 case '?':
960 default:
961 fprintf(stderr, "ERROR: receive args invalid.\n");
962 return 1;
966 if (check_argc_exact(argc - optind, 1))
967 usage(cmd_receive_usage);
969 tomnt = argv[optind];
971 if (fromfile) {
972 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
973 if (receive_fd < 0) {
974 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
975 return 1;
979 ret = do_receive(&r, tomnt, receive_fd, max_errors);
981 return !!ret;
984 const char * const cmd_receive_usage[] = {
985 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
986 "Receive subvolumes from stdin.",
987 "Receives one or more subvolumes that were previously",
988 "sent with btrfs send. The received subvolumes are stored",
989 "into <mount>.",
990 "btrfs receive will fail in case a receiving subvolume",
991 "already exists. It will also fail in case a previously",
992 "received subvolume was changed after it was received.",
993 "After receiving a subvolume, it is immediately set to",
994 "read only.\n",
995 "-v Enable verbose debug output. Each",
996 " occurrence of this option increases the",
997 " verbose level more.",
998 "-f <infile> By default, btrfs receive uses stdin",
999 " to receive the subvolumes. Use this",
1000 " option to specify a file to use instead.",
1001 "-e Terminate after receiving an <end cmd>",
1002 " in the data stream. Without this option,",
1003 " the receiver terminates only if an error",
1004 " is recognized or on EOF.",
1005 "--max-errors <N> Terminate as soon as N errors happened while",
1006 " processing commands from the send stream.",
1007 " Default value is 1. A value of 0 means no limit.",
1008 NULL