diff options
Diffstat (limited to 'contrib/android/ext2simg.c')
-rw-r--r-- | contrib/android/ext2simg.c | 123 |
1 files changed, 73 insertions, 50 deletions
diff --git a/contrib/android/ext2simg.c b/contrib/android/ext2simg.c index 017e16f..2bf76b9 100644 --- a/contrib/android/ext2simg.c +++ b/contrib/android/ext2simg.c @@ -24,16 +24,14 @@ #include <sparse/sparse.h> struct { - int crc; - int sparse; - int gzip; + bool crc; + bool sparse; + bool gzip; char *in_file; char *out_file; bool overwrite_input; } params = { - .crc = 0, - .sparse = 1, - .gzip = 0, + .sparse = true, }; #define ext2fs_fatal(Retval, Format, ...) \ @@ -60,39 +58,41 @@ static void usage(char *path) static struct buf_item { struct buf_item *next; - void *buf[0]; + void *buf[]; } *buf_list; -static void add_chunk(ext2_filsys fs, struct sparse_file *s, blk_t chunk_start, blk_t chunk_end) +/* + * Add @num_blks blocks, starting at index @chunk_start, of the filesystem @fs + * to the sparse file @s. + */ +static void add_chunk(ext2_filsys fs, struct sparse_file *s, + blk_t chunk_start, int num_blks) { + uint64_t len = (uint64_t)num_blks * fs->blocksize; + int64_t offset = (int64_t)chunk_start * fs->blocksize; + struct buf_item *bi; int retval; - unsigned int nb_blk = chunk_end - chunk_start; - size_t len = nb_blk * fs->blocksize; - int64_t offset = (int64_t)chunk_start * (int64_t)fs->blocksize; - if (params.overwrite_input == false) { + if (!params.overwrite_input) { if (sparse_file_add_file(s, params.in_file, offset, len, chunk_start) < 0) sparse_fatal("adding data to the sparse file"); - } else { - /* - * The input file will be overwritten, make a copy of - * the blocks - */ - struct buf_item *bi = calloc(1, sizeof(struct buf_item) + len); - if (buf_list == NULL) - buf_list = bi; - else { - bi->next = buf_list; - buf_list = bi; - } + return; + } - retval = io_channel_read_blk64(fs->io, chunk_start, nb_blk, bi->buf); - if (retval < 0) - ext2fs_fatal(retval, "reading block %u - %u", chunk_start, chunk_end); + /* The input file will be overwritten, so make a copy of the blocks. */ + if (len > SIZE_MAX - sizeof(*bi)) + sparse_fatal("filesystem is too large"); + bi = calloc(1, sizeof(*bi) + len); + if (!bi) + sparse_fatal("out of memory"); + bi->next = buf_list; + buf_list = bi; + retval = io_channel_read_blk64(fs->io, chunk_start, num_blks, bi->buf); + if (retval) + ext2fs_fatal(retval, "reading data from %s", params.in_file); - if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0) - sparse_fatal("adding data to the sparse file"); - } + if (sparse_file_add_data(s, bi->buf, len, chunk_start) < 0) + sparse_fatal("adding data to the sparse file"); } static void free_chunks(void) @@ -106,13 +106,23 @@ static void free_chunks(void) } } +static blk_t fs_blocks_count(ext2_filsys fs) +{ + blk64_t blks = ext2fs_blocks_count(fs->super); + + /* libsparse assumes 32-bit block numbers. */ + if ((blk_t)blks != blks) + sparse_fatal("filesystem is too large"); + return blks; +} + static struct sparse_file *ext_to_sparse(const char *in_file) { errcode_t retval; ext2_filsys fs; struct sparse_file *s; int64_t chunk_start = -1; - blk_t first_blk, last_blk, nb_blk, cur_blk; + blk_t fs_blks, cur_blk; retval = ext2fs_open(in_file, 0, 0, 0, unix_io_manager, &fs); if (retval) @@ -122,11 +132,9 @@ static struct sparse_file *ext_to_sparse(const char *in_file) if (retval) ext2fs_fatal(retval, "while reading block bitmap of %s", in_file); - first_blk = ext2fs_get_block_bitmap_start2(fs->block_map); - last_blk = ext2fs_get_block_bitmap_end2(fs->block_map); - nb_blk = last_blk - first_blk + 1; + fs_blks = fs_blocks_count(fs); - s = sparse_file_new(fs->blocksize, (uint64_t)fs->blocksize * (uint64_t)nb_blk); + s = sparse_file_new(fs->blocksize, (uint64_t)fs_blks * fs->blocksize); if (!s) sparse_fatal("creating sparse file"); @@ -138,24 +146,39 @@ static struct sparse_file *ext_to_sparse(const char *in_file) * larger than INT32_MAX (32-bit _and_ 64-bit systems). * Make sure we do not create chunks larger than this limit. */ - int64_t max_blk_per_chunk = (INT32_MAX - 12) / fs->blocksize; + int32_t max_blk_per_chunk = (INT32_MAX - 12) / fs->blocksize; - /* Iter on the blocks to merge contiguous chunk */ - for (cur_blk = first_blk; cur_blk <= last_blk; ++cur_blk) { + /* + * Iterate through the filesystem's blocks, identifying "chunks" that + * are contiguous ranges of blocks that are in-use by the filesystem. + * Add each chunk to the sparse_file. + */ + for (cur_blk = ext2fs_get_block_bitmap_start2(fs->block_map); + cur_blk < fs_blks; ++cur_blk) { if (ext2fs_test_block_bitmap2(fs->block_map, cur_blk)) { + /* + * @cur_blk is in-use. Append it to the pending chunk + * if there is one, otherwise start a new chunk. + */ if (chunk_start == -1) { chunk_start = cur_blk; } else if (cur_blk - chunk_start + 1 == max_blk_per_chunk) { - add_chunk(fs, s, chunk_start, cur_blk); + /* + * Appending @cur_blk to the pending chunk made + * it reach the maximum length, so end it. + */ + add_chunk(fs, s, chunk_start, max_blk_per_chunk); chunk_start = -1; } } else if (chunk_start != -1) { - add_chunk(fs, s, chunk_start, cur_blk); + /* @cur_blk is not in-use, so end the pending chunk. */ + add_chunk(fs, s, chunk_start, cur_blk - chunk_start); chunk_start = -1; } } + /* If there's still a pending chunk, end it. */ if (chunk_start != -1) - add_chunk(fs, s, chunk_start, cur_blk - 1); + add_chunk(fs, s, chunk_start, cur_blk - chunk_start); ext2fs_free(fs); return s; @@ -165,14 +188,14 @@ static bool same_file(const char *in, const char *out) { struct stat st1, st2; - if (access(out, F_OK) == -1) - return false; - - if (lstat(in, &st1) == -1) + if (stat(in, &st1) == -1) ext2fs_fatal(errno, "stat %s\n", in); - if (lstat(out, &st2) == -1) + if (stat(out, &st2) == -1) { + if (errno == ENOENT) + return false; ext2fs_fatal(errno, "stat %s\n", out); - return st1.st_ino == st2.st_ino; + } + return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino; } int main(int argc, char *argv[]) @@ -184,13 +207,13 @@ int main(int argc, char *argv[]) while ((opt = getopt(argc, argv, "czS")) != -1) { switch(opt) { case 'c': - params.crc = 1; + params.crc = true; break; case 'z': - params.gzip = 1; + params.gzip = true; break; case 'S': - params.sparse = 0; + params.sparse = false; break; default: usage(argv[0]); |