btrfs-progs: backref: add list_first_pref helper
[btrfs-progs-unstable/devel.git] / send-dump.c
blob1591e0cc2a5f75bc3f93e0e7021e8acae8d34420
1 /*
2 * Copyright (C) 2016 Fujitsu. All rights reserved.
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.
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.
13 * You should have received a copy of the GNU General Public
14 * License along with this program.
17 #include <unistd.h>
18 #include <stdint.h>
19 #include <dirent.h>
20 #include <pthread.h>
21 #include <math.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <sys/ioctl.h>
26 #include <libgen.h>
27 #include <mntent.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <ctype.h>
32 #include <asm/types.h>
33 #include <uuid/uuid.h>
34 #include "utils.h"
35 #include "commands.h"
36 #include "send-utils.h"
37 #include "send-stream.h"
38 #include "send-dump.h"
40 #define PATH_CAT_OR_RET(function_name, outpath, path1, path2, ret) \
41 ({ \
42 ret = path_cat_out(outpath, path1, path2); \
43 if (ret < 0) { \
44 error("%s: path invalid: %s\n", function_name, path2); \
45 return ret; \
46 } \
50 * Print path and escape chaacters (in a C way) that could break the line.
51 * Returns the length of the escaped characters. Unprintable characters are
52 * escaped as octals.
54 static int print_path_escaped(const char *path)
56 size_t i;
57 size_t path_len = strlen(path);
58 int len = 0;
60 for (i = 0; i < path_len; i++) {
61 char c = path[i];
63 len++;
64 switch (c) {
65 case '\a': putchar('\\'); putchar('a'); len++; break;
66 case '\b': putchar('\\'); putchar('b'); len++; break;
67 case '\e': putchar('\\'); putchar('e'); len++; break;
68 case '\f': putchar('\\'); putchar('f'); len++; break;
69 case '\n': putchar('\\'); putchar('n'); len++; break;
70 case '\r': putchar('\\'); putchar('r'); len++; break;
71 case '\t': putchar('\\'); putchar('t'); len++; break;
72 case '\v': putchar('\\'); putchar('v'); len++; break;
73 case ' ': putchar('\\'); putchar(' '); len++; break;
74 case '\\': putchar('\\'); putchar('\\'); len++; break;
75 default:
76 if (!isprint(c)) {
77 printf("\\%c%c%c",
78 '0' + ((c & 0300) >> 6),
79 '0' + ((c & 070) >> 3),
80 '0' + (c & 07));
81 len += 3;
82 } else {
83 putchar(c);
87 return len;
91 * Underlying PRINT_DUMP, the only difference is how we handle
92 * the full path.
94 __attribute__ ((format (printf, 5, 6)))
95 static int __print_dump(int subvol, void *user, const char *path,
96 const char *title, const char *fmt, ...)
98 struct btrfs_dump_send_args *r = user;
99 char full_path[PATH_MAX] = {0};
100 char *out_path;
101 va_list args;
102 int ret;
104 if (subvol) {
105 PATH_CAT_OR_RET(title, r->full_subvol_path, r->root_path, path, ret);
106 out_path = r->full_subvol_path;
107 } else {
108 PATH_CAT_OR_RET(title, full_path, r->full_subvol_path, path, ret);
109 out_path = full_path;
112 /* Unified header */
113 printf("%-16s", title);
114 ret = print_path_escaped(out_path);
115 if (!fmt) {
116 putchar('\n');
117 return 0;
119 /* Short paths are aligned to 32 chars; longer paths get a single space */
120 do {
121 putchar(' ');
122 } while (++ret < 32);
123 va_start(args, fmt);
124 /* Operation specified ones */
125 vprintf(fmt, args);
126 va_end(args);
127 putchar('\n');
128 return 0;
131 /* For subvolume/snapshot operation only */
132 #define PRINT_DUMP_SUBVOL(user, path, title, fmt, ...) \
133 __print_dump(1, user, path, title, fmt, ##__VA_ARGS__)
135 /* For other operations */
136 #define PRINT_DUMP(user, path, title, fmt, ...) \
137 __print_dump(0, user, path, title, fmt, ##__VA_ARGS__)
139 static int print_subvol(const char *path, const u8 *uuid, u64 ctransid,
140 void *user)
142 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
144 uuid_unparse(uuid, uuid_str);
146 return PRINT_DUMP_SUBVOL(user, path, "subvol", "uuid=%s transid=%llu",
147 uuid_str, ctransid);
150 static int print_snapshot(const char *path, const u8 *uuid, u64 ctransid,
151 const u8 *parent_uuid, u64 parent_ctransid,
152 void *user)
154 char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
155 char parent_uuid_str[BTRFS_UUID_UNPARSED_SIZE];
156 int ret;
158 uuid_unparse(uuid, uuid_str);
159 uuid_unparse(parent_uuid, parent_uuid_str);
161 ret = PRINT_DUMP_SUBVOL(user, path, "snapshot",
162 "uuid=%s transid=%llu parent_uuid=%s parent_transid=%llu",
163 uuid_str, ctransid, parent_uuid_str,
164 parent_ctransid);
165 return ret;
168 static int print_mkfile(const char *path, void *user)
170 return PRINT_DUMP(user, path, "mkfile", NULL);
173 static int print_mkdir(const char *path, void *user)
175 return PRINT_DUMP(user, path, "mkdir", NULL);
178 static int print_mknod(const char *path, u64 mode, u64 dev, void *user)
180 return PRINT_DUMP(user, path, "mknod", "mode=%llo dev=0x%llx", mode,
181 dev);
184 static int print_mkfifo(const char *path, void *user)
186 return PRINT_DUMP(user, path, "mkfifo", NULL);
189 static int print_mksock(const char *path, void *user)
191 return PRINT_DUMP(user, path, "mksock", NULL);
194 static int print_symlink(const char *path, const char *lnk, void *user)
196 return PRINT_DUMP(user, path, "symlink", "dest=%s", lnk);
199 static int print_rename(const char *from, const char *to, void *user)
201 struct btrfs_dump_send_args *r = user;
202 char full_to[PATH_MAX];
203 int ret;
205 PATH_CAT_OR_RET("rename", full_to, r->full_subvol_path, to, ret);
206 return PRINT_DUMP(user, from, "rename", "dest=%s", full_to);
209 static int print_link(const char *path, const char *lnk, void *user)
211 return PRINT_DUMP(user, path, "link", "dest=%s", lnk);
214 static int print_unlink(const char *path, void *user)
216 return PRINT_DUMP(user, path, "unlink", NULL);
219 static int print_rmdir(const char *path, void *user)
221 return PRINT_DUMP(user, path, "rmdir", NULL);
224 static int print_write(const char *path, const void *data, u64 offset,
225 u64 len, void *user)
227 return PRINT_DUMP(user, path, "write", "offset=%llu len=%llu",
228 offset, len);
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,
234 void *user)
236 struct btrfs_dump_send_args *r = user;
237 char full_path[PATH_MAX];
238 int ret;
240 PATH_CAT_OR_RET("clone", full_path, r->full_subvol_path, clone_path,
241 ret);
242 return PRINT_DUMP(user, path, "clone",
243 "offset=%llu len=%llu from=%s clone_offset=%llu",
244 offset, len, full_path, clone_offset);
247 static int print_set_xattr(const char *path, const char *name,
248 const void *data, int len, void *user)
250 return PRINT_DUMP(user, path, "set_xattr", "name=%s data=%.*s len=%d",
251 name, len, (char *)data, len);
254 static int print_remove_xattr(const char *path, const char *name, void *user)
257 return PRINT_DUMP(user, path, "remove_xattr", "name=%s", name);
260 static int print_truncate(const char *path, u64 size, void *user)
262 return PRINT_DUMP(user, path, "truncate", "size=%llu", size);
265 static int print_chmod(const char *path, u64 mode, void *user)
267 return PRINT_DUMP(user, path, "chmod", "mode=%llo", mode);
270 static int print_chown(const char *path, u64 uid, u64 gid, void *user)
272 return PRINT_DUMP(user, path, "chown", "gid=%llu uid=%llu", gid, uid);
275 static int sprintf_timespec(struct timespec *ts, char *dest, int max_size)
277 struct tm tm;
278 int ret;
280 if (!localtime_r(&ts->tv_sec, &tm)) {
281 error("failed to convert time %lld.%.9ld to local time",
282 (long long)ts->tv_sec, ts->tv_nsec);
283 return -EINVAL;
285 ret = strftime(dest, max_size, "%FT%T%z", &tm);
286 if (ret == 0) {
287 error(
288 "time %lld.%ld is too long to convert into readable string",
289 (long long)ts->tv_sec, ts->tv_nsec);
290 return -EINVAL;
292 return 0;
295 #define TIME_STRING_MAX 64
296 static int print_utimes(const char *path, struct timespec *at,
297 struct timespec *mt, struct timespec *ct,
298 void *user)
300 char at_str[TIME_STRING_MAX];
301 char mt_str[TIME_STRING_MAX];
302 char ct_str[TIME_STRING_MAX];
304 if (sprintf_timespec(at, at_str, TIME_STRING_MAX - 1) < 0 ||
305 sprintf_timespec(mt, mt_str, TIME_STRING_MAX - 1) < 0 ||
306 sprintf_timespec(ct, ct_str, TIME_STRING_MAX - 1) < 0)
307 return -EINVAL;
308 return PRINT_DUMP(user, path, "utimes", "atime=%s mtime=%s ctime=%s",
309 at_str, mt_str, ct_str);
312 static int print_update_extent(const char *path, u64 offset, u64 len,
313 void *user)
315 return PRINT_DUMP(user, path, "update_extent", "offset=%llu len=%llu",
316 offset, len);
319 struct btrfs_send_ops btrfs_print_send_ops = {
320 .subvol = print_subvol,
321 .snapshot = print_snapshot,
322 .mkfile = print_mkfile,
323 .mkdir = print_mkdir,
324 .mknod = print_mknod,
325 .mkfifo = print_mkfifo,
326 .mksock = print_mksock,
327 .symlink = print_symlink,
328 .rename = print_rename,
329 .link = print_link,
330 .unlink = print_unlink,
331 .rmdir = print_rmdir,
332 .write = print_write,
333 .clone = print_clone,
334 .set_xattr = print_set_xattr,
335 .remove_xattr = print_remove_xattr,
336 .truncate = print_truncate,
337 .chmod = print_chmod,
338 .chown = print_chown,
339 .utimes = print_utimes,
340 .update_extent = print_update_extent