a57f8d9f0b6280290b10c93fca3178c96dedc546
[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         int dest_dir_chroot;
65
66         struct subvol_info *cur_subvol;
67
68         struct subvol_uuid_search sus;
69
70         int honor_end_cmd;
71
72         /*
73          * Buffer to store capabilities from security.capabilities xattr,
74          * usually 20 bytes, but make same room for potentially larger
75          * encodings. Must be set only once per file, denoted by length > 0.
76          */
77         char cached_capabilities[64];
78         int cached_capabilities_len;
79 };
80
81 static int finish_subvol(struct btrfs_receive *r)
82 {
83         int ret;
84         int subvol_fd = -1;
85         struct btrfs_ioctl_received_subvol_args rs_args;
86         char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
87         u64 flags;
88
89         if (r->cur_subvol == NULL)
90                 return 0;
91
92         subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
93                         O_RDONLY | O_NOATIME);
94         if (subvol_fd < 0) {
95                 ret = -errno;
96                 fprintf(stderr, "ERROR: open %s failed. %s\n",
97                                 r->cur_subvol->path, strerror(-ret));
98                 goto out;
99         }
100
101         memset(&rs_args, 0, sizeof(rs_args));
102         memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
103         rs_args.stransid = r->cur_subvol->stransid;
104
105         if (g_verbose >= 1) {
106                 uuid_unparse((u8*)rs_args.uuid, uuid_str);
107                 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
108                                 "stransid=%llu\n", uuid_str, rs_args.stransid);
109         }
110
111         ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
112         if (ret < 0) {
113                 ret = -errno;
114                 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
115                                 strerror(-ret));
116                 goto out;
117         }
118         r->cur_subvol->rtransid = rs_args.rtransid;
119
120         ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
121         if (ret < 0) {
122                 ret = -errno;
123                 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
124                                 strerror(-ret));
125                 goto out;
126         }
127
128         flags |= BTRFS_SUBVOL_RDONLY;
129
130         ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
131         if (ret < 0) {
132                 ret = -errno;
133                 fprintf(stderr, "ERROR: failed to make subvolume read only. "
134                                 "%s\n", strerror(-ret));
135                 goto out;
136         }
137
138         ret = 0;
139
140 out:
141         if (r->cur_subvol) {
142                 free(r->cur_subvol->path);
143                 free(r->cur_subvol);
144                 r->cur_subvol = 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         r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
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         r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
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         /*if (rs_args.ctransid > rs_args.rtransid) {
252                 if (!r->force) {
253                         ret = -EINVAL;
254                         fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
255                         goto out;
256                 } else {
257                         fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
258                 }
259         }*/
260
261         args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
262                         O_RDONLY | O_NOATIME);
263         if (args_v2.fd < 0) {
264                 ret = -errno;
265                 if (errno != ENOENT)
266                         fprintf(stderr, "ERROR: open %s failed. %s\n",
267                                         parent_subvol->path, strerror(-ret));
268                 else
269                         fprintf(stderr,
270                                 "It seems that you have changed your default "
271                                 "subvolume or you specify other subvolume to\n"
272                                 "mount btrfs, try to remount this btrfs filesystem "
273                                 "with fs tree, and run btrfs receive again!\n");
274                 goto out;
275         }
276
277         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
278         close(args_v2.fd);
279         if (ret < 0) {
280                 ret = -errno;
281                 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
282                                 "failed. %s\n", parent_subvol->path,
283                                 path, strerror(-ret));
284                 goto out;
285         }
286
287 out:
288         if (parent_subvol) {
289                 free(parent_subvol->path);
290                 free(parent_subvol);
291         }
292         return ret;
293 }
294
295 static int process_mkfile(const char *path, void *user)
296 {
297         int ret;
298         struct btrfs_receive *r = user;
299         char *full_path = path_cat(r->full_subvol_path, path);
300
301         if (g_verbose >= 2)
302                 fprintf(stderr, "mkfile %s\n", path);
303
304         ret = creat(full_path, 0600);
305         if (ret < 0) {
306                 ret = -errno;
307                 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
308                                 strerror(-ret));
309                 goto out;
310         }
311         close(ret);
312         ret = 0;
313
314 out:
315         free(full_path);
316         return ret;
317 }
318
319 static int process_mkdir(const char *path, void *user)
320 {
321         int ret;
322         struct btrfs_receive *r = user;
323         char *full_path = path_cat(r->full_subvol_path, path);
324
325         if (g_verbose >= 2)
326                 fprintf(stderr, "mkdir %s\n", path);
327
328         ret = mkdir(full_path, 0700);
329         if (ret < 0) {
330                 ret = -errno;
331                 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
332                                 strerror(-ret));
333         }
334
335         free(full_path);
336         return ret;
337 }
338
339 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
340 {
341         int ret;
342         struct btrfs_receive *r = user;
343         char *full_path = path_cat(r->full_subvol_path, path);
344
345         if (g_verbose >= 2)
346                 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
347                                 path, mode, dev);
348
349         ret = mknod(full_path, mode & S_IFMT, dev);
350         if (ret < 0) {
351                 ret = -errno;
352                 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
353                                 strerror(-ret));
354         }
355
356         free(full_path);
357         return ret;
358 }
359
360 static int process_mkfifo(const char *path, void *user)
361 {
362         int ret;
363         struct btrfs_receive *r = user;
364         char *full_path = path_cat(r->full_subvol_path, path);
365
366         if (g_verbose >= 2)
367                 fprintf(stderr, "mkfifo %s\n", path);
368
369         ret = mkfifo(full_path, 0600);
370         if (ret < 0) {
371                 ret = -errno;
372                 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
373                                 strerror(-ret));
374         }
375
376         free(full_path);
377         return ret;
378 }
379
380 static int process_mksock(const char *path, void *user)
381 {
382         int ret;
383         struct btrfs_receive *r = user;
384         char *full_path = path_cat(r->full_subvol_path, path);
385
386         if (g_verbose >= 2)
387                 fprintf(stderr, "mksock %s\n", path);
388
389         ret = mknod(full_path, 0600 | S_IFSOCK, 0);
390         if (ret < 0) {
391                 ret = -errno;
392                 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
393                                 strerror(-ret));
394         }
395
396         free(full_path);
397         return ret;
398 }
399
400 static int process_symlink(const char *path, const char *lnk, void *user)
401 {
402         int ret;
403         struct btrfs_receive *r = user;
404         char *full_path = path_cat(r->full_subvol_path, path);
405
406         if (g_verbose >= 2)
407                 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
408
409         ret = symlink(lnk, full_path);
410         if (ret < 0) {
411                 ret = -errno;
412                 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
413                                 lnk, strerror(-ret));
414         }
415
416         free(full_path);
417         return ret;
418 }
419
420 static int process_rename(const char *from, const char *to, void *user)
421 {
422         int ret;
423         struct btrfs_receive *r = user;
424         char *full_from = path_cat(r->full_subvol_path, from);
425         char *full_to = path_cat(r->full_subvol_path, to);
426
427         if (g_verbose >= 2)
428                 fprintf(stderr, "rename %s -> %s\n", from, to);
429
430         ret = rename(full_from, full_to);
431         if (ret < 0) {
432                 ret = -errno;
433                 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
434                                 to, strerror(-ret));
435         }
436
437         free(full_from);
438         free(full_to);
439         return ret;
440 }
441
442 static int process_link(const char *path, const char *lnk, void *user)
443 {
444         int ret;
445         struct btrfs_receive *r = user;
446         char *full_path = path_cat(r->full_subvol_path, path);
447         char *full_link_path = path_cat(r->full_subvol_path, lnk);
448
449         if (g_verbose >= 2)
450                 fprintf(stderr, "link %s -> %s\n", path, lnk);
451
452         ret = link(full_link_path, full_path);
453         if (ret < 0) {
454                 ret = -errno;
455                 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
456                                 lnk, strerror(-ret));
457         }
458
459         free(full_path);
460         free(full_link_path);
461         return ret;
462 }
463
464
465 static int process_unlink(const char *path, void *user)
466 {
467         int ret;
468         struct btrfs_receive *r = user;
469         char *full_path = path_cat(r->full_subvol_path, path);
470
471         if (g_verbose >= 2)
472                 fprintf(stderr, "unlink %s\n", path);
473
474         ret = unlink(full_path);
475         if (ret < 0) {
476                 ret = -errno;
477                 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
478                                 strerror(-ret));
479         }
480
481         free(full_path);
482         return ret;
483 }
484
485 static int process_rmdir(const char *path, void *user)
486 {
487         int ret;
488         struct btrfs_receive *r = user;
489         char *full_path = path_cat(r->full_subvol_path, path);
490
491         if (g_verbose >= 2)
492                 fprintf(stderr, "rmdir %s\n", path);
493
494         ret = rmdir(full_path);
495         if (ret < 0) {
496                 ret = -errno;
497                 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
498                                 strerror(-ret));
499         }
500
501         free(full_path);
502         return ret;
503 }
504
505
506 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
507 {
508         int ret = 0;
509
510         if (r->write_fd != -1) {
511                 if (strcmp(r->write_path, path) == 0)
512                         goto out;
513                 close(r->write_fd);
514                 r->write_fd = -1;
515         }
516
517         r->write_fd = open(path, O_RDWR);
518         if (r->write_fd < 0) {
519                 ret = -errno;
520                 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
521                                 strerror(-ret));
522                 goto out;
523         }
524         free(r->write_path);
525         r->write_path = strdup(path);
526
527 out:
528         return ret;
529 }
530
531 static void close_inode_for_write(struct btrfs_receive *r)
532 {
533         if(r->write_fd == -1)
534                 return;
535
536         close(r->write_fd);
537         r->write_fd = -1;
538         r->write_path[0] = 0;
539 }
540
541 static int process_write(const char *path, const void *data, u64 offset,
542                          u64 len, void *user)
543 {
544         int ret = 0;
545         struct btrfs_receive *r = user;
546         char *full_path = path_cat(r->full_subvol_path, path);
547         u64 pos = 0;
548         int w;
549
550         ret = open_inode_for_write(r, full_path);
551         if (ret < 0)
552                 goto out;
553
554         while (pos < len) {
555                 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
556                                 offset + pos);
557                 if (w < 0) {
558                         ret = -errno;
559                         fprintf(stderr, "ERROR: writing to %s failed. %s\n",
560                                         path, strerror(-ret));
561                         goto out;
562                 }
563                 pos += w;
564         }
565
566 out:
567         free(full_path);
568         return ret;
569 }
570
571 static int process_clone(const char *path, u64 offset, u64 len,
572                          const u8 *clone_uuid, u64 clone_ctransid,
573                          const char *clone_path, u64 clone_offset,
574                          void *user)
575 {
576         int ret;
577         struct btrfs_receive *r = user;
578         struct btrfs_ioctl_clone_range_args clone_args;
579         struct subvol_info *si = NULL;
580         char *full_path = path_cat(r->full_subvol_path, path);
581         char *subvol_path = NULL;
582         char *full_clone_path = NULL;
583         int clone_fd = -1;
584
585         ret = open_inode_for_write(r, full_path);
586         if (ret < 0)
587                 goto out;
588
589         si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
590                         subvol_search_by_received_uuid);
591         if (!si) {
592                 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
593                                 BTRFS_UUID_SIZE) == 0) {
594                         /* TODO check generation of extent */
595                         subvol_path = strdup(r->cur_subvol->path);
596                 } else {
597                         ret = -ENOENT;
598                         fprintf(stderr, "ERROR: did not find source subvol.\n");
599                         goto out;
600                 }
601         } else {
602                 /*if (rs_args.ctransid > rs_args.rtransid) {
603                         if (!r->force) {
604                                 ret = -EINVAL;
605                                 fprintf(stderr, "ERROR: subvolume %s was "
606                                                 "modified after it was "
607                                                 "received.\n",
608                                                 r->subvol_parent_name);
609                                 goto out;
610                         } else {
611                                 fprintf(stderr, "WARNING: subvolume %s was "
612                                                 "modified after it was "
613                                                 "received.\n",
614                                                 r->subvol_parent_name);
615                         }
616                 }*/
617                 subvol_path = strdup(si->path);
618         }
619
620         full_clone_path = path_cat(subvol_path, clone_path);
621
622         clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
623         if (clone_fd < 0) {
624                 ret = -errno;
625                 fprintf(stderr, "ERROR: failed to open %s. %s\n",
626                                 full_clone_path, strerror(-ret));
627                 goto out;
628         }
629
630         clone_args.src_fd = clone_fd;
631         clone_args.src_offset = clone_offset;
632         clone_args.src_length = len;
633         clone_args.dest_offset = offset;
634         ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
635         if (ret) {
636                 ret = -errno;
637                 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
638                                 path, strerror(-ret));
639                 goto out;
640         }
641
642 out:
643         if (si) {
644                 free(si->path);
645                 free(si);
646         }
647         free(full_path);
648         free(full_clone_path);
649         free(subvol_path);
650         if (clone_fd != -1)
651                 close(clone_fd);
652         return ret;
653 }
654
655
656 static int process_set_xattr(const char *path, const char *name,
657                              const void *data, int len, void *user)
658 {
659         int ret = 0;
660         struct btrfs_receive *r = user;
661         char *full_path = path_cat(r->full_subvol_path, path);
662
663         if (strcmp("security.capability", name) == 0) {
664                 if (g_verbose >= 3)
665                         fprintf(stderr, "set_xattr: cache capabilities\n");
666                 if (r->cached_capabilities_len)
667                         fprintf(stderr,
668                           "WARNING: capabilities set multiple times per file: %s\n",
669                                 full_path);
670                 if (len > sizeof(r->cached_capabilities)) {
671                         fprintf(stderr,
672                           "ERROR: capabilities encoded to %d bytes, buffer too small\n",
673                                 len);
674                         ret = -E2BIG;
675                         goto out;
676                 }
677                 r->cached_capabilities_len = len;
678                 memcpy(r->cached_capabilities, data, len);
679         }
680
681         if (g_verbose >= 2) {
682                 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
683                                 "data=%.*s\n", path, name, len,
684                                 len, (char*)data);
685         }
686
687         ret = lsetxattr(full_path, name, data, len, 0);
688         if (ret < 0) {
689                 ret = -errno;
690                 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
691                                 path, name, len, (char*)data, strerror(-ret));
692                 goto out;
693         }
694
695 out:
696         free(full_path);
697         return ret;
698 }
699
700 static int process_remove_xattr(const char *path, const char *name, 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 (g_verbose >= 2) {
707                 fprintf(stderr, "remove_xattr %s - name=%s\n",
708                                 path, name);
709         }
710
711         ret = lremovexattr(full_path, name);
712         if (ret < 0) {
713                 ret = -errno;
714                 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
715                                 path, name, strerror(-ret));
716                 goto out;
717         }
718
719 out:
720         free(full_path);
721         return ret;
722 }
723
724 static int process_truncate(const char *path, u64 size, void *user)
725 {
726         int ret = 0;
727         struct btrfs_receive *r = user;
728         char *full_path = path_cat(r->full_subvol_path, path);
729
730         if (g_verbose >= 2)
731                 fprintf(stderr, "truncate %s size=%llu\n", path, size);
732
733         ret = truncate(full_path, size);
734         if (ret < 0) {
735                 ret = -errno;
736                 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
737                                 path, strerror(-ret));
738                 goto out;
739         }
740
741 out:
742         free(full_path);
743         return ret;
744 }
745
746 static int process_chmod(const char *path, u64 mode, void *user)
747 {
748         int ret = 0;
749         struct btrfs_receive *r = user;
750         char *full_path = path_cat(r->full_subvol_path, path);
751
752         if (g_verbose >= 2)
753                 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
754
755         ret = chmod(full_path, mode);
756         if (ret < 0) {
757                 ret = -errno;
758                 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
759                                 path, strerror(-ret));
760                 goto out;
761         }
762
763 out:
764         free(full_path);
765         return ret;
766 }
767
768 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
769 {
770         int ret = 0;
771         struct btrfs_receive *r = user;
772         char *full_path = path_cat(r->full_subvol_path, path);
773
774         if (g_verbose >= 2)
775                 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
776                                 uid, gid);
777
778         ret = lchown(full_path, uid, gid);
779         if (ret < 0) {
780                 ret = -errno;
781                 fprintf(stderr, "ERROR: chown %s failed. %s\n",
782                                 path, strerror(-ret));
783                 goto out;
784         }
785
786         if (r->cached_capabilities_len) {
787                 if (g_verbose >= 2)
788                         fprintf(stderr, "chown: restore capabilities\n");
789                 ret = lsetxattr(full_path, "security.capability",
790                                 r->cached_capabilities,
791                                 r->cached_capabilities_len, 0);
792                 memset(r->cached_capabilities, 0,
793                                 sizeof(r->cached_capabilities));
794                 r->cached_capabilities_len = 0;
795                 if (ret < 0) {
796                         ret = -errno;
797                         fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
798                                         path, strerror(-ret));
799                         goto out;
800                 }
801         }
802
803 out:
804         free(full_path);
805         return ret;
806 }
807
808 static int process_utimes(const char *path, struct timespec *at,
809                           struct timespec *mt, struct timespec *ct,
810                           void *user)
811 {
812         int ret = 0;
813         struct btrfs_receive *r = user;
814         char *full_path = path_cat(r->full_subvol_path, path);
815         struct timespec tv[2];
816
817         if (g_verbose >= 2)
818                 fprintf(stderr, "utimes %s\n", path);
819
820         tv[0] = *at;
821         tv[1] = *mt;
822         ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
823         if (ret < 0) {
824                 ret = -errno;
825                 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
826                                 path, strerror(-ret));
827                 goto out;
828         }
829
830 out:
831         free(full_path);
832         return ret;
833 }
834
835
836 static struct btrfs_send_ops send_ops = {
837         .subvol = process_subvol,
838         .snapshot = process_snapshot,
839         .mkfile = process_mkfile,
840         .mkdir = process_mkdir,
841         .mknod = process_mknod,
842         .mkfifo = process_mkfifo,
843         .mksock = process_mksock,
844         .symlink = process_symlink,
845         .rename = process_rename,
846         .link = process_link,
847         .unlink = process_unlink,
848         .rmdir = process_rmdir,
849         .write = process_write,
850         .clone = process_clone,
851         .set_xattr = process_set_xattr,
852         .remove_xattr = process_remove_xattr,
853         .truncate = process_truncate,
854         .chmod = process_chmod,
855         .chown = process_chown,
856         .utimes = process_utimes,
857 };
858
859 static int do_receive(struct btrfs_receive *r, const char *tomnt,
860                       char *realmnt, int r_fd, u64 max_errors)
861 {
862         int ret;
863         char *dest_dir_full_path;
864         int end = 0;
865
866         dest_dir_full_path = realpath(tomnt, NULL);
867         if (!dest_dir_full_path) {
868                 ret = -errno;
869                 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
870                         strerror(-ret));
871                 goto out;
872         }
873         r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
874         if (r->dest_dir_fd < 0) {
875                 ret = -errno;
876                 fprintf(stderr,
877                         "ERROR: failed to open destination directory %s. %s\n",
878                         dest_dir_full_path, strerror(-ret));
879                 goto out;
880         }
881
882         if (realmnt) {
883                 r->root_path = realmnt;
884         } else {
885                 ret = find_mount_root(dest_dir_full_path, &r->root_path);
886                 if (ret < 0) {
887                         fprintf(stderr,
888                                 "ERROR: failed to determine mount point for %s: %s\n",
889                                 dest_dir_full_path, strerror(-ret));
890                         ret = -EINVAL;
891                         goto out;
892                 }
893                 if (ret > 0) {
894                         fprintf(stderr,
895                         "ERROR: %s doesn't belong to btrfs mount point\n",
896                         dest_dir_full_path);
897                         ret = -EINVAL;
898                         goto out;
899                 }
900         }
901         r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
902         if (r->mnt_fd < 0) {
903                 ret = -errno;
904                 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
905                         strerror(-ret));
906                 goto out;
907         }
908
909         if (r->dest_dir_chroot) {
910                 if (chroot(dest_dir_full_path)) {
911                         ret = -errno;
912                         fprintf(stderr,
913                                 "ERROR: failed to chroot to %s, %s\n",
914                                 dest_dir_full_path,
915                                 strerror(-ret));
916                         goto out;
917                 }
918                 if (chdir("/")) {
919                         ret = -errno;
920                         fprintf(stderr,
921                                 "ERROR: failed to chdir to /, %s\n",
922                                 strerror(-ret));
923                         goto out;
924                 }
925                 fprintf(stderr, "Chroot to %s\n", dest_dir_full_path);
926                 r->root_path = strdup("/");
927                 r->dest_dir_path = r->root_path;
928         } else {
929                 /*
930                  * find_mount_root returns a root_path that is a subpath of
931                  * dest_dir_full_path. Now get the other part of root_path,
932                  * which is the destination dir relative to root_path.
933                  */
934                 r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
935                 while (r->dest_dir_path[0] == '/')
936                         r->dest_dir_path++;
937         }
938
939         ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
940         if (ret < 0)
941                 goto out;
942
943         while (!end) {
944                 if (r->cached_capabilities_len) {
945                         if (g_verbose >= 3)
946                                 fprintf(stderr, "clear cached capabilities\n");
947                         memset(r->cached_capabilities, 0,
948                                         sizeof(r->cached_capabilities));
949                         r->cached_capabilities_len = 0;
950                 }
951
952                 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
953                                                          r->honor_end_cmd,
954                                                          max_errors);
955                 if (ret < 0)
956                         goto out;
957                 if (ret)
958                         end = 1;
959
960                 close_inode_for_write(r);
961                 ret = finish_subvol(r);
962                 if (ret < 0)
963                         goto out;
964         }
965         ret = 0;
966
967 out:
968         if (r->write_fd != -1) {
969                 close(r->write_fd);
970                 r->write_fd = -1;
971         }
972         free(r->root_path);
973         r->root_path = NULL;
974         free(r->write_path);
975         r->write_path = NULL;
976         free(r->full_subvol_path);
977         r->full_subvol_path = NULL;
978         r->dest_dir_path = NULL;
979         free(dest_dir_full_path);
980         if (r->cur_subvol) {
981                 free(r->cur_subvol->path);
982                 free(r->cur_subvol);
983                 r->cur_subvol = NULL;
984         }
985         subvol_uuid_search_finit(&r->sus);
986         if (r->mnt_fd != -1) {
987                 close(r->mnt_fd);
988                 r->mnt_fd = -1;
989         }
990         if (r->dest_dir_fd != -1) {
991                 close(r->dest_dir_fd);
992                 r->dest_dir_fd = -1;
993         }
994         return ret;
995 }
996
997 int cmd_receive(int argc, char **argv)
998 {
999         char *tomnt = NULL;
1000         char *fromfile = NULL;
1001         char *realmnt = NULL;
1002         struct btrfs_receive r;
1003         int receive_fd = fileno(stdin);
1004         u64 max_errors = 1;
1005         int ret = 0;
1006
1007         memset(&r, 0, sizeof(r));
1008         r.mnt_fd = -1;
1009         r.write_fd = -1;
1010         r.dest_dir_fd = -1;
1011         r.dest_dir_chroot = 0;
1012
1013         while (1) {
1014                 int c;
1015                 static const struct option long_opts[] = {
1016                         { "max-errors", required_argument, NULL, 'E' },
1017                         { "chroot", no_argument, NULL, 'C' },
1018                         { NULL, 0, NULL, 0 }
1019                 };
1020
1021                 c = getopt_long(argc, argv, "Cevf:m:", long_opts, NULL);
1022                 if (c < 0)
1023                         break;
1024
1025                 switch (c) {
1026                 case 'v':
1027                         g_verbose++;
1028                         break;
1029                 case 'f':
1030                         fromfile = optarg;
1031                         break;
1032                 case 'e':
1033                         r.honor_end_cmd = 1;
1034                         break;
1035                 case 'C':
1036                         r.dest_dir_chroot = 1;
1037                         break;
1038                 case 'E':
1039                         max_errors = arg_strtou64(optarg);
1040                         break;
1041                 case 'm':
1042                         free(realmnt);
1043                         realmnt = strdup(optarg);
1044                         if (!realmnt) {
1045                                 fprintf(stderr, "ERROR: couldn't allocate realmnt.\n");
1046                                 goto out;
1047                         }
1048                         break;
1049                 case '?':
1050                 default:
1051                         fprintf(stderr, "ERROR: receive args invalid.\n");
1052                         return 1;
1053                 }
1054         }
1055
1056         if (check_argc_exact(argc - optind, 1))
1057                 usage(cmd_receive_usage);
1058
1059         tomnt = argv[optind];
1060
1061         if (fromfile) {
1062                 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
1063                 if (receive_fd < 0) {
1064                         fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
1065                         goto out;
1066                 }
1067         }
1068
1069         ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
1070
1071 out:
1072         free(realmnt);
1073
1074         return !!ret;
1075 }
1076
1077 const char * const cmd_receive_usage[] = {
1078         "btrfs receive [-ve] [-f <infile>] [--max-errors <N>] <mount>",
1079         "Receive subvolumes from stdin.",
1080         "Receives one or more subvolumes that were previously",
1081         "sent with btrfs send. The received subvolumes are stored",
1082         "into <mount>.",
1083         "btrfs receive will fail in case a receiving subvolume",
1084         "already exists. It will also fail in case a previously",
1085         "received subvolume was changed after it was received.",
1086         "After receiving a subvolume, it is immediately set to",
1087         "read only.\n",
1088         "-v               Enable verbose debug output. Each",
1089         "                 occurrence of this option increases the",
1090         "                 verbose level more.",
1091         "-f <infile>      By default, btrfs receive uses stdin",
1092         "                 to receive the subvolumes. Use this",
1093         "                 option to specify a file to use instead.",
1094         "-e               Terminate after receiving an <end cmd>",
1095         "                 in the data stream. Without this option,",
1096         "                 the receiver terminates only if an error",
1097         "                 is recognized or on EOF.",
1098         "-C|--chroot      confine the process to <mount> using chroot",
1099         "--max-errors <N> Terminate as soon as N errors happened while",
1100         "                 processing commands from the send stream.",
1101         "                 Default value is 1. A value of 0 means no limit.",
1102         "-m <mountpoint>  The root mount point of the destination fs.",
1103         "                 If you do not have /proc use this to tell us where ",
1104         "                 this file system is mounted.",
1105         NULL
1106 };