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