ext4 utils: Refactor read_ext, and expose some of the functions

Make read_ext an externally useable function. Use case is to
enable fast encryption by being able to look at whether each block
is in use or not.

Bug: 11985952
Change-Id: Ief71f408a55db7261c75ebe974620415ed8cfd29
diff --git a/ext4_utils/ext2simg.c b/ext4_utils/ext2simg.c
index 7b63836..6406729 100644
--- a/ext4_utils/ext2simg.c
+++ b/ext4_utils/ext2simg.c
@@ -53,66 +53,6 @@
 	fprintf(stderr, "  -S don't use sparse output format\n");
 }
 
-static int read_ext(int fd)
-{
-	off64_t ret;
-	struct ext4_super_block sb;
-
-	ret = lseek64(fd, 1024, SEEK_SET);
-	if (ret < 0)
-		critical_error_errno("failed to seek to superblock");
-
-	ret = read(fd, &sb, sizeof(sb));
-	if (ret < 0)
-		critical_error_errno("failed to read superblock");
-	if (ret != sizeof(sb))
-		critical_error("failed to read all of superblock");
-
-	ext4_parse_sb(&sb);
-
-	ret = lseek64(fd, info.len, SEEK_SET);
-	if (ret < 0)
-		critical_error_errno("failed to seek to end of input image");
-
-	ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
-	if (ret < 0)
-		critical_error_errno("failed to seek to block group descriptors");
-
-	ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
-	if (ret < 0)
-		critical_error_errno("failed to read block group descriptors");
-	if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
-		critical_error("failed to read all of block group descriptors");
-
-	if (verbose) {
-		printf("Found filesystem with parameters:\n");
-		printf("    Size: %llu\n", info.len);
-		printf("    Block size: %d\n", info.block_size);
-		printf("    Blocks per group: %d\n", info.blocks_per_group);
-		printf("    Inodes per group: %d\n", info.inodes_per_group);
-		printf("    Inode size: %d\n", info.inode_size);
-		printf("    Label: %s\n", info.label);
-		printf("    Blocks: %llu\n", aux_info.len_blocks);
-		printf("    Block groups: %d\n", aux_info.groups);
-		printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
-		printf("    Used %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,
-				aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
-				aux_info.sb->s_blocks_count_lo);
-	}
-
-	return 0;
-}
-
-static int bitmap_get_bit(u8 *bitmap, u32 bit)
-{
-	if (bitmap[bit / 8] & 1 << (bit % 8))
-		return 1;
-
-	return 0;
-}
-
 static int build_sparse_ext(int fd, const char *filename)
 {
 	unsigned int i;
@@ -228,7 +168,7 @@
 	if (infd < 0)
 		critical_error_errno("failed to open input image");
 
-	read_ext(infd);
+	read_ext(infd, verbose);
 
 	info.sparse_file = sparse_file_new(info.block_size, info.len);
 
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
index d4fbc7c..1b70afe 100644
--- a/ext4_utils/ext4_utils.c
+++ b/ext4_utils/ext4_utils.c
@@ -62,6 +62,21 @@
 	return (a == b) ? 1 : 0;
 }
 
