2 * Copyright (C) 2012 Alexander Block. 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; if not, write to the
15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 * Boston, MA 021110-1307, USA.
19 #include <uuid/uuid.h>
23 #include "send-stream.h"
26 struct btrfs_send_stream
{
28 char read_buf
[BTRFS_SEND_BUF_SIZE
];
31 struct btrfs_cmd_header
*cmd_hdr
;
32 struct btrfs_tlv_header
*cmd_attrs
[BTRFS_SEND_A_MAX
+ 1];
35 struct btrfs_send_ops
*ops
;
39 static int read_buf(struct btrfs_send_stream
*s
, void *buf
, int len
)
45 ret
= read(s
->fd
, (char*)buf
+ pos
, len
- pos
);
48 fprintf(stderr
, "ERROR: read from stream failed. %s\n",
66 * Reads a single command from kernel space and decodes the TLV's into
69 static int read_cmd(struct btrfs_send_stream
*s
)
78 struct btrfs_tlv_header
*tlv_hdr
;
82 memset(s
->cmd_attrs
, 0, sizeof(s
->cmd_attrs
));
84 ret
= read_buf(s
, s
->read_buf
, sizeof(*s
->cmd_hdr
));
89 fprintf(stderr
, "ERROR: unexpected EOF in stream.\n");
93 s
->cmd_hdr
= (struct btrfs_cmd_header
*)s
->read_buf
;
94 cmd
= le16_to_cpu(s
->cmd_hdr
->cmd
);
95 cmd_len
= le32_to_cpu(s
->cmd_hdr
->len
);
97 data
= s
->read_buf
+ sizeof(*s
->cmd_hdr
);
98 ret
= read_buf(s
, data
, cmd_len
);
103 fprintf(stderr
, "ERROR: unexpected EOF in stream.\n");
107 crc
= le32_to_cpu(s
->cmd_hdr
->crc
);
110 crc2
= crc32c(0, (unsigned char*)s
->read_buf
,
111 sizeof(*s
->cmd_hdr
) + cmd_len
);
115 fprintf(stderr
, "ERROR: crc32 mismatch in command.\n");
120 while (pos
< cmd_len
) {
121 tlv_hdr
= (struct btrfs_tlv_header
*)data
;
122 tlv_type
= le16_to_cpu(tlv_hdr
->tlv_type
);
123 tlv_len
= le16_to_cpu(tlv_hdr
->tlv_len
);
125 if (tlv_type
<= 0 || tlv_type
> BTRFS_SEND_A_MAX
||
126 tlv_len
< 0 || tlv_len
> BTRFS_SEND_BUF_SIZE
) {
127 fprintf(stderr
, "ERROR: invalid tlv in cmd. "
128 "tlv_type = %d, tlv_len = %d\n",
134 s
->cmd_attrs
[tlv_type
] = tlv_hdr
;
136 data
+= sizeof(*tlv_hdr
) + tlv_len
;
137 pos
+= sizeof(*tlv_hdr
) + tlv_len
;
147 static int tlv_get(struct btrfs_send_stream
*s
, int attr
, void **data
, int *len
)
150 struct btrfs_tlv_header
*h
;
152 if (attr
<= 0 || attr
> BTRFS_SEND_A_MAX
) {
153 fprintf(stderr
, "ERROR: invalid attribute requested. "
160 h
= s
->cmd_attrs
[attr
];
162 fprintf(stderr
, "ERROR: attribute %d requested "
163 "but not present.\n", attr
);
168 *len
= le16_to_cpu(h
->tlv_len
);
177 #define __TLV_GOTO_FAIL(expr) \
178 if ((ret = expr) < 0) \
181 #define __TLV_DO_WHILE_GOTO_FAIL(expr) \
183 __TLV_GOTO_FAIL(expr) \
187 #define TLV_GET(s, attr, data, len) \
188 __TLV_DO_WHILE_GOTO_FAIL(tlv_get(s, attr, data, len))
190 #define TLV_CHECK_LEN(expected, got) \
192 if (expected != got) { \
193 fprintf(stderr, "ERROR: invalid size for attribute. " \
194 "expected = %d, got = %d\n", \
195 (int)expected, (int)got); \
197 goto tlv_get_failed; \
201 #define TLV_GET_INT(s, attr, bits, v) \
205 TLV_GET(s, attr, (void**)&__tmp, &__len); \
206 TLV_CHECK_LEN(sizeof(*__tmp), __len); \
207 *v = get_unaligned_le##bits(__tmp); \
210 #define TLV_GET_U8(s, attr, v) TLV_GET_INT(s, attr, 8, v)
211 #define TLV_GET_U16(s, attr, v) TLV_GET_INT(s, attr, 16, v)
212 #define TLV_GET_U32(s, attr, v) TLV_GET_INT(s, attr, 32, v)
213 #define TLV_GET_U64(s, attr, v) TLV_GET_INT(s, attr, 64, v)
215 static int tlv_get_string(struct btrfs_send_stream
*s
, int attr
, char **str
)
221 TLV_GET(s
, attr
, &data
, &len
);
223 *str
= malloc(len
+ 1);
227 memcpy(*str
, data
, len
);
234 #define TLV_GET_STRING(s, attr, str) \
235 __TLV_DO_WHILE_GOTO_FAIL(tlv_get_string(s, attr, str))
237 static int tlv_get_timespec(struct btrfs_send_stream
*s
,
238 int attr
, struct timespec
*ts
)
242 struct btrfs_timespec
*bts
;
244 TLV_GET(s
, attr
, (void**)&bts
, &len
);
245 TLV_CHECK_LEN(sizeof(*bts
), len
);
247 ts
->tv_sec
= le64_to_cpu(bts
->sec
);
248 ts
->tv_nsec
= le32_to_cpu(bts
->nsec
);
254 #define TLV_GET_TIMESPEC(s, attr, ts) \
255 __TLV_DO_WHILE_GOTO_FAIL(tlv_get_timespec(s, attr, ts))
257 static int tlv_get_uuid(struct btrfs_send_stream
*s
, int attr
, u8
*uuid
)
263 TLV_GET(s
, attr
, &data
, &len
);
264 TLV_CHECK_LEN(BTRFS_UUID_SIZE
, len
);
265 memcpy(uuid
, data
, BTRFS_UUID_SIZE
);
272 #define TLV_GET_UUID(s, attr, uuid) \
273 __TLV_DO_WHILE_GOTO_FAIL(tlv_get_uuid(s, attr, uuid))
275 static int read_and_process_cmd(struct btrfs_send_stream
*s
)
279 char *path_to
= NULL
;
280 char *clone_path
= NULL
;
281 char *xattr_name
= NULL
;
282 void *xattr_data
= NULL
;
287 u8 uuid
[BTRFS_UUID_SIZE
];
288 u8 clone_uuid
[BTRFS_UUID_SIZE
];
305 case BTRFS_SEND_C_SUBVOL
:
306 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
307 TLV_GET_UUID(s
, BTRFS_SEND_A_UUID
, uuid
);
308 TLV_GET_U64(s
, BTRFS_SEND_A_CTRANSID
, &ctransid
);
309 ret
= s
->ops
->subvol(path
, uuid
, ctransid
, s
->user
);
311 case BTRFS_SEND_C_SNAPSHOT
:
312 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
313 TLV_GET_UUID(s
, BTRFS_SEND_A_UUID
, uuid
);
314 TLV_GET_U64(s
, BTRFS_SEND_A_CTRANSID
, &ctransid
);
315 TLV_GET_UUID(s
, BTRFS_SEND_A_CLONE_UUID
, clone_uuid
);
316 TLV_GET_U64(s
, BTRFS_SEND_A_CLONE_CTRANSID
, &clone_ctransid
);
317 ret
= s
->ops
->snapshot(path
, uuid
, ctransid
, clone_uuid
,
318 clone_ctransid
, s
->user
);
320 case BTRFS_SEND_C_MKFILE
:
321 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
322 ret
= s
->ops
->mkfile(path
, s
->user
);
324 case BTRFS_SEND_C_MKDIR
:
325 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
326 ret
= s
->ops
->mkdir(path
, s
->user
);
328 case BTRFS_SEND_C_MKNOD
:
329 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
330 TLV_GET_U64(s
, BTRFS_SEND_A_MODE
, &mode
);
331 TLV_GET_U64(s
, BTRFS_SEND_A_RDEV
, &dev
);
332 ret
= s
->ops
->mknod(path
, mode
, dev
, s
->user
);
334 case BTRFS_SEND_C_MKFIFO
:
335 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
336 ret
= s
->ops
->mkfifo(path
, s
->user
);
338 case BTRFS_SEND_C_MKSOCK
:
339 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
340 ret
= s
->ops
->mksock(path
, s
->user
);
342 case BTRFS_SEND_C_SYMLINK
:
343 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
344 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH_LINK
, &path_to
);
345 ret
= s
->ops
->symlink(path
, path_to
, s
->user
);
347 case BTRFS_SEND_C_RENAME
:
348 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
349 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH_TO
, &path_to
);
350 ret
= s
->ops
->rename(path
, path_to
, s
->user
);
352 case BTRFS_SEND_C_LINK
:
353 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
354 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH_LINK
, &path_to
);
355 ret
= s
->ops
->link(path
, path_to
, s
->user
);
357 case BTRFS_SEND_C_UNLINK
:
358 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
359 ret
= s
->ops
->unlink(path
, s
->user
);
361 case BTRFS_SEND_C_RMDIR
:
362 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
363 ret
= s
->ops
->rmdir(path
, s
->user
);
365 case BTRFS_SEND_C_WRITE
:
366 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
367 TLV_GET_U64(s
, BTRFS_SEND_A_FILE_OFFSET
, &offset
);
368 TLV_GET(s
, BTRFS_SEND_A_DATA
, &data
, &len
);
369 ret
= s
->ops
->write(path
, data
, offset
, len
, s
->user
);
371 case BTRFS_SEND_C_CLONE
:
372 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
373 TLV_GET_U64(s
, BTRFS_SEND_A_FILE_OFFSET
, &offset
);
374 TLV_GET_U64(s
, BTRFS_SEND_A_CLONE_LEN
, &len
);
375 TLV_GET_UUID(s
, BTRFS_SEND_A_CLONE_UUID
, clone_uuid
);
376 TLV_GET_U64(s
, BTRFS_SEND_A_CLONE_CTRANSID
, &clone_ctransid
);
377 TLV_GET_STRING(s
, BTRFS_SEND_A_CLONE_PATH
, &clone_path
);
378 TLV_GET_U64(s
, BTRFS_SEND_A_CLONE_OFFSET
, &clone_offset
);
379 ret
= s
->ops
->clone(path
, offset
, len
, clone_uuid
,
380 clone_ctransid
, clone_path
, clone_offset
,
383 case BTRFS_SEND_C_SET_XATTR
:
384 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
385 TLV_GET_STRING(s
, BTRFS_SEND_A_XATTR_NAME
, &xattr_name
);
386 TLV_GET(s
, BTRFS_SEND_A_XATTR_DATA
, &xattr_data
, &xattr_len
);
387 ret
= s
->ops
->set_xattr(path
, xattr_name
, xattr_data
,
390 case BTRFS_SEND_C_REMOVE_XATTR
:
391 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
392 TLV_GET_STRING(s
, BTRFS_SEND_A_XATTR_NAME
, &xattr_name
);
393 ret
= s
->ops
->remove_xattr(path
, xattr_name
, s
->user
);
395 case BTRFS_SEND_C_TRUNCATE
:
396 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
397 TLV_GET_U64(s
, BTRFS_SEND_A_SIZE
, &tmp
);
398 ret
= s
->ops
->truncate(path
, tmp
, s
->user
);
400 case BTRFS_SEND_C_CHMOD
:
401 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
402 TLV_GET_U64(s
, BTRFS_SEND_A_MODE
, &tmp
);
403 ret
= s
->ops
->chmod(path
, tmp
, s
->user
);
405 case BTRFS_SEND_C_CHOWN
:
406 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
407 TLV_GET_U64(s
, BTRFS_SEND_A_UID
, &tmp
);
408 TLV_GET_U64(s
, BTRFS_SEND_A_GID
, &tmp2
);
409 ret
= s
->ops
->chown(path
, tmp
, tmp2
, s
->user
);
411 case BTRFS_SEND_C_UTIMES
:
412 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
413 TLV_GET_TIMESPEC(s
, BTRFS_SEND_A_ATIME
, &at
);
414 TLV_GET_TIMESPEC(s
, BTRFS_SEND_A_MTIME
, &mt
);
415 TLV_GET_TIMESPEC(s
, BTRFS_SEND_A_CTIME
, &ct
);
416 ret
= s
->ops
->utimes(path
, &at
, &mt
, &ct
, s
->user
);
418 case BTRFS_SEND_C_UPDATE_EXTENT
:
419 TLV_GET_STRING(s
, BTRFS_SEND_A_PATH
, &path
);
420 TLV_GET_U64(s
, BTRFS_SEND_A_FILE_OFFSET
, &offset
);
421 TLV_GET_U64(s
, BTRFS_SEND_A_SIZE
, &tmp
);
422 ret
= s
->ops
->update_extent(path
, offset
, tmp
, s
->user
);
424 case BTRFS_SEND_C_END
:
439 * If max_errors is 0, then don't stop processing the stream if one of the
440 * callbacks in btrfs_send_ops structure returns an error. If greater than
441 * zero, stop after max_errors errors happened.
443 int btrfs_read_and_process_send_stream(int fd
,
444 struct btrfs_send_ops
*ops
, void *user
,
449 struct btrfs_send_stream s
;
450 struct btrfs_stream_header hdr
;
458 ret
= read_buf(&s
, &hdr
, sizeof(hdr
));
466 if (strcmp(hdr
.magic
, BTRFS_SEND_STREAM_MAGIC
)) {
468 fprintf(stderr
, "ERROR: Unexpected header\n");
472 s
.version
= le32_to_cpu(hdr
.version
);
473 if (s
.version
> BTRFS_SEND_STREAM_VERSION
) {
475 fprintf(stderr
, "ERROR: Stream version %d not supported. "
476 "Please upgrade btrfs-progs\n", s
.version
);
481 ret
= read_and_process_cmd(&s
);
485 if (max_errors
> 0 && errors
>= max_errors
)
487 } else if (ret
> 0) {
495 if (last_err
&& !ret
)