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