blob: c11bebbfc6fac6da57b4bbee4807217292fbcd5b [file] [log] [blame]
Colin Crossec0a2e82010-06-11 14:21:37 -07001/*
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 Cross33f96c62010-12-22 18:40:14 -080017#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 Cross2e905e52010-12-29 14:20:53 -080023#include "backed_block.h"
Colin Crossec0a2e82010-06-11 14:21:37 -070024
Raphael Moll4605b3f2012-02-03 23:02:33 -080025#include <assert.h>
Colin Crossec0a2e82010-06-11 14:21:37 -070026#include <dirent.h>
27#include <libgen.h>
Colin Cross881cca22010-06-20 23:57:06 -070028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include <unistd.h>
32#include <sys/stat.h>
33#include <sys/types.h>
Colin Crossec0a2e82010-06-11 14:21:37 -070034
Colin Crossec0a2e82010-06-11 14:21:37 -070035#ifdef ANDROID
36#include <private/android_filesystem_config.h>
37#endif
38
Raphael Moll4605b3f2012-02-03 23:02:33 -080039#ifdef USE_MINGW
40
41#include <winsock2.h>
42
43/* These match the Linux definitions of these flags.
44 L_xx is defined to avoid conflicting with the win32 versions.
45*/
46#define L_S_IRUSR 00400
47#define L_S_IWUSR 00200
48#define L_S_IXUSR 00100
49#define S_IRWXU (L_S_IRUSR | L_S_IWUSR | L_S_IXUSR)
50#define S_IRGRP 00040
51#define S_IWGRP 00020
52#define S_IXGRP 00010
53#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
54#define S_IROTH 00004
55#define S_IWOTH 00002
56#define S_IXOTH 00001
57#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
58#define S_ISUID 0004000
59#define S_ISGID 0002000
60#define S_ISVTX 0001000
61
62#endif
63
Colin Crossec0a2e82010-06-11 14:21:37 -070064/* TODO: Not implemented:
65 Allocating blocks in the same block group as the file inode
66 Hash or binary tree directories
Colin Cross7a8bee72010-06-20 14:53:14 -070067 Special files: sockets, devices, fifos
Colin Crossec0a2e82010-06-11 14:21:37 -070068 */
69
Colin Crossec0a2e82010-06-11 14:21:37 -070070static int filter_dot(const struct dirent *d)
71{
72 return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
73}
74
75static u32 build_default_directory_structure()
76{
77 u32 inode;
78 u32 root_inode;
79 struct dentry dentries = {
80 .filename = "lost+found",
81 .file_type = EXT4_FT_DIR,
82 .mode = S_IRWXU,
83 .uid = 0,
Colin Crossde61f982010-08-04 15:06:09 -070084 .gid = 0,
85 .mtime = 0,
Colin Crossec0a2e82010-06-11 14:21:37 -070086 };
87 root_inode = make_directory(0, 1, &dentries, 1);
88 inode = make_directory(root_inode, 0, NULL, 0);
89 *dentries.inode = inode;
Ken Sumrall75249ed2010-08-13 16:04:49 -070090 inode_set_permissions(inode, dentries.mode,
91 dentries.uid, dentries.gid, dentries.mtime);
Colin Crossec0a2e82010-06-11 14:21:37 -070092
93 return root_inode;
94}
95
Raphael Moll4605b3f2012-02-03 23:02:33 -080096#ifndef USE_MINGW
Colin Crossec0a2e82010-06-11 14:21:37 -070097/* Read a local directory and create the same tree in the generated filesystem.
98 Calls itself recursively with each directory in the given directory */
99static u32 build_directory_structure(const char *full_path, const char *dir_path,
100 u32 dir_inode, int android)
101{
102 int entries = 0;
103 struct dentry *dentries;
104 struct dirent **namelist;
105 struct stat stat;
106 int ret;
107 int i;
108 u32 inode;
109 u32 entry_inode;
110 u32 dirs = 0;
111
Colin Cross8aef66d2010-06-20 23:22:12 -0700112 entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
Colin Crossec0a2e82010-06-11 14:21:37 -0700113 if (entries < 0) {
114 error_errno("scandir");
115 return EXT4_ALLOCATE_FAILED;
116 }
117
118 dentries = calloc(entries, sizeof(struct dentry));
119 if (dentries == NULL)
120 critical_error_errno("malloc");
121
122 for (i = 0; i < entries; i++) {
123 dentries[i].filename = strdup(namelist[i]->d_name);
124 if (dentries[i].filename == NULL)
125 critical_error_errno("strdup");
126
127 asprintf(&dentries[i].path, "%s/%s", dir_path, namelist[i]->d_name);
128 asprintf(&dentries[i].full_path, "%s/%s", full_path, namelist[i]->d_name);
129
130 free(namelist[i]);
131
132 ret = lstat(dentries[i].full_path, &stat);
133 if (ret < 0) {
134 error_errno("lstat");
135 i--;
136 entries--;
137 continue;
138 }
139
140 dentries[i].size = stat.st_size;
141 dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
Colin Crossde61f982010-08-04 15:06:09 -0700142 dentries[i].mtime = stat.st_mtime;
Colin Crossec0a2e82010-06-11 14:21:37 -0700143 if (android) {
144#ifdef ANDROID
145 unsigned int mode = 0;
146 unsigned int uid = 0;
147 unsigned int gid = 0;
148 int dir = S_ISDIR(stat.st_mode);
149 fs_config(dentries[i].path, dir, &uid, &gid, &mode);
150 dentries[i].mode = mode;
151 dentries[i].uid = uid;
152 dentries[i].gid = gid;
153#else
154 error("can't set android permissions - built without android support");
155#endif
156 }
157
158 if (S_ISREG(stat.st_mode)) {
159 dentries[i].file_type = EXT4_FT_REG_FILE;
160 } else if (S_ISDIR(stat.st_mode)) {
161 dentries[i].file_type = EXT4_FT_DIR;
162 dirs++;
163 } else if (S_ISCHR(stat.st_mode)) {
164 dentries[i].file_type = EXT4_FT_CHRDEV;
165 } else if (S_ISBLK(stat.st_mode)) {
166 dentries[i].file_type = EXT4_FT_BLKDEV;
167 } else if (S_ISFIFO(stat.st_mode)) {
168 dentries[i].file_type = EXT4_FT_FIFO;
169 } else if (S_ISSOCK(stat.st_mode)) {
170 dentries[i].file_type = EXT4_FT_SOCK;
171 } else if (S_ISLNK(stat.st_mode)) {
172 dentries[i].file_type = EXT4_FT_SYMLINK;
173 dentries[i].link = calloc(info.block_size, 1);
174 readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1);
175 } else {
176 error("unknown file type on %s", dentries[i].path);
177 i--;
178 entries--;
179 }
180 }
181 free(namelist);
182
183 inode = make_directory(dir_inode, entries, dentries, dirs);
184
185 for (i = 0; i < entries; i++) {
186 if (dentries[i].file_type == EXT4_FT_REG_FILE) {
187 entry_inode = make_file(dentries[i].full_path, dentries[i].size);
188 } else if (dentries[i].file_type == EXT4_FT_DIR) {
189 entry_inode = build_directory_structure(dentries[i].full_path,
190 dentries[i].path, inode, android);
191 } else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
192 entry_inode = make_link(dentries[i].full_path, dentries[i].link);
193 } else {
194 error("unknown file type on %s", dentries[i].path);
195 entry_inode = 0;
196 }
197 *dentries[i].inode = entry_inode;
198
199 ret = inode_set_permissions(entry_inode, dentries[i].mode,
Colin Crossde61f982010-08-04 15:06:09 -0700200 dentries[i].uid, dentries[i].gid,
201 dentries[i].mtime);
Colin Crossec0a2e82010-06-11 14:21:37 -0700202 if (ret)
203 error("failed to set permissions on %s\n", dentries[i].path);
204
205 free(dentries[i].path);
206 free(dentries[i].full_path);
207 free(dentries[i].link);
208 free((void *)dentries[i].filename);
209 }
210
211 free(dentries);
212 return inode;
213}
Raphael Moll4605b3f2012-02-03 23:02:33 -0800214#endif
Colin Crossec0a2e82010-06-11 14:21:37 -0700215
216static u32 compute_block_size()
217{
218 return 4096;
219}
220
Colin Crosse4b5ae82010-08-03 14:10:07 -0700221static u32 compute_journal_blocks()
222{
223 u32 journal_blocks = DIV_ROUND_UP(info.len, info.block_size) / 64;
224 if (journal_blocks < 1024)
225 journal_blocks = 1024;
226 if (journal_blocks > 32768)
227 journal_blocks = 32768;
228 return journal_blocks;
229}
230
Colin Crossec0a2e82010-06-11 14:21:37 -0700231static u32 compute_blocks_per_group()
232{
233 return info.block_size * 8;
234}
235
236static u32 compute_inodes()
237{
238 return DIV_ROUND_UP(info.len, info.block_size) / 4;
239}
240
241static u32 compute_inodes_per_group()
242{
243 u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
244 u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
Colin Cross96cc54a2011-04-29 16:45:48 -0700245 u32 inodes = DIV_ROUND_UP(info.inodes, block_groups);
Ken Sumrall107a9f12011-06-29 20:28:30 -0700246 inodes = ALIGN(inodes, (info.block_size / info.inode_size));
247
248 /* After properly rounding up the number of inodes/group,
249 * make sure to update the total inodes field in the info struct.
250 */
251 info.inodes = inodes * block_groups;
252
253 return inodes;
Colin Crossec0a2e82010-06-11 14:21:37 -0700254}
255
Colin Cross22742ce2010-12-22 16:01:52 -0800256static u32 compute_bg_desc_reserve_blocks()
257{
258 u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
259 u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
260 u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
261 info.block_size);
262
263 u32 bg_desc_reserve_blocks =
264 DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
265 info.block_size) - bg_desc_blocks;
266
267 if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
268 bg_desc_reserve_blocks = info.block_size / sizeof(u32);
269
270 return bg_desc_reserve_blocks;
271}
272
Doug Zongker263eefd2010-06-29 17:23:14 -0700273void reset_ext4fs_info() {
274 // Reset all the global data structures used by make_ext4fs so it
275 // can be called again.
276 memset(&info, 0, sizeof(info));
277 memset(&aux_info, 0, sizeof(aux_info));
278 free_data_blocks();
Colin Crossec0a2e82010-06-11 14:21:37 -0700279}
280
Ken Sumrall983fb192011-01-19 17:15:42 -0800281int make_ext4fs(const char *filename, s64 len)
282{
Anatol Pomazau354350e2012-02-03 18:20:07 -0800283 reset_ext4fs_info();
284 info.len = len;
285 return make_ext4fs_internal(filename, NULL, NULL, 0, 0, 0, 0, 1, 0);
Ken Sumrall983fb192011-01-19 17:15:42 -0800286}
287
Anatol Pomazau354350e2012-02-03 18:20:07 -0800288int make_ext4fs_internal(const char *filename, const char *directory,
Ken Sumrall983fb192011-01-19 17:15:42 -0800289 char *mountpoint, int android, int gzip, int sparse,
Ken Sumrall107a9f12011-06-29 20:28:30 -0700290 int crc, int wipe, int init_itabs)
Colin Crossec0a2e82010-06-11 14:21:37 -0700291{
Anatol Pomazau354350e2012-02-03 18:20:07 -0800292 u32 root_inode_num;
293 u16 root_mode;
Colin Crossec0a2e82010-06-11 14:21:37 -0700294
Ken Sumrall2ae76632011-03-23 22:08:53 -0700295 if (setjmp(setjmp_env))
296 return EXIT_FAILURE; /* Handle a call to longjmp() */
297
Ken Sumrall435a8b62011-01-14 18:33:06 -0800298 if (info.len <= 0)
Anatol Pomazau354350e2012-02-03 18:20:07 -0800299 info.len = get_file_size(filename);
Colin Crossec0a2e82010-06-11 14:21:37 -0700300
301 if (info.len <= 0) {
302 fprintf(stderr, "Need size of filesystem\n");
Anatol Pomazau354350e2012-02-03 18:20:07 -0800303 return EXIT_FAILURE;
Colin Crossec0a2e82010-06-11 14:21:37 -0700304 }
305
Colin Crossec0a2e82010-06-11 14:21:37 -0700306 if (info.block_size <= 0)
307 info.block_size = compute_block_size();
308
Ken Sumrall88833a62011-07-13 17:27:07 -0700309 /* Round down the filesystem length to be a multiple of the block size */
310 info.len &= ~((u64)info.block_size - 1);
311
Colin Crosse4b5ae82010-08-03 14:10:07 -0700312 if (info.journal_blocks == 0)
313 info.journal_blocks = compute_journal_blocks();
314
315 if (info.no_journal == 0)
316 info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
317 else
318 info.journal_blocks = 0;
319
Colin Crossec0a2e82010-06-11 14:21:37 -0700320 if (info.blocks_per_group <= 0)
321 info.blocks_per_group = compute_blocks_per_group();
322
323 if (info.inodes <= 0)
324 info.inodes = compute_inodes();
325
326 if (info.inode_size <= 0)
327 info.inode_size = 256;
328
329 if (info.label == NULL)
330 info.label = "";
331
332 info.inodes_per_group = compute_inodes_per_group();
333
334 info.feat_compat |=
335 EXT4_FEATURE_COMPAT_RESIZE_INODE;
336
337 info.feat_ro_compat |=
338 EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
339 EXT4_FEATURE_RO_COMPAT_LARGE_FILE;
340
341 info.feat_incompat |=
342 EXT4_FEATURE_INCOMPAT_EXTENTS |
343 EXT4_FEATURE_INCOMPAT_FILETYPE;
344
345
Colin Cross22742ce2010-12-22 16:01:52 -0800346 info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
347
Colin Crossec0a2e82010-06-11 14:21:37 -0700348 printf("Creating filesystem with parameters:\n");
349 printf(" Size: %llu\n", info.len);
350 printf(" Block size: %d\n", info.block_size);
351 printf(" Blocks per group: %d\n", info.blocks_per_group);
352 printf(" Inodes per group: %d\n", info.inodes_per_group);
353 printf(" Inode size: %d\n", info.inode_size);
Colin Crosse4b5ae82010-08-03 14:10:07 -0700354 printf(" Journal blocks: %d\n", info.journal_blocks);
Colin Crossec0a2e82010-06-11 14:21:37 -0700355 printf(" Label: %s\n", info.label);
356
357 ext4_create_fs_aux_info();
358
359 printf(" Blocks: %llu\n", aux_info.len_blocks);
360 printf(" Block groups: %d\n", aux_info.groups);
Colin Cross22742ce2010-12-22 16:01:52 -0800361 printf(" Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
Colin Crossec0a2e82010-06-11 14:21:37 -0700362
363 block_allocator_init();
364
365 ext4_fill_in_sb();
366
367 if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
368 error("failed to reserve first 10 inodes");
369
370 if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
371 ext4_create_journal_inode();
372
373 if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
374 ext4_create_resize_inode();
375
Raphael Moll4605b3f2012-02-03 23:02:33 -0800376#ifdef USE_MINGW
377 // Windows needs only 'create an empty fs image' functionality
378 assert(!directory);
379 root_inode_num = build_default_directory_structure();
380#else
Colin Crossec0a2e82010-06-11 14:21:37 -0700381 if (directory)
382 root_inode_num = build_directory_structure(directory, mountpoint, 0, android);
383 else
384 root_inode_num = build_default_directory_structure();
Raphael Moll4605b3f2012-02-03 23:02:33 -0800385#endif
Doug Zongker263eefd2010-06-29 17:23:14 -0700386
Colin Crossec0a2e82010-06-11 14:21:37 -0700387 root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
Colin Crossde61f982010-08-04 15:06:09 -0700388 inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
Colin Crossec0a2e82010-06-11 14:21:37 -0700389
390 ext4_update_free();
391
Ken Sumrall107a9f12011-06-29 20:28:30 -0700392 if (init_itabs)
393 init_unused_inode_tables();
394
Colin Crossb7813302010-12-22 18:41:13 -0800395 ext4_queue_sb();
396
Colin Crossec0a2e82010-06-11 14:21:37 -0700397 printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
398 aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
399 aux_info.sb->s_inodes_count,
400 aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
401 aux_info.sb->s_blocks_count_lo);
402
Anatol Pomazau354350e2012-02-03 18:20:07 -0800403 write_ext4_image(filename, gzip, sparse, crc, wipe);
Colin Crossec0a2e82010-06-11 14:21:37 -0700404
405 return 0;
406}