make_ext4fs.c revision dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7
116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood/*
216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Copyright (C) 2010 The Android Open Source Project
316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * you may not use this file except in compliance with the License.
616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * You may obtain a copy of the License at
716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood *
1016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * See the License for the specific language governing permissions and
1416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood * limitations under the License.
1516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood */
1616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
17b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "make_ext4fs.h"
18b14e588bec4d5e39e61b020b5b575f2ce555d316Mike Lockwood#include "ext4_utils.h"
1916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "allocate.h"
2016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "contents.h"
2116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "uuid.h"
2216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include "wipe.h"
2316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
247850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood#include <sparse/sparse.h>
2516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
2616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <assert.h>
2716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <dirent.h>
2816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <fcntl.h>
2916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <libgen.h>
3016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <stdio.h>
3116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <stdlib.h>
3216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <string.h>
3316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <unistd.h>
3416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/stat.h>
3516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <sys/types.h>
3616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
3716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#ifdef USE_MINGW
3816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
3916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#include <winsock2.h>
40dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood
41dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood/* These match the Linux definitions of these flags.
42dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood   L_xx is defined to avoid conflicting with the win32 versions.
43dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood*/
44dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood#define L_S_IRUSR 00400
45dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood#define L_S_IWUSR 00200
46dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood#define L_S_IXUSR 00100
4716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IRWXU (L_S_IRUSR | L_S_IWUSR | L_S_IXUSR)
4816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IRGRP 00040
4916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IWGRP 00020
5016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IXGRP 00010
5116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
5216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IROTH 00004
5316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IWOTH 00002
5416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IXOTH 00001
5516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
5616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_ISUID 0004000
5716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_ISGID 0002000
5816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define S_ISVTX 0001000
5916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#else
6116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#define O_BINARY 0
6316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#endif
6516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
6616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood/* TODO: Not implemented:
6716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood   Allocating blocks in the same block group as the file inode
6816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood   Hash or binary tree directories
6916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood   Special files: sockets, devices, fifos
7016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood */
7116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic int filter_dot(const struct dirent *d)
7316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
7416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
7516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
7616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
7716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwoodstatic u32 build_default_directory_structure()
7816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood{
7916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	u32 inode;
8016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	u32 root_inode;
8116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	struct dentry dentries = {
8216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			.filename = "lost+found",
8316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			.file_type = EXT4_FT_DIR,
8416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			.mode = S_IRWXU,
8516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			.uid = 0,
8616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			.gid = 0,
8716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			.mtime = 0,
8816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	};
8916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	root_inode = make_directory(0, 1, &dentries, 1);
9016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	inode = make_directory(root_inode, 0, NULL, 0);
9116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	*dentries.inode = inode;
9216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	inode_set_permissions(inode, dentries.mode,
9316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		dentries.uid, dentries.gid, dentries.mtime);
9416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
9516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	return root_inode;
9616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood}
9716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
98dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood#ifndef USE_MINGW
99dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood/* Read a local directory and create the same tree in the generated filesystem.
100dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood   Calls itself recursively with each directory in the given directory */
101dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwoodstatic u32 build_directory_structure(const char *full_path, const char *dir_path,
102dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood		u32 dir_inode, fs_config_func_t fs_config_func,
103dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood		struct selabel_handle *sehnd)
104dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood{
105dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	int entries = 0;
106dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	struct dentry *dentries;
107dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	struct dirent **namelist;
108dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	struct stat stat;
109dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	int ret;
110dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	int i;
111dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	u32 inode;
112dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	u32 entry_inode;
113dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	u32 dirs = 0;
114dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood
115dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
116dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	if (entries < 0) {
117dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood		error_errno("scandir");
118dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood		return EXT4_ALLOCATE_FAILED;
119dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood	}
120dde372033b4da75ebde7ea2afdec1c1b86ab5a42Mike Lockwood
12116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	dentries = calloc(entries, sizeof(struct dentry));
12216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	if (dentries == NULL)
12316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		critical_error_errno("malloc");
12416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
12516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood	for (i = 0; i < entries; i++) {
12616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		dentries[i].filename = strdup(namelist[i]->d_name);
12716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		if (dentries[i].filename == NULL)
12816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			critical_error_errno("strdup");
12916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		asprintf(&dentries[i].path, "%s/%s", dir_path, namelist[i]->d_name);
13116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		asprintf(&dentries[i].full_path, "%s/%s", full_path, namelist[i]->d_name);
13216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		free(namelist[i]);
13416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
13516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		ret = lstat(dentries[i].full_path, &stat);
13616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		if (ret < 0) {
13716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			error_errno("lstat");
13816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			i--;
13916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			entries--;
14016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			continue;
14116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		}
14216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood
14316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		dentries[i].size = stat.st_size;
14416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
145de1e37aad04640ef76f3c017b65adca087c7be0fMike Lockwood		dentries[i].mtime = stat.st_mtime;
14616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		if (fs_config_func != NULL) {
14716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#ifdef ANDROID
14816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			unsigned int mode = 0;
14916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			unsigned int uid = 0;
15016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			unsigned int gid = 0;
15116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			int dir = S_ISDIR(stat.st_mode);
15216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			fs_config_func(dentries[i].path, dir, &uid, &gid, &mode);
15316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			dentries[i].mode = mode;
15416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			dentries[i].uid = uid;
15516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			dentries[i].gid = gid;
15616864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#else
15716864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			error("can't set android permissions - built without android support");
15816864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#endif
15916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		}
16016864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood#ifdef HAVE_SELINUX
16116864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood		if (sehnd) {
16216864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			char *sepath = NULL;
16316864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			asprintf(&sepath, "/%s", dentries[i].path);
16416864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			if (selabel_lookup(sehnd, &dentries[i].secon, sepath, stat.st_mode) < 0) {
16516864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood				error("cannot lookup security context for %s", sepath);
166de1e37aad04640ef76f3c017b65adca087c7be0fMike Lockwood			}
167de1e37aad04640ef76f3c017b65adca087c7be0fMike Lockwood			if (dentries[i].secon)
168de1e37aad04640ef76f3c017b65adca087c7be0fMike Lockwood				printf("Labeling %s as %s\n", sepath, dentries[i].secon);
16916864bae0f51c32c456da2c43adf7a057c0c4882Mike Lockwood			free(sepath);
1707850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood		}
1717850ef999740f214a1990a9c090d3f3865d435aaMike Lockwood#endif
172
173		if (S_ISREG(stat.st_mode)) {
174			dentries[i].file_type = EXT4_FT_REG_FILE;
175		} else if (S_ISDIR(stat.st_mode)) {
176			dentries[i].file_type = EXT4_FT_DIR;
177			dirs++;
178		} else if (S_ISCHR(stat.st_mode)) {
179			dentries[i].file_type = EXT4_FT_CHRDEV;
180		} else if (S_ISBLK(stat.st_mode)) {
181			dentries[i].file_type = EXT4_FT_BLKDEV;
182		} else if (S_ISFIFO(stat.st_mode)) {
183			dentries[i].file_type = EXT4_FT_FIFO;
184		} else if (S_ISSOCK(stat.st_mode)) {
185			dentries[i].file_type = EXT4_FT_SOCK;
186		} else if (S_ISLNK(stat.st_mode)) {
187			dentries[i].file_type = EXT4_FT_SYMLINK;
188			dentries[i].link = calloc(info.block_size, 1);
189			readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1);
190		} else {
191			error("unknown file type on %s", dentries[i].path);
192			i--;
193			entries--;
194		}
195	}
196	free(namelist);
197
198	inode = make_directory(dir_inode, entries, dentries, dirs);
199
200	for (i = 0; i < entries; i++) {
201		if (dentries[i].file_type == EXT4_FT_REG_FILE) {
202			entry_inode = make_file(dentries[i].full_path, dentries[i].size);
203		} else if (dentries[i].file_type == EXT4_FT_DIR) {
204			entry_inode = build_directory_structure(dentries[i].full_path,
205					dentries[i].path, inode, fs_config_func, sehnd);
206		} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
207			entry_inode = make_link(dentries[i].full_path, dentries[i].link);
208		} else {
209			error("unknown file type on %s", dentries[i].path);
210			entry_inode = 0;
211		}
212		*dentries[i].inode = entry_inode;
213
214		ret = inode_set_permissions(entry_inode, dentries[i].mode,
215			dentries[i].uid, dentries[i].gid,
216			dentries[i].mtime);
217		if (ret)
218			error("failed to set permissions on %s\n", dentries[i].path);
219		ret = inode_set_selinux(entry_inode, dentries[i].secon);
220		if (ret)
221			error("failed to set SELinux context on %s\n", dentries[i].path);
222
223		free(dentries[i].path);
224		free(dentries[i].full_path);
225		free(dentries[i].link);
226		free((void *)dentries[i].filename);
227		free(dentries[i].secon);
228	}
229
230	free(dentries);
231	return inode;
232}
233#endif
234
235static u32 compute_block_size()
236{
237	return 4096;
238}
239
240static u32 compute_journal_blocks()
241{
242	u32 journal_blocks = DIV_ROUND_UP(info.len, info.block_size) / 64;
243	if (journal_blocks < 1024)
244		journal_blocks = 1024;
245	if (journal_blocks > 32768)
246		journal_blocks = 32768;
247	return journal_blocks;
248}
249
250static u32 compute_blocks_per_group()
251{
252	return info.block_size * 8;
253}
254
255static u32 compute_inodes()
256{
257	return DIV_ROUND_UP(info.len, info.block_size) / 4;
258}
259
260static u32 compute_inodes_per_group()
261{
262	u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
263	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
264	u32 inodes = DIV_ROUND_UP(info.inodes, block_groups);
265	inodes = ALIGN(inodes, (info.block_size / info.inode_size));
266
267	/* After properly rounding up the number of inodes/group,
268	 * make sure to update the total inodes field in the info struct.
269	 */
270	info.inodes = inodes * block_groups;
271
272	return inodes;
273}
274
275static u32 compute_bg_desc_reserve_blocks()
276{
277	u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
278	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
279	u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
280			info.block_size);
281
282	u32 bg_desc_reserve_blocks =
283			DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
284					info.block_size) - bg_desc_blocks;
285
286	if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
287		bg_desc_reserve_blocks = info.block_size / sizeof(u32);
288
289	return bg_desc_reserve_blocks;
290}
291
292void reset_ext4fs_info() {
293    // Reset all the global data structures used by make_ext4fs so it
294    // can be called again.
295    memset(&info, 0, sizeof(info));
296    memset(&aux_info, 0, sizeof(aux_info));
297    free_data_blocks();
298}
299
300int make_ext4fs(const char *filename, s64 len,
301                const char *mountpoint, struct selabel_handle *sehnd)
302{
303	int fd;
304	int status;
305
306	reset_ext4fs_info();
307	info.len = len;
308
309	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
310	if (fd < 0) {
311		error_errno("open");
312		return EXIT_FAILURE;
313	}
314
315	status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, 0, sehnd);
316	close(fd);
317
318	return status;
319}
320
321int make_ext4fs_internal(int fd, const char *directory,
322                         char *mountpoint, fs_config_func_t fs_config_func, int gzip, int sparse,
323                         int crc, int wipe, int init_itabs, struct selabel_handle *sehnd)
324{
325	u32 root_inode_num;
326	u16 root_mode;
327
328	if (setjmp(setjmp_env))
329		return EXIT_FAILURE; /* Handle a call to longjmp() */
330
331	if (info.len <= 0)
332		info.len = get_file_size(fd);
333
334	if (info.len <= 0) {
335		fprintf(stderr, "Need size of filesystem\n");
336		return EXIT_FAILURE;
337	}
338
339	if (info.block_size <= 0)
340		info.block_size = compute_block_size();
341
342	/* Round down the filesystem length to be a multiple of the block size */
343	info.len &= ~((u64)info.block_size - 1);
344
345	if (info.journal_blocks == 0)
346		info.journal_blocks = compute_journal_blocks();
347
348	if (info.no_journal == 0)
349		info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
350	else
351		info.journal_blocks = 0;
352
353	if (info.blocks_per_group <= 0)
354		info.blocks_per_group = compute_blocks_per_group();
355
356	if (info.inodes <= 0)
357		info.inodes = compute_inodes();
358
359	if (info.inode_size <= 0)
360		info.inode_size = 256;
361
362	if (info.label == NULL)
363		info.label = "";
364
365	info.inodes_per_group = compute_inodes_per_group();
366
367	info.feat_compat |=
368			EXT4_FEATURE_COMPAT_RESIZE_INODE;
369
370	info.feat_ro_compat |=
371			EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
372			EXT4_FEATURE_RO_COMPAT_LARGE_FILE;
373
374	info.feat_incompat |=
375			EXT4_FEATURE_INCOMPAT_EXTENTS |
376			EXT4_FEATURE_INCOMPAT_FILETYPE;
377
378
379	info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
380
381	printf("Creating filesystem with parameters:\n");
382	printf("    Size: %llu\n", info.len);
383	printf("    Block size: %d\n", info.block_size);
384	printf("    Blocks per group: %d\n", info.blocks_per_group);
385	printf("    Inodes per group: %d\n", info.inodes_per_group);
386	printf("    Inode size: %d\n", info.inode_size);
387	printf("    Journal blocks: %d\n", info.journal_blocks);
388	printf("    Label: %s\n", info.label);
389
390	ext4_create_fs_aux_info();
391
392	printf("    Blocks: %llu\n", aux_info.len_blocks);
393	printf("    Block groups: %d\n", aux_info.groups);
394	printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
395
396	block_allocator_init();
397
398	ext4_fill_in_sb();
399
400	if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
401		error("failed to reserve first 10 inodes");
402
403	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
404		ext4_create_journal_inode();
405
406	if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
407		ext4_create_resize_inode();
408
409#ifdef USE_MINGW
410	// Windows needs only 'create an empty fs image' functionality
411	assert(!directory);
412	root_inode_num = build_default_directory_structure();
413#else
414	if (directory)
415		root_inode_num = build_directory_structure(directory, mountpoint, 0,
416                        fs_config_func, sehnd);
417	else
418		root_inode_num = build_default_directory_structure();
419#endif
420
421	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
422	inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
423
424#ifdef HAVE_SELINUX
425	if (sehnd) {
426		char *sepath = NULL;
427		char *secontext = NULL;
428
429		if (mountpoint[0] == '/')
430			sepath = strdup(mountpoint);
431		else
432			asprintf(&sepath, "/%s", mountpoint);
433		if (!sepath)
434			critical_error_errno("malloc");
435		if (selabel_lookup(sehnd, &secontext, sepath, S_IFDIR) < 0) {
436			error("cannot lookup security context for %s", sepath);
437		}
438		if (secontext) {
439			printf("Labeling %s as %s\n", sepath, secontext);
440			inode_set_selinux(root_inode_num, secontext);
441		}
442		free(sepath);
443		freecon(secontext);
444	}
445#endif
446
447	ext4_update_free();
448
449	if (init_itabs)
450		init_unused_inode_tables();
451
452	ext4_queue_sb();
453
454	printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
455			aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
456			aux_info.sb->s_inodes_count,
457			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
458			aux_info.sb->s_blocks_count_lo);
459
460	if (wipe)
461		wipe_block_device(fd, info.len);
462
463	write_ext4_image(fd, gzip, sparse, crc);
464
465	return 0;
466}
467