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