From a26a6bd6f36d29cdc959f746b495f79f74c7fad7 Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Wed, 30 Nov 2016 11:49:47 -0800 Subject: [PATCH] libsparse: add a function to retrieve the data blocks Test: m libsparse Change-Id: I04bd3912bb4364e591b064ec2aab782cf02f6bd7 --- libsparse/include/sparse/sparse.h | 25 ++++++++++++++ libsparse/sparse.c | 56 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h index 42d4adb87..356f65fd0 100644 --- a/libsparse/include/sparse/sparse.h +++ b/libsparse/include/sparse/sparse.h @@ -175,6 +175,13 @@ int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse, */ int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc); +/** + * sparse_file_block_size + * + * @s - sparse file cookie + */ +unsigned int sparse_file_block_size(struct sparse_file *s); + /** * sparse_file_callback - call a callback for blocks in sparse file * @@ -196,6 +203,24 @@ int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc); int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc, int (*write)(void *priv, const void *data, int len), void *priv); +/** + * sparse_file_foreach_chunk - call a callback for data blocks in sparse file + * + * @s - sparse file cookie + * @sparse - write in the Android sparse file format + * @crc - append a crc chunk + * @write - function to call for each block + * @priv - value that will be passed as the first argument to write + * + * The function has the same behavior as 'sparse_file_callback', except it only + * iterates on blocks that contain data. + * + * Returns 0 on success, negative errno on error. + */ +int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc, + int (*write)(void *priv, const void *data, int len, unsigned int block, + unsigned int nr_blocks), + void *priv); /** * sparse_file_read - read a file into a sparse file cookie * diff --git a/libsparse/sparse.c b/libsparse/sparse.c index 311678a34..b17586066 100644 --- a/libsparse/sparse.c +++ b/libsparse/sparse.c @@ -199,6 +199,57 @@ int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc, return ret; } +struct chunk_data { + void *priv; + unsigned int block; + unsigned int nr_blocks; + int (*write)(void *priv, const void *data, int len, unsigned int block, + unsigned int nr_blocks); +}; + +static int foreach_chunk_write(void *priv, const void *data, int len) +{ + struct chunk_data *chk = priv; + + return chk->write(chk->priv, data, len, chk->block, chk->nr_blocks); +} + +int sparse_file_foreach_chunk(struct sparse_file *s, bool sparse, bool crc, + int (*write)(void *priv, const void *data, int len, unsigned int block, + unsigned int nr_blocks), + void *priv) +{ + int ret; + int chunks; + struct chunk_data chk; + struct output_file *out; + struct backed_block *bb; + + chk.priv = priv; + chk.write = write; + chk.block = chk.nr_blocks = 0; + chunks = sparse_count_chunks(s); + out = output_file_open_callback(foreach_chunk_write, &chk, + s->block_size, s->len, false, sparse, + chunks, crc); + + if (!out) + return -ENOMEM; + + for (bb = backed_block_iter_new(s->backed_block_list); bb; + bb = backed_block_iter_next(bb)) { + chk.block = backed_block_block(bb); + chk.nr_blocks = (backed_block_len(bb) - 1) / s->block_size + 1; + ret = sparse_file_write_block(out, bb); + if (ret) + return ret; + } + + output_file_close(out); + + return ret; +} + static int out_counter_write(void *priv, const void *data __unused, int len) { int64_t *count = priv; @@ -230,6 +281,11 @@ int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc) return count; } +unsigned int sparse_file_block_size(struct sparse_file *s) +{ + return s->block_size; +} + static struct backed_block *move_chunks_up_to_len(struct sparse_file *from, struct sparse_file *to, unsigned int len) {