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