2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "make_ext4fs.h"
18 #include "output_file.h"
19 #include "ext4_utils.h"
23 #include "backed_block.h"
32 #include <sys/types.h>
35 #include <private/android_filesystem_config.h>
38 /* TODO: Not implemented:
39 Allocating blocks in the same block group as the file inode
40 Hash or binary tree directories
41 Special files: sockets, devices, fifos
44 static int filter_dot(const struct dirent *d)
46 return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
49 static u32 build_default_directory_structure()
53 struct dentry dentries = {
54 .filename = "lost+found",
55 .file_type = EXT4_FT_DIR,
61 root_inode = make_directory(0, 1, &dentries, 1);
62 inode = make_directory(root_inode, 0, NULL, 0);
63 *dentries.inode = inode;
64 inode_set_permissions(inode, dentries.mode,
65 dentries.uid, dentries.gid, dentries.mtime);
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)
76 struct dentry *dentries;
77 struct dirent **namelist;
85 entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
87 error_errno("scandir");
88 return EXT4_ALLOCATE_FAILED;
91 dentries = calloc(entries, sizeof(struct dentry));
93 critical_error_errno("malloc");
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");
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);
105 ret = lstat(dentries[i].full_path, &stat);
107 error_errno("lstat");
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);
115 dentries[i].mtime = stat.st_mtime;
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;
127 error("can't set android permissions - built without android support");
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;
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);
149 error("unknown file type on %s", dentries[i].path);
156 inode = make_directory(dir_inode, entries, dentries, dirs);
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);
167 error("unknown file type on %s", dentries[i].path);
170 *dentries[i].inode = entry_inode;
172 ret = inode_set_permissions(entry_inode, dentries[i].mode,
173 dentries[i].uid, dentries[i].gid,
176 error("failed to set permissions on %s\n", dentries[i].path);
178 free(dentries[i].path);
179 free(dentries[i].full_path);
180 free(dentries[i].link);
181 free((void *)dentries[i].filename);
188 static u32 compute_block_size()
193 static u32 compute_journal_blocks()
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;
203 static u32 compute_blocks_per_group()
205 return info.block_size * 8;
208 static u32 compute_inodes()
210 return DIV_ROUND_UP(info.len, info.block_size) / 4;
213 static u32 compute_inodes_per_group()
215 u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
216 u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
217 return DIV_ROUND_UP(info.inodes, block_groups);
220 static u32 compute_bg_desc_reserve_blocks()
222 u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
223 u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
224 u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
227 u32 bg_desc_reserve_blocks =
228 DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
229 info.block_size) - bg_desc_blocks;
231 if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
232 bg_desc_reserve_blocks = info.block_size / sizeof(u32);
234 return bg_desc_reserve_blocks;
237 void reset_ext4fs_info() {
238 // Reset all the global data structures used by make_ext4fs so it
239 // can be called again.
240 memset(&info, 0, sizeof(info));
241 memset(&aux_info, 0, sizeof(aux_info));
245 int make_ext4fs(const char *filename, s64 len)
249 return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1);
252 int make_ext4fs_internal(const char *filename, const char *directory,
253 char *mountpoint, int android, int gzip, int sparse,
260 info.len = get_file_size(filename);
263 fprintf(stderr, "Need size of filesystem\n");
267 if (info.block_size <= 0)
268 info.block_size = compute_block_size();
270 if (info.journal_blocks == 0)
271 info.journal_blocks = compute_journal_blocks();
273 if (info.no_journal == 0)
274 info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
276 info.journal_blocks = 0;
278 if (info.blocks_per_group <= 0)
279 info.blocks_per_group = compute_blocks_per_group();
281 if (info.inodes <= 0)
282 info.inodes = compute_inodes();
284 if (info.inode_size <= 0)
285 info.inode_size = 256;
287 if (info.label == NULL)
290 info.inodes_per_group = compute_inodes_per_group();
293 EXT4_FEATURE_COMPAT_RESIZE_INODE;
295 info.feat_ro_compat |=
296 EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
297 EXT4_FEATURE_RO_COMPAT_LARGE_FILE;
299 info.feat_incompat |=
300 EXT4_FEATURE_INCOMPAT_EXTENTS |
301 EXT4_FEATURE_INCOMPAT_FILETYPE;
304 info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
306 printf("Creating filesystem with parameters:\n");
307 printf(" Size: %llu\n", info.len);
308 printf(" Block size: %d\n", info.block_size);
309 printf(" Blocks per group: %d\n", info.blocks_per_group);
310 printf(" Inodes per group: %d\n", info.inodes_per_group);
311 printf(" Inode size: %d\n", info.inode_size);
312 printf(" Journal blocks: %d\n", info.journal_blocks);
313 printf(" Label: %s\n", info.label);
315 ext4_create_fs_aux_info();
317 printf(" Blocks: %llu\n", aux_info.len_blocks);
318 printf(" Block groups: %d\n", aux_info.groups);
319 printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
321 block_allocator_init();
325 if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
326 error("failed to reserve first 10 inodes");
328 if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
329 ext4_create_journal_inode();
331 if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
332 ext4_create_resize_inode();
335 root_inode_num = build_directory_structure(directory, mountpoint, 0, android);
337 root_inode_num = build_default_directory_structure();
339 root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
340 inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
346 printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
347 aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
348 aux_info.sb->s_inodes_count,
349 aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
350 aux_info.sb->s_blocks_count_lo);
352 write_ext4_image(filename, gzip, sparse, crc, wipe);