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