ext4_utils: Add an optional CRC chunk at the end of sparse files
Change-Id: Ibfcf1cdeab47ca13870350184abf83e530acbc07
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index 9d8a9b0..aac9c71 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -120,11 +120,11 @@
}
/* 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 a78b095..6e6c1ec 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -136,7 +136,7 @@
}
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 3f0141d..2160d56 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -242,7 +242,8 @@
}
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 @@
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 8c6b259..78fcb07 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 66d7aac..2b59082 100644
--- a/ext4_utils/make_ext4fs_main.c
+++ b/ext4_utils/make_ext4fs_main.c
@@ -46,8 +46,9 @@
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 @@
case 'J':
info.no_journal = 1;
break;
+ case 'c':
+ crc = 1;
+ break;
case 's':
sparse = 1;
break;
@@ -115,5 +119,6 @@
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 d147b0b..66550d5 100644
--- a/ext4_utils/output_file.c
+++ b/ext4_utils/output_file.c
@@ -52,6 +52,7 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
/* 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 @@
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 @@
munmap(data, len);
close(file_fd);
}
-
diff --git a/ext4_utils/output_file.h b/ext4_utils/output_file.h
index 0ac707c..c174cc3 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 9ef2509..38b6191 100644
--- a/ext4_utils/simg2img.c
+++ b/ext4_utils/simg2img.c
@@ -76,30 +76,38 @@
* 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 @@
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 @@
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 ba13214..6c62c34 100644
--- a/ext4_utils/sparse_format.h
+++ b/ext4_utils/sparse_format.h
@@ -33,6 +33,7 @@
#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 @@
__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
*/