| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 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 |  | 
| Colin Cross | 33f96c6 | 2010-12-22 18:40:14 -0800 | [diff] [blame] | 17 | #include "make_ext4fs.h" | 
 | 18 | #include "output_file.h" | 
 | 19 | #include "ext4_utils.h" | 
 | 20 | #include "allocate.h" | 
 | 21 | #include "contents.h" | 
 | 22 | #include "uuid.h" | 
| Colin Cross | 2e905e5 | 2010-12-29 14:20:53 -0800 | [diff] [blame] | 23 | #include "backed_block.h" | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 24 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 25 | #include <dirent.h> | 
 | 26 | #include <libgen.h> | 
| Colin Cross | 881cca2 | 2010-06-20 23:57:06 -0700 | [diff] [blame] | 27 | #include <stdio.h> | 
 | 28 | #include <stdlib.h> | 
 | 29 | #include <string.h> | 
 | 30 | #include <unistd.h> | 
 | 31 | #include <sys/stat.h> | 
 | 32 | #include <sys/types.h> | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 33 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 34 | #ifdef ANDROID | 
 | 35 | #include <private/android_filesystem_config.h> | 
 | 36 | #endif | 
 | 37 |  | 
 | 38 | /* TODO: Not implemented: | 
 | 39 |    Allocating blocks in the same block group as the file inode | 
 | 40 |    Hash or binary tree directories | 
| Colin Cross | 7a8bee7 | 2010-06-20 14:53:14 -0700 | [diff] [blame] | 41 |    Special files: sockets, devices, fifos | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 42 |  */ | 
 | 43 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 44 | static int filter_dot(const struct dirent *d) | 
 | 45 | { | 
 | 46 | 	return (strcmp(d->d_name, "..") && strcmp(d->d_name, ".")); | 
 | 47 | } | 
 | 48 |  | 
 | 49 | static u32 build_default_directory_structure() | 
 | 50 | { | 
 | 51 | 	u32 inode; | 
 | 52 | 	u32 root_inode; | 
 | 53 | 	struct dentry dentries = { | 
 | 54 | 			.filename = "lost+found", | 
 | 55 | 			.file_type = EXT4_FT_DIR, | 
 | 56 | 			.mode = S_IRWXU, | 
 | 57 | 			.uid = 0, | 
| Colin Cross | de61f98 | 2010-08-04 15:06:09 -0700 | [diff] [blame] | 58 | 			.gid = 0, | 
 | 59 | 			.mtime = 0, | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 60 | 	}; | 
 | 61 | 	root_inode = make_directory(0, 1, &dentries, 1); | 
 | 62 | 	inode = make_directory(root_inode, 0, NULL, 0); | 
 | 63 | 	*dentries.inode = inode; | 
| Ken Sumrall | 75249ed | 2010-08-13 16:04:49 -0700 | [diff] [blame] | 64 | 	inode_set_permissions(inode, dentries.mode, | 
 | 65 | 		dentries.uid, dentries.gid, dentries.mtime); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 66 |  | 
 | 67 | 	return root_inode; | 
 | 68 | } | 
 | 69 |  | 
 | 70 | /* Read a local directory and create the same tree in the generated filesystem. | 
 | 71 |    Calls itself recursively with each directory in the given directory */ | 
 | 72 | static u32 build_directory_structure(const char *full_path, const char *dir_path, | 
 | 73 | 		u32 dir_inode, int android) | 
 | 74 | { | 
 | 75 | 	int entries = 0; | 
 | 76 | 	struct dentry *dentries; | 
 | 77 | 	struct dirent **namelist; | 
 | 78 | 	struct stat stat; | 
 | 79 | 	int ret; | 
 | 80 | 	int i; | 
 | 81 | 	u32 inode; | 
 | 82 | 	u32 entry_inode; | 
 | 83 | 	u32 dirs = 0; | 
 | 84 |  | 
| Colin Cross | 8aef66d | 2010-06-20 23:22:12 -0700 | [diff] [blame] | 85 | 	entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 86 | 	if (entries < 0) { | 
 | 87 | 		error_errno("scandir"); | 
 | 88 | 		return EXT4_ALLOCATE_FAILED; | 
 | 89 | 	} | 
 | 90 |  | 
 | 91 | 	dentries = calloc(entries, sizeof(struct dentry)); | 
 | 92 | 	if (dentries == NULL) | 
 | 93 | 		critical_error_errno("malloc"); | 
 | 94 |  | 
 | 95 | 	for (i = 0; i < entries; i++) { | 
 | 96 | 		dentries[i].filename = strdup(namelist[i]->d_name); | 
 | 97 | 		if (dentries[i].filename == NULL) | 
 | 98 | 			critical_error_errno("strdup"); | 
 | 99 |  | 
 | 100 | 		asprintf(&dentries[i].path, "%s/%s", dir_path, namelist[i]->d_name); | 
 | 101 | 		asprintf(&dentries[i].full_path, "%s/%s", full_path, namelist[i]->d_name); | 
 | 102 |  | 
 | 103 | 		free(namelist[i]); | 
 | 104 |  | 
 | 105 | 		ret = lstat(dentries[i].full_path, &stat); | 
 | 106 | 		if (ret < 0) { | 
 | 107 | 			error_errno("lstat"); | 
 | 108 | 			i--; | 
 | 109 | 			entries--; | 
 | 110 | 			continue; | 
 | 111 | 		} | 
 | 112 |  | 
 | 113 | 		dentries[i].size = stat.st_size; | 
 | 114 | 		dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); | 
| Colin Cross | de61f98 | 2010-08-04 15:06:09 -0700 | [diff] [blame] | 115 | 		dentries[i].mtime = stat.st_mtime; | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 116 | 		if (android) { | 
 | 117 | #ifdef ANDROID | 
 | 118 | 			unsigned int mode = 0; | 
 | 119 | 			unsigned int uid = 0; | 
 | 120 | 			unsigned int gid = 0; | 
 | 121 | 			int dir = S_ISDIR(stat.st_mode); | 
 | 122 | 			fs_config(dentries[i].path, dir, &uid, &gid, &mode); | 
 | 123 | 			dentries[i].mode = mode; | 
 | 124 | 			dentries[i].uid = uid; | 
 | 125 | 			dentries[i].gid = gid; | 
 | 126 | #else | 
 | 127 | 			error("can't set android permissions - built without android support"); | 
 | 128 | #endif | 
 | 129 | 		} | 
 | 130 |  | 
 | 131 | 		if (S_ISREG(stat.st_mode)) { | 
 | 132 | 			dentries[i].file_type = EXT4_FT_REG_FILE; | 
 | 133 | 		} else if (S_ISDIR(stat.st_mode)) { | 
 | 134 | 			dentries[i].file_type = EXT4_FT_DIR; | 
 | 135 | 			dirs++; | 
 | 136 | 		} else if (S_ISCHR(stat.st_mode)) { | 
 | 137 | 			dentries[i].file_type = EXT4_FT_CHRDEV; | 
 | 138 | 		} else if (S_ISBLK(stat.st_mode)) { | 
 | 139 | 			dentries[i].file_type = EXT4_FT_BLKDEV; | 
 | 140 | 		} else if (S_ISFIFO(stat.st_mode)) { | 
 | 141 | 			dentries[i].file_type = EXT4_FT_FIFO; | 
 | 142 | 		} else if (S_ISSOCK(stat.st_mode)) { | 
 | 143 | 			dentries[i].file_type = EXT4_FT_SOCK; | 
 | 144 | 		} else if (S_ISLNK(stat.st_mode)) { | 
 | 145 | 			dentries[i].file_type = EXT4_FT_SYMLINK; | 
 | 146 | 			dentries[i].link = calloc(info.block_size, 1); | 
 | 147 | 			readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1); | 
 | 148 | 		} else { | 
 | 149 | 			error("unknown file type on %s", dentries[i].path); | 
 | 150 | 			i--; | 
 | 151 | 			entries--; | 
 | 152 | 		} | 
 | 153 | 	} | 
 | 154 | 	free(namelist); | 
 | 155 |  | 
 | 156 | 	inode = make_directory(dir_inode, entries, dentries, dirs); | 
 | 157 |  | 
 | 158 | 	for (i = 0; i < entries; i++) { | 
 | 159 | 		if (dentries[i].file_type == EXT4_FT_REG_FILE) { | 
 | 160 | 			entry_inode = make_file(dentries[i].full_path, dentries[i].size); | 
 | 161 | 		} else if (dentries[i].file_type == EXT4_FT_DIR) { | 
 | 162 | 			entry_inode = build_directory_structure(dentries[i].full_path, | 
 | 163 | 					dentries[i].path, inode, android); | 
 | 164 | 		} else if (dentries[i].file_type == EXT4_FT_SYMLINK) { | 
 | 165 | 			entry_inode = make_link(dentries[i].full_path, dentries[i].link); | 
 | 166 | 		} else { | 
 | 167 | 			error("unknown file type on %s", dentries[i].path); | 
 | 168 | 			entry_inode = 0; | 
 | 169 | 		} | 
 | 170 | 		*dentries[i].inode = entry_inode; | 
 | 171 |  | 
 | 172 | 		ret = inode_set_permissions(entry_inode, dentries[i].mode, | 
| Colin Cross | de61f98 | 2010-08-04 15:06:09 -0700 | [diff] [blame] | 173 | 			dentries[i].uid, dentries[i].gid, | 
 | 174 | 			dentries[i].mtime); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 175 | 		if (ret) | 
 | 176 | 			error("failed to set permissions on %s\n", dentries[i].path); | 
 | 177 |  | 
 | 178 | 		free(dentries[i].path); | 
 | 179 | 		free(dentries[i].full_path); | 
 | 180 | 		free(dentries[i].link); | 
 | 181 | 		free((void *)dentries[i].filename); | 
 | 182 | 	} | 
 | 183 |  | 
 | 184 | 	free(dentries); | 
 | 185 | 	return inode; | 
 | 186 | } | 
 | 187 |  | 
 | 188 | static u32 compute_block_size() | 
 | 189 | { | 
 | 190 | 	return 4096; | 
 | 191 | } | 
 | 192 |  | 