+int bitmap_get_bit(u8 *bitmap, u32 bit)
+{
+	if (bitmap[bit / 8] & (1 << (bit % 8)))
+		return 1;
+
+	return 0;
+}
+
+void bitmap_clear_bit(u8 *bitmap, u32 bit)
+{
+	bitmap[bit / 8] &= ~(1 << (bit % 8));
+
+	return;
+}
+
 /* Returns 1 if the bg contains a backup superblock.  On filesystems with
    the sparse_super feature, only block groups 0, 1, and powers of 3, 5,
    and 7 have backup superblocks.  Otherwise, all block groups have backup
@@ -81,6 +96,38 @@
 	return 0;
 }
 
+/* Function to read the primary superblock */
+void read_sb(int fd, struct ext4_super_block *sb)
+{
+	off64_t ret;
+
+	ret = lseek64(fd, 1024, SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to superblock");
+
+	ret = read(fd, sb, sizeof(*sb));
+	if (ret < 0)
+		critical_error_errno("failed to read superblock");
+	if (ret != sizeof(*sb))
+		critical_error("failed to read all of superblock");
+}
+
+/* Function to write a primary or backup superblock at a given offset */
+void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb)
+{
+	off64_t ret;
+
+	ret = lseek64(fd, offset, SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to superblock");
+
+	ret = write(fd, sb, sizeof(*sb));
+	if (ret < 0)
+		critical_error_errno("failed to write superblock");
+	if (ret != sizeof(*sb))
+		critical_error("failed to write all of superblock");
+}
+
 /* Write the filesystem image to a file */
 void write_ext4_image(int fd, int gz, int sparse, int crc)
 {
@@ -450,3 +497,48 @@
 
 	return num;
 }
+
+int read_ext(int fd, int verbose)
+{
+	off64_t ret;
+	struct ext4_super_block sb;
+
+	read_sb(fd, &sb);
+
+	ext4_parse_sb(&sb);
+
+	ret = lseek64(fd, info.len, SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to end of input image");
+
+	ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to block group descriptors");
+
+	ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
+	if (ret < 0)
+		critical_error_errno("failed to read block group descriptors");
+	if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
+		critical_error("failed to read all of block group descriptors");
+
+	if (verbose) {
+		printf("Found filesystem with parameters:\n");
+		printf("    Size: %llu\n", info.len);
+		printf("    Block size: %d\n", info.block_size);
+		printf("    Blocks per group: %d\n", info.blocks_per_group);
+		printf("    Inodes per group: %d\n", info.inodes_per_group);
+		printf("    Inode size: %d\n", info.inode_size);
+		printf("    Label: %s\n", info.label);
+		printf("    Blocks: %llu\n", aux_info.len_blocks);
+		printf("    Block groups: %d\n", aux_info.groups);
+		printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
+		printf("    Used %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,
+			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
+			aux_info.sb->s_blocks_count_lo);
+	}
+
+	return 0;
+}
+
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index 1e13a90..7f96ac2 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -156,7 +156,11 @@
 	return i - 1;
 }
 
+int bitmap_get_bit(u8 *bitmap, u32 bit);
+void bitmap_clear_bit(u8 *bitmap, u32 bit);
 int ext4_bg_has_super_block(int bg);
+void read_sb(int fd, struct ext4_super_block *sb);
+void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb);
 void write_ext4_image(int fd, int gz, int sparse, int crc);
 void ext4_create_fs_aux_info(void);
 void ext4_free_fs_aux_info(void);
@@ -181,6 +185,8 @@
 						 int sparse, int crc, int wipe,
 						 struct selabel_handle *sehnd, int verbose, time_t fixed_time);
 
+int read_ext(int fd, int verbose);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/ext4_utils/ext4fixup.c b/ext4_utils/ext4fixup.c
index d271116..0e51765 100644
--- a/ext4_utils/ext4fixup.c
+++ b/ext4_utils/ext4fixup.c
@@ -83,42 +83,6 @@
     return (group * new_inodes_per_group) + offset + 1;
 }
 
-/* Function to read the primary superblock */
-static void read_sb(int fd, struct ext4_super_block *sb)
-{
-    off64_t ret;
-
-    ret = lseek64(fd, 1024, SEEK_SET);
-    if (ret < 0)
-        critical_error_errno("failed to seek to superblock");
-
-    ret = read(fd, sb, sizeof(*sb));
-    if (ret < 0)
-        critical_error_errno("failed to read superblock");
-    if (ret != sizeof(*sb))
-        critical_error("failed to read all of superblock");
-}
-
-/* Function to write a primary or backup superblock at a given offset */
-static void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb)
-{
-    off64_t ret;
-
-    if (no_write) {
-        return;
-    }
-
-    ret = lseek64(fd, offset, SEEK_SET);
-    if (ret < 0)
-        critical_error_errno("failed to seek to superblock");
-
-    ret = write(fd, sb, sizeof(*sb));
-    if (ret < 0)
-        critical_error_errno("failed to write superblock");
-    if (ret != sizeof(*sb))
-        critical_error("failed to write all of superblock");
-}
-
 static int get_fs_fixup_state(int fd)
 {
     unsigned long long magic;
@@ -191,64 +155,9 @@
         /* we are done, so make the filesystem mountable again */
         sb.s_desc_size &= ~1;
     }
-    write_sb(fd, 1024, &sb);
 
