X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=send-stream.c;h=78f2571ae40be82cbce1b7eb40e80c5293acd6c8;hb=d4833d709b338df0edf7a721a155e9e00723911a;hp=450854f6057612724a8fb82db96319a3c022af89;hpb=23ac27781eb54ccdc60b2738f2d3ea1ff67966df;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/send-stream.c b/send-stream.c index 450854f..78f2571 100644 --- a/send-stream.c +++ b/send-stream.c @@ -33,32 +33,54 @@ struct btrfs_send_stream { struct btrfs_tlv_header *cmd_attrs[BTRFS_SEND_A_MAX + 1]; u32 version; + /* + * end of last successful read, equivalent to start of current + * malformated part of block + */ + size_t stream_pos; + struct btrfs_send_ops *ops; void *user; }; +/* + * Read len bytes to buf. + * Return: + * 0 - success + * < 0 - negative errno in case of error + * > 0 - no data read, EOF + */ static int read_buf(struct btrfs_send_stream *sctx, char *buf, size_t len) { int ret; size_t pos = 0; while (pos < len) { - ret = read(sctx->fd, buf + pos, len - pos); - if (ret < 0) { + ssize_t rbytes; + + rbytes = read(sctx->fd, buf + pos, len - pos); + if (rbytes < 0) { ret = -errno; error("read from stream failed: %s", strerror(-ret)); goto out; } - if (ret == 0) { + if (rbytes == 0) { ret = 1; - goto out; + goto out_eof; } - pos += ret; + pos += rbytes; } - ret = 0; +out_eof: + if (0 < pos && pos < len) { + error("short read from stream: expected %zu read %zu", len, pos); + ret = -EIO; + } else { + sctx->stream_pos += pos; + } + out: return ret; } @@ -66,17 +88,18 @@ out: /* * Reads a single command from kernel space and decodes the TLV's into * sctx->cmd_attrs + * + * Returns: + * 0 - success + * < 0 - an error in the command */ static int read_cmd(struct btrfs_send_stream *sctx) { int ret; - int cmd; - int cmd_len; - int tlv_type; - int tlv_len; + u16 cmd; + u32 cmd_len; char *data; - int pos; - struct btrfs_tlv_header *tlv_hdr; + u32 pos; u32 crc; u32 crc2; @@ -98,7 +121,7 @@ static int read_cmd(struct btrfs_send_stream *sctx) if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) { ret = -EINVAL; - error("command length %d too big for buffer %zu", + error("command length %u too big for buffer %zu", cmd_len, sizeof(sctx->read_buf)); goto out; } @@ -127,13 +150,17 @@ static int read_cmd(struct btrfs_send_stream *sctx) pos = 0; while (pos < cmd_len) { + struct btrfs_tlv_header *tlv_hdr; + u16 tlv_type; + u16 tlv_len; + tlv_hdr = (struct btrfs_tlv_header *)data; tlv_type = le16_to_cpu(tlv_hdr->tlv_type); tlv_len = le16_to_cpu(tlv_hdr->tlv_len); - if (tlv_type <= 0 || tlv_type > BTRFS_SEND_A_MAX || - tlv_len < 0 || tlv_len > BTRFS_SEND_BUF_SIZE) { - error("invalid tlv in cmd tlv_type = %d, tlv_len = %d", + if (tlv_type == 0 || tlv_type > BTRFS_SEND_A_MAX + || tlv_len > BTRFS_SEND_BUF_SIZE) { + error("invalid tlv in cmd tlv_type = %hu, tlv_len = %hu", tlv_type, tlv_len); ret = -EINVAL; goto out; @@ -155,7 +182,7 @@ out: static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *len) { int ret; - struct btrfs_tlv_header *h; + struct btrfs_tlv_header *hdr; if (attr <= 0 || attr > BTRFS_SEND_A_MAX) { error("invalid attribute requested, attr = %d", attr); @@ -163,15 +190,15 @@ static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *l goto out; } - h = sctx->cmd_attrs[attr]; - if (!h) { + hdr = sctx->cmd_attrs[attr]; + if (!hdr) { error("attribute %d requested but not present", attr); ret = -ENOENT; goto out; } - *len = le16_to_cpu(h->tlv_len); - *data = h + 1; + *len = le16_to_cpu(hdr->tlv_len); + *data = hdr + 1; ret = 0; @@ -459,12 +486,13 @@ int btrfs_read_and_process_send_stream(int fd, sctx.fd = fd; sctx.ops = ops; sctx.user = user; + sctx.stream_pos = 0; ret = read_buf(&sctx, (char*)&hdr, sizeof(hdr)); if (ret < 0) goto out; if (ret) { - ret = 1; + ret = -ENODATA; goto out; }