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