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