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