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/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;
+}
+