| Colin Cross | e4b5ae8 | 2010-08-03 14:10:07 -0700 | [diff] [blame] | 193 | static u32 compute_journal_blocks() | 
 | 194 | { | 
 | 195 | 	u32 journal_blocks = DIV_ROUND_UP(info.len, info.block_size) / 64; | 
 | 196 | 	if (journal_blocks < 1024) | 
 | 197 | 		journal_blocks = 1024; | 
 | 198 | 	if (journal_blocks > 32768) | 
 | 199 | 		journal_blocks = 32768; | 
 | 200 | 	return journal_blocks; | 
 | 201 | } | 
 | 202 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 203 | static u32 compute_blocks_per_group() | 
 | 204 | { | 
 | 205 | 	return info.block_size * 8; | 
 | 206 | } | 
 | 207 |  | 
 | 208 | static u32 compute_inodes() | 
 | 209 | { | 
 | 210 | 	return DIV_ROUND_UP(info.len, info.block_size) / 4; | 
 | 211 | } | 
 | 212 |  | 
 | 213 | static u32 compute_inodes_per_group() | 
 | 214 | { | 
 | 215 | 	u32 blocks = DIV_ROUND_UP(info.len, info.block_size); | 
 | 216 | 	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group); | 
| Colin Cross | 96cc54a | 2011-04-29 16:45:48 -0700 | [diff] [blame] | 217 | 	u32 inodes = DIV_ROUND_UP(info.inodes, block_groups); | 
 | 218 | 	return ALIGN(inodes, (info.block_size / info.inode_size)); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 219 | } | 
 | 220 |  | 
