From 757ace516d8e4350616b5fd10da0c982d3d5ec74 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Wed, 29 Dec 2010 13:57:01 -0800 Subject: [PATCH] ext4_utils: Add an optional CRC chunk at the end of sparse files Change-Id: Ibfcf1cdeab47ca13870350184abf83e530acbc07 --- ext4_utils/ext4_utils.c | 4 ++-- ext4_utils/ext4_utils.h | 2 +- ext4_utils/make_ext4fs.c | 5 +++-- ext4_utils/make_ext4fs.h | 3 ++- ext4_utils/make_ext4fs_main.c | 9 +++++++-- ext4_utils/output_file.c | 40 ++++++++++++++++++++++++---------------- ext4_utils/output_file.h | 2 +- ext4_utils/simg2img.c | 35 ++++++++++++++++++++--------------- ext4_utils/sparse_format.h | 5 ++++- 9 files changed, 64 insertions(+), 41 deletions(-) diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c index 9d8a9b0f..aac9c713 100644 --- a/ext4_utils/ext4_utils.c +++ b/ext4_utils/ext4_utils.c @@ -120,11 +120,11 @@ static void ext4_write_data_file(void *priv, u64 off, const char *file, } /* Write the filesystem image to a file */ -void write_ext4_image(const char *filename, int gz, int sparse) +void write_ext4_image(const char *filename, int gz, int sparse, int crc) { int ret = 0; struct output_file *out = open_output_file(filename, gz, sparse, - count_sparse_chunks()); + count_sparse_chunks(), crc); if (!out) return; diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h index a78b095b..6e6c1ec8 100644 --- a/ext4_utils/ext4_utils.h +++ b/ext4_utils/ext4_utils.h @@ -136,7 +136,7 @@ static inline int log_2(int j) } int ext4_bg_has_super_block(int bg); -void write_ext4_image(const char *filename, int gz, int sparse); +void write_ext4_image(const char *filename, int gz, int sparse, int crc); void ext4_create_fs_aux_info(void); void ext4_free_fs_aux_info(void); void ext4_fill_in_sb(void); diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c index 3f0141d0..2160d563 100644 --- a/ext4_utils/make_ext4fs.c +++ b/ext4_utils/make_ext4fs.c @@ -242,7 +242,8 @@ void reset_ext4fs_info() { } int make_ext4fs(const char *filename, const char *directory, - char *mountpoint, int android, int gzip, int sparse) + char *mountpoint, int android, int gzip, int sparse, + int crc) { u32 root_inode_num; u16 root_mode; @@ -340,7 +341,7 @@ int make_ext4fs(const char *filename, const char *directory, aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, aux_info.sb->s_blocks_count_lo); - write_ext4_image(filename, gzip, sparse); + write_ext4_image(filename, gzip, sparse, crc); return 0; } diff --git a/ext4_utils/make_ext4fs.h b/ext4_utils/make_ext4fs.h index 8c6b2592..78fcb075 100644 --- a/ext4_utils/make_ext4fs.h +++ b/ext4_utils/make_ext4fs.h @@ -22,6 +22,7 @@ void reset_ext4fs_info(); int make_ext4fs(const char *filename, const char *directory, - char *mountpoint, int android, int gzip, int sparse); + char *mountpoint, int android, int gzip, int sparse, + int crc); #endif diff --git a/ext4_utils/make_ext4fs_main.c b/ext4_utils/make_ext4fs_main.c index 66d7aac6..2b590820 100644 --- a/ext4_utils/make_ext4fs_main.c +++ b/ext4_utils/make_ext4fs_main.c @@ -46,8 +46,9 @@ int main(int argc, char **argv) int android = 0; int gzip = 0; int sparse = 0; + int crc = 0; - while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fzJs")) != -1) { + while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:fzJsc")) != -1) { switch (opt) { case 'l': info.len = parse_num(optarg); @@ -83,6 +84,9 @@ int main(int argc, char **argv) case 'J': info.no_journal = 1; break; + case 'c': + crc = 1; + break; case 's': sparse = 1; break; @@ -115,5 +119,6 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } - return make_ext4fs(filename, directory, mountpoint, android, gzip, sparse); + return make_ext4fs(filename, directory, mountpoint, android, gzip, + sparse, crc); } diff --git a/ext4_utils/output_file.c b/ext4_utils/output_file.c index d147b0bc..66550d56 100644 --- a/ext4_utils/output_file.c +++ b/ext4_utils/output_file.c @@ -52,6 +52,7 @@ struct output_file { u32 chunk_cnt; u32 crc32; struct output_file_ops *ops; + int use_crc; }; static int file_seek(struct output_file *out, off64_t off) @@ -170,13 +171,6 @@ static int emit_skip_chunk(struct output_file *out, u64 skip_len) out->cur_out_ptr += skip_len; out->chunk_cnt++; - /* Compute the CRC for all those zeroes. Do it block_size bytes at a time. */ - while (skip_len) { - chunk = (skip_len > info.block_size) ? info.block_size : skip_len; - out->crc32 = sparse_crc32(out->crc32, zero_buf, chunk); - skip_len -= chunk; - } - return 0; } @@ -238,9 +232,12 @@ static int write_chunk_raw(struct output_file *out, u64 off, u8 *data, int len) return -1; } - out->crc32 = sparse_crc32(out->crc32, data, len); - if (zero_len) - out->crc32 = sparse_crc32(out->crc32, zero_buf, zero_len); + if (out->use_crc) { + out->crc32 = sparse_crc32(out->crc32, data, len); + if (zero_len) + out->crc32 = sparse_crc32(out->crc32, zero_buf, zero_len); + } + out->cur_out_ptr += rnd_up_len; out->chunk_cnt++; @@ -253,6 +250,18 @@ void close_output_file(struct output_file *out) chunk_header_t chunk_header; if (out->sparse) { + if (out->use_crc) { + chunk_header.chunk_type = CHUNK_TYPE_CRC32; + chunk_header.reserved1 = 0; + chunk_header.chunk_sz = 0; + chunk_header.total_sz = CHUNK_HEADER_LEN + 4; + + out->ops->write(out, (u8 *)&chunk_header, sizeof(chunk_header)); + out->ops->write(out, (u8 *)&out->crc32, 4); + + out->chunk_cnt++; + } + if (out->chunk_cnt != sparse_header.total_chunks) error("sparse chunk count did not match: %d %d", out->chunk_cnt, sparse_header.total_chunks); @@ -261,7 +270,7 @@ void close_output_file(struct output_file *out) } struct output_file *open_output_file(const char *filename, int gz, int sparse, - int chunks) + int chunks, int crc) { int ret; struct output_file *out = malloc(sizeof(struct output_file)); @@ -303,14 +312,15 @@ struct output_file *open_output_file(const char *filename, int gz, int sparse, /* Initialize the crc32 value */ out->crc32 = 0; + out->use_crc = crc; if (out->sparse) { - /* Write out the file header. We'll update the unknown fields - * when we close the file. - */ sparse_header.blk_sz = info.block_size, sparse_header.total_blks = info.len / info.block_size, sparse_header.total_chunks = chunks; + if (out->use_crc) + sparse_header.total_chunks++; + ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header)); if (ret < 0) return NULL; @@ -331,7 +341,6 @@ void pad_output_file(struct output_file *out, u64 len) if (out->sparse) { /* We need to emit a DONT_CARE chunk to pad out the file if the * cur_out_ptr is not already at the end of the filesystem. - * We also need to compute the CRC for it. */ if (len < out->cur_out_ptr) { error("attempted to pad file %llu bytes less than the current output pointer", @@ -431,4 +440,3 @@ err: munmap(data, len); close(file_fd); } - diff --git a/ext4_utils/output_file.h b/ext4_utils/output_file.h index 0ac707c9..c174cc3c 100644 --- a/ext4_utils/output_file.h +++ b/ext4_utils/output_file.h @@ -20,7 +20,7 @@ struct output_file; struct output_file *open_output_file(const char *filename, int gz, int sparse, - int chunks); + int chunks, int crc); void write_data_block(struct output_file *out, u64 off, u8 *data, int len); void write_data_file(struct output_file *out, u64 off, const char *file, off64_t offset, int len); diff --git a/ext4_utils/simg2img.c b/ext4_utils/simg2img.c index 9ef25094..38b61917 100644 --- a/ext4_utils/simg2img.c +++ b/ext4_utils/simg2img.c @@ -76,30 +76,38 @@ int process_skip_chunk(FILE *out, u32 blocks, u32 blk_sz, u32 *crc32) * as a 32 bit value of blocks. */ u64 len = (u64)blocks * blk_sz; - u64 len_save; u32 skip_chunk; /* Fseek takes the offset as a long, which may be 32 bits on some systems. * So, lets do a sequence of fseeks() with SEEK_CUR to get the file pointer * where we want it. */ - len_save = len; while (len) { skip_chunk = (len > 0x80000000) ? 0x80000000 : len; fseek(out, skip_chunk, SEEK_CUR); len -= skip_chunk; } - /* And compute the CRC of the skipped region a chunk at a time */ - len = len_save; - while (len) { - skip_chunk = (skip_chunk > blk_sz) ? blk_sz : skip_chunk; - *crc32 = sparse_crc32(*crc32, zerobuf, skip_chunk); - len -= skip_chunk; - } return blocks; } +int process_crc32_chunk(FILE *in, u32 crc32) +{ + u32 file_crc32; + if (fread(&file_crc32, 4, 1, in) != 1) { + fprintf(stderr, "fread returned an error copying a crc32 chunk\n"); + exit(-1); + } + + if (file_crc32 != crc32) { + fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n", + crc32, file_crc32); + exit(-1); + } + + return 0; +} + int main(int argc, char *argv[]) { FILE *in, *out; @@ -187,6 +195,9 @@ int main(int argc, char *argv[]) total_blocks += process_skip_chunk(out, chunk_header.chunk_sz, sparse_header.blk_sz, &crc32); break; + case CHUNK_TYPE_CRC32: + process_crc32_chunk(in, crc32); + break; default: fprintf(stderr, "Unknown chunk type 0x%4.4x\n", chunk_header.chunk_type); exit(-1); @@ -213,12 +224,6 @@ int main(int argc, char *argv[]) exit(-1); } - if (sparse_header.image_checksum != crc32) { - fprintf(stderr, "computed crc32 of 0x%8.8x, expected 0x%8.8x\n", - crc32, sparse_header.image_checksum); - exit(-1); - } - exit(0); } diff --git a/ext4_utils/sparse_format.h b/ext4_utils/sparse_format.h index ba132140..6c62c34c 100644 --- a/ext4_utils/sparse_format.h +++ b/ext4_utils/sparse_format.h @@ -33,6 +33,7 @@ typedef struct sparse_header { #define CHUNK_TYPE_RAW 0xCAC1 #define CHUNK_TYPE_FILL 0xCAC2 #define CHUNK_TYPE_DONT_CARE 0xCAC3 +#define CHUNK_TYPE_CRC32 0xCAC4 typedef struct chunk_header { __le16 chunk_type; /* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */ @@ -41,7 +42,9 @@ typedef struct chunk_header { __le32 total_sz; /* in bytes of chunk input file including chunk header and data */ } chunk_header_t; -/* Following a Raw or Fill chunk is data. For a Raw chunk, it's the data in chunk_sz * blk_sz. +/* Following a Raw or Fill or CRC32 chunk is data. + * For a Raw chunk, it's the data in chunk_sz * blk_sz. * For a Fill chunk, it's 4 bytes of the fill data. + * For a CRC32 chunk, it's 4 bytes of CRC32 */ -- 2.11.0