summaryrefslogtreecommitdiff
path: root/ext4_utils
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2010-06-20 23:57:06 -0700
committerColin Cross <ccross@android.com>2010-06-29 14:43:32 -0700
commit881cca2f88ddcce86483b3ba95546b5641de8c0e (patch)
treed8e920c1d2871f8239b5a215a47e24681eccc80d /ext4_utils
parent8aef66d2125af8de7672a12895276802fcc1948f (diff)
downloadextras-881cca2f88ddcce86483b3ba95546b5641de8c0e.tar.gz
Split out libext4_utils
Change-Id: I12aa52b75607379add2669fddba4cd7dc2bb527f
Diffstat (limited to 'ext4_utils')
-rw-r--r--ext4_utils/Android.mk34
-rw-r--r--ext4_utils/allocate.c1
-rw-r--r--ext4_utils/ext4_utils.c391
-rw-r--r--ext4_utils/ext4_utils.h11
-rw-r--r--ext4_utils/ext_utils.c49
-rw-r--r--ext4_utils/ext_utils.h24
-rw-r--r--ext4_utils/make_ext4fs.c352
7 files changed, 434 insertions, 428 deletions
diff --git a/ext4_utils/Android.mk b/ext4_utils/Android.mk
index 819e6345..08e59f57 100644
--- a/ext4_utils/Android.mk
+++ b/ext4_utils/Android.mk
@@ -3,9 +3,8 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-make_ext4fs_src_files := \
- make_ext4fs.c \
- ext_utils.c \
+libext4_utils_src_files := \
+ ext4_utils.c \
allocate.c \
backed_block.c \
output_file.c \
@@ -15,18 +14,37 @@ make_ext4fs_src_files := \
uuid.c \
sha1.c \
-LOCAL_SRC_FILES := $(make_ext4fs_src_files)
-LOCAL_MODULE := make_ext4fs
+LOCAL_SRC_FILES := $(libext4_utils_src_files)
+LOCAL_MODULE := libext4_utils
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES += external/zlib
-LOCAL_SHARED_LIBRARIES += libz
+LOCAL_SHARED_LIBRARIES := libz
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(libext4_utils_src_files)
+LOCAL_MODULE := libext4_utils
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES := libz
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := make_ext4fs.c
+LOCAL_MODULE := make_ext4fs
+LOCAL_MODULE_TAGS := optional
+LOCAL_SHARED_LIBRARIES += libext4_utils libz
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(make_ext4fs_src_files)
+LOCAL_SRC_FILES := make_ext4fs.c
LOCAL_MODULE := make_ext4fs
-LOCAL_STATIC_LIBRARIES += libz
+LOCAL_STATIC_LIBRARIES += libext4_utils libz
include $(BUILD_HOST_EXECUTABLE)
diff --git a/ext4_utils/allocate.c b/ext4_utils/allocate.c
index 61c1be10..20ba1548 100644
--- a/ext4_utils/allocate.c
+++ b/ext4_utils/allocate.c
@@ -20,7 +20,6 @@
#include "ext4_utils.h"
#include "allocate.h"
#include "backed_block.h"
-#include "ext_utils.h"
#include "ext4.h"
struct region_list {
diff --git a/ext4_utils/ext4_utils.c b/ext4_utils/ext4_utils.c
new file mode 100644
index 00000000..cd82827a
--- /dev/null
+++ b/ext4_utils/ext4_utils.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ext4_utils.h"
+#include "output_file.h"
+#include "backed_block.h"
+#include "uuid.h"
+#include "allocate.h"
+#include "indirect.h"
+#include "extent.h"
+
+#include "ext4.h"
+#include "jbd2.h"
+
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#if defined(__linux__)
+#include <linux/fs.h>
+#elif defined(__APPLE__) && defined(__MACH__)
+#include <sys/disk.h>
+#endif
+
+int force = 0;
+struct fs_info info;
+struct fs_aux_info aux_info;
+
+/* returns 1 if a is a power of b */
+static int is_power_of(int a, int b)
+{
+ while (a > b) {
+ if (a % b)
+ return 0;
+ a /= b;
+ }
+
+ return (a == b) ? 1 : 0;
+}
+
+/* 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
+ superblocks */
+int ext4_bg_has_super_block(int bg)
+{
+ /* Without sparse_super, every block group has a superblock */
+ if (!(info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
+ return 1;
+
+ if (bg == 0 || bg == 1)
+ return 1;
+
+ if (is_power_of(bg, 3) || is_power_of(bg, 5) || is_power_of(bg, 7))
+ return 1;
+
+ return 0;
+}
+
+/* Write the filesystem image to a file */
+void write_ext4_image(const char *filename, int gz)
+{
+ int ret = 0;
+ struct output_file *out = open_output_file(filename, gz);
+ off_t off;
+
+ if (!out)
+ return;
+
+ write_data_block(out, 1024, (u8*)aux_info.sb, 1024);
+
+ write_data_block(out, (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);
+
+ write_data_block(out, info.len - 1, (u8*)"", 1);
+
+ close_output_file(out);
+}
+
+/* Compute the rest of the parameters of the filesystem from the basic info */
+void ext4_create_fs_aux_info()
+{
+ aux_info.first_data_block = (info.block_size > 1024) ? 0 : 1;
+ aux_info.len_blocks = info.len / info.block_size;
+ aux_info.inode_table_blocks = DIV_ROUND_UP(info.inodes_per_group * info.inode_size,
+ info.block_size);
+ aux_info.groups = DIV_ROUND_UP(aux_info.len_blocks - aux_info.first_data_block,
+ info.blocks_per_group);
+ aux_info.blocks_per_ind = info.block_size / sizeof(u32);
+ aux_info.blocks_per_dind = aux_info.blocks_per_ind * aux_info.blocks_per_ind;
+ aux_info.blocks_per_tind = aux_info.blocks_per_dind * aux_info.blocks_per_dind;
+
+ aux_info.bg_desc_blocks =
+ DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc),
+ info.block_size);
+
+ aux_info.bg_desc_reserve_blocks =
+ DIV_ROUND_UP(aux_info.groups * 1024 * sizeof(struct ext2_group_desc),
+ info.block_size) - aux_info.bg_desc_blocks;
+
+ if (aux_info.bg_desc_reserve_blocks > aux_info.blocks_per_ind)
+ aux_info.bg_desc_reserve_blocks = aux_info.blocks_per_ind;
+
+ aux_info.default_i_flags = EXT4_NOATIME_FL;
+
+ u32 last_group_size = aux_info.len_blocks % info.blocks_per_group;
+ u32 last_header_size = 2 + aux_info.inode_table_blocks;
+ if (ext4_bg_has_super_block(aux_info.groups - 1))
+ last_header_size += 1 + aux_info.bg_desc_blocks +
+ aux_info.bg_desc_reserve_blocks;
+ if (last_group_size > 0 && last_group_size < last_header_size) {
+ aux_info.groups--;
+ aux_info.len_blocks -= last_group_size;
+ }
+
+ aux_info.sb = calloc(info.block_size, 1);
+ if (!aux_info.sb)
+ critical_error_errno("calloc");
+
+ aux_info.bg_desc = calloc(info.block_size, aux_info.bg_desc_blocks);
+ if (!aux_info.bg_desc)
+ critical_error_errno("calloc");
+}
+
+void ext4_free_fs_aux_info()
+{
+ free(aux_info.sb);
+ free(aux_info.bg_desc);
+}
+
+/* Fill in the superblock memory buffer based on the filesystem parameters */
+void ext4_fill_in_sb()
+{
+ unsigned int i;
+ struct ext4_super_block *sb = aux_info.sb;
+
+ sb->s_inodes_count = info.inodes_per_group * aux_info.groups;
+ sb->s_blocks_count_lo = aux_info.len_blocks;
+ sb->s_r_blocks_count_lo = 0;
+ sb->s_free_blocks_count_lo = 0;
+ sb->s_free_inodes_count = 0;
+ sb->s_first_data_block = aux_info.first_data_block;
+ sb->s_log_block_size = log_2(info.block_size / 1024);
+ sb->s_obso_log_frag_size = log_2(info.block_size / 1024);
+ sb->s_blocks_per_group = info.blocks_per_group;
+ sb->s_obso_frags_per_group = info.blocks_per_group;
+ sb->s_inodes_per_group = info.inodes_per_group;
+ sb->s_mtime = 0;
+ sb->s_wtime = 0;
+ sb->s_mnt_count = 0;
+ sb->s_max_mnt_count = 0xFFFF;
+ sb->s_magic = EXT4_SUPER_MAGIC;
+ sb->s_state = EXT4_VALID_FS;
+ sb->s_errors = EXT4_ERRORS_RO;
+ sb->s_minor_rev_level = 0;
+ sb->s_lastcheck = 0;
+ sb->s_checkinterval = 0;
+ sb->s_creator_os = EXT4_OS_LINUX;
+ sb->s_rev_level = EXT4_DYNAMIC_REV;
+ sb->s_def_resuid = EXT4_DEF_RESUID;
+ sb->s_def_resgid = EXT4_DEF_RESGID;
+
+ sb->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
+ sb->s_inode_size = info.inode_size;
+ sb->s_block_group_nr = 0;
+ sb->s_feature_compat = info.feat_compat;
+ sb->s_feature_incompat = info.feat_incompat;
+ sb->s_feature_ro_compat = info.feat_ro_compat;
+ generate_uuid("extandroid/make_ext4fs", info.label, sb->s_uuid);
+ memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
+ strncpy(sb->s_volume_name, info.label, sizeof(sb->s_volume_name));
+ memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
+ sb->s_algorithm_usage_bitmap = 0;
+
+ sb->s_reserved_gdt_blocks = aux_info.bg_desc_reserve_blocks;
+ sb->s_prealloc_blocks = 0;
+ sb->s_prealloc_dir_blocks = 0;
+
+ //memcpy(sb->s_journal_uuid, sb->s_uuid, sizeof(sb->s_journal_uuid));
+ if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
+ sb->s_journal_inum = EXT4_JOURNAL_INO;
+ sb->s_journal_dev = 0;
+ sb->s_last_orphan = 0;
+ sb->s_hash_seed[0] = 0; /* FIXME */
+ sb->s_def_hash_version = DX_HASH_TEA;
+ sb->s_reserved_char_pad = EXT4_JNL_BACKUP_BLOCKS;
+ sb->s_desc_size = sizeof(struct ext2_group_desc);
+ sb->s_default_mount_opts = 0; /* FIXME */
+ sb->s_first_meta_bg = 0;
+ sb->s_mkfs_time = 0;
+ //sb->s_jnl_blocks[17]; /* FIXME */
+
+ sb->s_blocks_count_hi = aux_info.len_blocks >> 32;
+ sb->s_r_blocks_count_hi = 0;
+ sb->s_free_blocks_count_hi = 0;
+ sb->s_min_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ sb->s_want_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ sb->s_flags = 0;
+ sb->s_raid_stride = 0;
+ sb->s_mmp_interval = 0;
+ sb->s_mmp_block = 0;
+ sb->s_raid_stripe_width = 0;
+ sb->s_log_groups_per_flex = 0;
+ sb->s_kbytes_written = 0;
+
+ for (i = 0; i < aux_info.groups; i++) {
+ u64 group_start_block = aux_info.first_data_block + i *
+ info.blocks_per_group;
+ u32 header_size = 0;
+ if (ext4_bg_has_super_block(i)) {
+ 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);
+ }
+ header_size = 1 + aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks;
+ }
+
+ aux_info.bg_desc[i].bg_block_bitmap = group_start_block + header_size;
+ aux_info.bg_desc[i].bg_inode_bitmap = group_start_block + header_size + 1;
+ aux_info.bg_desc[i].bg_inode_table = group_start_block + header_size + 2;
+
+ aux_info.bg_desc[i].bg_free_blocks_count = sb->s_blocks_per_group;
+ aux_info.bg_desc[i].bg_free_inodes_count = sb->s_inodes_per_group;
+ aux_info.bg_desc[i].bg_used_dirs_count = 0;
+ }
+}
+
+void ext4_create_resize_inode()
+{
+ struct block_allocation *reserve_inode_alloc = create_allocation();
+ u32 reserve_inode_len = 0;
+ unsigned int i;
+
+ struct ext4_inode *inode = get_inode(EXT4_RESIZE_INO);
+ if (inode == NULL) {
+ error("failed to get resize inode");
+ return;
+ }
+
+ for (i = 0; i < aux_info.groups; i++) {
+ if (ext4_bg_has_super_block(i)) {
+ u64 group_start_block = aux_info.first_data_block + i *
+ info.blocks_per_group;
+ u32 reserved_block_start = group_start_block + 1 +
+ aux_info.bg_desc_blocks;
+ u32 reserved_block_len = aux_info.bg_desc_reserve_blocks;
+ append_region(reserve_inode_alloc, reserved_block_start,
+ reserved_block_len, i);
+ reserve_inode_len += reserved_block_len;
+ }
+ }
+
+ inode_attach_resize(inode, reserve_inode_alloc);
+
+ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+ inode->i_links_count = 1;
+
+ free_alloc(reserve_inode_alloc);
+}
+
+/* Allocate the blocks to hold a journal inode and connect them to the
+ reserved journal inode */
+void ext4_create_journal_inode()
+{
+ struct ext4_inode *inode = get_inode(EXT4_JOURNAL_INO);
+ if (inode == NULL) {
+ error("failed to get journal inode");
+ return;
+ }
+
+ u8 *journal_data = inode_allocate_data_extents(inode,
+ info.journal_blocks * info.block_size,
+ info.block_size);
+ if (!journal_data) {
+ error("failed to allocate extents for journal data");
+ return;
+ }
+
+ inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+ inode->i_links_count = 1;
+
+ journal_superblock_t *jsb = (journal_superblock_t *)journal_data;
+ jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER);
+ jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
+ jsb->s_blocksize = htonl(info.block_size);
+ jsb->s_maxlen = htonl(info.journal_blocks);
+ jsb->s_nr_users = htonl(1);
+ jsb->s_first = htonl(1);
+ jsb->s_sequence = htonl(1);
+
+ memcpy(aux_info.sb->s_jnl_blocks, &inode->i_block, sizeof(inode->i_block));
+}
+
+/* Update the number of free blocks and inodes in the filesystem and in each
+ block group */
+void ext4_update_free()
+{
+ unsigned int i;
+
+ for (i = 0; i < aux_info.groups; i++) {
+ u32 bg_free_blocks = get_free_blocks(i);
+ u32 bg_free_inodes = get_free_inodes(i);
+
+ aux_info.bg_desc[i].bg_free_blocks_count = bg_free_blocks;
+ aux_info.sb->s_free_blocks_count_lo += bg_free_blocks;
+
+ aux_info.bg_desc[i].bg_free_inodes_count = bg_free_inodes;
+ aux_info.sb->s_free_inodes_count += bg_free_inodes;
+
+ aux_info.bg_desc[i].bg_used_dirs_count += get_directories(i);
+ }
+}
+
+static u64 get_block_device_size(const char *filename)
+{
+ int fd = open(filename, O_RDONLY);
+ u64 size = 0;
+ int ret;
+
+ if (fd < 0)
+ return 0;
+
+#if defined(__linux__)
+ ret = ioctl(fd, BLKGETSIZE64, &size);
+#elif defined(__APPLE__) && defined(__MACH__)
+ ret = ioctl(fd, DKIOCGETBLOCKCOUNT, &size);
+#else
+ return 0;
+#endif
+
+ close(fd);
+
+ if (ret)
+ return 0;
+
+ return size;
+}
+
+u64 get_file_size(const char *filename)
+{
+ struct stat buf;
+ int ret;
+
+ ret = stat(filename, &buf);
+ if (ret)
+ return 0;
+
+ if (S_ISREG(buf.st_mode))
+ return buf.st_size;
+ else if (S_ISBLK(buf.st_mode))
+ return get_block_device_size(filename);
+ else
+ return 0;
+}
+
+u64 parse_num(const char *arg)
+{
+ char *endptr;
+ u64 num = strtoull(arg, &endptr, 10);
+ if (*endptr == 'k' || *endptr == 'K')
+ num *= 1024LL;
+ else if (*endptr == 'm' || *endptr == 'M')
+ num *= 1024LL * 1024LL;
+ else if (*endptr == 'g' || *endptr == 'G')
+ num *= 1024LL * 1024LL * 1024LL;
+
+ return num;
+}
+
diff --git a/ext4_utils/ext4_utils.h b/ext4_utils/ext4_utils.h
index 40c0676b..fe3ccd63 100644
--- a/ext4_utils/ext4_utils.h
+++ b/ext4_utils/ext4_utils.h
@@ -113,4 +113,15 @@ static inline int log_2(int j)
return i - 1;
}
+int ext4_bg_has_super_block(int bg);
+void write_ext4_image(const char *filename, int gz);
+void ext4_create_fs_aux_info(void);
+void ext4_free_fs_aux_info(void);
+void ext4_fill_in_sb(void);
+void ext4_create_resize_inode(void);
+void ext4_create_journal_inode(void);
+void ext4_update_free(void);
+u64 get_file_size(const char *filename);
+u64 parse_num(const char *arg);
+
#endif
diff --git a/ext4_utils/ext_utils.c b/ext4_utils/ext_utils.c
deleted file mode 100644
index c2764e1f..00000000
--- a/ext4_utils/ext_utils.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ext4_utils.h"
-#include "ext4.h"
-
-/* returns 1 if a is a power of b */
-static int is_power_of(int a, int b)
-{
- while (a > b) {
- if (a % b)
- return 0;
- a /= b;
- }
-
- return (a == b) ? 1 : 0;
-}
-
-/* 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
- superblocks */
-int ext4_bg_has_super_block(int bg)
-{
- /* Without sparse_super, every block group has a superblock */
- if (!(info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
- return 1;
-
- if (bg == 0 || bg == 1)
- return 1;
-
- if (is_power_of(bg, 3) || is_power_of(bg, 5) || is_power_of(bg, 7))
- return 1;
-
- return 0;
-}
diff --git a/ext4_utils/ext_utils.h b/ext4_utils/ext_utils.h
deleted file mode 100644
index eacd3a1b..00000000
--- a/ext4_utils/ext_utils.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _EXT_UTILS_H_
-#define _EXT_UTILS_H_
-
-#include "ext4.h"
-
-int ext4_bg_has_super_block(int bg);
-
-#endif
diff --git a/ext4_utils/make_ext4fs.c b/ext4_utils/make_ext4fs.c
index e69b11f9..347943b7 100644
--- a/ext4_utils/make_ext4fs.c
+++ b/ext4_utils/make_ext4fs.c
@@ -16,40 +16,22 @@
#define _GNU_SOURCE
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <limits.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <strings.h>
-#include <string.h>
-#include <stdio.h>
#include <dirent.h>
#include <libgen.h>
-
-#if defined(__linux__)
-#include <linux/fs.h>
-#elif defined(__APPLE__) && defined(__MACH__)
-#include <sys/disk.h>
-#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "make_ext4fs.h"
#include "output_file.h"
#include "ext4_utils.h"
#include "allocate.h"
-#include "ext_utils.h"
-#include "backed_block.h"
#include "contents.h"
-#include "extent.h"
-#include "indirect.h"
#include "uuid.h"
-#include "jbd2.h"
-#include "ext4.h"
-
#ifdef ANDROID
#include <private/android_filesystem_config.h>
#endif
@@ -60,272 +42,6 @@
Special files: sockets, devices, fifos
*/
-int force = 0;
-
-struct fs_info info;
-struct fs_aux_info aux_info;
-
-/* Write the filesystem image to a file */
-static void write_ext4_image(const char *filename, int gz)
-{
- int ret = 0;
- struct output_file *out = open_output_file(filename, gz);
- off_t off;
-
- if (!out)
- return;
-
- write_data_block(out, 1024, (u8*)aux_info.sb, 1024);
-
- write_data_block(out, (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);
-
- write_data_block(out, info.len - 1, (u8*)"", 1);
-
- close_output_file(out);
-}
-
-/* Compute the rest of the parameters of the filesystem from the basic info */
-static void ext4_create_fs_aux_info()
-{
- aux_info.first_data_block = (info.block_size > 1024) ? 0 : 1;
- aux_info.len_blocks = info.len / info.block_size;
- aux_info.inode_table_blocks = DIV_ROUND_UP(info.inodes_per_group * info.inode_size,
- info.block_size);
- aux_info.groups = DIV_ROUND_UP(aux_info.len_blocks - aux_info.first_data_block,
- info.blocks_per_group);
- aux_info.blocks_per_ind = info.block_size / sizeof(u32);
- aux_info.blocks_per_dind = aux_info.blocks_per_ind * aux_info.blocks_per_ind;
- aux_info.blocks_per_tind = aux_info.blocks_per_dind * aux_info.blocks_per_dind;
-
- aux_info.bg_desc_blocks =
- DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc),
- info.block_size);
-
- aux_info.bg_desc_reserve_blocks =
- DIV_ROUND_UP(aux_info.groups * 1024 * sizeof(struct ext2_group_desc),
- info.block_size) - aux_info.bg_desc_blocks;
-
- if (aux_info.bg_desc_reserve_blocks > aux_info.blocks_per_ind)
- aux_info.bg_desc_reserve_blocks = aux_info.blocks_per_ind;
-
- aux_info.default_i_flags = EXT4_NOATIME_FL;
-
- u32 last_group_size = aux_info.len_blocks % info.blocks_per_group;
- u32 last_header_size = 2 + aux_info.inode_table_blocks;
- if (ext4_bg_has_super_block(aux_info.groups - 1))
- last_header_size += 1 + aux_info.bg_desc_blocks +
- aux_info.bg_desc_reserve_blocks;
- if (last_group_size > 0 && last_group_size < last_header_size) {
- aux_info.groups--;
- aux_info.len_blocks -= last_group_size;
- }
-
- aux_info.sb = calloc(info.block_size, 1);
- if (!aux_info.sb)
- critical_error_errno("calloc");
-
- aux_info.bg_desc = calloc(info.block_size, aux_info.bg_desc_blocks);
- if (!aux_info.bg_desc)
- critical_error_errno("calloc");
-}
-
-void ext4_free_fs_aux_info()
-{
- free(aux_info.sb);
- free(aux_info.bg_desc);
-}
-
-/* Fill in the superblock memory buffer based on the filesystem parameters */
-static void ext4_fill_in_sb()
-{
- unsigned int i;
- struct ext4_super_block *sb = aux_info.sb;
-
- sb->s_inodes_count = info.inodes_per_group * aux_info.groups;
- sb->s_blocks_count_lo = aux_info.len_blocks;
- sb->s_r_blocks_count_lo = 0;
- sb->s_free_blocks_count_lo = 0;
- sb->s_free_inodes_count = 0;
- sb->s_first_data_block = aux_info.first_data_block;
- sb->s_log_block_size = log_2(info.block_size / 1024);
- sb->s_obso_log_frag_size = log_2(info.block_size / 1024);
- sb->s_blocks_per_group = info.blocks_per_group;
- sb->s_obso_frags_per_group = info.blocks_per_group;
- sb->s_inodes_per_group = info.inodes_per_group;
- sb->s_mtime = 0;
- sb->s_wtime = 0;
- sb->s_mnt_count = 0;
- sb->s_max_mnt_count = 0xFFFF;
- sb->s_magic = EXT4_SUPER_MAGIC;
- sb->s_state = EXT4_VALID_FS;
- sb->s_errors = EXT4_ERRORS_RO;
- sb->s_minor_rev_level = 0;
- sb->s_lastcheck = 0;
- sb->s_checkinterval = 0;
- sb->s_creator_os = EXT4_OS_LINUX;
- sb->s_rev_level = EXT4_DYNAMIC_REV;
- sb->s_def_resuid = EXT4_DEF_RESUID;
- sb->s_def_resgid = EXT4_DEF_RESGID;
-
- sb->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
- sb->s_inode_size = info.inode_size;
- sb->s_block_group_nr = 0;
- sb->s_feature_compat = info.feat_compat;
- sb->s_feature_incompat = info.feat_incompat;
- sb->s_feature_ro_compat = info.feat_ro_compat;
- generate_uuid("extandroid/make_ext4fs", info.label, sb->s_uuid);
- memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
- strncpy(sb->s_volume_name, info.label, sizeof(sb->s_volume_name));
- memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
- sb->s_algorithm_usage_bitmap = 0;
-
- sb->s_reserved_gdt_blocks = aux_info.bg_desc_reserve_blocks;
- sb->s_prealloc_blocks = 0;
- sb->s_prealloc_dir_blocks = 0;
-
- //memcpy(sb->s_journal_uuid, sb->s_uuid, sizeof(sb->s_journal_uuid));
- if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
- sb->s_journal_inum = EXT4_JOURNAL_INO;
- sb->s_journal_dev = 0;
- sb->s_last_orphan = 0;
- sb->s_hash_seed[0] = 0; /* FIXME */
- sb->s_def_hash_version = DX_HASH_TEA;
- sb->s_reserved_char_pad = EXT4_JNL_BACKUP_BLOCKS;
- sb->s_desc_size = sizeof(struct ext2_group_desc);
- sb->s_default_mount_opts = 0; /* FIXME */
- sb->s_first_meta_bg = 0;
- sb->s_mkfs_time = 0;
- //sb->s_jnl_blocks[17]; /* FIXME */
-
- sb->s_blocks_count_hi = aux_info.len_blocks >> 32;
- sb->s_r_blocks_count_hi = 0;
- sb->s_free_blocks_count_hi = 0;
- sb->s_min_extra_isize = sizeof(struct ext4_inode) -
- EXT4_GOOD_OLD_INODE_SIZE;
- sb->s_want_extra_isize = sizeof(struct ext4_inode) -
- EXT4_GOOD_OLD_INODE_SIZE;
- sb->s_flags = 0;
- sb->s_raid_stride = 0;
- sb->s_mmp_interval = 0;
- sb->s_mmp_block = 0;
- sb->s_raid_stripe_width = 0;
- sb->s_log_groups_per_flex = 0;
- sb->s_kbytes_written = 0;
-
- for (i = 0; i < aux_info.groups; i++) {
- u64 group_start_block = aux_info.first_data_block + i *
- info.blocks_per_group;
- u32 header_size = 0;
- if (ext4_bg_has_super_block(i)) {
- 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);
- }
- header_size = 1 + aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks;
- }
-
- aux_info.bg_desc[i].bg_block_bitmap = group_start_block + header_size;
- aux_info.bg_desc[i].bg_inode_bitmap = group_start_block + header_size + 1;
- aux_info.bg_desc[i].bg_inode_table = group_start_block + header_size + 2;
-
- aux_info.bg_desc[i].bg_free_blocks_count = sb->s_blocks_per_group;
- aux_info.bg_desc[i].bg_free_inodes_count = sb->s_inodes_per_group;
- aux_info.bg_desc[i].bg_used_dirs_count = 0;
- }
-}
-
-static void ext4_create_resize_inode()
-{
- struct block_allocation *reserve_inode_alloc = create_allocation();
- u32 reserve_inode_len = 0;
- unsigned int i;
-
- struct ext4_inode *inode = get_inode(EXT4_RESIZE_INO);
- if (inode == NULL) {
- error("failed to get resize inode");
- return;
- }
-
- for (i = 0; i < aux_info.groups; i++) {
- if (ext4_bg_has_super_block(i)) {
- u64 group_start_block = aux_info.first_data_block + i *
- info.blocks_per_group;
- u32 reserved_block_start = group_start_block + 1 +
- aux_info.bg_desc_blocks;
- u32 reserved_block_len = aux_info.bg_desc_reserve_blocks;
- append_region(reserve_inode_alloc, reserved_block_start,
- reserved_block_len, i);
- reserve_inode_len += reserved_block_len;
- }
- }
-
- inode_attach_resize(inode, reserve_inode_alloc);
-
- inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
- inode->i_links_count = 1;
-
- free_alloc(reserve_inode_alloc);
-}
-
-/* Allocate the blocks to hold a journal inode and connect them to the
- reserved journal inode */
-static void ext4_create_journal_inode()
-{
- struct ext4_inode *inode = get_inode(EXT4_JOURNAL_INO);
- if (inode == NULL) {
- error("failed to get journal inode");
- return;
- }
-
- u8 *journal_data = inode_allocate_data_extents(inode,
- info.journal_blocks * info.block_size,
- info.block_size);
- if (!journal_data) {
- error("failed to allocate extents for journal data");
- return;
- }
-
- inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
- inode->i_links_count = 1;
-
- journal_superblock_t *jsb = (journal_superblock_t *)journal_data;
- jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER);
- jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
- jsb->s_blocksize = htonl(info.block_size);
- jsb->s_maxlen = htonl(info.journal_blocks);
- jsb->s_nr_users = htonl(1);
- jsb->s_first = htonl(1);
- jsb->s_sequence = htonl(1);
-
- memcpy(aux_info.sb->s_jnl_blocks, &inode->i_block, sizeof(inode->i_block));
-}
-
-/* Update the number of free blocks and inodes in the filesystem and in each
- block group */
-static void ext4_update_free()
-{
- unsigned int i;
-
- for (i = 0; i < aux_info.groups; i++) {
- u32 bg_free_blocks = get_free_blocks(i);
- u32 bg_free_inodes = get_free_inodes(i);
-
- aux_info.bg_desc[i].bg_free_blocks_count = bg_free_blocks;
- aux_info.sb->s_free_blocks_count_lo += bg_free_blocks;
-
- aux_info.bg_desc[i].bg_free_inodes_count = bg_free_inodes;
- aux_info.sb->s_free_inodes_count += bg_free_inodes;
-
- aux_info.bg_desc[i].bg_used_dirs_count += get_directories(i);
- }
-}
-
static int filter_dot(const struct dirent *d)
{
return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
@@ -487,48 +203,6 @@ static u32 compute_inodes_per_group()
return DIV_ROUND_UP(info.inodes, block_groups);
}
-static u64 get_block_device_size(const char *filename)
-{
- int fd = open(filename, O_RDONLY);
- u64 size = 0;
- int ret;
-
- if (fd < 0)
- return 0;
-
-#if defined(__linux__)
- ret = ioctl(fd, BLKGETSIZE64, &size);
-#elif defined(__APPLE__) && defined(__MACH__)
- ret = ioctl(fd, DKIOCGETBLOCKCOUNT, &size);
-#else
- return 0;
-#endif
-
- close(fd);
-
- if (ret)
- return 0;
-
- return size;
-}
-
-static u64 get_file_size(const char *filename)
-{
- struct stat buf;
- int ret;
-
- ret = stat(filename, &buf);
- if (ret)
- return 0;
-
- if (S_ISREG(buf.st_mode))
- return buf.st_size;
- else if (S_ISBLK(buf.st_mode))
- return get_block_device_size(filename);
- else
- return 0;
-}
-
static void usage(char *path)
{
fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
@@ -537,20 +211,6 @@ static void usage(char *path)
fprintf(stderr, " <filename> [<directory>]\n");
}
-static u64 parse_num(const char *arg)
-{
- char *endptr;
- u64 num = strtoull(arg, &endptr, 10);
- if (*endptr == 'k' || *endptr == 'K')
- num *= 1024LL;
- else if (*endptr == 'm' || *endptr == 'M')
- num *= 1024LL * 1024LL;
- else if (*endptr == 'g' || *endptr == 'G')
- num *= 1024LL * 1024LL * 1024LL;
-
- return num;
-}
-
int main(int argc, char **argv)
{
int opt;