From fca594c2dee4972301d6301fbdc0b7b4ac0045fe Mon Sep 17 00:00:00 2001 From: Jeremy Compostella Date: Fri, 30 Sep 2016 14:54:25 +0200 Subject: [PATCH] libsparse: output_file.c, fix large data chunk issue CHUNK_HEADER structure type allows DATA chunk to be up to MAX_UINT large. The write() callback LEN parameter should be unsigned int. Also: - write() callback should continue to write data if less than expected data have been written. - gzerror() returns LEN on success, 0 otherwise Test: manual Change-Id: Id46d664b84c1a506f419524fe28055f784c2ae7a Signed-off-by: Jeremy Compostella --- libsparse/output_file.c | 51 ++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/libsparse/output_file.c b/libsparse/output_file.c index 6578d99b8..21159987f 100644 --- a/libsparse/output_file.c +++ b/libsparse/output_file.c @@ -63,7 +63,7 @@ struct output_file_ops { int (*open)(struct output_file *, int fd); int (*skip)(struct output_file *, int64_t); int (*pad)(struct output_file *, int64_t); - int (*write)(struct output_file *, void *, int); + int (*write)(struct output_file *, void *, size_t); void (*close)(struct output_file *); }; @@ -149,18 +149,23 @@ static int file_pad(struct output_file *out, int64_t len) return 0; } -static int file_write(struct output_file *out, void *data, int len) +static int file_write(struct output_file *out, void *data, size_t len) { - int ret; + ssize_t ret; struct output_file_normal *outn = to_output_file_normal(out); - ret = write(outn->fd, data, len); - if (ret < 0) { - error_errno("write"); - return -1; - } else if (ret < len) { - error("incomplete write"); - return -1; + while (len > 0) { + ret = write(outn->fd, data, len); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + error_errno("write"); + return -1; + } + + data = (char *)data + ret; + len -= ret; } return 0; @@ -232,18 +237,20 @@ static int gz_file_pad(struct output_file *out, int64_t len) return 0; } -static int gz_file_write(struct output_file *out, void *data, int len) +static int gz_file_write(struct output_file *out, void *data, size_t len) { int ret; struct output_file_gz *outgz = to_output_file_gz(out); - ret = gzwrite(outgz->gz_fd, data, len); - if (ret < 0) { - error_errno("gzwrite"); - return -1; - } else if (ret < len) { - error("incomplete gzwrite"); - return -1; + while (len > 0) { + ret = gzwrite(outgz->gz_fd, data, + min(len, (unsigned int)INT_MAX)); + if (ret == 0) { + error("gzwrite %s", gzerror(outgz->gz_fd, NULL)); + return -1; + } + len -= ret; + data = (char *)data + ret; } return 0; @@ -293,7 +300,7 @@ static int callback_file_pad(struct output_file *out __unused, int64_t len __unu return -1; } -static int callback_file_write(struct output_file *out, void *data, int len) +static int callback_file_write(struct output_file *out, void *data, size_t len) { struct output_file_callback *outc = to_output_file_callback(out); @@ -698,14 +705,16 @@ int write_fd_chunk(struct output_file *out, unsigned int len, int ret; int64_t aligned_offset; int aligned_diff; - int buffer_size; + uint64_t buffer_size; char *ptr; aligned_offset = offset & ~(4096 - 1); aligned_diff = offset - aligned_offset; - buffer_size = len + aligned_diff; + buffer_size = (uint64_t)len + (uint64_t)aligned_diff; #ifndef _WIN32 + if (buffer_size > SIZE_MAX) + return -E2BIG; char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset); if (data == MAP_FAILED) {