OSDN Git Service

ext4_utils: Get rid of CRC in sparse file header
authorColin Cross <ccross@android.com>
Thu, 23 Dec 2010 02:41:13 +0000 (18:41 -0800)
committerColin Cross <ccross@android.com>
Wed, 5 Jan 2011 23:36:06 +0000 (15:36 -0800)
Also removes the need to seek in the output file, allowing
stdin and stdout to be used for input and output.

Change-Id: I93cbe335d9cc83a6d21daa696af2cb54952dcc9f

ext4_utils/backed_block.c
ext4_utils/backed_block.h
ext4_utils/ext4_utils.c
ext4_utils/ext4_utils.h
ext4_utils/make_ext4fs.c
ext4_utils/output_file.c
ext4_utils/output_file.h

index 82c4bcc..473cce2 100644 (file)
@@ -102,7 +102,7 @@ void queue_data_file(const char *filename, off64_t offset, u32 len,
 /* Iterates over the queued data blocks, calling data_func for each contiguous
    data block, and file_func for each contiguous file block */
 void for_each_data_block(data_block_callback_t data_func,
-       data_block_file_callback_t file_func, struct output_file *out)
+       data_block_file_callback_t file_func, void *priv)
 {
        struct data_block *db;
        u32 last_block = 0;
@@ -113,9 +113,9 @@ void for_each_data_block(data_block_callback_t data_func,
                last_block = db->block + DIV_ROUND_UP(db->len, info.block_size) - 1;
 
                if (db->filename)
-                       file_func(out, (u64)db->block * info.block_size, db->filename, db->offset, db->len);
+                       file_func(priv, (u64)db->block * info.block_size, db->filename, db->offset, db->len);
                else
-                       data_func(out, (u64)db->block * info.block_size, db->data, db->len);
+                       data_func(priv, (u64)db->block * info.block_size, db->data, db->len);
        }
 }
 
index 61a1b1c..d131dc6 100644 (file)
@@ -20,9 +20,8 @@
 #include "ext4_utils.h"
 #include "output_file.h"
 
-typedef void (*data_block_callback_t)(struct output_file *out, u64 off,
-       u8 *data, int len);
-typedef void (*data_block_file_callback_t)(struct output_file *out, u64 off,
+typedef void (*data_block_callback_t)(void *priv, u64 off, u8 *data, int len);
+typedef void (*data_block_file_callback_t)(void *priv, u64 off,
                                           const char *file, off64_t offset,
                                           int len);
 
@@ -30,7 +29,7 @@ void queue_data_block(u8 *data, u32 len, u32 block);
 void queue_data_file(const char *filename, off64_t offset, u32 len,
        u32 block);
 void for_each_data_block(data_block_callback_t data_func,
-       data_block_file_callback_t file_func, struct output_file *out);
+       data_block_file_callback_t file_func, void *priv);
 void free_data_blocks();
 
 #endif
index 1551633..9d8a9b0 100644 (file)
@@ -73,34 +73,63 @@ int ext4_bg_has_super_block(int bg)
        return 0;
 }
 
+struct count_chunks {
+       u32 chunks;
+       u64 cur_ptr;
+};
+
+void count_data_block(void *priv, u64 off, u8 *data, int len)
+{
+       struct count_chunks *count_chunks = priv;
+       if (off > count_chunks->cur_ptr)
+               count_chunks->chunks++;
+       count_chunks->cur_ptr = off + ALIGN(len, info.block_size);
+       count_chunks->chunks++;
+}
+
+void count_file_block(void *priv, u64 off, const char *file,
+               off64_t offset, int len)
+{
+       struct count_chunks *count_chunks = priv;
+       if (off > count_chunks->cur_ptr)
+               count_chunks->chunks++;
+       count_chunks->cur_ptr = off + ALIGN(len, info.block_size);
+       count_chunks->chunks++;
+}
+
+int count_sparse_chunks()
+{
+       struct count_chunks count_chunks = {0, 0};
+
+       for_each_data_block(count_data_block, count_file_block, &count_chunks);
+
+       if (count_chunks.cur_ptr != info.len)
+               count_chunks.chunks++;
+
+       return count_chunks.chunks;
+}
+
+static void ext4_write_data_block(void *priv, u64 off, u8 *data, int len)
+{
+       write_data_block(priv, off, data, len);
+}
+static void ext4_write_data_file(void *priv, u64 off, const char *file,
+               off64_t offset, int len)
+{
+       write_data_file(priv, off, file, offset, len);
+}
+
 /* Write the filesystem image to a file */
 void write_ext4_image(const char *filename, int gz, int sparse)
 {
        int ret = 0;
-       struct output_file *out = open_output_file(filename, gz, sparse);
+       struct output_file *out = open_output_file(filename, gz, sparse,
+               count_sparse_chunks());
 
        if (!out)
                return;
 
-       /* The write_data* functions expect only block aligned calls.
-        * This is not an issue, except when we write out the super
-        * block on a system with a block size > 1K.  So, we need to
-        * deal with that here.
-        */
-       if (info.block_size > 1024) {
-               u8 buf[4096] = { 0 };   /* The larget supported ext4 block size */
-               memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
-               write_data_block(out, 0, buf, info.block_size);
-
-       } else {
-               write_data_block(out, 1024, (u8*)aux_info.sb, 1024);
-       }
-
-       write_data_block(out, (u64)(aux_info.first_data_block + 1) * info.block_size,
-                        (u8*)aux_info.bg_desc,
-                        aux_info.bg_desc_blocks * info.block_size);
-
-       for_each_data_block(write_data_block, write_data_file, out);
+       for_each_data_block(ext4_write_data_block, ext4_write_data_file, out);
 
        pad_output_file(out, info.len);
 
@@ -233,12 +262,11 @@ void ext4_fill_in_sb()
                        info.blocks_per_group;
                u32 header_size = 0;
                if (ext4_bg_has_super_block(i)) {
-                       if (i != 0) {
+                       if (i != 0)
                                queue_data_block((u8 *)sb, info.block_size, group_start_block);
-                               queue_data_block((u8 *)aux_info.bg_desc,
-                                       aux_info.bg_desc_blocks * info.block_size,
-                                       group_start_block + 1);
-                       }
+                       queue_data_block((u8 *)aux_info.bg_desc,
+                               aux_info.bg_desc_blocks * info.block_size,
+                               group_start_block + 1);
                        header_size = 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
                }
 
@@ -252,6 +280,22 @@ void ext4_fill_in_sb()
        }
 }
 