| Colin Cross | 22742ce | 2010-12-22 16:01:52 -0800 | [diff] [blame] | 221 | static u32 compute_bg_desc_reserve_blocks() | 
 | 222 | { | 
 | 223 | 	u32 blocks = DIV_ROUND_UP(info.len, info.block_size); | 
 | 224 | 	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group); | 
 | 225 | 	u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc), | 
 | 226 | 			info.block_size); | 
 | 227 |  | 
 | 228 | 	u32 bg_desc_reserve_blocks = | 
 | 229 | 			DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc), | 
 | 230 | 					info.block_size) - bg_desc_blocks; | 
 | 231 |  | 
 | 232 | 	if (bg_desc_reserve_blocks > info.block_size / sizeof(u32)) | 
 | 233 | 		bg_desc_reserve_blocks = info.block_size / sizeof(u32); | 
 | 234 |  | 
 | 235 | 	return bg_desc_reserve_blocks; | 
 | 236 | } | 
 | 237 |  | 
| Doug Zongker | 263eefd | 2010-06-29 17:23:14 -0700 | [diff] [blame] | 238 | void reset_ext4fs_info() { | 
 | 239 |     // Reset all the global data structures used by make_ext4fs so it | 
 | 240 |     // can be called again. | 
 | 241 |     memset(&info, 0, sizeof(info)); | 
 | 242 |     memset(&aux_info, 0, sizeof(aux_info)); | 
 | 243 |     free_data_blocks(); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 244 | } | 
 | 245 |  | 
