projects
/
platform
/
upstream
/
btrfs-progs.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
btrfs-progs: dump-tree: print c/o/s/r time of ROOT_ITEM
[platform/upstream/btrfs-progs.git]
/
send-stream.c
diff --git
a/send-stream.c
b/send-stream.c
index
7b64dc2
..
78f2571
100644
(file)
--- 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;
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;
};
struct btrfs_send_ops *ops;
void *user;
};
-static int read_buf(struct btrfs_send_stream *sctx, void *buf, size_t len)
+/*
+ * 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) {
{
int ret;
size_t pos = 0;
while (pos < len) {
- ret = read(sctx->fd, (char*)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;
}
ret = -errno;
error("read from stream failed: %s",
strerror(-ret));
goto out;
}
- if (r
et
== 0) {
+ if (r
bytes
== 0) {
ret = 1;
ret = 1;
- goto out;
+ goto out
_eof
;
}
}
- pos += r
et
;
+ pos += r
bytes
;
}
}
-
ret = 0;
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;
}
out:
return ret;
}
@@
-66,22
+88,24
@@
out:
/*
* Reads a single command from kernel space and decodes the TLV's into
* sctx->cmd_attrs
/*
* 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;
*/
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;
char *data;
- int pos;
- struct btrfs_tlv_header *tlv_hdr;
+ u32 pos;
u32 crc;
u32 crc2;
memset(sctx->cmd_attrs, 0, sizeof(sctx->cmd_attrs));
u32 crc;
u32 crc2;
memset(sctx->cmd_attrs, 0, sizeof(sctx->cmd_attrs));
+ ASSERT(sizeof(*sctx->cmd_hdr) <= sizeof(sctx->read_buf));
ret = read_buf(sctx, sctx->read_buf, sizeof(*sctx->cmd_hdr));
if (ret < 0)
goto out;
ret = read_buf(sctx, sctx->read_buf, sizeof(*sctx->cmd_hdr));
if (ret < 0)
goto out;
@@
-95,6
+119,13
@@
static int read_cmd(struct btrfs_send_stream *sctx)
cmd = le16_to_cpu(sctx->cmd_hdr->cmd);
cmd_len = le32_to_cpu(sctx->cmd_hdr->len);
cmd = le16_to_cpu(sctx->cmd_hdr->cmd);
cmd_len = le32_to_cpu(sctx->cmd_hdr->len);
+ if (cmd_len + sizeof(*sctx->cmd_hdr) >= sizeof(sctx->read_buf)) {
+ ret = -EINVAL;
+ error("command length %u too big for buffer %zu",
+ cmd_len, sizeof(sctx->read_buf));
+ goto out;
+ }
+
data = sctx->read_buf + sizeof(*sctx->cmd_hdr);
ret = read_buf(sctx, data, cmd_len);
if (ret < 0)
data = sctx->read_buf + sizeof(*sctx->cmd_hdr);
ret = read_buf(sctx, data, cmd_len);
if (ret < 0)
@@
-119,13
+150,17
@@
static int read_cmd(struct btrfs_send_stream *sctx)
pos = 0;
while (pos < cmd_len) {
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);
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;
tlv_type, tlv_len);
ret = -EINVAL;
goto out;
@@
-147,7
+182,7
@@
out:
static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *len)
{
int ret;
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 *h
dr
;
if (attr <= 0 || attr > BTRFS_SEND_A_MAX) {
error("invalid attribute requested, attr = %d", attr);
if (attr <= 0 || attr > BTRFS_SEND_A_MAX) {
error("invalid attribute requested, attr = %d", attr);
@@
-155,15
+190,15
@@
static int tlv_get(struct btrfs_send_stream *sctx, int attr, void **data, int *l
goto out;
}
goto out;
}
- h = sctx->cmd_attrs[attr];
- if (!h) {
+ h
dr
= sctx->cmd_attrs[attr];
+ if (!h
dr
) {
error("attribute %d requested but not present", attr);
ret = -ENOENT;
goto out;
}
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(h
dr
->tlv_len);
+ *data = h
dr
+ 1;
ret = 0;
ret = 0;
@@
-451,12
+486,13
@@
int btrfs_read_and_process_send_stream(int fd,
sctx.fd = fd;
sctx.ops = ops;
sctx.user = user;
sctx.fd = fd;
sctx.ops = ops;
sctx.user = user;
+ sctx.stream_pos = 0;
- ret = read_buf(&sctx, &hdr, sizeof(hdr));
+ ret = read_buf(&sctx,
(char*)
&hdr, sizeof(hdr));
if (ret < 0)
goto out;
if (ret) {
if (ret < 0)
goto out;
if (ret) {
- ret =
1
;
+ ret =
-ENODATA
;
goto out;
}
goto out;
}