btrfs-progs: use calloc instead of malloc+memset for tree roots
[btrfs-progs-unstable/devel.git] / cmds-receive.c
blob1d7d897fffccda271ae84697183f689b089d226a
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 #include "kerncompat.h"
20 #include "androidcompat.h"
22 #include <unistd.h>
23 #include <stdint.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <pthread.h>
27 #include <math.h>
28 #include <ftw.h>
29 #include <sys/wait.h>
30 #include <assert.h>
31 #include <getopt.h>
32 #include <limits.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <sys/time.h>
38 #include <sys/types.h>
39 #include <sys/xattr.h>
40 #include <uuid/uuid.h>
42 #include "ctree.h"
43 #include "ioctl.h"
44 #include "commands.h"
45 #include "utils.h"
46 #include "list.h"
47 #include "btrfs-list.h"
49 #include "send.h"
50 #include "send-stream.h"
51 #include "send-utils.h"
53 static int g_verbose = 0;
55 struct btrfs_receive
57 int mnt_fd;
58 int dest_dir_fd;
60 int write_fd;
61 char write_path[PATH_MAX];
63 char *root_path;
64 char *dest_dir_path; /* relative to root_path */
65 char full_subvol_path[PATH_MAX];
66 char *full_root_path;
67 int dest_dir_chroot;
69 struct subvol_info cur_subvol;
71 * Substitute for cur_subvol::path which is a pointer and we cannot
72 * change it to an array as it's a public API.
74 char cur_subvol_path[PATH_MAX];
76 struct subvol_uuid_search sus;
78 int honor_end_cmd;
81 * Buffer to store capabilities from security.capabilities xattr,
82 * usually 20 bytes, but make same room for potentially larger
83 * encodings. Must be set only once per file, denoted by length > 0.
85 char cached_capabilities[64];
86 int cached_capabilities_len;
89 static int finish_subvol(struct btrfs_receive *r)
91 int ret;
92 int subvol_fd = -1;
93 struct btrfs_ioctl_received_subvol_args rs_args;
94 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
95 u64 flags;
97 if (r->cur_subvol_path[0] == 0)
98 return 0;
100 subvol_fd = openat(r->mnt_fd, r->cur_subvol_path,
101 O_RDONLY | O_NOATIME);
102 if (subvol_fd < 0) {
103 ret = -errno;
104 fprintf(stderr, "ERROR: open %s failed. %s\n",
105 r->cur_subvol_path, strerror(-ret));
106 goto out;
109 memset(&rs_args, 0, sizeof(rs_args));
110 memcpy(rs_args.uuid, r->cur_subvol.received_uuid, BTRFS_UUID_SIZE);
111 rs_args.stransid = r->cur_subvol.stransid;
113 if (g_verbose >= 1) {
114 uuid_unparse((u8*)rs_args.uuid, uuid_str);
115 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
116 "stransid=%llu\n", uuid_str, rs_args.stransid);
119 ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
120 if (ret < 0) {
121 ret = -errno;
122 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
123 strerror(-ret));
124 goto out;
126 r->cur_subvol.rtransid = rs_args.rtransid;
128 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
129 if (ret < 0) {
130 ret = -errno;
131 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
132 strerror(-ret));
133 goto out;
136 flags |= BTRFS_SUBVOL_RDONLY;
138 ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
139 if (ret < 0) {
140 ret = -errno;
141 fprintf(stderr, "ERROR: failed to make subvolume read only. "
142 "%s\n", strerror(-ret));
143 goto out;
146 ret = 0;
148 out:
149 if (r->cur_subvol_path[0]) {
150 r->cur_subvol_path[0] = 0;
152 if (subvol_fd != -1)
153 close(subvol_fd);
154 return ret;
157 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
158 void *user)
160 int ret;
161 struct btrfs_receive *r = user;
162 struct btrfs_ioctl_vol_args args_v1;
163 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
165 ret = finish_subvol(r);
166 if (ret < 0)
167 goto out;
169 BUG_ON(r->cur_subvol.path);
170 BUG_ON(r->cur_subvol_path[0]);
172 if (strlen(r->dest_dir_path) == 0) {
173 strncpy_null(r->cur_subvol_path, path);
174 } else {
175 ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
176 if (ret < 0) {
177 fprintf(stderr, "ERROR: subvol: path invalid: %s\n",
178 path);
179 goto out;
182 ret = path_cat3_out(r->full_subvol_path, r->root_path,
183 r->dest_dir_path, path);
184 if (ret < 0) {
185 fprintf(stderr, "ERROR: subvol: path invalid: %s\n", path);
186 goto out;
189 fprintf(stderr, "At subvol %s\n", path);
191 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
192 r->cur_subvol.stransid = ctransid;
194 if (g_verbose) {
195 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
196 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
197 path, uuid_str,
198 r->cur_subvol.stransid);
201 memset(&args_v1, 0, sizeof(args_v1));
202 strncpy_null(args_v1.name, path);
203 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
204 if (ret < 0) {
205 ret = -errno;
206 fprintf(stderr, "ERROR: creating subvolume %s failed. "
207 "%s\n", path, strerror(-ret));
208 goto out;
211 out:
212 return ret;
215 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
216 const u8 *parent_uuid, u64 parent_ctransid,
217 void *user)
219 int ret;
220 struct btrfs_receive *r = user;
221 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
222 struct btrfs_ioctl_vol_args_v2 args_v2;
223 struct subvol_info *parent_subvol = NULL;
225 ret = finish_subvol(r);
226 if (ret < 0)
227 goto out;
229 BUG_ON(r->cur_subvol.path);
230 BUG_ON(r->cur_subvol_path[0]);
232 if (strlen(r->dest_dir_path) == 0) {
233 strncpy_null(r->cur_subvol_path, path);
234 } else {
235 ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
236 if (ret < 0) {
237 fprintf(stderr, "ERROR: snapshot: path invalid: %s\n",
238 path);
239 goto out;
242 ret = path_cat3_out(r->full_subvol_path, r->root_path,
243 r->dest_dir_path, path);
244 if (ret < 0) {
245 fprintf(stderr, "ERROR: snapshot: path invalid: %s\n", path);
246 goto out;
249 fprintf(stdout, "At snapshot %s\n", path);
251 memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
252 r->cur_subvol.stransid = ctransid;
254 if (g_verbose) {
255 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
256 fprintf(stderr, "receiving snapshot %s uuid=%s, "
257 "ctransid=%llu ", path, uuid_str,
258 r->cur_subvol.stransid);
259 uuid_unparse(parent_uuid, uuid_str);
260 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
261 uuid_str, parent_ctransid);
264 memset(&args_v2, 0, sizeof(args_v2));
265 strncpy_null(args_v2.name, path);
267 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
268 parent_ctransid, NULL, subvol_search_by_received_uuid);
269 if (!parent_subvol) {
270 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
271 parent_ctransid, NULL, subvol_search_by_uuid);
273 if (!parent_subvol) {
274 ret = -ENOENT;
275 fprintf(stderr, "ERROR: could not find parent subvolume\n");
276 goto out;
280 * The path is resolved from the root subvol, but we could be in some
281 * subvolume under the root subvolume, so try and adjust the path to be
282 * relative to our root path.
284 if (r->full_root_path) {
285 size_t root_len;
286 size_t sub_len;
288 root_len = strlen(r->full_root_path);
289 sub_len = strlen(parent_subvol->path);
291 /* First make sure the parent subvol is actually in our path */
292 if (sub_len < root_len ||
293 strstr(parent_subvol->path, r->full_root_path) == NULL) {
294 fprintf(stderr, "ERROR: parent subvol is not reachable"
295 " from inside the root subvol.\n");
296 ret = -ENOENT;
297 goto out;
300 if (sub_len == root_len) {
301 parent_subvol->path[0] = '/';
302 parent_subvol->path[1] = '\0';
303 } else {
305 * root path is foo/bar
306 * subvol path is foo/bar/baz
308 * we need to have baz be the path, so we need to move
309 * the bit after foo/bar/, so path + root_len + 1, and
310 * move the part we care about, so sub_len - root_len -
311 * 1.
313 memmove(parent_subvol->path,
314 parent_subvol->path + root_len + 1,
315 sub_len - root_len - 1);
316 parent_subvol->path[sub_len - root_len - 1] = '\0';
319 /*if (rs_args.ctransid > rs_args.rtransid) {
320 if (!r->force) {
321 ret = -EINVAL;
322 fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
323 goto out;
324 } else {
325 fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
329 if (strlen(parent_subvol->path) == 0)
330 args_v2.fd = dup(r->mnt_fd);
331 else
332 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
333 O_RDONLY | O_NOATIME);
334 if (args_v2.fd < 0) {
335 ret = -errno;
336 if (errno != ENOENT)
337 fprintf(stderr, "ERROR: open %s failed. %s\n",
338 parent_subvol->path, strerror(-ret));
339 else
340 fprintf(stderr,
341 "It seems that you have changed your default "
342 "subvolume or you specify other subvolume to\n"
343 "mount btrfs, try to remount this btrfs filesystem "
344 "with fs tree, and run btrfs receive again!\n");
345 goto out;
348 ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
349 close(args_v2.fd);
350 if (ret < 0) {
351 ret = -errno;
352 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
353 "failed. %s\n", parent_subvol->path,
354 path, strerror(-ret));
355 goto out;
358 out:
359 if (parent_subvol) {
360 free(parent_subvol->path);
361 free(parent_subvol);
363 return ret;
366 static int process_mkfile(const char *path, void *user)
368 int ret;
369 struct btrfs_receive *r = user;
370 char full_path[PATH_MAX];
372 ret = path_cat_out(full_path, r->full_subvol_path, path);
373 if (ret < 0) {
374 fprintf(stderr, "ERROR: mkfile: path invalid: %s\n", path);
375 goto out;
378 if (g_verbose >= 2)
379 fprintf(stderr, "mkfile %s\n", path);
381 ret = creat(full_path, 0600);
382 if (ret < 0) {
383 ret = -errno;
384 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
385 strerror(-ret));
386 goto out;
388 close(ret);
389 ret = 0;
391 out:
392 return ret;
395 static int process_mkdir(const char *path, void *user)
397 int ret;
398 struct btrfs_receive *r = user;
399 char full_path[PATH_MAX];
401 ret = path_cat_out(full_path, r->full_subvol_path, path);
402 if (ret < 0) {
403 fprintf(stderr, "ERROR: mkdir: path invalid: %s\n", path);
404 goto out;
407 if (g_verbose >= 2)
408 fprintf(stderr, "mkdir %s\n", path);
410 ret = mkdir(full_path, 0700);
411 if (ret < 0) {
412 ret = -errno;
413 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
414 strerror(-ret));
417 out:
418 return ret;
421 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
423 int ret;
424 struct btrfs_receive *r = user;
425 char full_path[PATH_MAX];
427 ret = path_cat_out(full_path, r->full_subvol_path, path);
428 if (ret < 0) {
429 fprintf(stderr, "ERROR: mknod: path invalid: %s\n", path);
430 goto out;
433 if (g_verbose >= 2)
434 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
435 path, mode, dev);
437 ret = mknod(full_path, mode & S_IFMT, dev);
438 if (ret < 0) {
439 ret = -errno;
440 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
441 strerror(-ret));
444 out:
445 return ret;
448 static int process_mkfifo(const char *path, void *user)
450 int ret;
451 struct btrfs_receive *r = user;
452 char full_path[PATH_MAX];
454 ret = path_cat_out(full_path, r->full_subvol_path, path);
455 if (ret < 0) {
456 fprintf(stderr, "ERROR: mkfifo: path invalid: %s\n", path);
457 goto out;
460 if (g_verbose >= 2)
461 fprintf(stderr, "mkfifo %s\n", path);
463 ret = mkfifo(full_path, 0600);
464 if (ret < 0) {
465 ret = -errno;
466 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
467 strerror(-ret));
470 out:
471 return ret;
474 static int process_mksock(const char *path, void *user)
476 int ret;
477 struct btrfs_receive *r = user;
478 char full_path[PATH_MAX];
480 ret = path_cat_out(full_path, r->full_subvol_path, path);
481 if (ret < 0) {
482 fprintf(stderr, "ERROR: mksock: path invalid: %s\n", path);
483 goto out;
486 if (g_verbose >= 2)
487 fprintf(stderr, "mksock %s\n", path);
489 ret = mknod(full_path, 0600 | S_IFSOCK, 0);
490 if (ret < 0) {
491 ret = -errno;
492 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
493 strerror(-ret));
496 out:
497 return ret;
500 static int process_symlink(const char *path, const char *lnk, void *user)
502 int ret;
503 struct btrfs_receive *r = user;
504 char full_path[PATH_MAX];
506 ret = path_cat_out(full_path, r->full_subvol_path, path);
507 if (ret < 0) {
508 fprintf(stderr, "ERROR: symlink: path invalid: %s\n", path);
509 goto out;
512 if (g_verbose >= 2)
513 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
515 ret = symlink(lnk, full_path);
516 if (ret < 0) {
517 ret = -errno;
518 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
519 lnk, strerror(-ret));
522 out:
523 return ret;
526 static int process_rename(const char *from, const char *to, void *user)
528 int ret;
529 struct btrfs_receive *r = user;
530 char full_from[PATH_MAX];
531 char full_to[PATH_MAX];
533 ret = path_cat_out(full_from, r->full_subvol_path, from);
534 if (ret < 0) {
535 fprintf(stderr, "ERROR: rename: source path invalid: %s\n",
536 from);
537 goto out;
540 ret = path_cat_out(full_to, r->full_subvol_path, to);
541 if (ret < 0) {
542 fprintf(stderr, "ERROR: rename: target path invalid: %s\n",
543 to);
544 goto out;
547 if (g_verbose >= 2)
548 fprintf(stderr, "rename %s -> %s\n", from, to);
550 ret = rename(full_from, full_to);
551 if (ret < 0) {
552 ret = -errno;
553 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
554 to, strerror(-ret));
557 out:
558 return ret;
561 static int process_link(const char *path, const char *lnk, void *user)
563 int ret;
564 struct btrfs_receive *r = user;
565 char full_path[PATH_MAX];
566 char full_link_path[PATH_MAX];
568 ret = path_cat_out(full_path, r->full_subvol_path, path);
569 if (ret < 0) {
570 fprintf(stderr, "ERROR: link: source path invalid: %s\n",
571 full_path);
572 goto out;
575 ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
576 if (ret < 0) {
577 fprintf(stderr, "ERROR: link: target path invalid: %s\n",
578 full_link_path);
579 goto out;
582 if (g_verbose >= 2)
583 fprintf(stderr, "link %s -> %s\n", path, lnk);
585 ret = link(full_link_path, full_path);
586 if (ret < 0) {
587 ret = -errno;
588 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
589 lnk, strerror(-ret));
592 out:
593 return ret;
597 static int process_unlink(const char *path, void *user)
599 int ret;
600 struct btrfs_receive *r = user;
601 char full_path[PATH_MAX];
603 ret = path_cat_out(full_path, r->full_subvol_path, path);
604 if (ret < 0) {
605 fprintf(stderr, "ERROR: unlink: path invalid: %s\n", path);
606 goto out;
609 if (g_verbose >= 2)
610 fprintf(stderr, "unlink %s\n", path);
612 ret = unlink(full_path);
613 if (ret < 0) {
614 ret = -errno;
615 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
616 strerror(-ret));
619 out:
620 return ret;
623 static int process_rmdir(const char *path, void *user)
625 int ret;
626 struct btrfs_receive *r = user;
627 char full_path[PATH_MAX];
629 ret = path_cat_out(full_path, r->full_subvol_path, path);
630 if (ret < 0) {
631 fprintf(stderr, "ERROR: rmdir: path invalid: %s\n", path);
632 goto out;
635 if (g_verbose >= 2)
636 fprintf(stderr, "rmdir %s\n", path);
638 ret = rmdir(full_path);
639 if (ret < 0) {
640 ret = -errno;
641 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
642 strerror(-ret));
645 out:
646 return ret;
649 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
651 int ret = 0;
653 if (r->write_fd != -1) {
654 if (strcmp(r->write_path, path) == 0)
655 goto out;
656 close(r->write_fd);
657 r->write_fd = -1;
660 r->write_fd = open(path, O_RDWR);
661 if (r->write_fd < 0) {
662 ret = -errno;
663 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
664 strerror(-ret));
665 goto out;
667 strncpy_null(r->write_path, path);
669 out:
670 return ret;
673 static void close_inode_for_write(struct btrfs_receive *r)
675 if(r->write_fd == -1)
676 return;
678 close(r->write_fd);
679 r->write_fd = -1;
680 r->write_path[0] = 0;
683 static int process_write(const char *path, const void *data, u64 offset,
684 u64 len, void *user)
686 int ret = 0;
687 struct btrfs_receive *r = user;
688 char full_path[PATH_MAX];
689 u64 pos = 0;
690 int w;
692 ret = path_cat_out(full_path, r->full_subvol_path, path);
693 if (ret < 0) {
694 fprintf(stderr, "ERROR: write: path invalid: %s\n", path);
695 goto out;
698 ret = open_inode_for_write(r, full_path);
699 if (ret < 0)
700 goto out;
702 while (pos < len) {
703 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
704 offset + pos);
705 if (w < 0) {
706 ret = -errno;
707 fprintf(stderr, "ERROR: writing to %s failed. %s\n",
708 path, strerror(-ret));
709 goto out;
711 pos += w;
714 out:
715 return ret;
718 static int process_clone(const char *path, u64 offset, u64 len,
719 const u8 *clone_uuid, u64 clone_ctransid,
720 const char *clone_path, u64 clone_offset,
721 void *user)
723 int ret;
724 struct btrfs_receive *r = user;
725 struct btrfs_ioctl_clone_range_args clone_args;
726 struct subvol_info *si = NULL;
727 char full_path[PATH_MAX];
728 char *subvol_path = NULL;
729 char full_clone_path[PATH_MAX];
730 int clone_fd = -1;
732 ret = path_cat_out(full_path, r->full_subvol_path, path);
733 if (ret < 0) {
734 fprintf(stderr, "ERROR: clone: source path invalid: %s\n",
735 path);
736 goto out;
739 ret = open_inode_for_write(r, full_path);
740 if (ret < 0)
741 goto out;
743 si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
744 subvol_search_by_received_uuid);
745 if (!si) {
746 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
747 BTRFS_UUID_SIZE) == 0) {
748 /* TODO check generation of extent */
749 subvol_path = strdup(r->cur_subvol_path);
750 } else {
751 ret = -ENOENT;
752 fprintf(stderr, "ERROR: did not find source subvol.\n");
753 goto out;
755 } else {
756 /*if (rs_args.ctransid > rs_args.rtransid) {
757 if (!r->force) {
758 ret = -EINVAL;
759 fprintf(stderr, "ERROR: subvolume %s was "
760 "modified after it was "
761 "received.\n",
762 r->subvol_parent_name);
763 goto out;
764 } else {
765 fprintf(stderr, "WARNING: subvolume %s was "
766 "modified after it was "
767 "received.\n",
768 r->subvol_parent_name);
771 subvol_path = strdup(si->path);
774 ret = path_cat_out(full_clone_path, subvol_path, clone_path);
775 if (ret < 0) {
776 fprintf(stderr, "ERROR: clone: target path invalid: %s\n",
777 clone_path);
778 goto out;
781 clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
782 if (clone_fd < 0) {
783 ret = -errno;
784 fprintf(stderr, "ERROR: failed to open %s. %s\n",
785 full_clone_path, strerror(-ret));
786 goto out;
789 clone_args.src_fd = clone_fd;
790 clone_args.src_offset = clone_offset;
791 clone_args.src_length = len;
792 clone_args.dest_offset = offset;
793 ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
794 if (ret) {
795 ret = -errno;
796 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
797 path, strerror(-ret));
798 goto out;
801 out:
802 if (si) {
803 free(si->path);
804 free(si);
806 free(subvol_path);
807 if (clone_fd != -1)
808 close(clone_fd);
809 return ret;
813 static int process_set_xattr(const char *path, const char *name,
814 const void *data, int len, void *user)
816 int ret = 0;
817 struct btrfs_receive *r = user;
818 char full_path[PATH_MAX];
820 ret = path_cat_out(full_path, r->full_subvol_path, path);
821 if (ret < 0) {
822 fprintf(stderr, "ERROR: set_xattr: path invalid: %s\n", path);
823 goto out;
826 if (strcmp("security.capability", name) == 0) {
827 if (g_verbose >= 3)
828 fprintf(stderr, "set_xattr: cache capabilities\n");
829 if (r->cached_capabilities_len)
830 fprintf(stderr,
831 "WARNING: capabilities set multiple times per file: %s\n",
832 full_path);
833 if (len > sizeof(r->cached_capabilities)) {
834 fprintf(stderr,
835 "ERROR: capabilities encoded to %d bytes, buffer too small\n",
836 len);
837 ret = -E2BIG;
838 goto out;
840 r->cached_capabilities_len = len;
841 memcpy(r->cached_capabilities, data, len);
844 if (g_verbose >= 2) {
845 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
846 "data=%.*s\n", path, name, len,
847 len, (char*)data);
850 ret = lsetxattr(full_path, name, data, len, 0);
851 if (ret < 0) {
852 ret = -errno;
853 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
854 path, name, len, (char*)data, strerror(-ret));
855 goto out;
858 out:
859 return ret;
862 static int process_remove_xattr(const char *path, const char *name, void *user)
864 int ret = 0;
865 struct btrfs_receive *r = user;
866 char full_path[PATH_MAX];
868 ret = path_cat_out(full_path, r->full_subvol_path, path);
869 if (ret < 0) {
870 fprintf(stderr, "ERROR: remove_xattr: path invalid: %s\n",
871 path);
872 goto out;
875 if (g_verbose >= 2) {
876 fprintf(stderr, "remove_xattr %s - name=%s\n",
877 path, name);
880 ret = lremovexattr(full_path, name);
881 if (ret < 0) {
882 ret = -errno;
883 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
884 path, name, strerror(-ret));
885 goto out;
888 out:
889 return ret;
892 static int process_truncate(const char *path, u64 size, void *user)
894 int ret = 0;
895 struct btrfs_receive *r = user;
896 char full_path[PATH_MAX];
898 ret = path_cat_out(full_path, r->full_subvol_path, path);
899 if (ret < 0) {
900 fprintf(stderr, "ERROR: truncate: path invalid: %s\n", path);
901 goto out;
904 if (g_verbose >= 2)
905 fprintf(stderr, "truncate %s size=%llu\n", path, size);
907 ret = truncate(full_path, size);
908 if (ret < 0) {
909 ret = -errno;
910 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
911 path, strerror(-ret));
912 goto out;
915 out:
916 return ret;
919 static int process_chmod(const char *path, u64 mode, void *user)
921 int ret = 0;
922 struct btrfs_receive *r = user;
923 char full_path[PATH_MAX];
925 ret = path_cat_out(full_path, r->full_subvol_path, path);
926 if (ret < 0) {
927 fprintf(stderr, "ERROR: chmod: path invalid: %s\n", path);
928 goto out;
931 if (g_verbose >= 2)
932 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
934 ret = chmod(full_path, mode);
935 if (ret < 0) {
936 ret = -errno;
937 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
938 path, strerror(-ret));
939 goto out;
942 out:
943 return ret;
946 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
948 int ret = 0;
949 struct btrfs_receive *r = user;
950 char full_path[PATH_MAX];
952 ret = path_cat_out(full_path, r->full_subvol_path, path);
953 if (ret < 0) {
954 fprintf(stderr, "ERROR: chown: path invalid: %s\n", path);
955 goto out;
958 if (g_verbose >= 2)
959 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
960 uid, gid);
962 ret = lchown(full_path, uid, gid);
963 if (ret < 0) {
964 ret = -errno;
965 fprintf(stderr, "ERROR: chown %s failed. %s\n",
966 path, strerror(-ret));
967 goto out;
970 if (r->cached_capabilities_len) {
971 if (g_verbose >= 2)
972 fprintf(stderr, "chown: restore capabilities\n");
973 ret = lsetxattr(full_path, "security.capability",
974 r->cached_capabilities,
975 r->cached_capabilities_len, 0);
976 memset(r->cached_capabilities, 0,
977 sizeof(r->cached_capabilities));
978 r->cached_capabilities_len = 0;
979 if (ret < 0) {
980 ret = -errno;
981 fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
982 path, strerror(-ret));
983 goto out;
987 out:
988 return ret;
991 static int process_utimes(const char *path, struct timespec *at,
992 struct timespec *mt, struct timespec *ct,
993 void *user)
995 int ret = 0;
996 struct btrfs_receive *r = user;
997 char full_path[PATH_MAX];
998 struct timespec tv[2];
1000 ret = path_cat_out(full_path, r->full_subvol_path, path);
1001 if (ret < 0) {
1002 fprintf(stderr, "ERROR: utimes: path invalid: %s\n", path);
1003 goto out;
1006 if (g_verbose >= 2)
1007 fprintf(stderr, "utimes %s\n", path);
1009 tv[0] = *at;
1010 tv[1] = *mt;
1011 ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
1012 if (ret < 0) {
1013 ret = -errno;
1014 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
1015 path, strerror(-ret));
1016 goto out;
1019 out:
1020 return ret;
1023 static int process_update_extent(const char *path, u64 offset, u64 len,
1024 void *user)
1026 if (g_verbose >= 2)
1027 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
1028 path, (unsigned long long)offset,
1029 (unsigned long long)len);
1032 * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1035 return 0;
1038 static struct btrfs_send_ops send_ops = {
1039 .subvol = process_subvol,
1040 .snapshot = process_snapshot,
1041 .mkfile = process_mkfile,
1042 .mkdir = process_mkdir,
1043 .mknod = process_mknod,
1044 .mkfifo = process_mkfifo,
1045 .mksock = process_mksock,
1046 .symlink = process_symlink,
1047 .rename = process_rename,
1048 .link = process_link,
1049 .unlink = process_unlink,
1050 .rmdir = process_rmdir,
1051 .write = process_write,
1052 .clone = process_clone,
1053 .set_xattr = process_set_xattr,
1054 .remove_xattr = process_remove_xattr,
1055 .truncate = process_truncate,
1056 .chmod = process_chmod,
1057 .chown = process_chown,
1058 .utimes = process_utimes,
1059 .update_extent = process_update_extent,
1062 static int do_receive(struct btrfs_receive *r, const char *tomnt,
1063 char *realmnt, int r_fd, u64 max_errors)
1065 u64 subvol_id;
1066 int ret;
1067 char *dest_dir_full_path;
1068 char root_subvol_path[PATH_MAX];
1069 int end = 0;
1071 dest_dir_full_path = realpath(tomnt, NULL);
1072 if (!dest_dir_full_path) {
1073 ret = -errno;
1074 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
1075 strerror(-ret));
1076 goto out;
1078 r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
1079 if (r->dest_dir_fd < 0) {
1080 ret = -errno;
1081 fprintf(stderr,
1082 "ERROR: failed to open destination directory %s. %s\n",
1083 dest_dir_full_path, strerror(-ret));
1084 goto out;
1087 if (realmnt[0]) {
1088 r->root_path = realmnt;
1089 } else {
1090 ret = find_mount_root(dest_dir_full_path, &r->root_path);
1091 if (ret < 0) {
1092 fprintf(stderr,
1093 "ERROR: failed to determine mount point for %s: %s\n",
1094 dest_dir_full_path, strerror(-ret));
1095 ret = -EINVAL;
1096 goto out;
1098 if (ret > 0) {
1099 fprintf(stderr,
1100 "ERROR: %s doesn't belong to btrfs mount point\n",
1101 dest_dir_full_path);
1102 ret = -EINVAL;
1103 goto out;
1106 r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
1107 if (r->mnt_fd < 0) {
1108 ret = -errno;
1109 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
1110 strerror(-ret));
1111 goto out;
1115 * If we use -m or a default subvol we want to resolve the path to the
1116 * subvolume we're sitting in so that we can adjust the paths of any
1117 * subvols we want to receive in.
1119 ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
1120 if (ret) {
1121 fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
1122 ret);
1123 goto out;
1126 root_subvol_path[0] = 0;
1127 ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
1128 PATH_MAX, subvol_id);
1129 if (ret) {
1130 fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
1131 goto out;
1135 * Ok we're inside of a subvol off of the root subvol, we need to
1136 * actually set full_root_path.
1138 if (strlen(root_subvol_path))
1139 r->full_root_path = root_subvol_path;
1141 if (r->dest_dir_chroot) {
1142 if (chroot(dest_dir_full_path)) {
1143 ret = -errno;
1144 fprintf(stderr,
1145 "ERROR: failed to chroot to %s, %s\n",
1146 dest_dir_full_path,
1147 strerror(-ret));
1148 goto out;
1150 if (chdir("/")) {
1151 ret = -errno;
1152 fprintf(stderr,
1153 "ERROR: failed to chdir to /, %s\n",
1154 strerror(-ret));
1155 goto out;
1157 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1158 r->root_path = strdup("/");
1159 r->dest_dir_path = r->root_path;
1160 } else {
1162 * find_mount_root returns a root_path that is a subpath of
1163 * dest_dir_full_path. Now get the other part of root_path,
1164 * which is the destination dir relative to root_path.
1166 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1167 while (r->dest_dir_path[0] == '/')
1168 r->dest_dir_path++;
1171 ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1172 if (ret < 0)
1173 goto out;
1175 while (!end) {
1176 if (r->cached_capabilities_len) {
1177 if (g_verbose >= 3)
1178 fprintf(stderr, "clear cached capabilities\n");
1179 memset(r->cached_capabilities, 0,
1180 sizeof(r->cached_capabilities));
1181 r->cached_capabilities_len = 0;
1184 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1185 r->honor_end_cmd,
1186 max_errors);
1187 if (ret < 0)
1188 goto out;
1189 if (ret)
1190 end = 1;
1192 close_inode_for_write(r);
1193 ret = finish_subvol(r);
1194 if (ret < 0)
1195 goto out;
1197 ret = 0;
1199 out:
1200 if (r->write_fd != -1) {
1201 close(r->write_fd);
1202 r->write_fd = -1;
1204 free(r->root_path);
1205 r->root_path = NULL;
1206 r->dest_dir_path = NULL;
1207 free(dest_dir_full_path);
1208 subvol_uuid_search_finit(&r->sus);
1209 if (r->mnt_fd != -1) {
1210 close(r->mnt_fd);
1211 r->mnt_fd = -1;
1213 if (r->dest_dir_fd != -1) {
1214 close(r->dest_dir_fd);
1215 r->dest_dir_fd = -1;
1218 return ret;
1221 int cmd_receive(int argc, char **argv)
1223 char *tomnt = NULL;
1224 char fromfile[PATH_MAX];
1225 char realmnt[PATH_MAX];
1226 struct btrfs_receive r;
1227 int receive_fd = fileno(stdin);
1228 u64 max_errors = 1;
1229 int ret = 0;
1231 memset(&r, 0, sizeof(r));
1232 r.mnt_fd = -1;
1233 r.write_fd = -1;
1234 r.dest_dir_fd = -1;
1235 r.dest_dir_chroot = 0;
1236 realmnt[0] = 0;
1237 fromfile[0] = 0;
1239 while (1) {
1240 int c;
1241 static const struct option long_opts[] = {
1242 { "max-errors", required_argument, NULL, 'E' },
1243 { "chroot", no_argument, NULL, 'C' },
1244 { NULL, 0, NULL, 0 }
1247 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1248 if (c < 0)
1249 break;
1251 switch (c) {
1252 case 'v':
1253 g_verbose++;
1254 break;
1255 case 'f':
1256 if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
1257 fprintf(stderr,
1258 "ERROR: input file path too long (%zu)\n",
1259 strlen(optarg));
1260 ret = 1;
1261 goto out;
1263 break;
1264 case 'e':
1265 r.honor_end_cmd = 1;
1266 break;
1267 case 'C':
1268 r.dest_dir_chroot = 1;
1269 break;
1270 case 'E':
1271 max_errors = arg_strtou64(optarg);
1272 break;
1273 case 'm':
1274 if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
1275 fprintf(stderr,
1276 "ERROR: mount point path too long (%zu)\n",
1277 strlen(optarg));
1278 ret = 1;
1279 goto out;
1281 break;
1282 case '?':
1283 default:
1284 fprintf(stderr, "ERROR: receive args invalid.\n");
1285 return 1;
1289 if (check_argc_exact(argc - optind, 1))
1290 usage(cmd_receive_usage);
1292 tomnt = argv[optind];
1294 if (fromfile[0]) {
1295 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1296 if (receive_fd < 0) {
1297 fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1298 goto out;
1302 ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1304 out:
1306 return !!ret;
1309 const char * const cmd_receive_usage[] = {
1310 "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1311 "Receive subvolumes from stdin.",
1312 "Receives one or more subvolumes that were previously",
1313 "sent with btrfs send. The received subvolumes are stored",
1314 "into <mount>.",
1315 "btrfs receive will fail in case a receiving subvolume",
1316 "already exists. It will also fail in case a previously",
1317 "received subvolume was changed after it was received.",
1318 "After receiving a subvolume, it is immediately set to",
1319 "read only.\n",
1320 "-v Enable verbose debug output. Each",
1321 " occurrence of this option increases the",
1322 " verbose level more.",
1323 "-f <infile> By default, btrfs receive uses stdin",
1324 " to receive the subvolumes. Use this",
1325 " option to specify a file to use instead.",
1326 "-e Terminate after receiving an <end cmd>",
1327 " in the data stream. Without this option,",
1328 " the receiver terminates only if an error",
1329 " is recognized or on EOF.",
1330 "-C|--chroot confine the process to <mount> using chroot",
1331 "--max-errors <N> Terminate as soon as N errors happened while",
1332 " processing commands from the send stream.",
1333 " Default value is 1. A value of 0 means no limit.",
1334 "-m <mountpoint> The root mount point of the destination fs.",
1335 " If you do not have /proc use this to tell us where ",
1336 " this file system is mounted.",
1337 NULL