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