+void ext4_queue_sb(void)
+{
+       /* The write_data* functions expect only block aligned calls.
+        * This is not an issue, except when we write out the super
+        * block on a system with a block size > 1K.  So, we need to
+        * deal with that here.
+        */
+       if (info.block_size > 1024) {
+               u8 *buf = calloc(info.block_size, 1);
+               memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
+               queue_data_block(buf, info.block_size, 0);
+       } else {
+               queue_data_block((u8*)aux_info.sb, 1024, 1);
+       }
+}
+
 void ext4_create_resize_inode()
 {
        struct block_allocation *reserve_inode_alloc = create_allocation();
index 8a6c3c4..a78b095 100644 (file)
@@ -143,6 +143,7 @@ void ext4_fill_in_sb(void);
 void ext4_create_resize_inode(void);
 void ext4_create_journal_inode(void);
 void ext4_update_free(void);
+void ext4_queue_sb(void);
 u64 get_file_size(const char *filename);
 u64 parse_num(const char *arg);
 
index cbec2ad..3f0141d 100644 (file)
@@ -332,6 +332,8 @@ int make_ext4fs(const char *filename, const char *directory,
 
        ext4_update_free();
 
+       ext4_queue_sb();
+
        printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
                        aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
                        aux_info.sb->s_inodes_count,
index efb1307..d147b0b 100644 (file)
@@ -49,7 +49,7 @@ struct output_file {
        gzFile gz_fd;
        int sparse;
        u64 cur_out_ptr;
-       int chunk_cnt;
+       u32 chunk_cnt;
        u32 crc32;
        struct output_file_ops *ops;
 };
@@ -250,24 +250,18 @@ static int write_chunk_raw(struct output_file *out, u64 off, u8 *data, int len)
 void close_output_file(struct output_file *out)
 {
        int ret;
+       chunk_header_t chunk_header;
 
        if (out->sparse) {
-               /* we need to seek back to the beginning and update the file header */
-               sparse_header.total_chunks = out->chunk_cnt;
-               sparse_header.image_checksum = out->crc32;
-
-               ret = out->ops->seek(out, 0);
-               if (ret < 0)
-                       error("failure seeking to start of sparse file");
-
-               ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header));
-               if (ret < 0)
-                       error("failure updating sparse file header");
+               if (out->chunk_cnt != sparse_header.total_chunks)
+                       error("sparse chunk count did not match: %d %d", out->chunk_cnt,
+                                       sparse_header.total_chunks);
        }
        out->ops->close(out);
 }
 
-struct output_file *open_output_file(const char *filename, int gz, int sparse)
+struct output_file *open_output_file(const char *filename, int gz, int sparse,
+        int chunks)
 {
        int ret;
        struct output_file *out = malloc(sizeof(struct output_file));
@@ -291,13 +285,17 @@ struct output_file *open_output_file(const char *filename, int gz, int sparse)
                        return NULL;
                }
        } else {
-               out->ops = &file_ops;
-               out->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-               if (out->fd < 0) {
-                       error_errno("open");
-                       free(out);
-                       return NULL;
+               if (strcmp(filename, "-")) {
+                       out->fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+                       if (out->fd < 0) {
+                               error_errno("open");
+                               free(out);
+                               return NULL;
+                       }
+               } else {
+                       out->fd = STDOUT_FILENO;
                }
+               out->ops = &file_ops;
        }
        out->sparse = sparse;
        out->cur_out_ptr = 0ll;
@@ -312,6 +310,7 @@ struct output_file *open_output_file(const char *filename, int gz, int sparse)
                 */
                sparse_header.blk_sz = info.block_size,
                sparse_header.total_blks = info.len / info.block_size,
+               sparse_header.total_chunks = chunks;
                ret = out->ops->write(out, (u8 *)&sparse_header, sizeof(sparse_header));
                if (ret < 0)
                        return NULL;
index 393bc9b..0ac707c 100644 (file)
@@ -19,7 +19,8 @@
 
 struct output_file;
 
-struct output_file *open_output_file(const char *filename, int gz, int sparse);
+struct output_file *open_output_file(const char *filename, int gz, int sparse,
+        int chunks);
 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);