| Ken Sumrall | 983fb19 | 2011-01-19 17:15:42 -0800 | [diff] [blame] | 246 | int make_ext4fs(const char *filename, s64 len) | 
 | 247 | { | 
 | 248 |     reset_ext4fs_info(); | 
 | 249 |     info.len = len; | 
| Colin Cross | c247065 | 2011-01-26 16:39:46 -0800 | [diff] [blame] | 250 |     return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1); | 
| Ken Sumrall | 983fb19 | 2011-01-19 17:15:42 -0800 | [diff] [blame] | 251 | } | 
 | 252 |  | 
 | 253 | int make_ext4fs_internal(const char *filename, const char *directory, | 
 | 254 |                          char *mountpoint, int android, int gzip, int sparse, | 
| Colin Cross | c247065 | 2011-01-26 16:39:46 -0800 | [diff] [blame] | 255 |                          int crc, int wipe) | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 256 | { | 
| Doug Zongker | 263eefd | 2010-06-29 17:23:14 -0700 | [diff] [blame] | 257 |         u32 root_inode_num; | 
 | 258 |         u16 root_mode; | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 259 |  | 
| Ken Sumrall | 2ae7663 | 2011-03-23 22:08:53 -0700 | [diff] [blame] | 260 | 	if (setjmp(setjmp_env)) | 
 | 261 | 		return EXIT_FAILURE; /* Handle a call to longjmp() */ | 
 | 262 |  | 
| Ken Sumrall | 435a8b6 | 2011-01-14 18:33:06 -0800 | [diff] [blame] | 263 | 	if (info.len <= 0) | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 264 | 		info.len = get_file_size(filename); | 
 | 265 |  | 
 | 266 | 	if (info.len <= 0) { | 
 | 267 | 		fprintf(stderr, "Need size of filesystem\n"); | 
| Doug Zongker | 263eefd | 2010-06-29 17:23:14 -0700 | [diff] [blame] | 268 |                 return EXIT_FAILURE; | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 269 | 	} | 
 | 270 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 271 | 	if (info.block_size <= 0) | 
 | 272 | 		info.block_size = compute_block_size(); | 
 | 273 |  | 
| Colin Cross | e4b5ae8 | 2010-08-03 14:10:07 -0700 | [diff] [blame] | 274 | 	if (info.journal_blocks == 0) | 
 | 275 | 		info.journal_blocks = compute_journal_blocks(); | 
 | 276 |  | 
 | 277 | 	if (info.no_journal == 0) | 
 | 278 | 		info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL; | 
 | 279 | 	else | 
 | 280 | 		info.journal_blocks = 0; | 
 | 281 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 282 | 	if (info.blocks_per_group <= 0) | 
 | 283 | 		info.blocks_per_group = compute_blocks_per_group(); | 
 | 284 |  | 
 | 285 | 	if (info.inodes <= 0) | 
 | 286 | 		info.inodes = compute_inodes(); | 
 | 287 |  | 
 | 288 | 	if (info.inode_size <= 0) | 
 | 289 | 		info.inode_size = 256; | 
 | 290 |  | 
 | 291 | 	if (info.label == NULL) | 
 | 292 | 		info.label = ""; | 
 | 293 |  | 
 | 294 | 	info.inodes_per_group = compute_inodes_per_group(); | 
 | 295 |  | 
 | 296 | 	info.feat_compat |= | 
 | 297 | 			EXT4_FEATURE_COMPAT_RESIZE_INODE; | 
 | 298 |  | 
 | 299 | 	info.feat_ro_compat |= | 
 | 300 | 			EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER | | 
 | 301 | 			EXT4_FEATURE_RO_COMPAT_LARGE_FILE; | 
 | 302 |  | 
 | 303 | 	info.feat_incompat |= | 
 | 304 | 			EXT4_FEATURE_INCOMPAT_EXTENTS | | 
 | 305 | 			EXT4_FEATURE_INCOMPAT_FILETYPE; | 
 | 306 |  | 
 | 307 |  | 
| Colin Cross | 22742ce | 2010-12-22 16:01:52 -0800 | [diff] [blame] | 308 | 	info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks(); | 
 | 309 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 310 | 	printf("Creating filesystem with parameters:\n"); | 
 | 311 | 	printf("    Size: %llu\n", info.len); | 
 | 312 | 	printf("    Block size: %d\n", info.block_size); | 
 | 313 | 	printf("    Blocks per group: %d\n", info.blocks_per_group); | 
 | 314 | 	printf("    Inodes per group: %d\n", info.inodes_per_group); | 
 | 315 | 	printf("    Inode size: %d\n", info.inode_size); | 
| Colin Cross | e4b5ae8 | 2010-08-03 14:10:07 -0700 | [diff] [blame] | 316 | 	printf("    Journal blocks: %d\n", info.journal_blocks); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 317 | 	printf("    Label: %s\n", info.label); | 
 | 318 |  | 
 | 319 | 	ext4_create_fs_aux_info(); | 
 | 320 |  | 
 | 321 | 	printf("    Blocks: %llu\n", aux_info.len_blocks); | 
 | 322 | 	printf("    Block groups: %d\n", aux_info.groups); | 
| Colin Cross | 22742ce | 2010-12-22 16:01:52 -0800 | [diff] [blame] | 323 | 	printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 324 |  | 
 | 325 | 	block_allocator_init(); | 
 | 326 |  | 
 | 327 | 	ext4_fill_in_sb(); | 
 | 328 |  | 
 | 329 | 	if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED) | 
 | 330 | 		error("failed to reserve first 10 inodes"); | 
 | 331 |  | 
 | 332 | 	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL) | 
 | 333 | 		ext4_create_journal_inode(); | 
 | 334 |  | 
 | 335 | 	if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE) | 
 | 336 | 		ext4_create_resize_inode(); | 
 | 337 |  | 
 | 338 | 	if (directory) | 
 | 339 | 		root_inode_num = build_directory_structure(directory, mountpoint, 0, android); | 
 | 340 | 	else | 
 | 341 | 		root_inode_num = build_default_directory_structure(); | 
