Btrfs-progs: try harder to make btrfs receive successfully
[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 #define _GNU_SOURCE
20 #define _POSIX_C_SOURCE 200809
21 #define _XOPEN_SOURCE 700
22 #define _BSD_SOURCE
23
24 #include "kerncompat.h"
25
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <dirent.h>
29 #include <fcntl.h>
30 #include <pthread.h>
31 #include <math.h>
32 #include <ftw.h>
33 #include <wait.h>
34 #include <assert.h>
35
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/ioctl.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/xattr.h>
42 #include <uuid/uuid.h>
43
44 #include "ctree.h"
45 #include "ioctl.h"
46 #include "commands.h"
47 #include "utils.h"
48 #include "list.h"
49 #include "btrfs-list.h"
50
51 #include "send.h"
52 #include "send-stream.h"
53 #include "send-utils.h"
54
55 static int g_verbose = 0;
56
57 struct btrfs_receive
58 {
59         int mnt_fd;
60         int dest_dir_fd;
61
62         int write_fd;
63         char *write_path;
64
65         char *root_path;
66         char *dest_dir_path; /* relative to root_path */
67         char *full_subvol_path;
68
69         struct subvol_info *cur_subvol;
70
71         struct subvol_uuid_search sus;
72
73         int honor_end_cmd;
74 };
75
76 static int finish_subvol(struct btrfs_receive *r)
77 {
78         int ret;
79         int subvol_fd = -1;
80         struct btrfs_ioctl_received_subvol_args rs_args;
81         char uuid_str[128];
82         u64 flags;
83
84         if (r->cur_subvol == NULL)
85                 return 0;
86
87         subvol_fd = openat(r->mnt_fd, r->cur_subvol->path,
88                         O_RDONLY | O_NOATIME);
89         if (subvol_fd < 0) {
90                 ret = -errno;
91                 fprintf(stderr, "ERROR: open %s failed. %s\n",
92                                 r->cur_subvol->path, strerror(-ret));
93                 goto out;
94         }
95
96         memset(&rs_args, 0, sizeof(rs_args));
97         memcpy(rs_args.uuid, r->cur_subvol->received_uuid, BTRFS_UUID_SIZE);
98         rs_args.stransid = r->cur_subvol->stransid;
99
100         if (g_verbose >= 1) {
101                 uuid_unparse((u8*)rs_args.uuid, uuid_str);
102                 fprintf(stderr, "BTRFS_IOC_SET_RECEIVED_SUBVOL uuid=%s, "
103                                 "stransid=%llu\n", uuid_str, rs_args.stransid);
104         }
105
106         ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
107         if (ret < 0) {
108                 ret = -errno;
109                 fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
110                                 strerror(-ret));
111                 goto out;
112         }
113         r->cur_subvol->rtransid = rs_args.rtransid;
114
115         ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
116         if (ret < 0) {
117                 ret = -errno;
118                 fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
119                                 strerror(-ret));
120                 goto out;
121         }
122
123         flags |= BTRFS_SUBVOL_RDONLY;
124
125         ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
126         if (ret < 0) {
127                 ret = -errno;
128                 fprintf(stderr, "ERROR: failed to make subvolume read only. "
129                                 "%s\n", strerror(-ret));
130                 goto out;
131         }
132
133         ret = 0;
134
135 out:
136         if (r->cur_subvol) {
137                 free(r->cur_subvol->path);
138                 free(r->cur_subvol);
139                 r->cur_subvol = NULL;
140         }
141         if (subvol_fd != -1)
142                 close(subvol_fd);
143         return ret;
144 }
145
146 static int process_subvol(const char *path, const u8 *uuid, u64 ctransid,
147                           void *user)
148 {
149         int ret;
150         struct btrfs_receive *r = user;
151         struct btrfs_ioctl_vol_args args_v1;
152         char uuid_str[128];
153
154         ret = finish_subvol(r);
155         if (ret < 0)
156                 goto out;
157
158         r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
159
160         if (strlen(r->dest_dir_path) == 0)
161                 r->cur_subvol->path = strdup(path);
162         else
163                 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
164         free(r->full_subvol_path);
165         r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
166
167         fprintf(stderr, "At subvol %s\n", path);
168
169         memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
170         r->cur_subvol->stransid = ctransid;
171
172         if (g_verbose) {
173                 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
174                 fprintf(stderr, "receiving subvol %s uuid=%s, stransid=%llu\n",
175                                 path, uuid_str,
176                                 r->cur_subvol->stransid);
177         }
178
179         memset(&args_v1, 0, sizeof(args_v1));
180         strncpy_null(args_v1.name, path);
181         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
182         if (ret < 0) {
183                 ret = -errno;
184                 fprintf(stderr, "ERROR: creating subvolume %s failed. "
185                                 "%s\n", path, strerror(-ret));
186                 goto out;
187         }
188
189 out:
190         return ret;
191 }
192
193 static int process_snapshot(const char *path, const u8 *uuid, u64 ctransid,
194                             const u8 *parent_uuid, u64 parent_ctransid,
195                             void *user)
196 {
197         int ret;
198         struct btrfs_receive *r = user;
199         char uuid_str[128];
200         struct btrfs_ioctl_vol_args_v2 args_v2;
201         struct subvol_info *parent_subvol = NULL;
202
203         ret = finish_subvol(r);
204         if (ret < 0)
205                 goto out;
206
207         r->cur_subvol = calloc(1, sizeof(*r->cur_subvol));
208
209         if (strlen(r->dest_dir_path) == 0)
210                 r->cur_subvol->path = strdup(path);
211         else
212                 r->cur_subvol->path = path_cat(r->dest_dir_path, path);
213         free(r->full_subvol_path);
214         r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
215
216         fprintf(stderr, "At snapshot %s\n", path);
217
218         memcpy(r->cur_subvol->received_uuid, uuid, BTRFS_UUID_SIZE);
219         r->cur_subvol->stransid = ctransid;
220
221         if (g_verbose) {
222                 uuid_unparse((u8*)r->cur_subvol->received_uuid, uuid_str);
223                 fprintf(stderr, "receiving snapshot %s uuid=%s, "
224                                 "ctransid=%llu ", path, uuid_str,
225                                 r->cur_subvol->stransid);
226                 uuid_unparse(parent_uuid, uuid_str);
227                 fprintf(stderr, "parent_uuid=%s, parent_ctransid=%llu\n",
228                                 uuid_str, parent_ctransid);
229         }
230
231         memset(&args_v2, 0, sizeof(args_v2));
232         strncpy_null(args_v2.name, path);
233
234         parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
235                         parent_ctransid, NULL, subvol_search_by_received_uuid);
236         if (!parent_subvol) {
237                 parent_subvol = subvol_uuid_search(&r->sus, 0, parent_uuid,
238                                 parent_ctransid, NULL, subvol_search_by_uuid);
239         }
240         if (!parent_subvol) {
241                 ret = -ENOENT;
242                 fprintf(stderr, "ERROR: could not find parent subvolume\n");
243                 goto out;
244         }
245
246         /*if (rs_args.ctransid > rs_args.rtransid) {
247                 if (!r->force) {
248                         ret = -EINVAL;
249                         fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
250                         goto out;
251                 } else {
252                         fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
253                 }
254         }*/
255
256         args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
257                         O_RDONLY | O_NOATIME);
258         if (args_v2.fd < 0) {
259                 ret = -errno;
260                 fprintf(stderr, "ERROR: open %s failed. %s\n",
261                                 parent_subvol->path, strerror(-ret));
262                 goto out;
263         }
264
265         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
266         close(args_v2.fd);
267         if (ret < 0) {
268                 ret = -errno;
269                 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
270                                 "failed. %s\n", parent_subvol->path,
271                                 path, strerror(-ret));
272                 goto out;
273         }
274
275 out:
276         if (parent_subvol) {
277                 free(parent_subvol->path);
278                 free(parent_subvol);
279         }
280         return ret;
281 }
282
283 static int process_mkfile(const char *path, void *user)
284 {
285         int ret;
286         struct btrfs_receive *r = user;
287         char *full_path = path_cat(r->full_subvol_path, path);
288
289         if (g_verbose >= 2)
290                 fprintf(stderr, "mkfile %s\n", path);
291
292         ret = creat(full_path, 0600);
293         if (ret < 0) {
294                 ret = -errno;
295                 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
296                                 strerror(-ret));
297                 goto out;
298         }
299         close(ret);
300         ret = 0;
301
302 out:
303         free(full_path);
304         return ret;
305 }
306
307 static int process_mkdir(const char *path, void *user)
308 {
309         int ret;
310         struct btrfs_receive *r = user;
311         char *full_path = path_cat(r->full_subvol_path, path);
312
313         if (g_verbose >= 2)
314                 fprintf(stderr, "mkdir %s\n", path);
315
316         ret = mkdir(full_path, 0700);
317         if (ret < 0) {
318                 ret = -errno;
319                 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
320                                 strerror(-ret));
321         }
322
323         free(full_path);
324         return ret;
325 }
326
327 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
328 {
329         int ret;
330         struct btrfs_receive *r = user;
331         char *full_path = path_cat(r->full_subvol_path, path);
332
333         if (g_verbose >= 2)
334                 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
335                                 path, mode, dev);
336
337         ret = mknod(full_path, mode & S_IFMT, dev);
338         if (ret < 0) {
339                 ret = -errno;
340                 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
341                                 strerror(-ret));
342         }
343
344         free(full_path);
345         return ret;
346 }
347
348 static int process_mkfifo(const char *path, void *user)
349 {
350         int ret;
351         struct btrfs_receive *r = user;
352         char *full_path = path_cat(r->full_subvol_path, path);
353
354         if (g_verbose >= 2)
355                 fprintf(stderr, "mkfifo %s\n", path);
356
357         ret = mkfifo(full_path, 0600);
358         if (ret < 0) {
359                 ret = -errno;
360                 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
361                                 strerror(-ret));
362         }
363
364         free(full_path);
365         return ret;
366 }
367
368 static int process_mksock(const char *path, void *user)
369 {
370         int ret;
371         struct btrfs_receive *r = user;
372         char *full_path = path_cat(r->full_subvol_path, path);
373
374         if (g_verbose >= 2)
375                 fprintf(stderr, "mksock %s\n", path);
376
377         ret = mknod(full_path, 0600 | S_IFSOCK, 0);
378         if (ret < 0) {
379                 ret = -errno;
380                 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
381                                 strerror(-ret));
382         }
383
384         free(full_path);
385         return ret;
386 }
387
388 static int process_symlink(const char *path, const char *lnk, void *user)
389 {
390         int ret;
391         struct btrfs_receive *r = user;
392         char *full_path = path_cat(r->full_subvol_path, path);
393
394         if (g_verbose >= 2)
395                 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
396
397         ret = symlink(lnk, full_path);
398         if (ret < 0) {
399                 ret = -errno;
400                 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
401                                 lnk, strerror(-ret));
402         }
403
404         free(full_path);
405         return ret;
406 }
407
408 static int process_rename(const char *from, const char *to, void *user)
409 {
410         int ret;
411         struct btrfs_receive *r = user;
412         char *full_from = path_cat(r->full_subvol_path, from);
413         char *full_to = path_cat(r->full_subvol_path, to);
414
415         if (g_verbose >= 2)
416                 fprintf(stderr, "rename %s -> %s\n", from, to);
417
418         ret = rename(full_from, full_to);
419         if (ret < 0) {
420                 ret = -errno;
421                 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
422                                 to, strerror(-ret));
423         }
424
425         free(full_from);
426         free(full_to);
427         return ret;
428 }
429
430 static int process_link(const char *path, const char *lnk, void *user)
431 {
432         int ret;
433         struct btrfs_receive *r = user;
434         char *full_path = path_cat(r->full_subvol_path, path);
435         char *full_link_path = path_cat(r->full_subvol_path, lnk);
436
437         if (g_verbose >= 2)
438                 fprintf(stderr, "link %s -> %s\n", path, lnk);
439
440         ret = link(full_link_path, full_path);
441         if (ret < 0) {
442                 ret = -errno;
443                 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
444                                 lnk, strerror(-ret));
445         }
446
447         free(full_path);
448         free(full_link_path);
449         return ret;
450 }
451
452
453 static int process_unlink(const char *path, void *user)
454 {
455         int ret;
456         struct btrfs_receive *r = user;
457         char *full_path = path_cat(r->full_subvol_path, path);
458
459         if (g_verbose >= 2)
460                 fprintf(stderr, "unlink %s\n", path);
461
462         ret = unlink(full_path);
463         if (ret < 0) {
464                 ret = -errno;
465                 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
466                                 strerror(-ret));
467         }
468
469         free(full_path);
470         return ret;
471 }
472
473 static int process_rmdir(const char *path, void *user)
474 {
475         int ret;
476         struct btrfs_receive *r = user;
477         char *full_path = path_cat(r->full_subvol_path, path);
478
479         if (g_verbose >= 2)
480                 fprintf(stderr, "rmdir %s\n", path);
481
482         ret = rmdir(full_path);
483         if (ret < 0) {
484                 ret = -errno;
485                 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
486                                 strerror(-ret));
487         }
488
489         free(full_path);
490         return ret;
491 }
492
493
494 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
495 {
496         int ret = 0;
497
498         if (r->write_fd != -1) {
499                 if (strcmp(r->write_path, path) == 0)
500                         goto out;
501                 close(r->write_fd);
502                 r->write_fd = -1;
503         }
504
505         r->write_fd = open(path, O_RDWR);
506         if (r->write_fd < 0) {
507                 ret = -errno;
508                 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
509                                 strerror(-ret));
510                 goto out;
511         }
512         free(r->write_path);
513         r->write_path = strdup(path);
514
515 out:
516         return ret;
517 }
518
519 static int close_inode_for_write(struct btrfs_receive *r)
520 {
521         int ret = 0;
522
523         if(r->write_fd == -1)
524                 goto out;
525
526         close(r->write_fd);
527         r->write_fd = -1;
528         r->write_path[0] = 0;
529
530 out:
531         return ret;
532 }
533
534 static int process_write(const char *path, const void *data, u64 offset,
535                          u64 len, void *user)
536 {
537         int ret = 0;
538         struct btrfs_receive *r = user;
539         char *full_path = path_cat(r->full_subvol_path, path);
540         u64 pos = 0;
541         int w;
542
543         ret = open_inode_for_write(r, full_path);
544         if (ret < 0)
545                 goto out;
546
547         while (pos < len) {
548                 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
549                                 offset + pos);
550                 if (w < 0) {
551                         ret = -errno;
552                         fprintf(stderr, "ERROR: writing to %s failed. %s\n",
553                                         path, strerror(-ret));
554                         goto out;
555                 }
556                 pos += w;
557         }
558
559 out:
560         free(full_path);
561         return ret;
562 }
563
564 static int process_clone(const char *path, u64 offset, u64 len,
565                          const u8 *clone_uuid, u64 clone_ctransid,
566                          const char *clone_path, u64 clone_offset,
567                          void *user)
568 {
569         int ret;
570         struct btrfs_receive *r = user;
571         struct btrfs_ioctl_clone_range_args clone_args;
572         struct subvol_info *si = NULL;
573         char *full_path = path_cat(r->full_subvol_path, path);
574         char *subvol_path = NULL;
575         char *full_clone_path = NULL;
576         int clone_fd = -1;
577
578         ret = open_inode_for_write(r, full_path);
579         if (ret < 0)
580                 goto out;
581
582         si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
583                         subvol_search_by_received_uuid);
584         if (!si) {
585                 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
586                                 BTRFS_UUID_SIZE) == 0) {
587                         /* TODO check generation of extent */
588                         subvol_path = strdup(r->cur_subvol->path);
589                 } else {
590                         ret = -ENOENT;
591                         fprintf(stderr, "ERROR: did not find source subvol.\n");
592                         goto out;
593                 }
594         } else {
595                 /*if (rs_args.ctransid > rs_args.rtransid) {
596                         if (!r->force) {
597                                 ret = -EINVAL;
598                                 fprintf(stderr, "ERROR: subvolume %s was "
599                                                 "modified after it was "
600                                                 "received.\n",
601                                                 r->subvol_parent_name);
602                                 goto out;
603                         } else {
604                                 fprintf(stderr, "WARNING: subvolume %s was "
605                                                 "modified after it was "
606                                                 "received.\n",
607                                                 r->subvol_parent_name);
608                         }
609                 }*/
610                 subvol_path = strdup(si->path);
611         }
612
613         full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
614
615         clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
616         if (clone_fd < 0) {
617                 ret = -errno;
618                 fprintf(stderr, "ERROR: failed to open %s. %s\n",
619                                 full_clone_path, strerror(-ret));
620                 goto out;
621         }
622
623         clone_args.src_fd = clone_fd;
624         clone_args.src_offset = clone_offset;
625         clone_args.src_length = len;
626         clone_args.dest_offset = offset;
627         ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
628         if (ret) {
629                 ret = -errno;
630                 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
631                                 path, strerror(-ret));
632                 goto out;
633         }
634
635 out:
636         if (si) {
637                 free(si->path);
638                 free(si);
639         }
640         free(full_path);
641         free(full_clone_path);
642         free(subvol_path);
643         if (clone_fd != -1)
644                 close(clone_fd);
645         return ret;
646 }
647
648
649 static int process_set_xattr(const char *path, const char *name,
650                              const void *data, int len, void *user)
651 {
652         int ret = 0;
653         struct btrfs_receive *r = user;
654         char *full_path = path_cat(r->full_subvol_path, path);
655
656         if (g_verbose >= 2) {
657                 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
658                                 "data=%.*s\n", path, name, len,
659                                 len, (char*)data);
660         }
661
662         ret = lsetxattr(full_path, name, data, len, 0);
663         if (ret < 0) {
664                 ret = -errno;
665                 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
666                                 path, name, len, (char*)data, strerror(-ret));
667                 goto out;
668         }
669
670 out:
671         free(full_path);
672         return ret;
673 }
674
675 static int process_remove_xattr(const char *path, const char *name, void *user)
676 {
677         int ret = 0;
678         struct btrfs_receive *r = user;
679         char *full_path = path_cat(r->full_subvol_path, path);
680
681         if (g_verbose >= 2) {
682                 fprintf(stderr, "remove_xattr %s - name=%s\n",
683                                 path, name);
684         }
685
686         ret = lremovexattr(full_path, name);
687         if (ret < 0) {
688                 ret = -errno;
689                 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
690                                 path, name, strerror(-ret));
691                 goto out;
692         }
693
694 out:
695         free(full_path);
696         return ret;
697 }
698
699 static int process_truncate(const char *path, u64 size, void *user)
700 {
701         int ret = 0;
702         struct btrfs_receive *r = user;
703         char *full_path = path_cat(r->full_subvol_path, path);
704
705         if (g_verbose >= 2)
706                 fprintf(stderr, "truncate %s size=%llu\n", path, size);
707
708         ret = truncate(full_path, size);
709         if (ret < 0) {
710                 ret = -errno;
711                 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
712                                 path, strerror(-ret));
713                 goto out;
714         }
715
716 out:
717         free(full_path);
718         return ret;
719 }
720
721 static int process_chmod(const char *path, u64 mode, void *user)
722 {
723         int ret = 0;
724         struct btrfs_receive *r = user;
725         char *full_path = path_cat(r->full_subvol_path, path);
726
727         if (g_verbose >= 2)
728                 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
729
730         ret = chmod(full_path, mode);
731         if (ret < 0) {
732                 ret = -errno;
733                 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
734                                 path, strerror(-ret));
735                 goto out;
736         }
737
738 out:
739         free(full_path);
740         return ret;
741 }
742
743 static int process_chown(const char *path, u64 uid, u64 gid, 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, "chown %s - uid=%llu, gid=%llu\n", path,
751                                 uid, gid);
752
753         ret = lchown(full_path, uid, gid);
754         if (ret < 0) {
755                 ret = -errno;
756                 fprintf(stderr, "ERROR: chown %s failed. %s\n",
757                                 path, strerror(-ret));
758                 goto out;
759         }
760
761 out:
762         free(full_path);
763         return ret;
764 }
765
766 static int process_utimes(const char *path, struct timespec *at,
767                           struct timespec *mt, struct timespec *ct,
768                           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         struct timespec tv[2];
774
775         if (g_verbose >= 2)
776                 fprintf(stderr, "utimes %s\n", path);
777
778         tv[0] = *at;
779         tv[1] = *mt;
780         ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
781         if (ret < 0) {
782                 ret = -errno;
783                 fprintf(stderr, "ERROR: utimes %s failed. %s\n",
784                                 path, strerror(-ret));
785                 goto out;
786         }
787
788 out:
789         free(full_path);
790         return ret;
791 }
792
793
794 static struct btrfs_send_ops send_ops = {
795         .subvol = process_subvol,
796         .snapshot = process_snapshot,
797         .mkfile = process_mkfile,
798         .mkdir = process_mkdir,
799         .mknod = process_mknod,
800         .mkfifo = process_mkfifo,
801         .mksock = process_mksock,
802         .symlink = process_symlink,
803         .rename = process_rename,
804         .link = process_link,
805         .unlink = process_unlink,
806         .rmdir = process_rmdir,
807         .write = process_write,
808         .clone = process_clone,
809         .set_xattr = process_set_xattr,
810         .remove_xattr = process_remove_xattr,
811         .truncate = process_truncate,
812         .chmod = process_chmod,
813         .chown = process_chown,
814         .utimes = process_utimes,
815 };
816
817 static int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
818 {
819         int ret;
820         char *dest_dir_full_path;
821         int end = 0;
822
823         dest_dir_full_path = realpath(tomnt, NULL);
824         if (!dest_dir_full_path) {
825                 ret = -errno;
826                 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
827                         strerror(-ret));
828                 goto out;
829         }
830         r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
831         if (r->dest_dir_fd < 0) {
832                 ret = -errno;
833                 fprintf(stderr,
834                         "ERROR: failed to open destination directory %s. %s\n",
835                         dest_dir_full_path, strerror(-ret));
836                 goto out;
837         }
838
839         ret = find_mount_root(dest_dir_full_path, &r->root_path);
840         if (ret < 0) {
841                 ret = -EINVAL;
842                 fprintf(stderr, "ERROR: failed to determine mount point "
843                         "for %s\n", dest_dir_full_path);
844                 goto out;
845         }
846         r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
847         if (r->mnt_fd < 0) {
848                 ret = -errno;
849                 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
850                         strerror(-ret));
851                 goto out;
852         }
853
854         /*
855          * find_mount_root returns a root_path that is a subpath of
856          * dest_dir_full_path. Now get the other part of root_path,
857          * which is the destination dir relative to root_path.
858          */
859         r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
860         while (r->dest_dir_path[0] == '/')
861                 r->dest_dir_path++;
862
863         ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
864         if (ret < 0)
865                 goto out;
866
867         while (!end) {
868                 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
869                                                          r->honor_end_cmd);
870                 if (ret < 0)
871                         goto out;
872                 if (ret)
873                         end = 1;
874
875                 ret = close_inode_for_write(r);
876                 if (ret < 0)
877                         goto out;
878                 ret = finish_subvol(r);
879                 if (ret < 0)
880                         goto out;
881         }
882         ret = 0;
883
884 out:
885         if (r->write_fd != -1) {
886                 close(r->write_fd);
887                 r->write_fd = -1;
888         }
889         free(r->root_path);
890         r->root_path = NULL;
891         free(r->write_path);
892         r->write_path = NULL;
893         free(r->full_subvol_path);
894         r->full_subvol_path = NULL;
895         r->dest_dir_path = NULL;
896         free(dest_dir_full_path);
897         if (r->cur_subvol) {
898                 free(r->cur_subvol->path);
899                 free(r->cur_subvol);
900                 r->cur_subvol = NULL;
901         }
902         subvol_uuid_search_finit(&r->sus);
903         if (r->mnt_fd != -1) {
904                 close(r->mnt_fd);
905                 r->mnt_fd = -1;
906         }
907         if (r->dest_dir_fd != -1) {
908                 close(r->dest_dir_fd);
909                 r->dest_dir_fd = -1;
910         }
911         return ret;
912 }
913
914 int cmd_receive(int argc, char **argv)
915 {
916         int c;
917         char *tomnt = NULL;
918         char *fromfile = NULL;
919         struct btrfs_receive r;
920         int receive_fd = fileno(stdin);
921
922         int ret;
923
924         memset(&r, 0, sizeof(r));
925         r.mnt_fd = -1;
926         r.write_fd = -1;
927         r.dest_dir_fd = -1;
928
929         while ((c = getopt(argc, argv, "evf:")) != -1) {
930                 switch (c) {
931                 case 'v':
932                         g_verbose++;
933                         break;
934                 case 'f':
935                         fromfile = optarg;
936                         break;
937                 case 'e':
938                         r.honor_end_cmd = 1;
939                         break;
940                 case '?':
941                 default:
942                         fprintf(stderr, "ERROR: receive args invalid.\n");
943                         return 1;
944                 }
945         }
946
947         if (optind + 1 != argc) {
948                 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
949                 return 1;
950         }
951
952         tomnt = argv[optind];
953
954         if (fromfile) {
955                 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
956                 if (receive_fd < 0) {
957                         fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
958                         return 1;
959                 }
960         }
961
962         ret = do_receive(&r, tomnt, receive_fd);
963
964         return !!ret;
965 }
966
967 const char * const cmd_receive_usage[] = {
968         "btrfs receive [-ve] [-f <infile>] <mount>",
969         "Receive subvolumes from stdin.",
970         "Receives one or more subvolumes that were previously ",
971         "sent with btrfs send. The received subvolumes are stored",
972         "into <mount>.",
973         "btrfs receive will fail in case a receiving subvolume",
974         "already exists. It will also fail in case a previously",
975         "received subvolume was changed after it was received.",
976         "After receiving a subvolume, it is immediately set to",
977         "read only.\n",
978         "-v               Enable verbose debug output. Each",
979         "                 occurrence of this option increases the",
980         "                 verbose level more.",
981         "-f <infile>      By default, btrfs receive uses stdin",
982         "                 to receive the subvolumes. Use this",
983         "                 option to specify a file to use instead.",
984         "-e               Terminate after receiving an <end cmd>",
985         "                 in the data stream. Without this option,",
986         "                 the receiver terminates only if an error",
987         "                 is recognized or on EOF.",
988         NULL
989 };