Btrfs-progs: use UUID tree for send/receive
[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                 ret = -ENOENT;
238                 fprintf(stderr, "ERROR: could not find parent subvolume\n");
239                 goto out;
240         }
241
242         /*if (rs_args.ctransid > rs_args.rtransid) {
243                 if (!r->force) {
244                         ret = -EINVAL;
245                         fprintf(stderr, "ERROR: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
246                         goto out;
247                 } else {
248                         fprintf(stderr, "WARNING: subvolume %s was modified after it was received.\n", r->subvol_parent_name);
249                 }
250         }*/
251
252         args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
253                         O_RDONLY | O_NOATIME);
254         if (args_v2.fd < 0) {
255                 ret = -errno;
256                 fprintf(stderr, "ERROR: open %s failed. %s\n",
257                                 parent_subvol->path, strerror(-ret));
258                 goto out;
259         }
260
261         ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SNAP_CREATE_V2, &args_v2);
262         close(args_v2.fd);
263         if (ret < 0) {
264                 ret = -errno;
265                 fprintf(stderr, "ERROR: creating snapshot %s -> %s "
266                                 "failed. %s\n", parent_subvol->path,
267                                 path, strerror(-ret));
268                 goto out;
269         }
270
271 out:
272         if (parent_subvol) {
273                 free(parent_subvol->path);
274                 free(parent_subvol);
275         }
276         return ret;
277 }
278
279 static int process_mkfile(const char *path, void *user)
280 {
281         int ret;
282         struct btrfs_receive *r = user;
283         char *full_path = path_cat(r->full_subvol_path, path);
284
285         if (g_verbose >= 2)
286                 fprintf(stderr, "mkfile %s\n", path);
287
288         ret = creat(full_path, 0600);
289         if (ret < 0) {
290                 ret = -errno;
291                 fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
292                                 strerror(-ret));
293                 goto out;
294         }
295         close(ret);
296         ret = 0;
297
298 out:
299         free(full_path);
300         return ret;
301 }
302
303 static int process_mkdir(const char *path, void *user)
304 {
305         int ret;
306         struct btrfs_receive *r = user;
307         char *full_path = path_cat(r->full_subvol_path, path);
308
309         if (g_verbose >= 2)
310                 fprintf(stderr, "mkdir %s\n", path);
311
312         ret = mkdir(full_path, 0700);
313         if (ret < 0) {
314                 ret = -errno;
315                 fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
316                                 strerror(-ret));
317         }
318
319         free(full_path);
320         return ret;
321 }
322
323 static int process_mknod(const char *path, u64 mode, u64 dev, void *user)
324 {
325         int ret;
326         struct btrfs_receive *r = user;
327         char *full_path = path_cat(r->full_subvol_path, path);
328
329         if (g_verbose >= 2)
330                 fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
331                                 path, mode, dev);
332
333         ret = mknod(full_path, mode & S_IFMT, dev);
334         if (ret < 0) {
335                 ret = -errno;
336                 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
337                                 strerror(-ret));
338         }
339
340         free(full_path);
341         return ret;
342 }
343
344 static int process_mkfifo(const char *path, void *user)
345 {
346         int ret;
347         struct btrfs_receive *r = user;
348         char *full_path = path_cat(r->full_subvol_path, path);
349
350         if (g_verbose >= 2)
351                 fprintf(stderr, "mkfifo %s\n", path);
352
353         ret = mkfifo(full_path, 0600);
354         if (ret < 0) {
355                 ret = -errno;
356                 fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
357                                 strerror(-ret));
358         }
359
360         free(full_path);
361         return ret;
362 }
363
364 static int process_mksock(const char *path, void *user)
365 {
366         int ret;
367         struct btrfs_receive *r = user;
368         char *full_path = path_cat(r->full_subvol_path, path);
369
370         if (g_verbose >= 2)
371                 fprintf(stderr, "mksock %s\n", path);
372
373         ret = mknod(full_path, 0600 | S_IFSOCK, 0);
374         if (ret < 0) {
375                 ret = -errno;
376                 fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
377                                 strerror(-ret));
378         }
379
380         free(full_path);
381         return ret;
382 }
383
384 static int process_symlink(const char *path, const char *lnk, void *user)
385 {
386         int ret;
387         struct btrfs_receive *r = user;
388         char *full_path = path_cat(r->full_subvol_path, path);
389
390         if (g_verbose >= 2)
391                 fprintf(stderr, "symlink %s -> %s\n", path, lnk);
392
393         ret = symlink(lnk, full_path);
394         if (ret < 0) {
395                 ret = -errno;
396                 fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
397                                 lnk, strerror(-ret));
398         }
399
400         free(full_path);
401         return ret;
402 }
403
404 static int process_rename(const char *from, const char *to, void *user)
405 {
406         int ret;
407         struct btrfs_receive *r = user;
408         char *full_from = path_cat(r->full_subvol_path, from);
409         char *full_to = path_cat(r->full_subvol_path, to);
410
411         if (g_verbose >= 2)
412                 fprintf(stderr, "rename %s -> %s\n", from, to);
413
414         ret = rename(full_from, full_to);
415         if (ret < 0) {
416                 ret = -errno;
417                 fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
418                                 to, strerror(-ret));
419         }
420
421         free(full_from);
422         free(full_to);
423         return ret;
424 }
425
426 static int process_link(const char *path, const char *lnk, void *user)
427 {
428         int ret;
429         struct btrfs_receive *r = user;
430         char *full_path = path_cat(r->full_subvol_path, path);
431         char *full_link_path = path_cat(r->full_subvol_path, lnk);
432
433         if (g_verbose >= 2)
434                 fprintf(stderr, "link %s -> %s\n", path, lnk);
435
436         ret = link(full_link_path, full_path);
437         if (ret < 0) {
438                 ret = -errno;
439                 fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
440                                 lnk, strerror(-ret));
441         }
442
443         free(full_path);
444         free(full_link_path);
445         return ret;
446 }
447
448
449 static int process_unlink(const char *path, void *user)
450 {
451         int ret;
452         struct btrfs_receive *r = user;
453         char *full_path = path_cat(r->full_subvol_path, path);
454
455         if (g_verbose >= 2)
456                 fprintf(stderr, "unlink %s\n", path);
457
458         ret = unlink(full_path);
459         if (ret < 0) {
460                 ret = -errno;
461                 fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
462                                 strerror(-ret));
463         }
464
465         free(full_path);
466         return ret;
467 }
468
469 static int process_rmdir(const char *path, void *user)
470 {
471         int ret;
472         struct btrfs_receive *r = user;
473         char *full_path = path_cat(r->full_subvol_path, path);
474
475         if (g_verbose >= 2)
476                 fprintf(stderr, "rmdir %s\n", path);
477
478         ret = rmdir(full_path);
479         if (ret < 0) {
480                 ret = -errno;
481                 fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
482                                 strerror(-ret));
483         }
484
485         free(full_path);
486         return ret;
487 }
488
489
490 static int open_inode_for_write(struct btrfs_receive *r, const char *path)
491 {
492         int ret = 0;
493
494         if (r->write_fd != -1) {
495                 if (strcmp(r->write_path, path) == 0)
496                         goto out;
497                 close(r->write_fd);
498                 r->write_fd = -1;
499         }
500
501         r->write_fd = open(path, O_RDWR);
502         if (r->write_fd < 0) {
503                 ret = -errno;
504                 fprintf(stderr, "ERROR: open %s failed. %s\n", path,
505                                 strerror(-ret));
506                 goto out;
507         }
508         free(r->write_path);
509         r->write_path = strdup(path);
510
511 out:
512         return ret;
513 }
514
515 static int close_inode_for_write(struct btrfs_receive *r)
516 {
517         int ret = 0;
518
519         if(r->write_fd == -1)
520                 goto out;
521
522         close(r->write_fd);
523         r->write_fd = -1;
524         r->write_path[0] = 0;
525
526 out:
527         return ret;
528 }
529
530 static int process_write(const char *path, const void *data, u64 offset,
531                          u64 len, void *user)
532 {
533         int ret = 0;
534         struct btrfs_receive *r = user;
535         char *full_path = path_cat(r->full_subvol_path, path);
536         u64 pos = 0;
537         int w;
538
539         ret = open_inode_for_write(r, full_path);
540         if (ret < 0)
541                 goto out;
542
543         while (pos < len) {
544                 w = pwrite(r->write_fd, (char*)data + pos, len - pos,
545                                 offset + pos);
546                 if (w < 0) {
547                         ret = -errno;
548                         fprintf(stderr, "ERROR: writing to %s failed. %s\n",
549                                         path, strerror(-ret));
550                         goto out;
551                 }
552                 pos += w;
553         }
554
555 out:
556         free(full_path);
557         return ret;
558 }
559
560 static int process_clone(const char *path, u64 offset, u64 len,
561                          const u8 *clone_uuid, u64 clone_ctransid,
562                          const char *clone_path, u64 clone_offset,
563                          void *user)
564 {
565         int ret;
566         struct btrfs_receive *r = user;
567         struct btrfs_ioctl_clone_range_args clone_args;
568         struct subvol_info *si = NULL;
569         char *full_path = path_cat(r->full_subvol_path, path);
570         char *subvol_path = NULL;
571         char *full_clone_path = NULL;
572         int clone_fd = -1;
573
574         ret = open_inode_for_write(r, full_path);
575         if (ret < 0)
576                 goto out;
577
578         si = subvol_uuid_search(&r->sus, 0, clone_uuid, clone_ctransid, NULL,
579                         subvol_search_by_received_uuid);
580         if (!si) {
581                 if (memcmp(clone_uuid, r->cur_subvol->received_uuid,
582                                 BTRFS_UUID_SIZE) == 0) {
583                         /* TODO check generation of extent */
584                         subvol_path = strdup(r->cur_subvol->path);
585                 } else {
586                         ret = -ENOENT;
587                         fprintf(stderr, "ERROR: did not find source subvol.\n");
588                         goto out;
589                 }
590         } else {
591                 /*if (rs_args.ctransid > rs_args.rtransid) {
592                         if (!r->force) {
593                                 ret = -EINVAL;
594                                 fprintf(stderr, "ERROR: subvolume %s was "
595                                                 "modified after it was "
596                                                 "received.\n",
597                                                 r->subvol_parent_name);
598                                 goto out;
599                         } else {
600                                 fprintf(stderr, "WARNING: subvolume %s was "
601                                                 "modified after it was "
602                                                 "received.\n",
603                                                 r->subvol_parent_name);
604                         }
605                 }*/
606                 subvol_path = strdup(si->path);
607         }
608
609         full_clone_path = path_cat3(r->root_path, subvol_path, clone_path);
610
611         clone_fd = open(full_clone_path, O_RDONLY | O_NOATIME);
612         if (clone_fd < 0) {
613                 ret = -errno;
614                 fprintf(stderr, "ERROR: failed to open %s. %s\n",
615                                 full_clone_path, strerror(-ret));
616                 goto out;
617         }
618
619         clone_args.src_fd = clone_fd;
620         clone_args.src_offset = clone_offset;
621         clone_args.src_length = len;
622         clone_args.dest_offset = offset;
623         ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
624         if (ret) {
625                 ret = -errno;
626                 fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
627                                 path, strerror(-ret));
628                 goto out;
629         }
630
631 out:
632         if (si) {
633                 free(si->path);
634                 free(si);
635         }
636         free(full_path);
637         free(full_clone_path);
638         free(subvol_path);
639         if (clone_fd != -1)
640                 close(clone_fd);
641         return ret;
642 }
643
644
645 static int process_set_xattr(const char *path, const char *name,
646                              const void *data, int len, void *user)
647 {
648         int ret = 0;
649         struct btrfs_receive *r = user;
650         char *full_path = path_cat(r->full_subvol_path, path);
651
652         if (g_verbose >= 2) {
653                 fprintf(stderr, "set_xattr %s - name=%s data_len=%d "
654                                 "data=%.*s\n", path, name, len,
655                                 len, (char*)data);
656         }
657
658         ret = lsetxattr(full_path, name, data, len, 0);
659         if (ret < 0) {
660                 ret = -errno;
661                 fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
662                                 path, name, len, (char*)data, strerror(-ret));
663                 goto out;
664         }
665
666 out:
667         free(full_path);
668         return ret;
669 }
670
671 static int process_remove_xattr(const char *path, const char *name, void *user)
672 {
673         int ret = 0;
674         struct btrfs_receive *r = user;
675         char *full_path = path_cat(r->full_subvol_path, path);
676
677         if (g_verbose >= 2) {
678                 fprintf(stderr, "remove_xattr %s - name=%s\n",
679                                 path, name);
680         }
681
682         ret = lremovexattr(full_path, name);
683         if (ret < 0) {
684                 ret = -errno;
685                 fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
686                                 path, name, strerror(-ret));
687                 goto out;
688         }
689
690 out:
691         free(full_path);
692         return ret;
693 }
694
695 static int process_truncate(const char *path, u64 size, void *user)
696 {
697         int ret = 0;
698         struct btrfs_receive *r = user;
699         char *full_path = path_cat(r->full_subvol_path, path);
700
701         if (g_verbose >= 2)
702                 fprintf(stderr, "truncate %s size=%llu\n", path, size);
703
704         ret = truncate(full_path, size);
705         if (ret < 0) {
706                 ret = -errno;
707                 fprintf(stderr, "ERROR: truncate %s failed. %s\n",
708                                 path, strerror(-ret));
709                 goto out;
710         }
711
712 out:
713         free(full_path);
714         return ret;
715 }
716
717 static int process_chmod(const char *path, u64 mode, void *user)
718 {
719         int ret = 0;
720         struct btrfs_receive *r = user;
721         char *full_path = path_cat(r->full_subvol_path, path);
722
723         if (g_verbose >= 2)
724                 fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
725
726         ret = chmod(full_path, mode);
727         if (ret < 0) {
728                 ret = -errno;
729                 fprintf(stderr, "ERROR: chmod %s failed. %s\n",
730                                 path, strerror(-ret));
731                 goto out;
732         }
733
734 out:
735         free(full_path);
736         return ret;
737 }
738
739 static int process_chown(const char *path, u64 uid, u64 gid, void *user)
740 {
741         int ret = 0;
742         struct btrfs_receive *r = user;
743         char *full_path = path_cat(r->full_subvol_path, path);
744
745         if (g_verbose >= 2)
746                 fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
747                                 uid, gid);
748
749         ret = lchown(full_path, uid, gid);
750         if (ret < 0) {
751                 ret = -errno;
752                 fprintf(stderr, "ERROR: chown %s failed. %s\n",
753                                 path, strerror(-ret));
754                 goto out;
755         }
756
757 out:
758         free(full_path);
759         return ret;
760 }
761
762 static int process_utimes(const char *path, struct timespec *at,
763                           struct timespec *mt, struct timespec *ct,
764                           void *user)
765 {
766         int ret = 0;
767         struct btrfs_receive *r = user;
768         char *full_path = path_cat(r->full_subvol_path, path);
769         struct timespec tv[2];
770
771         if (g_verbose >= 2)
772                 fprintf(stderr, "utimes %s\n", path);
773
774         tv[0] = *at;
775         tv[1] = *mt;
776         ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
777         if (ret < 0) {
778                 ret = -errno;
779                 fprintf(stderr, "ERROR: utimes %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
790 struct btrfs_send_ops send_ops = {
791         .subvol = process_subvol,
792         .snapshot = process_snapshot,
793         .mkfile = process_mkfile,
794         .mkdir = process_mkdir,
795         .mknod = process_mknod,
796         .mkfifo = process_mkfifo,
797         .mksock = process_mksock,
798         .symlink = process_symlink,
799         .rename = process_rename,
800         .link = process_link,
801         .unlink = process_unlink,
802         .rmdir = process_rmdir,
803         .write = process_write,
804         .clone = process_clone,
805         .set_xattr = process_set_xattr,
806         .remove_xattr = process_remove_xattr,
807         .truncate = process_truncate,
808         .chmod = process_chmod,
809         .chown = process_chown,
810         .utimes = process_utimes,
811 };
812
813 int do_receive(struct btrfs_receive *r, const char *tomnt, int r_fd)
814 {
815         int ret;
816         char *dest_dir_full_path;
817         int end = 0;
818
819         dest_dir_full_path = realpath(tomnt, NULL);
820         if (!dest_dir_full_path) {
821                 ret = -errno;
822                 fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
823                         strerror(-ret));
824                 goto out;
825         }
826         r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
827         if (r->dest_dir_fd < 0) {
828                 ret = -errno;
829                 fprintf(stderr,
830                         "ERROR: failed to open destination directory %s. %s\n",
831                         dest_dir_full_path, strerror(-ret));
832                 goto out;
833         }
834
835         ret = find_mount_root(dest_dir_full_path, &r->root_path);
836         if (ret < 0) {
837                 ret = -EINVAL;
838                 fprintf(stderr, "ERROR: failed to determine mount point "
839                         "for %s\n", dest_dir_full_path);
840                 goto out;
841         }
842         r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
843         if (r->mnt_fd < 0) {
844                 ret = -errno;
845                 fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
846                         strerror(-ret));
847                 goto out;
848         }
849
850         /*
851          * find_mount_root returns a root_path that is a subpath of
852          * dest_dir_full_path. Now get the other part of root_path,
853          * which is the destination dir relative to root_path.
854          */
855         r->dest_dir_path = dest_dir_full_path + strlen(r->root_path);
856         while (r->dest_dir_path[0] == '/')
857                 r->dest_dir_path++;
858
859         ret = subvol_uuid_search_init(r->mnt_fd, &r->sus);
860         if (ret < 0)
861                 goto out;
862
863         while (!end) {
864                 ret = btrfs_read_and_process_send_stream(r_fd, &send_ops, r,
865                                                          r->honor_end_cmd);
866                 if (ret < 0)
867                         goto out;
868                 if (ret)
869                         end = 1;
870
871                 ret = close_inode_for_write(r);
872                 if (ret < 0)
873                         goto out;
874                 ret = finish_subvol(r);
875                 if (ret < 0)
876                         goto out;
877         }
878         ret = 0;
879
880 out:
881         if (r->write_fd != -1) {
882                 close(r->write_fd);
883                 r->write_fd = -1;
884         }
885         free(r->root_path);
886         r->root_path = NULL;
887         free(r->write_path);
888         r->write_path = NULL;
889         free(r->full_subvol_path);
890         r->full_subvol_path = NULL;
891         r->dest_dir_path = NULL;
892         free(dest_dir_full_path);
893         if (r->cur_subvol) {
894                 free(r->cur_subvol->path);
895                 free(r->cur_subvol);
896                 r->cur_subvol = NULL;
897         }
898         subvol_uuid_search_finit(&r->sus);
899         if (r->mnt_fd != -1) {
900                 close(r->mnt_fd);
901                 r->mnt_fd = -1;
902         }
903         if (r->dest_dir_fd != -1) {
904                 close(r->dest_dir_fd);
905                 r->dest_dir_fd = -1;
906         }
907         return ret;
908 }
909
910 static int do_cmd_receive(int argc, char **argv)
911 {
912         int c;
913         char *tomnt = NULL;
914         char *fromfile = NULL;
915         struct btrfs_receive r;
916         int receive_fd = fileno(stdin);
917
918         int ret;
919
920         memset(&r, 0, sizeof(r));
921         r.mnt_fd = -1;
922         r.write_fd = -1;
923         r.dest_dir_fd = -1;
924
925         while ((c = getopt(argc, argv, "evf:")) != -1) {
926                 switch (c) {
927                 case 'v':
928                         g_verbose++;
929                         break;
930                 case 'f':
931                         fromfile = optarg;
932                         break;
933                 case 'e':
934                         r.honor_end_cmd = 1;
935                         break;
936                 case '?':
937                 default:
938                         fprintf(stderr, "ERROR: receive args invalid.\n");
939                         return 1;
940                 }
941         }
942
943         if (optind + 1 != argc) {
944                 fprintf(stderr, "ERROR: receive needs path to subvolume\n");
945                 return 1;
946         }
947
948         tomnt = argv[optind];
949
950         if (fromfile) {
951                 receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
952                 if (receive_fd < 0) {
953                         fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
954                         return -errno;
955                 }
956         }
957
958         ret = do_receive(&r, tomnt, receive_fd);
959
960         return ret;
961 }
962
963 static const char * const receive_cmd_group_usage[] = {
964         "btrfs receive <command> <args>",
965         NULL
966 };
967
968 const char * const cmd_receive_usage[] = {
969         "btrfs receive [-ve] [-f <infile>] <mount>",
970         "Receive subvolumes from stdin.",
971         "Receives one or more subvolumes that were previously ",
972         "sent with btrfs send. The received subvolumes are stored",
973         "into <mount>.",
974         "btrfs receive will fail in case a receiving subvolume",
975         "already exists. It will also fail in case a previously",
976         "received subvolume was changed after it was received.",
977         "After receiving a subvolume, it is immediately set to",
978         "read only.\n",
979         "-v               Enable verbose debug output. Each",
980         "                 occurrence of this option increases the",
981         "                 verbose level more.",
982         "-f <infile>      By default, btrfs receive uses stdin",
983         "                 to receive the subvolumes. Use this",
984         "                 option to specify a file to use instead.",
985         "-e               Terminate after receiving an <end cmd>",
986         "                 in the data stream. Without this option,",
987         "                 the receiver terminates only if an error",
988         "                 is recognized or on EOF.",
989         NULL
990 };
991
992 const struct cmd_group receive_cmd_group = {
993         receive_cmd_group_usage, NULL, {
994                 { "receive", do_cmd_receive, cmd_receive_usage, NULL, 0 },
995                 { 0, 0, 0, 0, 0 },
996         },
997 };
998
999 int cmd_receive(int argc, char **argv)
1000 {
1001         return do_cmd_receive(argc, argv);
1002 }