| Doug Zongker | 263eefd | 2010-06-29 17:23:14 -0700 | [diff] [blame] | 342 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 343 | 	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; | 
| Colin Cross | de61f98 | 2010-08-04 15:06:09 -0700 | [diff] [blame] | 344 | 	inode_set_permissions(root_inode_num, root_mode, 0, 0, 0); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 345 |  | 
 | 346 | 	ext4_update_free(); | 
 | 347 |  | 
| Colin Cross | b781330 | 2010-12-22 18:41:13 -0800 | [diff] [blame] | 348 | 	ext4_queue_sb(); | 
 | 349 |  | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 350 | 	printf("Created filesystem with %d/%d inodes and %d/%d blocks\n", | 
 | 351 | 			aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count, | 
 | 352 | 			aux_info.sb->s_inodes_count, | 
 | 353 | 			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo, | 
 | 354 | 			aux_info.sb->s_blocks_count_lo); | 
 | 355 |  | 
| Colin Cross | c247065 | 2011-01-26 16:39:46 -0800 | [diff] [blame] | 356 | 	write_ext4_image(filename, gzip, sparse, crc, wipe); | 
| Colin Cross | ec0a2e8 | 2010-06-11 14:21:37 -0700 | [diff] [blame] | 357 |  | 
 | 358 | 	return 0; | 
 | 359 | } |