2 * Copyright (C) 2013 SUSE. All rights reserved.
4 * This code is adapted from cmds-send.c and cmds-receive.c,
7 * Copyright (C) 2012 Alexander Block. All rights reserved.
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public
11 * License v2 as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 021110-1307, USA.
31 #include <sys/types.h>
34 #include <sys/ioctl.h>
39 #include <asm/types.h>
40 #include <uuid/uuid.h>
43 * This should be compilable without the rest of the btrfs-progs
44 * source distribution.
46 #if BTRFS_FLAT_INCLUDES
47 #include "send-utils.h"
48 #include "send-stream.h"
50 #include <btrfs/send-utils.h>
51 #include <btrfs/send-stream.h>
52 #endif /* BTRFS_FLAT_INCLUDES */
55 struct btrfs_ioctl_send_args io_send = {0, };
56 static char *subvol_path;
57 static char *root_path;
60 char *full_subvol_path;
66 printf("send-test <btrfs root> <subvol>\n");
71 static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
74 struct recv_args *r = user;
75 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
77 r->full_subvol_path = path_cat(r->root_path, path);
78 uuid_unparse(uuid, uuid_str);
80 printf("subvol\t%s\t%llu\t%s\n", uuid_str,
81 (unsigned long long)ctransid, r->full_subvol_path);
86 static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
87 const u8 *parent_uuid, u64 parent_ctransid,
90 struct recv_args *r = user;
91 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
92 char parent_uuid_str[BTRFS_UUID_UNPARSED_SIZE];
94 r->full_subvol_path = path_cat(r->root_path, path);
95 uuid_unparse(uuid, uuid_str);
96 uuid_unparse(parent_uuid, parent_uuid_str);
98 printf("snapshot\t%s\t%llu\t%s\t%llu\t%s\n", uuid_str,
99 (unsigned long long)ctransid, parent_uuid_str,
100 (unsigned long long)parent_ctransid, r->full_subvol_path);
105 static int print_mkfile(const char *path, void *user)
107 struct recv_args *r = user;
108 char *full_path = path_cat(r->full_subvol_path, path);
110 printf("mkfile\t%s\n", full_path);
116 static int print_mkdir(const char *path, void *user)
118 struct recv_args *r = user;
119 char *full_path = path_cat(r->full_subvol_path, path);
121 printf("mkdir\t%s\n", full_path);
127 static int print_mknod(const char *path, u64 mode, u64 dev, void *user)
129 struct recv_args *r = user;
130 char *full_path = path_cat(r->full_subvol_path, path);
132 printf("mknod\t%llo\t0x%llx\t%s\n", (unsigned long long)mode,
133 (unsigned long long)dev, full_path);
139 static int print_mkfifo(const char *path, void *user)
141 struct recv_args *r = user;
142 char *full_path = path_cat(r->full_subvol_path, path);
144 printf("mkfifo\t%s\n", full_path);
150 static int print_mksock(const char *path, void *user)
152 struct recv_args *r = user;
153 char *full_path = path_cat(r->full_subvol_path, path);
155 printf("mksock\t%s\n", full_path);
161 static int print_symlink(const char *path, const char *lnk, void *user)
163 struct recv_args *r = user;
164 char *full_path = path_cat(r->full_subvol_path, path);
166 printf("symlink\t%s\t%s\n", lnk, full_path);
172 static int print_rename(const char *from, const char *to, void *user)
174 struct recv_args *r = user;
175 char *full_from = path_cat(r->full_subvol_path, from);
176 char *full_to = path_cat(r->full_subvol_path, to);
178 printf("rename\t%s\t%s\n", from, to);
185 static int print_link(const char *path, const char *lnk, void *user)
187 struct recv_args *r = user;
188 char *full_path = path_cat(r->full_subvol_path, path);
190 printf("link\t%s\t%s\n", lnk, full_path);
196 static int print_unlink(const char *path, void *user)
198 struct recv_args *r = user;
199 char *full_path = path_cat(r->full_subvol_path, path);
201 printf("unlink\t%s\n", full_path);
207 static int print_rmdir(const char *path, void *user)
209 struct recv_args *r = user;
210 char *full_path = path_cat(r->full_subvol_path, path);
212 printf("rmdir\t%s\n", full_path);
218 static int print_write(const char *path, const void *data, u64 offset,
221 struct recv_args *r = user;
222 char *full_path = path_cat(r->full_subvol_path, path);
224 printf("write\t%llu\t%llu\t%s\n", (unsigned long long)offset,
225 (unsigned long long)len, full_path);
231 static int print_clone(const char *path, u64 offset, u64 len,
232 const u8 *clone_uuid, u64 clone_ctransid,
233 const char *clone_path, u64 clone_offset,
236 struct recv_args *r = user;
237 char *full_path = path_cat(r->full_subvol_path, path);
239 printf("clone\t%s\t%s\n", full_path, clone_path);
245 static int print_set_xattr(const char *path, const char *name,
246 const void *data, int len, void *user)
248 struct recv_args *r = user;
249 char *full_path = path_cat(r->full_subvol_path, path);
251 printf("set_xattr\t%s\t%s\t%d\n", full_path,
258 static int print_remove_xattr(const char *path, const char *name, void *user)
260 struct recv_args *r = user;
261 char *full_path = path_cat(r->full_subvol_path, path);
263 printf("remove_xattr\t%s\t%s\n", full_path, name);
269 static int print_truncate(const char *path, u64 size, void *user)
271 struct recv_args *r = user;
272 char *full_path = path_cat(r->full_subvol_path, path);
274 printf("truncate\t%llu\t%s\n", (unsigned long long)size, full_path);
280 static int print_chmod(const char *path, u64 mode, void *user)
282 struct recv_args *r = user;
283 char *full_path = path_cat(r->full_subvol_path, path);
285 printf("chmod\t%llo\t%s\n", (unsigned long long)mode, full_path);
291 static int print_chown(const char *path, u64 uid, u64 gid, void *user)
293 struct recv_args *r = user;
294 char *full_path = path_cat(r->full_subvol_path, path);
296 printf("chown\t%llu\t%llu\t%s\n", (unsigned long long)uid,
297 (unsigned long long)gid, full_path);
303 static int print_utimes(const char *path, struct timespec *at,
304 struct timespec *mt, struct timespec *ct,
307 struct recv_args *r = user;
308 char *full_path = path_cat(r->full_subvol_path, path);
310 printf("utimes\t%s\n", full_path);
316 static int print_update_extent(const char *path, u64 offset, u64 len,
319 struct recv_args *r = user;
320 char *full_path = path_cat(r->full_subvol_path, path);
322 printf("update_extent\t%s\t%llu\t%llu\n", full_path, offset, len);
328 static struct btrfs_send_ops send_ops_print = {
329 .subvol = print_subvol,
330 .snapshot = print_snapshot,
331 .mkfile = print_mkfile,
332 .mkdir = print_mkdir,
333 .mknod = print_mknod,
334 .mkfifo = print_mkfifo,
335 .mksock = print_mksock,
336 .symlink = print_symlink,
337 .rename = print_rename,
339 .unlink = print_unlink,
340 .rmdir = print_rmdir,
341 .write = print_write,
342 .clone = print_clone,
343 .set_xattr = print_set_xattr,
344 .remove_xattr = print_remove_xattr,
345 .truncate = print_truncate,
346 .chmod = print_chmod,
347 .chown = print_chown,
348 .utimes = print_utimes,
349 .update_extent = print_update_extent,
352 static void *process_thread(void *arg_)
357 ret = btrfs_read_and_process_send_stream(pipefd[0],
358 &send_ops_print, arg_, 0);
369 int main(int argc, char **argv)
380 root_path = realpath(argv[1], NULL);
386 subvol_path = realpath(argv[2], NULL);
392 r.full_subvol_path = subvol_path;
393 r.root_path = root_path;
395 subvol_fd = open(subvol_path, O_RDONLY|O_NOATIME);
398 fprintf(stderr, "ERROR: Subvolume open failed. %s\n",
406 fprintf(stderr, "ERROR: pipe failed. %s\n", strerror(ret));
410 ret = pthread_create(&t_read, NULL, process_thread, &r);
413 fprintf(stderr, "ERROR: pthread create failed. %s\n",
418 io_send.send_fd = pipefd[1];
419 io_send.clone_sources_count = 0;
420 io_send.clone_sources = NULL;
421 io_send.parent_root = 0;
422 io_send.flags = BTRFS_SEND_FLAG_NO_FILE_DATA;
424 ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send);
427 fprintf(stderr, "ERROR: send ioctl failed with %d: %s\n", ret,
434 ret = pthread_join(t_read, &t_err);
436 fprintf(stderr, "ERROR: pthread_join failed: %s\n",
441 ret = (long int)t_err;
442 fprintf(stderr, "ERROR: failed to process send stream, ret=%ld "
443 "(%s)\n", (long int)t_err, strerror(ret));