Home | History | Annotate | Download | only in ext4_utils
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <fcntl.h>
     18 #include <arpa/inet.h>
     19 #include <sys/ioctl.h>
     20 #include <sys/stat.h>
     21 #include <sys/types.h>
     22 #include <string.h>
     23 
     24 #if defined(__linux__)
     25 #include <linux/fs.h>
     26 #elif defined(__APPLE__) && defined(__MACH__)
     27 #include <sys/disk.h>
     28 #endif
     29 
     30 #include "ext4_utils.h"
     31 #include "output_file.h"
     32 #include "backed_block.h"
     33 #include "uuid.h"
     34 #include "allocate.h"
     35 #include "indirect.h"
     36 #include "extent.h"
     37 
     38 #include "ext4.h"
     39 #include "jbd2.h"
     40 
     41 int force = 0;
     42 struct fs_info info;
     43 struct fs_aux_info aux_info;
     44 
     45 /* returns 1 if a is a power of b */
     46 static int is_power_of(int a, int b)
     47 {
     48 	while (a > b) {
     49 		if (a % b)
     50 			return 0;
     51 		a /= b;
     52 	}
     53 
     54 	return (a == b) ? 1 : 0;
     55 }
     56 
     57 /* Returns 1 if the bg contains a backup superblock.  On filesystems with
     58    the sparse_super feature, only block groups 0, 1, and powers of 3, 5,
     59    and 7 have backup superblocks.  Otherwise, all block groups have backup
     60    superblocks */
     61 int ext4_bg_has_super_block(int bg)
     62 {
     63 	/* Without sparse_super, every block group has a superblock */
     64 	if (!(info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
     65 		return 1;
     66 
     67 	if (bg == 0 || bg == 1)
     68 		return 1;
     69 
     70 	if (is_power_of(bg, 3) || is_power_of(bg, 5) || is_power_of(bg, 7))
     71 		return 1;
     72 
     73 	return 0;
     74 }
     75 
     76 /* Write the filesystem image to a file */
     77 void write_ext4_image(const char *filename, int gz, int sparse)
     78 {
     79 	int ret = 0;
     80 	struct output_file *out = open_output_file(filename, gz, sparse);
     81 	off_t off;
     82 
     83 	if (!out)
     84 		return;
     85 
     86 	/* The write_data* functions expect only block aligned calls.
     87 	 * This is not an issue, except when we write out the super
     88 	 * block on a system with a block size > 1K.  So, we need to
     89 	 * deal with that here.
     90 	 */
     91 	if (info.block_size > 1024) {
     92 		u8 buf[4096] = { 0 }; 	/* The larget supported ext4 block size */
     93 		memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
     94 		write_data_block(out, 0, buf, info.block_size);
     95 
     96 	} else {
     97 		write_data_block(out, 1024, (u8*)aux_info.sb, 1024);
     98 	}
     99 
    100 	write_data_block(out, (u64)(aux_info.first_data_block + 1) * info.block_size,
    101 			 (u8*)aux_info.bg_desc,
    102 			 aux_info.bg_desc_blocks * info.block_size);
    103 
    104 	for_each_data_block(write_data_block, write_data_file, out);
    105 
    106 	pad_output_file(out, info.len);
    107 
    108 	close_output_file(out);
    109 }
    110 
    111 /* Compute the rest of the parameters of the filesystem from the basic info */
    112 void ext4_create_fs_aux_info()
    113 {
    114 	aux_info.first_data_block = (info.block_size > 1024) ? 0 : 1;
    115 	aux_info.len_blocks = info.len / info.block_size;
    116 	aux_info.inode_table_blocks = DIV_ROUND_UP(info.inodes_per_group * info.inode_size,
    117 		info.block_size);
    118 	aux_info.groups = DIV_ROUND_UP(aux_info.len_blocks - aux_info.first_data_block,
    119 		info.blocks_per_group);
    120 	aux_info.blocks_per_ind = info.block_size / sizeof(u32);
    121 	aux_info.blocks_per_dind = aux_info.blocks_per_ind * aux_info.blocks_per_ind;
    122 	aux_info.blocks_per_tind = aux_info.blocks_per_dind * aux_info.blocks_per_dind;
    123 
    124 	aux_info.bg_desc_blocks =
    125 		DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc),
    126 			info.block_size);
    127 
    128 	aux_info.bg_desc_reserve_blocks =
    129 		DIV_ROUND_UP(aux_info.groups * 1024 * sizeof(struct ext2_group_desc),
    130 			info.block_size) - aux_info.bg_desc_blocks;
    131 
    132 	if (aux_info.bg_desc_reserve_blocks > aux_info.blocks_per_ind)
    133 		aux_info.bg_desc_reserve_blocks = aux_info.blocks_per_ind;
    134 
    135 	aux_info.default_i_flags = EXT4_NOATIME_FL;
    136 
    137 	u32 last_group_size = aux_info.len_blocks % info.blocks_per_group;
    138 	u32 last_header_size = 2 + aux_info.inode_table_blocks;
    139 	if (ext4_bg_has_super_block(aux_info.groups - 1))
    140 		last_header_size += 1 + aux_info.bg_desc_blocks +
    141 			aux_info.bg_desc_reserve_blocks;
    142 	if (last_group_size > 0 && last_group_size < last_header_size) {
    143 		aux_info.groups--;
    144 		aux_info.len_blocks -= last_group_size;
    145 	}
    146 
    147 	aux_info.sb = calloc(info.block_size, 1);
    148 	if (!aux_info.sb)
    149 		critical_error_errno("calloc");
    150 
    151 	aux_info.bg_desc = calloc(info.block_size, aux_info.bg_desc_blocks);
    152 	if (!aux_info.bg_desc)
    153 		critical_error_errno("calloc");
    154 }
    155 
    156 void ext4_free_fs_aux_info()
    157 {
    158 	free(aux_info.sb);
    159 	free(aux_info.bg_desc);
    160 }
    161 
    162 /* Fill in the superblock memory buffer based on the filesystem parameters */
    163 void ext4_fill_in_sb()
    164 {
    165 	unsigned int i;
    166 	struct ext4_super_block *sb = aux_info.sb;
    167 
    168 	sb->s_inodes_count = info.inodes_per_group * aux_info.groups;
    169 	sb->s_blocks_count_lo = aux_info.len_blocks;
    170 	sb->s_r_blocks_count_lo = 0;
    171 	sb->s_free_blocks_count_lo = 0;
    172 	sb->s_free_inodes_count = 0;
    173 	sb->s_first_data_block = aux_info.first_data_block;
    174 	sb->s_log_block_size = log_2(info.block_size / 1024);
    175 	sb->s_obso_log_frag_size = log_2(info.block_size / 1024);
    176 	sb->s_blocks_per_group = info.blocks_per_group;
    177 	sb->s_obso_frags_per_group = info.blocks_per_group;
    178 	sb->s_inodes_per_group = info.inodes_per_group;
    179 	sb->s_mtime = 0;
    180 	sb->s_wtime = 0;
    181 	sb->s_mnt_count = 0;
    182 	sb->s_max_mnt_count = 0xFFFF;
    183 	sb->s_magic = EXT4_SUPER_MAGIC;
    184 	sb->s_state = EXT4_VALID_FS;
    185 	sb->s_errors = EXT4_ERRORS_RO;
    186 	sb->s_minor_rev_level = 0;
    187 	sb->s_lastcheck = 0;
    188 	sb->s_checkinterval = 0;
    189 	sb->s_creator_os = EXT4_OS_LINUX;
    190 	sb->s_rev_level = EXT4_DYNAMIC_REV;
    191 	sb->s_def_resuid = EXT4_DEF_RESUID;
    192 	sb->s_def_resgid = EXT4_DEF_RESGID;
    193 
    194 	sb->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
    195 	sb->s_inode_size = info.inode_size;
    196 	sb->s_block_group_nr = 0;
    197 	sb->s_feature_compat = info.feat_compat;
    198 	sb->s_feature_incompat = info.feat_incompat;
    199 	sb->s_feature_ro_compat = info.feat_ro_compat;
    200 	generate_uuid("extandroid/make_ext4fs", info.label, sb->s_uuid);
    201 	memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
    202 	strncpy(sb->s_volume_name, info.label, sizeof(sb->s_volume_name));
    203 	memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
    204 	sb->s_algorithm_usage_bitmap = 0;
    205 
    206 	sb->s_reserved_gdt_blocks = aux_info.bg_desc_reserve_blocks;
    207 	sb->s_prealloc_blocks = 0;
    208 	sb->s_prealloc_dir_blocks = 0;
    209 
    210 	//memcpy(sb->s_journal_uuid, sb->s_uuid, sizeof(sb->s_journal_uuid));
    211 	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
    212 		sb->s_journal_inum = EXT4_JOURNAL_INO;
    213 	sb->s_journal_dev = 0;
    214 	sb->s_last_orphan = 0;
    215 	sb->s_hash_seed[0] = 0; /* FIXME */
    216 	sb->s_def_hash_version = DX_HASH_TEA;
    217 	sb->s_reserved_char_pad = EXT4_JNL_BACKUP_BLOCKS;
    218 	sb->s_desc_size = sizeof(struct ext2_group_desc);
    219 	sb->s_default_mount_opts = 0; /* FIXME */
    220 	sb->s_first_meta_bg = 0;
    221 	sb->s_mkfs_time = 0;
    222 	//sb->s_jnl_blocks[17]; /* FIXME */
    223 
    224 	sb->s_blocks_count_hi = aux_info.len_blocks >> 32;
    225 	sb->s_r_blocks_count_hi = 0;
    226 	sb->s_free_blocks_count_hi = 0;
    227 	sb->s_min_extra_isize = sizeof(struct ext4_inode) -
    228 		EXT4_GOOD_OLD_INODE_SIZE;
    229 	sb->s_want_extra_isize = sizeof(struct ext4_inode) -
    230 		EXT4_GOOD_OLD_INODE_SIZE;
    231 	sb->s_flags = 0;
    232 	sb->s_raid_stride = 0;
    233 	sb->s_mmp_interval = 0;
    234 	sb->s_mmp_block = 0;
    235 	sb->s_raid_stripe_width = 0;
    236 	sb->s_log_groups_per_flex = 0;
    237 	sb->s_kbytes_written = 0;
    238 
    239 	for (i = 0; i < aux_info.groups; i++) {
    240 		u64 group_start_block = aux_info.first_data_block + i *
    241 			info.blocks_per_group;
    242 		u32 header_size = 0;
    243 		if (ext4_bg_has_super_block(i)) {
    244 			if (i != 0) {
    245 				queue_data_block((u8 *)sb, info.block_size, group_start_block);
    246 				queue_data_block((u8 *)aux_info.bg_desc,
    247 					aux_info.bg_desc_blocks * info.block_size,
    248 					group_start_block + 1);
    249 			}
    250 			header_size = 1 + aux_info.bg_desc_blocks + aux_info.bg_desc_reserve_blocks;
    251 		}
    252 
    253 		aux_info.bg_desc[i].bg_block_bitmap = group_start_block + header_size;
    254 		aux_info.bg_desc[i].bg_inode_bitmap = group_start_block + header_size + 1;
    255 		aux_info.bg_desc[i].bg_inode_table = group_start_block + header_size + 2;
    256 
    257 		aux_info.bg_desc[i].bg_free_blocks_count = sb->s_blocks_per_group;
    258 		aux_info.bg_desc[i].bg_free_inodes_count = sb->s_inodes_per_group;
    259 		aux_info.bg_desc[i].bg_used_dirs_count = 0;
    260 	}
    261 }
    262 
    263 void ext4_create_resize_inode()
    264 {
    265 	struct block_allocation *reserve_inode_alloc = create_allocation();
    266 	u32 reserve_inode_len = 0;
    267 	unsigned int i;
    268 
    269 	struct ext4_inode *inode = get_inode(EXT4_RESIZE_INO);
    270 	if (inode == NULL) {
    271 		error("failed to get resize inode");
    272 		return;
    273 	}
    274 
    275 	for (i = 0; i < aux_info.groups; i++) {
    276 		if (ext4_bg_has_super_block(i)) {
    277 			u64 group_start_block = aux_info.first_data_block + i *
    278 				info.blocks_per_group;
    279 			u32 reserved_block_start = group_start_block + 1 +
    280 				aux_info.bg_desc_blocks;
    281 			u32 reserved_block_len = aux_info.bg_desc_reserve_blocks;
    282 			append_region(reserve_inode_alloc, reserved_block_start,
    283 				reserved_block_len, i);
    284 			reserve_inode_len += reserved_block_len;
    285 		}
    286 	}
    287 
    288 	inode_attach_resize(inode, reserve_inode_alloc);
    289 
    290 	inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
    291 	inode->i_links_count = 1;
    292 
    293 	free_alloc(reserve_inode_alloc);
    294 }
    295 
    296 /* Allocate the blocks to hold a journal inode and connect them to the
    297    reserved journal inode */
    298 void ext4_create_journal_inode()
    299 {
    300 	struct ext4_inode *inode = get_inode(EXT4_JOURNAL_INO);
    301 	if (inode == NULL) {
    302 		error("failed to get journal inode");
    303 		return;
    304 	}
    305 
    306 	u8 *journal_data = inode_allocate_data_extents(inode,
    307 			info.journal_blocks * info.block_size,
    308 			info.journal_blocks * info.block_size);
    309 	if (!journal_data) {
    310 		error("failed to allocate extents for journal data");
    311 		return;
    312 	}
    313 
    314 	inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
    315 	inode->i_links_count = 1;
    316 
    317 	journal_superblock_t *jsb = (journal_superblock_t *)journal_data;
    318 	jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER);
    319 	jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
    320 	jsb->s_blocksize = htonl(info.block_size);
    321 	jsb->s_maxlen = htonl(info.journal_blocks);
    322 	jsb->s_nr_users = htonl(1);
    323 	jsb->s_first = htonl(1);
    324 	jsb->s_sequence = htonl(1);
    325 
    326 	memcpy(aux_info.sb->s_jnl_blocks, &inode->i_block, sizeof(inode->i_block));
    327 }
    328 
    329 /* Update the number of free blocks and inodes in the filesystem and in each
    330    block group */
    331 void ext4_update_free()
    332 {
    333 	unsigned int i;
    334 
    335 	for (i = 0; i < aux_info.groups; i++) {
    336 		u32 bg_free_blocks = get_free_blocks(i);
    337 		u32 bg_free_inodes = get_free_inodes(i);
    338 
    339 		aux_info.bg_desc[i].bg_free_blocks_count = bg_free_blocks;
    340 		aux_info.sb->s_free_blocks_count_lo += bg_free_blocks;
    341 
    342 		aux_info.bg_desc[i].bg_free_inodes_count = bg_free_inodes;
    343 		aux_info.sb->s_free_inodes_count += bg_free_inodes;
    344 
    345 		aux_info.bg_desc[i].bg_used_dirs_count += get_directories(i);
    346 	}
    347 }
    348 
    349 static u64 get_block_device_size(const char *filename)
    350 {
    351 	int fd = open(filename, O_RDONLY);
    352 	u64 size = 0;
    353 	int ret;
    354 
    355 	if (fd < 0)
    356 		return 0;
    357 
    358 #if defined(__linux__)
    359 	ret = ioctl(fd, BLKGETSIZE64, &size);
    360 #elif defined(__APPLE__) && defined(__MACH__)
    361 	ret = ioctl(fd, DKIOCGETBLOCKCOUNT, &size);
    362 #else
    363 	return 0;
    364 #endif
    365 
    366 	close(fd);
    367 
    368 	if (ret)
    369 		return 0;
    370 
    371 	return size;
    372 }
    373 
    374 u64 get_file_size(const char *filename)
    375 {
    376 	struct stat buf;
    377 	int ret;
    378 
    379 	ret = stat(filename, &buf);
    380 	if (ret)
    381 		return 0;
    382 
    383 	if (S_ISREG(buf.st_mode))
    384 		return buf.st_size;
    385 	else if (S_ISBLK(buf.st_mode))
    386 		return get_block_device_size(filename);
    387 	else
    388 		return 0;
    389 }
    390 
    391 u64 parse_num(const char *arg)
    392 {
    393 	char *endptr;
    394 	u64 num = strtoull(arg, &endptr, 10);
    395 	if (*endptr == 'k' || *endptr == 'K')
    396 		num *= 1024LL;
    397 	else if (*endptr == 'm' || *endptr == 'M')
    398 		num *= 1024LL * 1024LL;
    399 	else if (*endptr == 'g' || *endptr == 'G')
    400 		num *= 1024LL * 1024LL * 1024LL;
    401 
    402 	return num;
    403 }
    404 
    405