-    return 0;
-}
-
-static int read_ext(int fd)
-{
-    off64_t ret;
-    struct ext4_super_block sb;
-
-    read_sb(fd, &sb);
-
-    ext4_parse_sb(&sb);
-
-    if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) {
-        critical_error("Filesystem needs recovery first, mount and unmount to do that\n");
-    }
-
-    /* Clear the low bit which is set while this tool is in progress.
-     * If the tool crashes, it will still be set when we restart.
-     * The low bit is set to make the filesystem unmountable while
-     * it is being fixed up.  Also allow 0, which means the old ext2
-     * size is in use.
-     */
-    if (((sb.s_desc_size & ~1) != sizeof(struct ext2_group_desc)) &&
-        ((sb.s_desc_size & ~1) != 0))
-        critical_error("error: bg_desc_size != sizeof(struct ext2_group_desc)\n");
-
-    ret = lseek64(fd, info.len, SEEK_SET);
-    if (ret < 0)
-        critical_error_errno("failed to seek to end of input image");
-
-    ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
-    if (ret < 0)
-        critical_error_errno("failed to seek to block group descriptors");
-
-    ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
-    if (ret < 0)
-        critical_error_errno("failed to read block group descriptors");
-    if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
-        critical_error("failed to read all of block group descriptors");
-
-    if (verbose) {
-        printf("Found filesystem with parameters:\n");
-        printf("    Size: %llu\n", info.len);
-        printf("    Block size: %d\n", info.block_size);
-        printf("    Blocks per group: %d\n", info.blocks_per_group);
-        printf("    Inodes per group: %d\n", info.inodes_per_group);
-        printf("    Inode size: %d\n", info.inode_size);
-        printf("    Label: %s\n", info.label);
-        printf("    Blocks: %llu\n", aux_info.len_blocks);
-        printf("    Block groups: %d\n", aux_info.groups);
-        printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
-        printf("    Used %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,
-                aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
-                aux_info.sb->s_blocks_count_lo);
+    if (!no_write) {
+        write_sb(fd, 1024, &sb);
     }
 
     return 0;
@@ -320,21 +229,6 @@
     return 0;
 }
 
-static int bitmap_get_bit(u8 *bitmap, u32 bit)
-{
-        if (bitmap[bit / 8] & (1 << (bit % 8)))
-                return 1;
-
-        return 0;
-}
-
-static void bitmap_clear_bit(u8 *bitmap, u32 bit)
-{
-        bitmap[bit / 8] &= ~(1 << (bit % 8));
-
-        return;
-}
-
 static void check_inode_bitmap(int fd, unsigned int bg_num)
 {
     unsigned int inode_bitmap_block_num;
@@ -425,7 +319,13 @@
                 sb.s_desc_size &= ~1;
             }
 
-            write_sb(fd, (unsigned long long)i * info.blocks_per_group * info.block_size + sb_offset, &sb);
+            if (!no_write) {
+                write_sb(fd,
+                         (unsigned long long)i
+                         * info.blocks_per_group * info.block_size
+                         + sb_offset,
+                         &sb);
+            }
 
             ret = lseek64(fd, ((unsigned long long)i * info.blocks_per_group * info.block_size) +
                               (info.block_size * (aux_info.first_data_block + 1)), SEEK_SET);
@@ -805,7 +705,21 @@
     if (fd < 0)
         critical_error_errno("failed to open filesystem image");
 
-    read_ext(fd);
+    read_ext(fd, verbose);
+
+    if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) {
+        critical_error("Filesystem needs recovery first, mount and unmount to do that\n");
+    }
+
+    /* Clear the low bit which is set while this tool is in progress.
+     * If the tool crashes, it will still be set when we restart.
+     * The low bit is set to make the filesystem unmountable while
+     * it is being fixed up.  Also allow 0, which means the old ext2
+     * size is in use.
+     */
+    if (((aux_info.sb->s_desc_size & ~1) != sizeof(struct ext2_group_desc)) &&
+        ((aux_info.sb->s_desc_size & ~1) != 0))
+        critical_error("error: bg_desc_size != sizeof(struct ext2_group_desc)\n");
 
     if ((info.feat_incompat & EXT4_FEATURE_INCOMPAT_FILETYPE) == 0) {
         critical_error("Expected filesystem to have filetype flag set\n");