From fca4a9c27950a4a4281de0f413280cff9f4da653 Mon Sep 17 00:00:00 2001 From: Tobias Thierer Date: Thu, 26 Jul 2018 03:13:45 +0000 Subject: [PATCH] Revert "libsparse: Add sparse typed callback" This reverts commit db69f0d47f3ccb3ff656c56fe2b68aaf5ab853f6. Reason for revert: Broke the build: In file included from system/core/libsparse/sparse.cpp:26: system/core/libsparse/output_file.h:34:72: error: unknown type name 'off64_t'; did you mean 'off_t'? int (*skip_write)(void*, off64_t), void* priv, ^~~~~~~ off_t /Applications/Xcode6.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/include/sys/_types/_off_t.h:30:25: note: 'off_t' declared here typedef __darwin_off_t off_t; ^ 1 error generated. Bug: 78793464 Change-Id: I0f8bc4e9aa2f74612bfd8721d00d961e3f7e695f --- libsparse/include/sparse/sparse.h | 31 ---- libsparse/output_file.cpp | 266 ++++++++++-------------------- libsparse/output_file.h | 10 +- libsparse/sparse.cpp | 37 +---- 4 files changed, 97 insertions(+), 247 deletions(-) diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h index 586578633..3d5fb0c53 100644 --- a/libsparse/include/sparse/sparse.h +++ b/libsparse/include/sparse/sparse.h @@ -209,37 +209,6 @@ unsigned int sparse_file_block_size(struct sparse_file *s); int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc, int (*write)(void *priv, const void *data, size_t len), void *priv); -/** - * sparse_file_callback_typed - call a callback for blocks based on type - * - * @s - sparse file cookie - * @sparse - write in the Android sparse file format - * @data_write - function to call for data blocks. must not be null - * @fd_write - function to call for fd blocks - * @fill_write - function to call for fill blocks - * @skip_write - function to call for skip blocks - * @priv - value that will be passed as the first argument to each write - * - * Writes a sparse file by calling callback functions. If sparse is true, the - * file will be written in the Android sparse file format, and fill and skip blocks - * along with metadata will be written with data_write. If sparse is false, the file - * will be expanded into normal format and fill and skip blocks will be written with - * the given callbacks. - * If a callback function is provided, the library will not unroll data into a buffer, - * and will instead pass it directly to the caller for custom implementation. If a - * callback is not provided, that type of block will be converted into a void* and - * written with data_write. If no callbacks other than data are provided, the behavior - * is the same as sparse_file_callback(). The callback should return negative on error, - * 0 on success. - * - * Returns 0 on success, negative errno on error. - */ -int sparse_file_callback_typed(struct sparse_file* s, bool sparse, - int (*data_write)(void* priv, const void* data, size_t len), - int (*fd_write)(void* priv, int fd, size_t len), - int (*fill_write)(void* priv, uint32_t fill_val, size_t len), - int (*skip_write)(void* priv, int64_t len), void* priv); - /** * sparse_file_foreach_chunk - call a callback for data blocks in sparse file * diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp index 8a21daba1..fe314b30e 100644 --- a/libsparse/output_file.cpp +++ b/libsparse/output_file.cpp @@ -29,8 +29,6 @@ #include #include -#include - #include "defs.h" #include "output_file.h" #include "sparse_crc32.h" @@ -50,6 +48,13 @@ #define off64_t off_t #endif +#define min(a, b) \ + ({ \ + typeof(a) _a = (a); \ + typeof(b) _b = (b); \ + (_a < _b) ? _a : _b; \ + }) + #define SPARSE_HEADER_MAJOR_VER 1 #define SPARSE_HEADER_MINOR_VER 0 #define SPARSE_HEADER_LEN (sizeof(sparse_header_t)) @@ -62,14 +67,11 @@ struct output_file_ops { int (*skip)(struct output_file*, int64_t); int (*pad)(struct output_file*, int64_t); int (*write)(struct output_file*, void*, size_t); - int (*write_fd)(struct output_file*, int, size_t); - int (*write_fill)(struct output_file*, uint32_t, size_t); void (*close)(struct output_file*); }; struct sparse_file_ops { int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data); - int (*write_fd_chunk)(struct output_file* out, unsigned int len, int fd); int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val); int (*write_skip_chunk)(struct output_file* out, int64_t len); int (*write_end_chunk)(struct output_file* out); @@ -106,96 +108,11 @@ struct output_file_normal { struct output_file_callback { struct output_file out; void* priv; - int (*data_write)(void* priv, const void* data, size_t len); - int (*fd_write)(void* priv, int fd, size_t len); - int (*fill_write)(void* priv, uint32_t fill_val, size_t len); - int (*skip_write)(void* priv, off64_t len); + int (*write)(void* priv, const void* buf, size_t len); }; #define to_output_file_callback(_o) container_of((_o), struct output_file_callback, out) -union handle_data { - void* data_ptr; - int fd; -}; - -static int default_file_write_fd(struct output_file* out, int fd, size_t len) { - int ret; - int64_t aligned_offset; - int aligned_diff; - uint64_t buffer_size; - char* ptr; - int64_t offset = lseek64(fd, 0, SEEK_CUR); - - if (offset < 0) { - return -errno; - } - - aligned_offset = offset & ~(4096 - 1); - aligned_diff = offset - aligned_offset; - buffer_size = (uint64_t)len + (uint64_t)aligned_diff; - -#ifndef _WIN32 - if (buffer_size > SIZE_MAX) { - return -E2BIG; - } - char* data = - reinterpret_cast(mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset)); - if (data == MAP_FAILED) { - return -errno; - } - ptr = data + aligned_diff; -#else - char* data = reinterpret_cast(malloc(len)); - if (!data) { - return -errno; - } - ret = read_all(fd, data, len); - if (ret < 0) { - free(data); - return -errno; - } - ptr = data; -#endif - - ret = out->ops->write(out, ptr, len); - - if (out->use_crc) { - out->crc32 = sparse_crc32(out->crc32, ptr, len); - } - -#ifndef _WIN32 - munmap(data, buffer_size); -#else - free(data); -#endif - - return ret; -} - -static int default_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) { - int ret; - unsigned int i; - unsigned int write_len; - - /* Initialize fill_buf with the fill_val */ - for (i = 0; i < out->block_size / sizeof(uint32_t); i++) { - out->fill_buf[i] = fill_val; - } - - while (len) { - write_len = std::min(len, static_cast(out->block_size)); - ret = out->ops->write(out, out->fill_buf, write_len); - if (ret < 0) { - return ret; - } - - len -= write_len; - } - - return 0; -} - static int file_open(struct output_file* out, int fd) { struct output_file_normal* outn = to_output_file_normal(out); @@ -259,8 +176,6 @@ static struct output_file_ops file_ops = { .skip = file_skip, .pad = file_pad, .write = file_write, - .write_fd = default_file_write_fd, - .write_fill = default_file_write_fill, .close = file_close, }; @@ -316,7 +231,7 @@ static int gz_file_write(struct output_file* out, void* data, size_t len) { struct output_file_gz* outgz = to_output_file_gz(out); while (len > 0) { - ret = gzwrite(outgz->gz_fd, data, std::min(len, static_cast(INT_MAX))); + ret = gzwrite(outgz->gz_fd, data, min(len, (unsigned int)INT_MAX)); if (ret == 0) { error("gzwrite %s", gzerror(outgz->gz_fd, nullptr)); return -1; @@ -340,8 +255,6 @@ static struct output_file_ops gz_file_ops = { .skip = gz_file_skip, .pad = gz_file_pad, .write = gz_file_write, - .write_fd = default_file_write_fd, - .write_fill = default_file_write_fill, .close = gz_file_close, }; @@ -354,13 +267,9 @@ static int callback_file_skip(struct output_file* out, int64_t off) { int to_write; int ret; - if (outc->skip_write) { - return outc->skip_write(outc->priv, off); - } - while (off > 0) { - to_write = std::min(off, static_cast(INT_MAX)); - ret = outc->data_write(outc->priv, nullptr, to_write); + to_write = min(off, (int64_t)INT_MAX); + ret = outc->write(outc->priv, nullptr, to_write); if (ret < 0) { return ret; } @@ -376,23 +285,8 @@ static int callback_file_pad(struct output_file* out __unused, int64_t len __unu static int callback_file_write(struct output_file* out, void* data, size_t len) { struct output_file_callback* outc = to_output_file_callback(out); - return outc->data_write(outc->priv, data, len); -} -static int callback_file_write_fd(struct output_file* out, int fd, size_t len) { - struct output_file_callback* outc = to_output_file_callback(out); - if (outc->fd_write) { - return outc->fd_write(outc->priv, fd, len); - } - return default_file_write_fd(out, fd, len); -} - -static int callback_file_write_fill(struct output_file* out, uint32_t fill_val, size_t len) { - struct output_file_callback* outc = to_output_file_callback(out); - if (outc->fill_write) { - return outc->fill_write(outc->priv, fill_val, len); - } - return default_file_write_fill(out, fill_val, len); + return outc->write(outc->priv, data, len); } static void callback_file_close(struct output_file* out) { @@ -406,8 +300,6 @@ static struct output_file_ops callback_file_ops = { .skip = callback_file_skip, .pad = callback_file_pad, .write = callback_file_write, - .write_fd = callback_file_write_fd, - .write_fill = callback_file_write_fill, .close = callback_file_close, }; @@ -484,8 +376,7 @@ static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, ui return 0; } -static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int len, - handle_data data, bool is_fd) { +static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) { chunk_header_t chunk_header; int rnd_up_len, zero_len; int ret; @@ -502,16 +393,7 @@ static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int ret = out->ops->write(out, &chunk_header, sizeof(chunk_header)); if (ret < 0) return -1; - - if (is_fd) { - // CRC is handled by write_fd - ret = out->ops->write_fd(out, data.fd, len); - } else { - ret = out->ops->write(out, data.data_ptr, len); - if (out->use_crc) { - out->crc32 = sparse_crc32(out->crc32, data.data_ptr, len); - } - } + ret = out->ops->write(out, data, len); if (ret < 0) return -1; if (zero_len) { ret = out->ops->write(out, out->zero_buf, zero_len); @@ -519,6 +401,7 @@ static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int } if (out->use_crc) { + out->crc32 = sparse_crc32(out->crc32, data, len); if (zero_len) out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len); } @@ -528,16 +411,6 @@ static int write_sparse_data_chunk_variant(struct output_file* out, unsigned int return 0; } -static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) { - handle_data data = {data_ptr}; - return write_sparse_data_chunk_variant(out, len, data, false /* isFd */); -} - -static int write_sparse_fd_chunk(struct output_file* out, unsigned int len, int fd) { - handle_data data = {.fd = fd}; - return write_sparse_data_chunk_variant(out, len, data, true /* isFd */); -} - int write_sparse_end_chunk(struct output_file* out) { chunk_header_t chunk_header; int ret; @@ -565,22 +438,16 @@ int write_sparse_end_chunk(struct output_file* out) { static struct sparse_file_ops sparse_file_ops = { .write_data_chunk = write_sparse_data_chunk, - .write_fd_chunk = write_sparse_fd_chunk, .write_fill_chunk = write_sparse_fill_chunk, .write_skip_chunk = write_sparse_skip_chunk, .write_end_chunk = write_sparse_end_chunk, }; -static int write_normal_data_chunk_variant(struct output_file* out, unsigned int len, - handle_data data, bool isFd) { +static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) { int ret; unsigned int rnd_up_len = ALIGN(len, out->block_size); - if (isFd) { - ret = out->ops->write_fd(out, data.fd, len); - } else { - ret = out->ops->write(out, data.data_ptr, len); - } + ret = out->ops->write(out, data, len); if (ret < 0) { return ret; } @@ -592,18 +459,27 @@ static int write_normal_data_chunk_variant(struct output_file* out, unsigned int return ret; } -static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data_ptr) { - handle_data data = {data_ptr}; - return write_normal_data_chunk_variant(out, len, data, false /* isFd */); -} - -static int write_normal_fd_chunk(struct output_file* out, unsigned int len, int fd) { - handle_data data = {.fd = fd}; - return write_normal_data_chunk_variant(out, len, data, true /* isFd */); -} - static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) { - return out->ops->write_fill(out, fill_val, len); + int ret; + unsigned int i; + unsigned int write_len; + + /* Initialize fill_buf with the fill_val */ + for (i = 0; i < out->block_size / sizeof(uint32_t); i++) { + out->fill_buf[i] = fill_val; + } + + while (len) { + write_len = min(len, out->block_size); + ret = out->ops->write(out, out->fill_buf, write_len); + if (ret < 0) { + return ret; + } + + len -= write_len; + } + + return 0; } static int write_normal_skip_chunk(struct output_file* out, int64_t len) { @@ -616,7 +492,6 @@ int write_normal_end_chunk(struct output_file* out) { static struct sparse_file_ops normal_file_ops = { .write_data_chunk = write_normal_data_chunk, - .write_fd_chunk = write_normal_fd_chunk, .write_fill_chunk = write_normal_fill_chunk, .write_skip_chunk = write_normal_skip_chunk, .write_end_chunk = write_normal_end_chunk, @@ -714,20 +589,12 @@ static struct output_file* output_file_new_normal(void) { return &outn->out; } -struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t), - int (*fd_write)(void*, int, size_t), - int (*fill_write)(void*, uint32_t, size_t), - int (*skip_write)(void*, off64_t), void* priv, - unsigned int block_size, int64_t len, int sparse, - int chunks, int crc) { +struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv, + unsigned int block_size, int64_t len, int gz __unused, + int sparse, int chunks, int crc) { int ret; struct output_file_callback* outc; - if (!data_write || (crc && (fd_write || fill_write))) { - errno = EINVAL; - return nullptr; - } - outc = reinterpret_cast(calloc(1, sizeof(struct output_file_callback))); if (!outc) { @@ -737,10 +604,7 @@ struct output_file* output_file_open_callback(int (*data_write)(void*, const voi outc->out.ops = &callback_file_ops; outc->priv = priv; - outc->data_write = data_write; - outc->fd_write = fd_write; - outc->fill_write = fill_write; - outc->skip_write = skip_write; + outc->write = write; ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc); if (ret < 0) { @@ -787,8 +651,52 @@ int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_va } int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) { - lseek64(fd, offset, SEEK_SET); - return out->sparse_ops->write_fd_chunk(out, len, fd); + int ret; + int64_t aligned_offset; + int aligned_diff; + uint64_t buffer_size; + char* ptr; + + aligned_offset = offset & ~(4096 - 1); + aligned_diff = offset - aligned_offset; + buffer_size = (uint64_t)len + (uint64_t)aligned_diff; + +#ifndef _WIN32 + if (buffer_size > SIZE_MAX) return -E2BIG; + char* data = + reinterpret_cast(mmap64(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, aligned_offset)); + if (data == MAP_FAILED) { + return -errno; + } + ptr = data + aligned_diff; +#else + off64_t pos; + char* data = reinterpret_cast(malloc(len)); + if (!data) { + return -errno; + } + pos = lseek64(fd, offset, SEEK_SET); + if (pos < 0) { + free(data); + return -errno; + } + ret = read_all(fd, data, len); + if (ret < 0) { + free(data); + return ret; + } + ptr = data; +#endif + + ret = out->sparse_ops->write_data_chunk(out, len, ptr); + +#ifndef _WIN32 + munmap(data, buffer_size); +#else + free(data); +#endif + + return ret; } /* Write a contiguous region of data blocks from a file */ diff --git a/libsparse/output_file.h b/libsparse/output_file.h index 114582e17..278430b6f 100644 --- a/libsparse/output_file.h +++ b/libsparse/output_file.h @@ -22,18 +22,14 @@ extern "C" { #endif #include -#include struct output_file; struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t len, int gz, int sparse, int chunks, int crc); -struct output_file* output_file_open_callback(int (*data_write)(void*, const void*, size_t), - int (*fd_write)(void*, int, size_t), - int (*fill_write)(void*, uint32_t, size_t), - int (*skip_write)(void*, off64_t), void* priv, - unsigned int block_size, int64_t len, int sparse, - int chunks, int crc); +struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv, + unsigned int block_size, int64_t len, int gz, + int sparse, int chunks, int crc); int write_data_chunk(struct output_file* out, unsigned int len, void* data); int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val); int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset); diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp index f5ca9071d..cb288c555 100644 --- a/libsparse/sparse.cpp +++ b/libsparse/sparse.cpp @@ -160,30 +160,7 @@ int sparse_file_callback(struct sparse_file* s, bool sparse, bool crc, struct output_file* out; chunks = sparse_count_chunks(s); - out = output_file_open_callback(write, nullptr, nullptr, nullptr, priv, s->block_size, s->len, - sparse, chunks, crc); - - if (!out) return -ENOMEM; - - ret = write_all_blocks(s, out); - - output_file_close(out); - - return ret; -} - -int sparse_file_callback_typed(struct sparse_file* s, bool sparse, - int (*data_write)(void* priv, const void* data, size_t len), - int (*fd_write)(void* priv, int fd, size_t len), - int (*fill_write)(void* priv, uint32_t fill_val, size_t len), - int (*skip_write)(void* priv, int64_t len), void* priv) { - int ret; - int chunks; - struct output_file* out; - - chunks = sparse_count_chunks(s); - out = output_file_open_callback(data_write, fd_write, fill_write, skip_write, priv, s->block_size, - s->len, sparse, chunks, false); + out = output_file_open_callback(write, priv, s->block_size, s->len, false, sparse, chunks, crc); if (!out) return -ENOMEM; @@ -221,8 +198,8 @@ int sparse_file_foreach_chunk(struct sparse_file* s, bool sparse, bool crc, chk.write = write; chk.block = chk.nr_blocks = 0; chunks = sparse_count_chunks(s); - out = output_file_open_callback(foreach_chunk_write, nullptr, nullptr, nullptr, &chk, - s->block_size, s->len, sparse, chunks, crc); + out = output_file_open_callback(foreach_chunk_write, &chk, s->block_size, s->len, false, sparse, + chunks, crc); if (!out) return -ENOMEM; @@ -250,8 +227,8 @@ int64_t sparse_file_len(struct sparse_file* s, bool sparse, bool crc) { int64_t count = 0; struct output_file* out; - out = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count, - s->block_size, s->len, sparse, chunks, crc); + out = output_file_open_callback(out_counter_write, &count, s->block_size, s->len, false, sparse, + chunks, crc); if (!out) { return -1; } @@ -290,8 +267,8 @@ static struct backed_block* move_chunks_up_to_len(struct sparse_file* from, stru len -= overhead; start = backed_block_iter_new(from->backed_block_list); - out_counter = output_file_open_callback(out_counter_write, nullptr, nullptr, nullptr, &count, - to->block_size, to->len, true, 0, false); + out_counter = output_file_open_callback(out_counter_write, &count, to->block_size, to->len, false, + true, 0, false); if (!out_counter) { return nullptr; }