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"
27 struct btrfs_send_stream {
29 char read_buf[BTRFS_SEND_BUF_SIZE];
32 struct btrfs_cmd_header *cmd_hdr;
33 struct btrfs_tlv_header *cmd_attrs[BTRFS_SEND_A_MAX + 1];
36 struct btrfs_send_ops *ops;
41 * Read len bytes to buf.
44 * < 0 - negative errno in case of error
45 * > 0 - no data read, EOF
47 static int read_buf(struct btrfs_send_stream *sctx, char *buf, size_t len)
55 rbytes = read(sctx->fd, buf + pos, len - pos);
58 error("read from stream failed: %s",
72 error("short read from stream: expected %zu read %zu", len, pos);
81 * Reads a single command from kernel space and decodes the TLV's into
86 * < 0 - an error in the command
88 static int read_cmd(struct btrfs_send_stream *sctx)
98 memset(sctx->cmd_attrs, 0, sizeof(sctx->cmd_attrs));
100 ASSERT(sizeof(*sctx->cmd_hdr) <= sizeof(sctx->read_buf));
101 ret = read_buf(sctx, sctx->read_buf, sizeof(*sctx->cmd_hdr));
106 error("unexpected EOF in stream");
110 sctx->cmd_hdr = (struct btrfs_cmd_header *)sctx->read_buf;
111 cmd = le16_to_cpu(sctx->cmd_hdr->cmd);
112 cmd_len = le32_to_cpu(sctx->cmd_hdr->len);
114 if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) {
116 error("command length %u too big for buffer %zu",
117 cmd_len, sizeof(sctx->read_buf));
121 data = sctx->read_buf + sizeof(*sctx->cmd_hdr);
122 ret = read_buf(sctx, data, cmd_len);
127 error("unexpected EOF in stream");
131 crc = le32_to_cpu(sctx->cmd_hdr->crc);
132 sctx->cmd_hdr->crc = 0;
134 crc2 = crc32c(0, (unsigned char*)sctx->read_buf,
135 sizeof(*sctx->cmd_hdr) + cmd_len);
139 error("crc32 mismatch in command");
144 while (pos < cmd_len) {
145 struct btrfs_tlv_header *tlv_hdr;
149 tlv_hdr = (struct btrfs_tlv_header *)data;
150 tlv_type = le16_to_cpu(tlv_hdr->tlv_type);
151 tlv_len = le16_to_cpu(tlv_hdr->tlv_len);
153 if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX
154 || tlv_len > BTRFS_SEND_BUF_SIZE) {
155 error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu",
161 sctx->cmd_attrs[tlv_type] = tlv_hdr;
163 data += sizeof(*tlv_hdr) + tlv_len;
164 pos += sizeof(*tlv_hdr) + tlv_len;
174 static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *len)
177 struct btrfs_tlv_header *hdr;
179 if (attr <= 0 || attr > BTRFS_SEND_A_MAX) {
180 error("invalid attribute requested, attr = %d", attr);
185 hdr = sctx->cmd_attrs[attr];
187 error("attribute %d requested but not present", attr);
192 *len = le16_to_cpu(hdr->tlv_len);
201 #define __TLV_GOTO_FAIL(expr) \
202 if ((ret = expr) < 0) \
205 #define __TLV_DO_WHILE_GOTO_FAIL(expr) \
207 __TLV_GOTO_FAIL(expr) \
211 #define TLV_GET(s, attr, data, len) \
212 __TLV_DO_WHILE_GOTO_FAIL(tlv_get(s, attr, data, len))
214 #define TLV_CHECK_LEN(expected, got) \
216 if (expected != got) { \
217 error("invalid size for attribute, " \
218 "expected = %d, got = %d", \
219 (int)expected, (int)got); \
221 goto tlv_get_failed; \
225 #define TLV_GET_INT(s, attr, bits, v) \
229 TLV_GET(s, attr, (void**)&__tmp, &__len); \
230 TLV_CHECK_LEN(sizeof(*__tmp), __len); \
231 *v = get_unaligned_le##bits(__tmp); \
234 #define TLV_GET_U8(s, attr, v) TLV_GET_INT(s, attr, 8, v)
235 #define TLV_GET_U16(s, attr, v) TLV_GET_INT(s, attr, 16, v)
236 #define TLV_GET_U32(s, attr, v) TLV_GET_INT(s, attr, 32, v)
237 #define TLV_GET_U64(s, attr, v) TLV_GET_INT(s, attr, 64, v)
239 static int tlv_get_string(struct btrfs_send_stream *sctx, int attr, char **str)
245 TLV_GET(sctx, attr, &data, &len);
247 *str = malloc(len + 1);
251 memcpy(*str, data, len);
258 #define TLV_GET_STRING(s, attr, str) \
259 __TLV_DO_WHILE_GOTO_FAIL(tlv_get_string(s, attr, str))
261 static int tlv_get_timespec(struct btrfs_send_stream *sctx,
262 int attr, struct timespec *ts)
266 struct btrfs_timespec *bts;
268 TLV_GET(sctx, attr, (void**)&bts, &len);
269 TLV_CHECK_LEN(sizeof(*bts), len);
271 ts->tv_sec = le64_to_cpu(bts->sec);
272 ts->tv_nsec = le32_to_cpu(bts->nsec);
278 #define TLV_GET_TIMESPEC(s, attr, ts) \
279 __TLV_DO_WHILE_GOTO_FAIL(tlv_get_timespec(s, attr, ts))
281 static int tlv_get_uuid(struct btrfs_send_stream *sctx, int attr, u8 *uuid)
287 TLV_GET(sctx, attr, &data, &len);
288 TLV_CHECK_LEN(BTRFS_UUID_SIZE, len);
289 memcpy(uuid, data, BTRFS_UUID_SIZE);
296 #define TLV_GET_UUID(s, attr, uuid) \
297 __TLV_DO_WHILE_GOTO_FAIL(tlv_get_uuid(s, attr, uuid))
299 static int read_and_process_cmd(struct btrfs_send_stream *sctx)
303 char *path_to = NULL;
304 char *clone_path = NULL;
305 char *xattr_name = NULL;
306 void *xattr_data = NULL;
311 u8 uuid[BTRFS_UUID_SIZE];
312 u8 clone_uuid[BTRFS_UUID_SIZE];
324 ret = read_cmd(sctx);
329 case BTRFS_SEND_C_SUBVOL:
330 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
331 TLV_GET_UUID(sctx, BTRFS_SEND_A_UUID, uuid);
332 TLV_GET_U64(sctx, BTRFS_SEND_A_CTRANSID, &ctransid);
333 ret = sctx->ops->subvol(path, uuid, ctransid, sctx->user);
335 case BTRFS_SEND_C_SNAPSHOT:
336 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
337 TLV_GET_UUID(sctx, BTRFS_SEND_A_UUID, uuid);
338 TLV_GET_U64(sctx, BTRFS_SEND_A_CTRANSID, &ctransid);
339 TLV_GET_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, clone_uuid);
340 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, &clone_ctransid);
341 ret = sctx->ops->snapshot(path, uuid, ctransid, clone_uuid,
342 clone_ctransid, sctx->user);
344 case BTRFS_SEND_C_MKFILE:
345 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
346 ret = sctx->ops->mkfile(path, sctx->user);
348 case BTRFS_SEND_C_MKDIR:
349 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
350 ret = sctx->ops->mkdir(path, sctx->user);
352 case BTRFS_SEND_C_MKNOD:
353 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
354 TLV_GET_U64(sctx, BTRFS_SEND_A_MODE, &mode);
355 TLV_GET_U64(sctx, BTRFS_SEND_A_RDEV, &dev);
356 ret = sctx->ops->mknod(path, mode, dev, sctx->user);
358 case BTRFS_SEND_C_MKFIFO:
359 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
360 ret = sctx->ops->mkfifo(path, sctx->user);
362 case BTRFS_SEND_C_MKSOCK:
363 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
364 ret = sctx->ops->mksock(path, sctx->user);
366 case BTRFS_SEND_C_SYMLINK:
367 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
368 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH_LINK, &path_to);
369 ret = sctx->ops->symlink(path, path_to, sctx->user);
371 case BTRFS_SEND_C_RENAME:
372 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
373 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH_TO, &path_to);
374 ret = sctx->ops->rename(path, path_to, sctx->user);
376 case BTRFS_SEND_C_LINK:
377 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
378 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH_LINK, &path_to);
379 ret = sctx->ops->link(path, path_to, sctx->user);
381 case BTRFS_SEND_C_UNLINK:
382 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
383 ret = sctx->ops->unlink(path, sctx->user);
385 case BTRFS_SEND_C_RMDIR:
386 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
387 ret = sctx->ops->rmdir(path, sctx->user);
389 case BTRFS_SEND_C_WRITE:
390 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
391 TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);
392 TLV_GET(sctx, BTRFS_SEND_A_DATA, &data, &len);
393 ret = sctx->ops->write(path, data, offset, len, sctx->user);
395 case BTRFS_SEND_C_CLONE:
396 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
397 TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);
398 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_LEN, &len);
399 TLV_GET_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, clone_uuid);
400 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, &clone_ctransid);
401 TLV_GET_STRING(sctx, BTRFS_SEND_A_CLONE_PATH, &clone_path);
402 TLV_GET_U64(sctx, BTRFS_SEND_A_CLONE_OFFSET, &clone_offset);
403 ret = sctx->ops->clone(path, offset, len, clone_uuid,
404 clone_ctransid, clone_path, clone_offset,
407 case BTRFS_SEND_C_SET_XATTR:
408 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
409 TLV_GET_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, &xattr_name);
410 TLV_GET(sctx, BTRFS_SEND_A_XATTR_DATA, &xattr_data, &xattr_len);
411 ret = sctx->ops->set_xattr(path, xattr_name, xattr_data,
412 xattr_len, sctx->user);
414 case BTRFS_SEND_C_REMOVE_XATTR:
415 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
416 TLV_GET_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, &xattr_name);
417 ret = sctx->ops->remove_xattr(path, xattr_name, sctx->user);
419 case BTRFS_SEND_C_TRUNCATE:
420 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
421 TLV_GET_U64(sctx, BTRFS_SEND_A_SIZE, &tmp);
422 ret = sctx->ops->truncate(path, tmp, sctx->user);
424 case BTRFS_SEND_C_CHMOD:
425 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
426 TLV_GET_U64(sctx, BTRFS_SEND_A_MODE, &tmp);
427 ret = sctx->ops->chmod(path, tmp, sctx->user);
429 case BTRFS_SEND_C_CHOWN:
430 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
431 TLV_GET_U64(sctx, BTRFS_SEND_A_UID, &tmp);
432 TLV_GET_U64(sctx, BTRFS_SEND_A_GID, &tmp2);
433 ret = sctx->ops->chown(path, tmp, tmp2, sctx->user);
435 case BTRFS_SEND_C_UTIMES:
436 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
437 TLV_GET_TIMESPEC(sctx, BTRFS_SEND_A_ATIME, &at);
438 TLV_GET_TIMESPEC(sctx, BTRFS_SEND_A_MTIME, &mt);
439 TLV_GET_TIMESPEC(sctx, BTRFS_SEND_A_CTIME, &ct);
440 ret = sctx->ops->utimes(path, &at, &mt, &ct, sctx->user);
442 case BTRFS_SEND_C_UPDATE_EXTENT:
443 TLV_GET_STRING(sctx, BTRFS_SEND_A_PATH, &path);
444 TLV_GET_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, &offset);
445 TLV_GET_U64(sctx, BTRFS_SEND_A_SIZE, &tmp);
446 ret = sctx->ops->update_extent(path, offset, tmp, sctx->user);
448 case BTRFS_SEND_C_END:
463 * If max_errors is 0, then don't stop processing the stream if one of the
464 * callbacks in btrfs_send_ops structure returns an error. If greater than
465 * zero, stop after max_errors errors happened.
467 int btrfs_read_and_process_send_stream(int fd,
468 struct btrfs_send_ops *ops, void *user,
473 struct btrfs_send_stream sctx;
474 struct btrfs_stream_header hdr;
482 ret = read_buf(&sctx, (char*)&hdr, sizeof(hdr));
490 if (strcmp(hdr.magic, BTRFS_SEND_STREAM_MAGIC)) {
492 error("unexpected header");
496 sctx.version = le32_to_cpu(hdr.version);
497 if (sctx.version > BTRFS_SEND_STREAM_VERSION) {
499 error("stream version %d not supported, please use newer version",
505 ret = read_and_process_cmd(&sctx);
509 if (max_errors > 0 && errors >= max_errors)
511 } else if (ret > 0) {
519 if (last_err && !ret)