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