btrfs-progs: ioctl: make build-time structure size checks optional
[platform/upstream/btrfs-progs.git] / cmds-receive.c
1 /*
2  * Copyright (C) 2012 Alexander Block.  All rights reserved.
3  *
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.
7  *
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.
12  *
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.
17  */
18
19 #include "kerncompat.h"
20 #include "androidcompat.h"
21
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>
33
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>
41
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"
48
49 #include "send.h"
50 #include "send-stream.h"
51 #include "send-utils.h"
52
53 static int g_verbose = 0;
54
55 struct btrfs_receive
56 {
57         int mnt_fd;
58         int dest_dir_fd;
59
60         int write_fd;
61         char write_path[PATH_MAX];
62
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;
68
69         struct subvol_info cur_subvol;
70         /*
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.
73          */
74         char cur_subvol_path[PATH_MAX];
75
76         struct subvol_uuid_search sus;
77
78         int honor_end_cmd;
79
80         /*
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.
84          */
85         char cached_capabilities[64];
86         int cached_capabilities_len;
87 };
88
89 static int finish_subvol(struct btrfs_receive *r)
90 {
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;
96
97         if (r->cur_subvol_path[0] == 0)
98                 return 0;
99
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                 error("cannot open %s: %s\n",
105                                 r->cur_subvol_path, strerror(-ret));
106                 goto out;
107         }
108
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;
112
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);
117         }
118
119         ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
120         if (ret < 0) {
121                 ret = -errno;
122                 error("ioctl BTRFS_IOC_SET_RECEIVED_SUBVOL failed: %s",
123                                 strerror(-ret));
124                 goto out;
125         }
126         r->cur_subvol.rtransid = rs_args.rtransid;
127
128         ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
129         if (ret < 0) {
130                 ret = -errno;
131                 error("ioctl BTRFS_IOC_SUBVOL_GETFLAGS failed: %s",
132                                 strerror(-ret));
133                 goto out;
134         }
135
136         flags |= BTRFS_SUBVOL_RDONLY;
137
138         ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
139         if (ret < 0) {
140                 ret = -errno;
141                 error("failed to make subvolume read only: %s",
142                                 strerror(-ret));
143                 goto out;
144         }
145
146         ret = 0;
147
148 out:
149         if (r->cur_subvol_path[0]) {
150                 r->cur_subvol_path[0] = 0;
151         }
152         if (subvol_fd != -1)
153                 close(subvol_fd);
154         return ret;
155 }
156
157 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
158                           void *user)
159 {
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];
164
165         ret = finish_subvol(r);
166         if (ret < 0)
167                 goto out;
168
169         if (r->cur_subvol.path) {
170                 error("subvol: another one already started, path ptr: %s",
171                                 r->cur_subvol.path);
172                 ret = -EINVAL;
173                 goto out;
174         }
175         if (r->cur_subvol_path[0]) {
176                 error("subvol: another one already started, path buf: %s",
177                                 r->cur_subvol.path);
178                 ret = -EINVAL;
179                 goto out;
180         }
181
182         if (*r->dest_dir_path == 0) {
183                 strncpy_null(r->cur_subvol_path, path);
184         } else {
185                 ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
186                 if (ret < 0) {
187                         error("subvol: path invalid: %s\n", path);
188                         goto out;
189                 }
190         }
191         ret = path_cat3_out(r->full_subvol_path, r->root_path,
192                         r->dest_dir_path, path);
193         if (ret < 0) {
194                 error("subvol: path invalid: %s", path);
195                 goto out;
196         }
197
198         fprintf(stderr, "At subvol %s\n", path);
199
200         memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
201         r->cur_subvol.stransid = ctransid;
202
203         if (g_verbose) {
204                 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
205                 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
206                                 path, uuid_str,
207                                 r->cur_subvol.stransid);
208         }
209
210         memset(&args_v1, 0, sizeof(args_v1));
211         strncpy_null(args_v1.name, path);
212         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
213         if (ret < 0) {
214                 ret = -errno;
215                 error("creating subvolume %s failed: %s", path, strerror(-ret));
216                 goto out;
217         }
218
219 out:
220         return ret;
221 }
222
223 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
224                             const u8 *parent_uuid, u64 parent_ctransid,
225                             void *user)
226 {
227         int ret;
228         struct btrfs_receive *r = user;
229         char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
230         struct btrfs_ioctl_vol_args_v2 args_v2;
231         struct subvol_info *parent_subvol = NULL;
232
233         ret = finish_subvol(r);
234         if (ret < 0)
235                 goto out;
236
237         if (r->cur_subvol.path) {
238                 error("snapshot: another one already started, path ptr: %s",
239                                 r->cur_subvol.path);
240                 ret = -EINVAL;
241                 goto out;
242         }
243         if (r->cur_subvol_path[0]) {
244                 error("snapshot: another one already started, path buf: %s",
245                                 r->cur_subvol.path);
246                 ret = -EINVAL;
247                 goto out;
248         }
249
250         if (*r->dest_dir_path == 0) {
251                 strncpy_null(r->cur_subvol_path, path);
252         } else {
253                 ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
254                 if (ret < 0) {
255                         error("snapshot: path invalid: %s", path);
256                         goto out;
257                 }
258         }
259         ret = path_cat3_out(r->full_subvol_path, r->root_path,
260                         r->dest_dir_path, path);
261         if (ret < 0) {
262                 error("snapshot: path invalid: %s", path);
263                 goto out;
264         }
265
266         fprintf(stdout, "At snapshot %s\n", path);
267
268         memcpy(r->cur_subvol.received_uuid, uuid, BTRFS_UUID_SIZE);
269         r->cur_subvol.stransid = ctransid;
270
271         if (g_verbose) {
272                 uuid_unparse((u8*)r->cur_subvol.received_uuid, uuid_str);
273                 fprintf(stderr, "receiving snapshot %s uuid=%s, "
274                                 "ctransid=%llu ", path, uuid_str,
275                                 r->cur_subvol.stransid);
276                 uuid_unparse(parent_uuid, uuid_str);
277                 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
278                                 uuid_str, parent_ctransid);
279         }
280
281         memset(&args_v2, 0, sizeof(args_v2));
282         strncpy_null(args_v2.name, path);
283
284         parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
285                         parent_ctransid, NULL, subvol_search_by_received_uuid);
286         if (!parent_subvol) {
287                 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
288                                 parent_ctransid, NULL, subvol_search_by_uuid);
289         }
290         if (!parent_subvol) {
291                 ret = -ENOENT;
292                 error("cannot find parent subvolume");
293                 goto out;
294         }
295
296         /*
297          * The path is resolved from the root subvol, but we could be in some
298          * subvolume under the root subvolume, so try and adjust the path to be
299          * relative to our root path.
300          */
301         if (r->full_root_path) {
302                 size_t root_len;
303                 size_t sub_len;
304
305                 root_len = strlen(r->full_root_path);
306                 sub_len = strlen(parent_subvol->path);
307
308                 /* First make sure the parent subvol is actually in our path */
309                 if (sub_len < root_len ||
310                     strstr(parent_subvol->path, r->full_root_path) == NULL) {
311                         error(
312                 "parent subvol is not reachable from inside the root subvol");
313                         ret = -ENOENT;
314                         goto out;
315                 }
316
317                 if (sub_len == root_len) {
318                         parent_subvol->path[0] = '/';
319                         parent_subvol->path[1] = '\0';
320                 } else {
321                         /*
322                          * root path is foo/bar
323                          * subvol path is foo/bar/baz
324                          *
325                          * we need to have baz be the path, so we need to move
326                          * the bit after foo/bar/, so path + root_len + 1, and
327                          * move the part we care about, so sub_len - root_len -
328                          * 1.
329                          */
330                         memmove(parent_subvol->path,
331                                 parent_subvol->path + root_len + 1,
332                                 sub_len - root_len - 1);
333                         parent_subvol->path[sub_len - root_len - 1] = '\0';
334                 }
335         }
336         /*if (rs_args.ctransid > rs_args.rtransid) {
337                 if (!r->force) {
338                         ret = -EINVAL;
339                         fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
340                         goto out;
341                 } else {
342                         fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
343                 }
344         }*/
345
346         if (*parent_subvol->path == 0)
347                 args_v2.fd = dup(r->mnt_fd);
348         else
349                 args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
350                                 O_RDONLY | O_NOATIME);
351         if (args_v2.fd < 0) {
352                 ret = -errno;
353                 if (errno != ENOENT)
354                         error("cannot open %s: %s",
355                                         parent_subvol->path, strerror(-ret));
356                 else
357                         fprintf(stderr,
358                                 "It seems that you have changed your default "
359                                 "subvolume or you specify other subvolume to\n"
360                                 "mount btrfs, try to remount this btrfs filesystem "
361                                 "with fs tree, and run btrfs receive again!\n");
362                 goto out;
363         }
364
365         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
366         close(args_v2.fd);
367         if (ret < 0) {
368                 ret = -errno;
369                 error("creating snapshot %s -> %s failed: %s",
370                                 parent_subvol->path, path, strerror(-ret));
371                 goto out;
372         }
373
374 out:
375         if (parent_subvol) {
376                 free(parent_subvol->path);
377                 free(parent_subvol);
378         }
379         return ret;
380 }
381
382 static int process_mkfile(const char *path, void *user)
383 {
384         int ret;
385         struct btrfs_receive *r = user;
386         char full_path[PATH_MAX];
387
388         ret = path_cat_out(full_path, r->full_subvol_path, path);
389         if (ret < 0) {
390                 error("mkfile: path invalid: %s", path);
391                 goto out;
392         }
393
394         if (g_verbose >= 2)
395                 fprintf(stderr, "mkfile %s\n", path);
396
397         ret = creat(full_path, 0600);
398         if (ret < 0) {
399                 ret = -errno;
400                 error("mkfile %s failed: %s", path, strerror(-ret));
401                 goto out;
402         }
403         close(ret);
404         ret = 0;
405
406 out:
407         return ret;
408 }
409
410 static int process_mkdir(const char *path, void *user)
411 {
412         int ret;
413         struct btrfs_receive *r = user;
414         char full_path[PATH_MAX];
415
416         ret = path_cat_out(full_path, r->full_subvol_path, path);
417         if (ret < 0) {
418                 error("mkdir: path invalid: %s", path);
419                 goto out;
420         }
421
422         if (g_verbose >= 2)
423                 fprintf(stderr, "mkdir %s\n", path);
424
425         ret = mkdir(full_path, 0700);
426         if (ret < 0) {
427                 ret = -errno;
428                 error("mkdir %s failed: %s", path, strerror(-ret));
429         }
430
431 out:
432         return ret;
433 }
434
435 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
436 {
437         int ret;
438         struct btrfs_receive *r = user;
439         char full_path[PATH_MAX];
440
441         ret = path_cat_out(full_path, r->full_subvol_path, path);
442         if (ret < 0) {
443                 error("mknod: path invalid: %s", path);
444                 goto out;
445         }
446
447         if (g_verbose >= 2)
448                 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
449                                 path, mode, dev);
450
451         ret = mknod(full_path, mode & S_IFMT, dev);
452         if (ret < 0) {
453                 ret = -errno;
454                 error("mknod %s failed: %s", path, strerror(-ret));
455         }
456
457 out:
458         return ret;
459 }
460
461 static int process_mkfifo(const char *path, void *user)
462 {
463         int ret;
464         struct btrfs_receive *r = user;
465         char full_path[PATH_MAX];
466
467         ret = path_cat_out(full_path, r->full_subvol_path, path);
468         if (ret < 0) {
469                 error("mkfifo: path invalid: %s", path);
470                 goto out;
471         }
472
473         if (g_verbose >= 2)
474                 fprintf(stderr, "mkfifo %s\n", path);
475
476         ret = mkfifo(full_path, 0600);
477         if (ret < 0) {
478                 ret = -errno;
479                 error("mkfifo %s failed: %s", path, strerror(-ret));
480         }
481
482 out:
483         return ret;
484 }
485
486 static int process_mksock(const char *path, void *user)
487 {
488         int ret;
489         struct btrfs_receive *r = user;
490         char full_path[PATH_MAX];
491
492         ret = path_cat_out(full_path, r->full_subvol_path, path);
493         if (ret < 0) {
494                 error("mksock: path invalid: %s", path);
495                 goto out;
496         }
497
498         if (g_verbose >= 2)
499                 fprintf(stderr, "mksock %s\n", path);
500
501         ret = mknod(full_path, 0600 | S_IFSOCK, 0);
502         if (ret < 0) {
503                 ret = -errno;
504                 error("mknod %s failed: %s", path, strerror(-ret));
505         }
506
507 out:
508         return ret;
509 }
510
511 static int process_symlink(const char *path, const char *lnk, void *user)
512 {
513         int ret;
514         struct btrfs_receive *r = user;
515         char full_path[PATH_MAX];
516
517         ret = path_cat_out(full_path, r->full_subvol_path, path);
518         if (ret < 0) {
519                 error("symlink: path invalid: %s", path);
520                 goto out;
521         }
522
523         if (g_verbose >= 2)
524                 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
525
526         ret = symlink(lnk, full_path);
527         if (ret < 0) {
528                 ret = -errno;
529                 error("symlink %s -> %s failed: %s", path,
530                                 lnk, strerror(-ret));
531         }
532
533 out:
534         return ret;
535 }
536
537 static int process_rename(const char *from, const char *to, void *user)
538 {
539         int ret;
540         struct btrfs_receive *r = user;
541         char full_from[PATH_MAX];
542         char full_to[PATH_MAX];
543
544         ret = path_cat_out(full_from, r->full_subvol_path, from);
545         if (ret < 0) {
546                 error("rename: source path invalid: %s", from);
547                 goto out;
548         }
549
550         ret = path_cat_out(full_to, r->full_subvol_path, to);
551         if (ret < 0) {
552                 error("rename: target path invalid: %s", to);
553                 goto out;
554         }
555
556         if (g_verbose >= 2)
557                 fprintf(stderr, "rename %s -> %s\n", from, to);
558
559         ret = rename(full_from, full_to);
560         if (ret < 0) {
561                 ret = -errno;
562                 error("rename %s -> %s failed: %s", from,
563                                 to, strerror(-ret));
564         }
565
566 out:
567         return ret;
568 }
569
570 static int process_link(const char *path, const char *lnk, void *user)
571 {
572         int ret;
573         struct btrfs_receive *r = user;
574         char full_path[PATH_MAX];
575         char full_link_path[PATH_MAX];
576
577         ret = path_cat_out(full_path, r->full_subvol_path, path);
578         if (ret < 0) {
579                 error("link: source path invalid: %s", full_path);
580                 goto out;
581         }
582
583         ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
584         if (ret < 0) {
585                 error("link: target path invalid: %s", full_link_path);
586                 goto out;
587         }
588
589         if (g_verbose >= 2)
590                 fprintf(stderr, "link %s -> %s\n", path, lnk);
591
592         ret = link(full_link_path, full_path);
593         if (ret < 0) {
594                 ret = -errno;
595                 error("link %s -> %s failed: %s", path, lnk, strerror(-ret));
596         }
597
598 out:
599         return ret;
600 }
601
602
603 static int process_unlink(const char *path, void *user)
604 {
605         int ret;
606         struct btrfs_receive *r = user;
607         char full_path[PATH_MAX];
608
609         ret = path_cat_out(full_path, r->full_subvol_path, path);
610         if (ret < 0) {
611                 error("unlink: path invalid: %s", path);
612                 goto out;
613         }
614
615         if (g_verbose >= 2)
616                 fprintf(stderr, "unlink %s\n", path);
617
618         ret = unlink(full_path);
619         if (ret < 0) {
620                 ret = -errno;
621                 error("unlink %s failed. %s", path, strerror(-ret));
622         }
623
624 out:
625         return ret;
626 }
627
628 static int process_rmdir(const char *path, void *user)
629 {
630         int ret;
631         struct btrfs_receive *r = user;
632         char full_path[PATH_MAX];
633
634         ret = path_cat_out(full_path, r->full_subvol_path, path);
635         if (ret < 0) {
636                 error("rmdir: path invalid: %s", path);
637                 goto out;
638         }
639
640         if (g_verbose >= 2)
641                 fprintf(stderr, "rmdir %s\n", path);
642
643         ret = rmdir(full_path);
644         if (ret < 0) {
645                 ret = -errno;
646                 error("rmdir %s failed: %s", path, strerror(-ret));
647         }
648
649 out:
650         return ret;
651 }
652
653 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
654 {
655         int ret = 0;
656
657         if (r->write_fd != -1) {
658                 if (strcmp(r->write_path, path) == 0)
659                         goto out;
660                 close(r->write_fd);
661                 r->write_fd = -1;
662         }
663
664         r->write_fd = open(path, O_RDWR);
665         if (r->write_fd < 0) {
666                 ret = -errno;
667                 error("cannot open %s: %s", path, strerror(-ret));
668                 goto out;
669         }
670         strncpy_null(r->write_path, path);
671
672 out:
673         return ret;
674 }
675
676 static void close_inode_for_write(struct btrfs_receive *r)
677 {
678         if(r->write_fd == -1)
679                 return;
680
681         close(r->write_fd);
682         r->write_fd = -1;
683         r->write_path[0] = 0;
684 }
685
686 static int process_write(const char *path, const void *data, u64 offset,
687                          u64 len, void *user)
688 {
689         int ret = 0;
690         struct btrfs_receive *r = user;
691         char full_path[PATH_MAX];
692         u64 pos = 0;
693         int w;
694
695         ret = path_cat_out(full_path, r->full_subvol_path, path);
696         if (ret < 0) {
697                 error("write: path invalid: %s", path);
698                 goto out;
699         }
700
701         ret = open_inode_for_write(r, full_path);
702         if (ret < 0)
703                 goto out;
704
705         while (pos < len) {
706                 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
707                                 offset + pos);
708                 if (w < 0) {
709                         ret = -errno;
710                         error("writing to %s failed: %s\n",
711                                         path, strerror(-ret));
712                         goto out;
713                 }
714                 pos += w;
715         }
716
717 out:
718         return ret;
719 }
720
721 static int process_clone(const char *path, u64 offset, u64 len,
722                          const u8 *clone_uuid, u64 clone_ctransid,
723                          const char *clone_path, u64 clone_offset,
724                          void *user)
725 {
726         int ret;
727         struct btrfs_receive *r = user;
728         struct btrfs_ioctl_clone_range_args clone_args;
729         struct subvol_info *si = NULL;
730         char full_path[PATH_MAX];
731         char *subvol_path = NULL;
732         char full_clone_path[PATH_MAX];
733         int clone_fd = -1;
734
735         ret = path_cat_out(full_path, r->full_subvol_path, path);
736         if (ret < 0) {
737                 error("clone: source path invalid: %s", path);
738                 goto out;
739         }
740
741         ret = open_inode_for_write(r, full_path);
742         if (ret < 0)
743                 goto out;
744
745         si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
746                         subvol_search_by_received_uuid);
747         if (!si) {
748                 if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
749                                 BTRFS_UUID_SIZE) == 0) {
750                         /* TODO check generation of extent */
751                         subvol_path = strdup(r->cur_subvol_path);
752                 } else {
753                         ret = -ENOENT;
754                         error("clone: did not find source subvol");
755                         goto out;
756                 }
757         } else {
758                 /*if (rs_args.ctransid > rs_args.rtransid) {
759                         if (!r->force) {
760                                 ret = -EINVAL;
761                                 fprintf(stderr, "ERROR: subvolume %s was "
762                                                 "modified after it was "
763                                                 "received.\n",
764                                                 r->subvol_parent_name);
765                                 goto out;
766                         } else {
767                                 fprintf(stderr, "WARNING: subvolume %s was "
768                                                 "modified after it was "
769                                                 "received.\n",
770                                                 r->subvol_parent_name);
771                         }
772                 }*/
773                 subvol_path = strdup(si->path);
774         }
775
776         ret = path_cat_out(full_clone_path, subvol_path, clone_path);
777         if (ret < 0) {
778                 error("clone: target path invalid: %s", clone_path);
779                 goto out;
780         }
781
782         clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
783         if (clone_fd < 0) {
784                 ret = -errno;
785                 error("cannot open %s: %s", full_clone_path, strerror(-ret));
786                 goto out;
787         }
788
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 < 0) {
795                 ret = -errno;
796                 error("failed to clone extents to %s\n%s\n",
797                                 path, strerror(-ret));
798                 goto out;
799         }
800
801 out:
802         if (si) {
803                 free(si->path);
804                 free(si);
805         }
806         free(subvol_path);
807         if (clone_fd != -1)
808                 close(clone_fd);
809         return ret;
810 }
811
812
813 static int process_set_xattr(const char *path, const char *name,
814                              const void *data, int len, void *user)
815 {
816         int ret = 0;
817         struct btrfs_receive *r = user;
818         char full_path[PATH_MAX];
819
820         ret = path_cat_out(full_path, r->full_subvol_path, path);
821         if (ret < 0) {
822                 error("set_xattr: path invalid: %s", path);
823                 goto out;
824         }
825
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                         warning("capabilities set multiple times per file: %s",
831                                 full_path);
832                 if (len > sizeof(r->cached_capabilities)) {
833                         error("capabilities encoded to %d bytes, buffer too small",
834                                 len);
835                         ret = -E2BIG;
836                         goto out;
837                 }
838                 r->cached_capabilities_len = len;
839                 memcpy(r->cached_capabilities, data, len);
840         }
841
842         if (g_verbose >= 2) {
843                 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
844                                 "data=%.*s\n", path, name, len,
845                                 len, (char*)data);
846         }
847
848         ret = lsetxattr(full_path, name, data, len, 0);
849         if (ret < 0) {
850                 ret = -errno;
851                 error("lsetxattr %s %s=%.*s failed: %s",
852                                 path, name, len, (char*)data, strerror(-ret));
853                 goto out;
854         }
855
856 out:
857         return ret;
858 }
859
860 static int process_remove_xattr(const char *path, const char *name, void *user)
861 {
862         int ret = 0;
863         struct btrfs_receive *r = user;
864         char full_path[PATH_MAX];
865
866         ret = path_cat_out(full_path, r->full_subvol_path, path);
867         if (ret < 0) {
868                 error("remove_xattr: path invalid: %s", path);
869                 goto out;
870         }
871
872         if (g_verbose >= 2) {
873                 fprintf(stderr, "remove_xattr %s - name=%s\n",
874                                 path, name);
875         }
876
877         ret = lremovexattr(full_path, name);
878         if (ret < 0) {
879                 ret = -errno;
880                 error("lremovexattr %s %s failed: %s",
881                                 path, name, strerror(-ret));
882                 goto out;
883         }
884
885 out:
886         return ret;
887 }
888
889 static int process_truncate(const char *path, u64 size, void *user)
890 {
891         int ret = 0;
892         struct btrfs_receive *r = user;
893         char full_path[PATH_MAX];
894
895         ret = path_cat_out(full_path, r->full_subvol_path, path);
896         if (ret < 0) {
897                 error("truncate: path invalid: %s", path);
898                 goto out;
899         }
900
901         if (g_verbose >= 2)
902                 fprintf(stderr, "truncate %s size=%llu\n", path, size);
903
904         ret = truncate(full_path, size);
905         if (ret < 0) {
906                 ret = -errno;
907                 error("truncate %s failed: %s", path, strerror(-ret));
908                 goto out;
909         }
910
911 out:
912         return ret;
913 }
914
915 static int process_chmod(const char *path, u64 mode, void *user)
916 {
917         int ret = 0;
918         struct btrfs_receive *r = user;
919         char full_path[PATH_MAX];
920
921         ret = path_cat_out(full_path, r->full_subvol_path, path);
922         if (ret < 0) {
923                 error("chmod: path invalid: %s", path);
924                 goto out;
925         }
926
927         if (g_verbose >= 2)
928                 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
929
930         ret = chmod(full_path, mode);
931         if (ret < 0) {
932                 ret = -errno;
933                 error("chmod %s failed: %s", path, strerror(-ret));
934                 goto out;
935         }
936
937 out:
938         return ret;
939 }
940
941 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
942 {
943         int ret = 0;
944         struct btrfs_receive *r = user;
945         char full_path[PATH_MAX];
946
947         ret = path_cat_out(full_path, r->full_subvol_path, path);
948         if (ret < 0) {
949                 error("chown: path invalid: %s", path);
950                 goto out;
951         }
952
953         if (g_verbose >= 2)
954                 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
955                                 uid, gid);
956
957         ret = lchown(full_path, uid, gid);
958         if (ret < 0) {
959                 ret = -errno;
960                 error("chown %s failed: %s", path, strerror(-ret));
961                 goto out;
962         }
963
964         if (r->cached_capabilities_len) {
965                 if (g_verbose >= 2)
966                         fprintf(stderr, "chown: restore capabilities\n");
967                 ret = lsetxattr(full_path, "security.capability",
968                                 r->cached_capabilities,
969                                 r->cached_capabilities_len, 0);
970                 memset(r->cached_capabilities, 0,
971                                 sizeof(r->cached_capabilities));
972                 r->cached_capabilities_len = 0;
973                 if (ret < 0) {
974                         ret = -errno;
975                         error("restoring capabilities %s: %s",
976                                         path, strerror(-ret));
977                         goto out;
978                 }
979         }
980
981 out:
982         return ret;
983 }
984
985 static int process_utimes(const char *path, struct timespec *at,
986                           struct timespec *mt, struct timespec *ct,
987                           void *user)
988 {
989         int ret = 0;
990         struct btrfs_receive *r = user;
991         char full_path[PATH_MAX];
992         struct timespec tv[2];
993
994         ret = path_cat_out(full_path, r->full_subvol_path, path);
995         if (ret < 0) {
996                 error("utimes: path invalid: %s", path);
997                 goto out;
998         }
999
1000         if (g_verbose >= 2)
1001                 fprintf(stderr, "utimes %s\n", path);
1002
1003         tv[0] = *at;
1004         tv[1] = *mt;
1005         ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
1006         if (ret < 0) {
1007                 ret = -errno;
1008                 error("utimes %s failed: %s",
1009                                 path, strerror(-ret));
1010                 goto out;
1011         }
1012
1013 out:
1014         return ret;
1015 }
1016
1017 static int process_update_extent(const char *path, u64 offset, u64 len,
1018                 void *user)
1019 {
1020         if (g_verbose >= 2)
1021                 fprintf(stderr, "update_extent %s: offset=%llu, len=%llu\n",
1022                                 path, (unsigned long long)offset,
1023                                 (unsigned long long)len);
1024
1025         /*
1026          * Sent with BTRFS_SEND_FLAG_NO_FILE_DATA, nothing to do.
1027          */
1028
1029         return 0;
1030 }
1031
1032 static struct btrfs_send_ops send_ops = {
1033         .subvol = process_subvol,
1034         .snapshot = process_snapshot,
1035         .mkfile = process_mkfile,
1036         .mkdir = process_mkdir,
1037         .mknod = process_mknod,
1038         .mkfifo = process_mkfifo,
1039         .mksock = process_mksock,
1040         .symlink = process_symlink,
1041         .rename = process_rename,
1042         .link = process_link,
1043         .unlink = process_unlink,
1044         .rmdir = process_rmdir,
1045         .write = process_write,
1046         .clone = process_clone,
1047         .set_xattr = process_set_xattr,
1048         .remove_xattr = process_remove_xattr,
1049         .truncate = process_truncate,
1050         .chmod = process_chmod,
1051         .chown = process_chown,
1052         .utimes = process_utimes,
1053         .update_extent = process_update_extent,
1054 };
1055
1056 static int do_receive(struct btrfs_receive *r, const char *tomnt,
1057                       char *realmnt, int r_fd, u64 max_errors)
1058 {
1059         u64 subvol_id;
1060         int ret;
1061         char *dest_dir_full_path;
1062         char root_subvol_path[PATH_MAX];
1063         int end = 0;
1064
1065         dest_dir_full_path = realpath(tomnt, NULL);
1066         if (!dest_dir_full_path) {
1067                 ret = -errno;
1068                 error("realpath(%s) failed: %s", tomnt, strerror(-ret));
1069                 goto out;
1070         }
1071         r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
1072         if (r->dest_dir_fd < 0) {
1073                 ret = -errno;
1074                 error("cannot open destination directory %s: %s",
1075                         dest_dir_full_path, strerror(-ret));
1076                 goto out;
1077         }
1078
1079         if (realmnt[0]) {
1080                 r->root_path = realmnt;
1081         } else {
1082                 ret = find_mount_root(dest_dir_full_path, &r->root_path);
1083                 if (ret < 0) {
1084                         error("failed to determine mount point for %s: %s",
1085                                 dest_dir_full_path, strerror(-ret));
1086                         ret = -EINVAL;
1087                         goto out;
1088                 }
1089                 if (ret > 0) {
1090                         error("%s doesn't belong to btrfs mount point",
1091                                 dest_dir_full_path);
1092                         ret = -EINVAL;
1093                         goto out;
1094                 }
1095         }
1096         r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
1097         if (r->mnt_fd < 0) {
1098                 ret = -errno;
1099                 error("cannot open %s: %s", r->root_path, strerror(-ret));
1100                 goto out;
1101         }
1102
1103         /*
1104          * If we use -m or a default subvol we want to resolve the path to the
1105          * subvolume we're sitting in so that we can adjust the paths of any
1106          * subvols we want to receive in.
1107          */
1108         ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
1109         if (ret) {
1110                 error("cannot resolve our subvolid: %d",
1111                         ret);
1112                 goto out;
1113         }
1114
1115         root_subvol_path[0] = 0;
1116         ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
1117                                      PATH_MAX, subvol_id);
1118         if (ret) {
1119                 error("cannot resolve our subvol path");
1120                 goto out;
1121         }
1122
1123         /*
1124          * Ok we're inside of a subvol off of the root subvol, we need to
1125          * actually set full_root_path.
1126          */
1127         if (*root_subvol_path)
1128                 r->full_root_path = root_subvol_path;
1129
1130         if (r->dest_dir_chroot) {
1131                 if (chroot(dest_dir_full_path)) {
1132                         ret = -errno;
1133                         error("failed to chroot to %s: %s",
1134                                 dest_dir_full_path, strerror(-ret));
1135                         goto out;
1136                 }
1137                 if (chdir("/")) {
1138                         ret = -errno;
1139                         error("failed to chdir to / after chroot: %s",
1140                                 strerror(-ret));
1141                         goto out;
1142                 }
1143                 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
1144                 r->root_path = strdup("/");
1145                 r->dest_dir_path = r->root_path;
1146         } else {
1147                 /*
1148                  * find_mount_root returns a root_path that is a subpath of
1149                  * dest_dir_full_path. Now get the other part of root_path,
1150                  * which is the destination dir relative to root_path.
1151                  */
1152                 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
1153                 while (r->dest_dir_path[0] == '/')
1154                         r->dest_dir_path++;
1155         }
1156
1157         ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
1158         if (ret < 0)
1159                 goto out;
1160
1161         while (!end) {
1162                 if (r->cached_capabilities_len) {
1163                         if (g_verbose >= 3)
1164                                 fprintf(stderr, "clear cached capabilities\n");
1165                         memset(r->cached_capabilities, 0,
1166                                         sizeof(r->cached_capabilities));
1167                         r->cached_capabilities_len = 0;
1168                 }
1169
1170                 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
1171                                                          r->honor_end_cmd,
1172                                                          max_errors);
1173                 if (ret < 0)
1174                         goto out;
1175                 if (ret)
1176                         end = 1;
1177
1178                 close_inode_for_write(r);
1179                 ret = finish_subvol(r);
1180                 if (ret < 0)
1181                         goto out;
1182         }
1183         ret = 0;
1184
1185 out:
1186         if (r->write_fd != -1) {
1187                 close(r->write_fd);
1188                 r->write_fd = -1;
1189         }
1190
1191         if (r->root_path != realmnt)
1192                 free(r->root_path);
1193         r->root_path = NULL;
1194         r->dest_dir_path = NULL;
1195         free(dest_dir_full_path);
1196         subvol_uuid_search_finit(&r->sus);
1197         if (r->mnt_fd != -1) {
1198                 close(r->mnt_fd);
1199                 r->mnt_fd = -1;
1200         }
1201         if (r->dest_dir_fd != -1) {
1202                 close(r->dest_dir_fd);
1203                 r->dest_dir_fd = -1;
1204         }
1205
1206         return ret;
1207 }
1208
1209 int cmd_receive(int argc, char **argv)
1210 {
1211         char *tomnt = NULL;
1212         char fromfile[PATH_MAX];
1213         char realmnt[PATH_MAX];
1214         struct btrfs_receive r;
1215         int receive_fd = fileno(stdin);
1216         u64 max_errors = 1;
1217         int ret = 0;
1218
1219         memset(&r, 0, sizeof(r));
1220         r.mnt_fd = -1;
1221         r.write_fd = -1;
1222         r.dest_dir_fd = -1;
1223         r.dest_dir_chroot = 0;
1224         realmnt[0] = 0;
1225         fromfile[0] = 0;
1226
1227         while (1) {
1228                 int c;
1229                 static const struct option long_opts[] = {
1230                         { "max-errors", required_argument, NULL, 'E' },
1231                         { "chroot", no_argument, NULL, 'C' },
1232                         { NULL, 0, NULL, 0 }
1233                 };
1234
1235                 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1236                 if (c < 0)
1237                         break;
1238
1239                 switch (c) {
1240                 case 'v':
1241                         g_verbose++;
1242                         break;
1243                 case 'f':
1244                         if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
1245                                 error("input file path too long (%zu)",
1246                                         strlen(optarg));
1247                                 ret = 1;
1248                                 goto out;
1249                         }
1250                         break;
1251                 case 'e':
1252                         r.honor_end_cmd = 1;
1253                         break;
1254                 case 'C':
1255                         r.dest_dir_chroot = 1;
1256                         break;
1257                 case 'E':
1258                         max_errors = arg_strtou64(optarg);
1259                         break;
1260                 case 'm':
1261                         if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
1262                                 error("mount point path too long (%zu)",
1263                                         strlen(optarg));
1264                                 ret = 1;
1265                                 goto out;
1266                         }
1267                         break;
1268                 case '?':
1269                 default:
1270                         error("receive args invalid");
1271                         return 1;
1272                 }
1273         }
1274
1275         if (check_argc_exact(argc - optind, 1))
1276                 usage(cmd_receive_usage);
1277
1278         tomnt = argv[optind];
1279
1280         if (fromfile[0]) {
1281                 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1282                 if (receive_fd < 0) {
1283                         error("cannot open %s: %s", fromfile, strerror(errno));
1284                         goto out;
1285                 }
1286         }
1287
1288         ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1289         if (receive_fd != fileno(stdin))
1290                 close(receive_fd);
1291
1292 out:
1293
1294         return !!ret;
1295 }
1296
1297 const char * const cmd_receive_usage[] = {
1298         "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1299         "Receive subvolumes from stdin.",
1300         "Receives one or more subvolumes that were previously",
1301         "sent with btrfs send. The received subvolumes are stored",
1302         "into <mount>.",
1303         "btrfs receive will fail in case a receiving subvolume",
1304         "already exists. It will also fail in case a previously",
1305         "received subvolume was changed after it was received.",
1306         "After receiving a subvolume, it is immediately set to",
1307         "read only.\n",
1308         "-v               Enable verbose debug output. Each",
1309         "                 occurrence of this option increases the",
1310         "                 verbose level more.",
1311         "-f <infile>      By default, btrfs receive uses stdin",
1312         "                 to receive the subvolumes. Use this",
1313         "                 option to specify a file to use instead.",
1314         "-e               Terminate after receiving an <end cmd>",
1315         "                 in the data stream. Without this option,",
1316         "                 the receiver terminates only if an error",
1317         "                 is recognized or on EOF.",
1318         "-C|--chroot      confine the process to <mount> using chroot",
1319         "--max-errors <N> Terminate as soon as N errors happened while",
1320         "                 processing commands from the send stream.",
1321         "                 Default value is 1. A value of 0 means no limit.",
1322         "-m <mountpoint>  The root mount point of the destination fs.",
1323         "                 If you do not have /proc use this to tell us where ",
1324         "                 this file system is mounted.",
1325         NULL
1326 };