1ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/*
2ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * Copyright (C) 2010 The Android Open Source Project
3ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *
4ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * Licensed under the Apache License, Version 2.0 (the "License");
5ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * you may not use this file except in compliance with the License.
6ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * You may obtain a copy of the License at
7ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *
89579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash *	  http://www.apache.org/licenses/LICENSE-2.0
9ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross *
10ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * Unless required by applicable law or agreed to in writing, software
11ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * distributed under the License is distributed on an "AS IS" BASIS,
12ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * See the License for the specific language governing permissions and
14ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross * limitations under the License.
15ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross */
16ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
17018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include "ext4_utils/make_ext4fs.h"
18dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross
19018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#ifndef _GNU_SOURCE
20018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#define _GNU_SOURCE
21018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#endif
22ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
234605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#include <assert.h>
24ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include <dirent.h>
250349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#include <fcntl.h>
26af0723439af552c170425416ee8e35f4f20bbe67Colin Cross#include <inttypes.h>
27ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#include <libgen.h>
28881cca2f88ddcce86483b3ba95546b5641de8c0eColin Cross#include <stdio.h>
29881cca2f88ddcce86483b3ba95546b5641de8c0eColin Cross#include <stdlib.h>
30881cca2f88ddcce86483b3ba95546b5641de8c0eColin Cross#include <string.h>
31881cca2f88ddcce86483b3ba95546b5641de8c0eColin Cross#include <sys/stat.h>
32881cca2f88ddcce86483b3ba95546b5641de8c0eColin Cross#include <sys/types.h>
33018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include <unistd.h>
34018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao
35018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include <sparse/sparse.h>
36018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao
37018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include "allocate.h"
38018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include "contents.h"
39018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include "ext4_utils/ext4_utils.h"
40018ef1be61e749d0fbe0f05179a4f0f9b858ae57Tao Bao#include "ext4_utils/wipe.h"
41ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
421eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifdef _WIN32
434605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll
444605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#include <winsock2.h>
454605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll
464605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll/* These match the Linux definitions of these flags.
474605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll   L_xx is defined to avoid conflicting with the win32 versions.
484605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll*/
49879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IRWXU
50879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IRGRP
51879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IWGRP
52879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IXGRP
53879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IRWXG
54879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IROTH
55879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IWOTH
56879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IXOTH
57879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_IRWXO
58879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_ISUID
59879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_ISGID
60879785074ca93e13896ce364a45eb5cc17081c4aDan Albert#undef S_ISVTX
61879785074ca93e13896ce364a45eb5cc17081c4aDan Albert
624605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define L_S_IRUSR 00400
634605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define L_S_IWUSR 00200
644605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define L_S_IXUSR 00100
654605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IRWXU (L_S_IRUSR | L_S_IWUSR | L_S_IXUSR)
664605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IRGRP 00040
674605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IWGRP 00020
684605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IXGRP 00010
694605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
704605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IROTH 00004
714605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IWOTH 00002
724605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IXOTH 00001
734605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
744605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_ISUID 0004000
754605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_ISGID 0002000
764605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#define S_ISVTX 0001000
774605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll
780349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#else
790349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
80965298695c981ee5a67e86977a8e40a50f7392abColin Cross#include <selinux/selinux.h>
81965298695c981ee5a67e86977a8e40a50f7392abColin Cross#include <selinux/label.h>
82965298695c981ee5a67e86977a8e40a50f7392abColin Cross
830349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau#define O_BINARY 0
840349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
854605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#endif
864605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll
879579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash#define MAX_PATH 4096
889579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash#define MAX_BLK_MAPPING_STR 1000
899579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
909579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashconst int blk_file_major_ver = 1;
919579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashconst int blk_file_minor_ver = 0;
929579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashconst char *blk_file_header_fmt = "Base EXT4 version %d.%d";
939579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
94ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* TODO: Not implemented:
95ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   Allocating blocks in the same block group as the file inode
96ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross   Hash or binary tree directories
977a8bee7653c393d8da0e28668cb51d3ccab793e8Colin Cross   Special files: sockets, devices, fifos
98ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross */
99ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
100ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic int filter_dot(const struct dirent *d)
101ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
102ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
103ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
104ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
1057907ac7c811670643c3606125657a39226507ea1Stephen Smalleystatic u32 build_default_directory_structure(const char *dir_path,
1069579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash						 struct selabel_handle *sehnd)
107ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
108ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode;
109ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 root_inode;
110ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct dentry dentries = {
111ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			.filename = "lost+found",
112ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			.file_type = EXT4_FT_DIR,
113ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			.mode = S_IRWXU,
114ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			.uid = 0,
115de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross			.gid = 0,
116de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross			.mtime = 0,
117ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	};
118ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	root_inode = make_directory(0, 1, &dentries, 1);
119ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = make_directory(root_inode, 0, NULL, 0);
120ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	*dentries.inode = inode;
12175249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall	inode_set_permissions(inode, dentries.mode,
12275249edab0b22ea9aae9c7278b9f2c196c7d25d4Ken Sumrall		dentries.uid, dentries.gid, dentries.mtime);
123ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
1241eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifndef _WIN32
1257907ac7c811670643c3606125657a39226507ea1Stephen Smalley	if (sehnd) {
1267907ac7c811670643c3606125657a39226507ea1Stephen Smalley		char *path = NULL;
1277907ac7c811670643c3606125657a39226507ea1Stephen Smalley		char *secontext = NULL;
1287907ac7c811670643c3606125657a39226507ea1Stephen Smalley
1297907ac7c811670643c3606125657a39226507ea1Stephen Smalley		asprintf(&path, "%slost+found", dir_path);
1307907ac7c811670643c3606125657a39226507ea1Stephen Smalley		if (selabel_lookup(sehnd, &secontext, path, S_IFDIR) < 0) {
1317907ac7c811670643c3606125657a39226507ea1Stephen Smalley			error("cannot lookup security context for %s", path);
1327907ac7c811670643c3606125657a39226507ea1Stephen Smalley		} else {
1337907ac7c811670643c3606125657a39226507ea1Stephen Smalley			inode_set_selinux(inode, secontext);
1347907ac7c811670643c3606125657a39226507ea1Stephen Smalley			freecon(secontext);
1357907ac7c811670643c3606125657a39226507ea1Stephen Smalley		}
1367907ac7c811670643c3606125657a39226507ea1Stephen Smalley		free(path);
1377907ac7c811670643c3606125657a39226507ea1Stephen Smalley	}
1387907ac7c811670643c3606125657a39226507ea1Stephen Smalley#endif
1397907ac7c811670643c3606125657a39226507ea1Stephen Smalley
140ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return root_inode;
141ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
142ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
1431eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifndef _WIN32
144ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross/* Read a local directory and create the same tree in the generated filesystem.
145a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross   Calls itself recursively with each directory in the given directory.
146a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross   full_path is an absolute or relative path, with a trailing slash, to the
147a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross   directory on disk that should be copied, or NULL if this is a directory
148a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross   that does not exist on disk (e.g. lost+found).
149a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross   dir_path is an absolute path, with trailing slash, to the same directory
150a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross   if the image were mounted at the specified mount point */
151b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudelstatic u32 build_directory_structure(const char *full_path, const char *dir_path, const char *target_out_path,
1522e5c52322d54d0f98d36b499fcaa31a0e84ca87cKenny Root		u32 dir_inode, fs_config_func_t fs_config_func,
1539526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker		struct selabel_handle *sehnd, int verbose, time_t fixed_time)
154ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
155ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	int entries = 0;
156ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct dentry *dentries;
157c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	struct dirent **namelist = NULL;
158ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	struct stat stat;
159ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	int ret;
160ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	int i;
161ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 inode;
162ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 entry_inode;
163ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 dirs = 0;
164c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	bool needs_lost_and_found = false;
165ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
166c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	if (full_path) {
167c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
168c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		if (entries < 0) {
16904f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban#ifdef __GLIBC__
17004f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			/* The scandir function implemented in glibc has a bug that makes it
17104f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			   erroneously fail with ENOMEM under certain circumstances.
17204f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			   As a workaround we can retry the scandir call with the same arguments.
17304f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			   GLIBC BZ: https://sourceware.org/bugzilla/show_bug.cgi?id=17804 */
17404f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			if (errno == ENOMEM)
17504f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban				entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
17604f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban#endif
17704f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			if (entries < 0) {
17804f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban				error_errno("scandir");
17904f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban				return EXT4_ALLOCATE_FAILED;
18004f4839594cb8ceea93b9c709bc5bba231d68ae0Mihai Serban			}
181c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		}
182c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	}
183c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross
184c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	if (dir_inode == 0) {
185c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		/* root directory, check if lost+found already exists */
186c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		for (i = 0; i < entries; i++)
187c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross			if (strcmp(namelist[i]->d_name, "lost+found") == 0)
188c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross				break;
189c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		if (i == entries)
190c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross			needs_lost_and_found = true;
191ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
192ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
193ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	dentries = calloc(entries, sizeof(struct dentry));
194ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (dentries == NULL)
195ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		critical_error_errno("malloc");
196ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
197ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	for (i = 0; i < entries; i++) {
198ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dentries[i].filename = strdup(namelist[i]->d_name);
199ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (dentries[i].filename == NULL)
200ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			critical_error_errno("strdup");
201ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
202a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross		asprintf(&dentries[i].path, "%s%s", dir_path, namelist[i]->d_name);
203a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross		asprintf(&dentries[i].full_path, "%s%s", full_path, namelist[i]->d_name);
204ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
205ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		free(namelist[i]);
206ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
207ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		ret = lstat(dentries[i].full_path, &stat);
208ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (ret < 0) {
209ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error_errno("lstat");
210ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			i--;
211ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			entries--;
212ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			continue;
213ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		}
214ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
215ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dentries[i].size = stat.st_size;
216ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
2179526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker		if (fixed_time == -1) {
2189526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker			dentries[i].mtime = stat.st_mtime;
2199526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker		} else {
2209526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker			dentries[i].mtime = fixed_time;
2219526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker		}
2224df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		uint64_t capabilities;
22368e3dfd81ddb9367a0c3e0c72148c23a3227ed48Kenny Root		if (fs_config_func != NULL) {
224ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#ifdef ANDROID
225ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			unsigned int mode = 0;
226ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			unsigned int uid = 0;
227ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			unsigned int gid = 0;
228ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			int dir = S_ISDIR(stat.st_mode);
229b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel			fs_config_func(dentries[i].path, dir, target_out_path, &uid, &gid, &mode, &capabilities);
230ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].mode = mode;
231ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].uid = uid;
232ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].gid = gid;
2334df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			dentries[i].capabilities = capabilities;
234ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#else
235ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error("can't set android permissions - built without android support");
236ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross#endif
237ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		}
2381eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifndef _WIN32
239b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		if (sehnd) {
240a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) {
241a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross				error("cannot lookup security context for %s", dentries[i].path);
242b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley			}
2432057370a2db739d8a7d8a475c9a0773efc3d91a0William Roberts
2442057370a2db739d8a7d8a475c9a0773efc3d91a0William Roberts			if (dentries[i].secon && verbose)
245a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross				printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon);
246b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		}
247b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#endif
248ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
249ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (S_ISREG(stat.st_mode)) {
250ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_REG_FILE;
251ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (S_ISDIR(stat.st_mode)) {
252ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_DIR;
253ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dirs++;
254ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (S_ISCHR(stat.st_mode)) {
255ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_CHRDEV;
256ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (S_ISBLK(stat.st_mode)) {
257ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_BLKDEV;
258ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (S_ISFIFO(stat.st_mode)) {
259ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_FIFO;
260ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (S_ISSOCK(stat.st_mode)) {
261ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_SOCK;
262ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (S_ISLNK(stat.st_mode)) {
263ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].file_type = EXT4_FT_SYMLINK;
264ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			dentries[i].link = calloc(info.block_size, 1);
265ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1);
266ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else {
267ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error("unknown file type on %s", dentries[i].path);
268ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			i--;
269ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			entries--;
270ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		}
271ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
272ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	free(namelist);
273ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
274c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	if (needs_lost_and_found) {
275c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		/* insert a lost+found directory at the beginning of the dentries */
276c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		struct dentry *tmp = calloc(entries + 1, sizeof(struct dentry));
277c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		memset(tmp, 0, sizeof(struct dentry));
278c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		memcpy(tmp + 1, dentries, entries * sizeof(struct dentry));
279c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries = tmp;
280c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross
281c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].filename = strdup("lost+found");
282a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross		asprintf(&dentries[0].path, "%slost+found", dir_path);
283c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].full_path = NULL;
284c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].size = 0;
285c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].mode = S_IRWXU;
286c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].file_type = EXT4_FT_DIR;
287c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].uid = 0;
288c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dentries[0].gid = 0;
289a532ecf00fcfdc334c55de75a63c3d0bc95a2379Colin Cross		if (sehnd) {
290a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0)
291a532ecf00fcfdc334c55de75a63c3d0bc95a2379Colin Cross				error("cannot lookup security context for %s", dentries[0].path);
292a532ecf00fcfdc334c55de75a63c3d0bc95a2379Colin Cross		}
293c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		entries++;
294c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross		dirs++;
295c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross	}
296c18120d04f164c00bad9d7006d29b4a795cf5d05Colin Cross
297ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	inode = make_directory(dir_inode, entries, dentries, dirs);
298ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
299ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	for (i = 0; i < entries; i++) {
300ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (dentries[i].file_type == EXT4_FT_REG_FILE) {
301ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			entry_inode = make_file(dentries[i].full_path, dentries[i].size);
302ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (dentries[i].file_type == EXT4_FT_DIR) {
303a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			char *subdir_full_path = NULL;
304a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			char *subdir_dir_path;
305a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			if (dentries[i].full_path) {
306a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross				ret = asprintf(&subdir_full_path, "%s/", dentries[i].full_path);
307a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross				if (ret < 0)
308a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross					critical_error_errno("asprintf");
309a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			}
310a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			ret = asprintf(&subdir_dir_path, "%s/", dentries[i].path);
311a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			if (ret < 0)
312a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross				critical_error_errno("asprintf");
313b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel			entry_inode = build_directory_structure(subdir_full_path, subdir_dir_path, target_out_path,
314b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel					inode, fs_config_func, sehnd, verbose, fixed_time);
315a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			free(subdir_full_path);
316a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			free(subdir_dir_path);
317ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
3185446bde9c02f6ae95a30d9c178b13a05bb580fe1Nick Kralevich			entry_inode = make_link(dentries[i].link);
319ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		} else {
320ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error("unknown file type on %s", dentries[i].path);
321ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			entry_inode = 0;
322ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		}
323ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		*dentries[i].inode = entry_inode;
324ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
325ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		ret = inode_set_permissions(entry_inode, dentries[i].mode,
326de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross			dentries[i].uid, dentries[i].gid,
327de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross			dentries[i].mtime);
328ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		if (ret)
329ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			error("failed to set permissions on %s\n", dentries[i].path);
3304df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich
3314df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		/*
3324df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		 * It's important to call inode_set_selinux() before
3334df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		 * inode_set_capabilities(). Extended attributes need to
3344df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		 * be stored sorted order, and we guarantee this by making
3354df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		 * the calls in the proper order.
3364df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		 * Please see xattr_assert_sane() in contents.c
3374df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		 */
338b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		ret = inode_set_selinux(entry_inode, dentries[i].secon);
339b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		if (ret)
340b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley			error("failed to set SELinux context on %s\n", dentries[i].path);
3414df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		ret = inode_set_capabilities(entry_inode, dentries[i].capabilities);
3424df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich		if (ret)
3434df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			error("failed to set capability on %s\n", dentries[i].path);
344ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
345ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		free(dentries[i].path);
346ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		free(dentries[i].full_path);
347ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		free(dentries[i].link);
348ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		free((void *)dentries[i].filename);
349b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		free(dentries[i].secon);
350ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	}
351ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
352ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	free(dentries);
353ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return inode;
354ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
3554605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#endif
356ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
357ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 compute_block_size()
358ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
359ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return 4096;
360ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
361ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
362e4b5ae8ab07e698b95f004c9226000b02f853abcColin Crossstatic u32 compute_journal_blocks()
363e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross{
364e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	u32 journal_blocks = DIV_ROUND_UP(info.len, info.block_size) / 64;
365e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	if (journal_blocks < 1024)
366e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross		journal_blocks = 1024;
367e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	if (journal_blocks > 32768)
368e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross		journal_blocks = 32768;
369e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	return journal_blocks;
370e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross}
371e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross
372ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 compute_blocks_per_group()
373ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
374ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return info.block_size * 8;
375ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
376ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
377ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 compute_inodes()
378ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
379ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return DIV_ROUND_UP(info.len, info.block_size) / 4;
380ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
381ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
382ec0a2e83dc66d67addeb90e83144187691852a3eColin Crossstatic u32 compute_inodes_per_group()
383ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
384ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
385ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
38696cc54a9bbc788673b7a38c23160d137211fd983Colin Cross	u32 inodes = DIV_ROUND_UP(info.inodes, block_groups);
38740ce87a70a064eeb462d3c3935422918c1f6114ePaul Lawrence	inodes = EXT4_ALIGN(inodes, (info.block_size / info.inode_size));
388107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall
389107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall	/* After properly rounding up the number of inodes/group,
390107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall	 * make sure to update the total inodes field in the info struct.
391107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall	 */
392107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall	info.inodes = inodes * block_groups;
393107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall
394107a9f161babc20daf915311146b0e864d3b4157Ken Sumrall	return inodes;
395ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
396ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
39722742ce739a046a079b2e1b03342a25472dfa352Colin Crossstatic u32 compute_bg_desc_reserve_blocks()
39822742ce739a046a079b2e1b03342a25472dfa352Colin Cross{
39922742ce739a046a079b2e1b03342a25472dfa352Colin Cross	u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
40022742ce739a046a079b2e1b03342a25472dfa352Colin Cross	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
40122742ce739a046a079b2e1b03342a25472dfa352Colin Cross	u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
40222742ce739a046a079b2e1b03342a25472dfa352Colin Cross			info.block_size);
40322742ce739a046a079b2e1b03342a25472dfa352Colin Cross
40422742ce739a046a079b2e1b03342a25472dfa352Colin Cross	u32 bg_desc_reserve_blocks =
40522742ce739a046a079b2e1b03342a25472dfa352Colin Cross			DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
40622742ce739a046a079b2e1b03342a25472dfa352Colin Cross					info.block_size) - bg_desc_blocks;
40722742ce739a046a079b2e1b03342a25472dfa352Colin Cross
40822742ce739a046a079b2e1b03342a25472dfa352Colin Cross	if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
40922742ce739a046a079b2e1b03342a25472dfa352Colin Cross		bg_desc_reserve_blocks = info.block_size / sizeof(u32);
41022742ce739a046a079b2e1b03342a25472dfa352Colin Cross
41122742ce739a046a079b2e1b03342a25472dfa352Colin Cross	return bg_desc_reserve_blocks;
41222742ce739a046a079b2e1b03342a25472dfa352Colin Cross}
41322742ce739a046a079b2e1b03342a25472dfa352Colin Cross
414263eefd9fb9608432636c903423e43848e69f39dDoug Zongkervoid reset_ext4fs_info() {
4159526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker	// Reset all the global data structures used by make_ext4fs so it
4169526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker	// can be called again.
4179526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker	memset(&info, 0, sizeof(info));
4189526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker	memset(&aux_info, 0, sizeof(aux_info));
4199526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker
4203843c14979dce08cc6f800fa9964bf2f8a4bbb2cColin Cross	if (ext4_sparse_file) {
4213843c14979dce08cc6f800fa9964bf2f8a4bbb2cColin Cross		sparse_file_destroy(ext4_sparse_file);
4223843c14979dce08cc6f800fa9964bf2f8a4bbb2cColin Cross		ext4_sparse_file = NULL;
4239526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker	}
424ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
425ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
426965298695c981ee5a67e86977a8e40a50f7392abColin Crossint make_ext4fs_sparse_fd(int fd, long long len,
4279526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker				const char *mountpoint, struct selabel_handle *sehnd)
42803ad99cff5743b9e0ce462f53dd2f0fcb17b169bColin Cross{
4297ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien	return make_ext4fs_sparse_fd_align(fd, len, mountpoint, sehnd, 0, 0);
4307ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien}
4317ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien
4327ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brienint make_ext4fs_sparse_fd_align(int fd, long long len,
4337ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien				const char *mountpoint, struct selabel_handle *sehnd,
4347ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien				unsigned eraseblk, unsigned logicalblk)
4357ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien{
4367ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien	return make_ext4fs_sparse_fd_directory_align(fd, len, mountpoint, sehnd, NULL,
4377ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien								eraseblk, logicalblk);
438d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowley}
439d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowley
440d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowleyint make_ext4fs_sparse_fd_directory(int fd, long long len,
441d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowley				const char *mountpoint, struct selabel_handle *sehnd,
442d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowley				const char *directory)
443d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowley{
4447ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien	return make_ext4fs_sparse_fd_directory_align(fd, len, mountpoint, sehnd, directory, 0, 0);
4457ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien}
4467ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien
4477ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brienint make_ext4fs_sparse_fd_directory_align(int fd, long long len,
4487ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien				const char *mountpoint, struct selabel_handle *sehnd,
4497ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien				const char *directory, unsigned eraseblk, unsigned logicalblk)
4507ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien{
45103ad99cff5743b9e0ce462f53dd2f0fcb17b169bColin Cross	reset_ext4fs_info();
45203ad99cff5743b9e0ce462f53dd2f0fcb17b169bColin Cross	info.len = len;
4537ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien	info.flash_erase_block_size = eraseblk;
4547ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien	info.flash_logical_block_size = logicalblk;
45503ad99cff5743b9e0ce462f53dd2f0fcb17b169bColin Cross
456d7a3fb4fc35fe729e5013474914746aeb8de35b7Paul Crowley	return make_ext4fs_internal(fd, directory, NULL, mountpoint, NULL,
4579579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash								0, 1, 0, 0, 0,
4589579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash								sehnd, 0, -1, NULL, NULL, NULL);
45903ad99cff5743b9e0ce462f53dd2f0fcb17b169bColin Cross}
46003ad99cff5743b9e0ce462f53dd2f0fcb17b169bColin Cross
461965298695c981ee5a67e86977a8e40a50f7392abColin Crossint make_ext4fs(const char *filename, long long len,
4629526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker				const char *mountpoint, struct selabel_handle *sehnd)
463983fb19d83d2391b19b289fc150495d8642378c4Ken Sumrall{
46401c43f2219df371b1bf6d3c2b7fb8c9059e45168Paul Lawrence	return make_ext4fs_directory(filename, len, mountpoint, sehnd, NULL);
46501c43f2219df371b1bf6d3c2b7fb8c9059e45168Paul Lawrence}
46601c43f2219df371b1bf6d3c2b7fb8c9059e45168Paul Lawrence
4677ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brienint make_ext4fs_directory(const char *filename, long long len,
4687ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien						  const char *mountpoint, struct selabel_handle *sehnd,
4697ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien						  const char *directory)
4707ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien{
4717ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien	return make_ext4fs_directory_align(filename, len, mountpoint, sehnd, directory, 0, 0);
4727ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien}
4737ba1e209f2c96b32bf023e24ff43a77d4f5341cbConnor O'Brien
474bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brienint make_ext4fs_directory_align(const char *filename, long long len,
475bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien						  const char *mountpoint, struct selabel_handle *sehnd,
476bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien						  const char *directory, unsigned eraseblk,
477bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien						  unsigned logicalblk)
478bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien{
479bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	int fd;
480bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	int status;
481bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien
482bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	reset_ext4fs_info();
483bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	info.len = len;
484bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	info.flash_erase_block_size = eraseblk;
485bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	info.flash_logical_block_size = logicalblk;
486bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien
487bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
488bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	if (fd < 0) {
489bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien		error_errno("open");
490bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien		return EXIT_FAILURE;
491bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	}
492bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien
493bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien	status = make_ext4fs_internal(fd, directory, NULL, mountpoint, NULL,
494bdd06dec245b204ade230ae8d1d03923305c4a04Connor O'Brien								  0, 0, 0, 1, 0,
4959579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash								  sehnd, 0, -1, NULL, NULL, NULL);
4960349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	close(fd);
4970349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau
4980349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	return status;
499983fb19d83d2391b19b289fc150495d8642378c4Ken Sumrall}
500983fb19d83d2391b19b289fc150495d8642378c4Ken Sumrall
5015b89a4a6003d429343e608d78a97f552b13894deColin Cross/* return a newly-malloc'd string that is a copy of str.  The new string
5025b89a4a6003d429343e608d78a97f552b13894deColin Cross   is guaranteed to have a trailing slash.  If absolute is true, the new string
5035b89a4a6003d429343e608d78a97f552b13894deColin Cross   is also guaranteed to have a leading slash.
5045b89a4a6003d429343e608d78a97f552b13894deColin Cross*/
5055b89a4a6003d429343e608d78a97f552b13894deColin Crossstatic char *canonicalize_slashes(const char *str, bool absolute)
5065b89a4a6003d429343e608d78a97f552b13894deColin Cross{
5075b89a4a6003d429343e608d78a97f552b13894deColin Cross	char *ret;
5085b89a4a6003d429343e608d78a97f552b13894deColin Cross	int len = strlen(str);
5095b89a4a6003d429343e608d78a97f552b13894deColin Cross	int newlen = len;
5105b89a4a6003d429343e608d78a97f552b13894deColin Cross	char *ptr;
5115b89a4a6003d429343e608d78a97f552b13894deColin Cross
5127b4448de8deaef2512fb0b17a30facc47b2f4a87Benoit Fradin	if (len == 0) {
5137b4448de8deaef2512fb0b17a30facc47b2f4a87Benoit Fradin		if (absolute)
5147b4448de8deaef2512fb0b17a30facc47b2f4a87Benoit Fradin			return strdup("/");
5157b4448de8deaef2512fb0b17a30facc47b2f4a87Benoit Fradin		else
5167b4448de8deaef2512fb0b17a30facc47b2f4a87Benoit Fradin			return strdup("");
5175b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5185b89a4a6003d429343e608d78a97f552b13894deColin Cross
5195b89a4a6003d429343e608d78a97f552b13894deColin Cross	if (str[0] != '/' && absolute) {
5205b89a4a6003d429343e608d78a97f552b13894deColin Cross		newlen++;
5215b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5225b89a4a6003d429343e608d78a97f552b13894deColin Cross	if (str[len - 1] != '/') {
5235b89a4a6003d429343e608d78a97f552b13894deColin Cross		newlen++;
5245b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5255b89a4a6003d429343e608d78a97f552b13894deColin Cross	ret = malloc(newlen + 1);
5265b89a4a6003d429343e608d78a97f552b13894deColin Cross	if (!ret) {
5275b89a4a6003d429343e608d78a97f552b13894deColin Cross		critical_error("malloc");
5285b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5295b89a4a6003d429343e608d78a97f552b13894deColin Cross
5305b89a4a6003d429343e608d78a97f552b13894deColin Cross	ptr = ret;
5315b89a4a6003d429343e608d78a97f552b13894deColin Cross	if (str[0] != '/' && absolute) {
5325b89a4a6003d429343e608d78a97f552b13894deColin Cross		*ptr++ = '/';
5335b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5345b89a4a6003d429343e608d78a97f552b13894deColin Cross
5355b89a4a6003d429343e608d78a97f552b13894deColin Cross	strcpy(ptr, str);
5365b89a4a6003d429343e608d78a97f552b13894deColin Cross	ptr += len;
5375b89a4a6003d429343e608d78a97f552b13894deColin Cross
5385b89a4a6003d429343e608d78a97f552b13894deColin Cross	if (str[len - 1] != '/') {
5395b89a4a6003d429343e608d78a97f552b13894deColin Cross		*ptr++ = '/';
5405b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5415b89a4a6003d429343e608d78a97f552b13894deColin Cross
5425b89a4a6003d429343e608d78a97f552b13894deColin Cross	if (ptr != ret + newlen) {
5435b89a4a6003d429343e608d78a97f552b13894deColin Cross		critical_error("assertion failed\n");
5445b89a4a6003d429343e608d78a97f552b13894deColin Cross	}
5455b89a4a6003d429343e608d78a97f552b13894deColin Cross
5465b89a4a6003d429343e608d78a97f552b13894deColin Cross	*ptr = '\0';
5475b89a4a6003d429343e608d78a97f552b13894deColin Cross
5485b89a4a6003d429343e608d78a97f552b13894deColin Cross	return ret;
5495b89a4a6003d429343e608d78a97f552b13894deColin Cross}
5505b89a4a6003d429343e608d78a97f552b13894deColin Cross
5515b89a4a6003d429343e608d78a97f552b13894deColin Crossstatic char *canonicalize_abs_slashes(const char *str)
5525b89a4a6003d429343e608d78a97f552b13894deColin Cross{
5535b89a4a6003d429343e608d78a97f552b13894deColin Cross	return canonicalize_slashes(str, true);
5545b89a4a6003d429343e608d78a97f552b13894deColin Cross}
5555b89a4a6003d429343e608d78a97f552b13894deColin Cross
5565b89a4a6003d429343e608d78a97f552b13894deColin Crossstatic char *canonicalize_rel_slashes(const char *str)
5575b89a4a6003d429343e608d78a97f552b13894deColin Cross{
5585b89a4a6003d429343e608d78a97f552b13894deColin Cross	return canonicalize_slashes(str, false);
5595b89a4a6003d429343e608d78a97f552b13894deColin Cross}
5605b89a4a6003d429343e608d78a97f552b13894deColin Cross
5619579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashstatic int compare_chunks(const void* chunk1, const void* chunk2) {
5629579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	struct region* c1 = (struct region*) chunk1;
5639579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	struct region* c2 = (struct region*) chunk2;
5649579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	return c1->block - c2->block;
5659579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash}
5669579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
5679579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashstatic int get_block_group(u32 block) {
568cd205307320b4da5dd7899f79b83539c620ae1d1Dmitry Shmidt	unsigned int i, group = 0;
569cd205307320b4da5dd7899f79b83539c620ae1d1Dmitry Shmidt
5709579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	for(i = 0; i < aux_info.groups; i++) {
5719579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		if (block >= aux_info.bgs[i].first_block)
5729579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			group = i;
5739579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		else
5749579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			break;
5759579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
5769579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	return group;
5779579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash}
5789579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
5799579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashstatic void extract_base_fs_allocations(const char *directory, const char *mountpoint,
5809579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash										FILE* base_alloc_file_in) {
5819579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash#define err_msg "base file badly formatted"
5821eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifndef _WIN32
5839579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	// FORMAT Version 1.0: filename blk_mapping
5849579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	const char *base_alloc_file_in_format = "%s %s";
5859579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	const int base_file_format_param_count = 2;
5869579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
5879579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	char stored_file_name[MAX_PATH], real_file_name[MAX_PATH], file_map[MAX_BLK_MAPPING_STR];
5889579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	struct block_allocation *fs_alloc;
5899579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	struct block_group_info *bgs = aux_info.bgs;
590cd205307320b4da5dd7899f79b83539c620ae1d1Dmitry Shmidt	int major_version = 0, minor_version = 0;
591cd205307320b4da5dd7899f79b83539c620ae1d1Dmitry Shmidt	unsigned int i;
5929579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	char *base_file_line = NULL;
5939579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	size_t base_file_line_len = 0;
5949579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
5959579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	printf("[v%d.%d] Generating an Incremental EXT4 image\n",
5969579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			blk_file_major_ver, blk_file_minor_ver);
5979579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	if (base_fs_allocations == NULL)
5989579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		base_fs_allocations = create_allocation();
5999579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	fs_alloc = base_fs_allocations;
6009579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6019579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	fscanf(base_alloc_file_in, blk_file_header_fmt, &major_version, &minor_version);
6029579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	if (major_version == 0) {
6039579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		critical_error("Invalid base file");
6049579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
6059579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6069579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	if (major_version != blk_file_major_ver) {
6079579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		critical_error("Incompatible base file: version required is %d.X",
6089579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				blk_file_major_ver);
6099579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
6109579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6119579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	if (minor_version < blk_file_minor_ver) {
6129579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		critical_error("Incompatible base file: version required is %d.%d or above",
6139579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				blk_file_major_ver, blk_file_minor_ver);
6149579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
6159579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6169579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	while (getline(&base_file_line, &base_file_line_len, base_alloc_file_in) != -1) {
6179579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		if (sscanf(base_file_line, base_alloc_file_in_format, &stored_file_name, &file_map)
6189579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				!= base_file_format_param_count) {
6199579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			continue;
6209579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		}
6219579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		if (strlen(stored_file_name) < strlen(mountpoint)) {
6229579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			continue;
6239579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		}
6249579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		snprintf(real_file_name, MAX_PATH, "%s%s", directory, stored_file_name + strlen(mountpoint));
6259579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		if (!access(real_file_name, R_OK)) {
6269579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			char *block_range, *end_string;
6279579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			int real_file_fd;
628cd205307320b4da5dd7899f79b83539c620ae1d1Dmitry Shmidt			int start_block, end_block;
629cd205307320b4da5dd7899f79b83539c620ae1d1Dmitry Shmidt			u32 block_file_size;
6309579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			u32 real_file_block_size;
6319579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6329579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			real_file_fd = open(real_file_name, O_RDONLY);
6339579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			if (real_file_fd == -1) {
6349579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				critical_error(err_msg);
6359579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			}
6369579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			real_file_block_size = get_file_size(real_file_fd);
6379579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			close(real_file_fd);
6389579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			real_file_block_size = DIV_ROUND_UP(real_file_block_size, info.block_size);
6399579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			fs_alloc->filename = strdup(real_file_name);
6409579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			block_range = strtok_r(file_map, ",", &end_string);
6419579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			while (block_range && real_file_block_size) {
6429579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				int block_group;
6439579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				char *range, *end_token = NULL;
6449579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				range = strtok_r(block_range, "-", &end_token);
6459579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				if (!range) {
6469579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash					critical_error(err_msg);
6479579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				}
6489579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				start_block = parse_num(range);
6499579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				range = strtok_r(NULL, "-", &end_token);
6509579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				if (!range) {
6519579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash					end_block = start_block;
6529579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				} else {
6539579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash					end_block = parse_num(range);
6549579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				}
6559579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				// Assummption is that allocations are within the same block group
6569579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				block_group = get_block_group(start_block);
6579579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				if (block_group != get_block_group(end_block)) {
6589579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash					critical_error("base file allocation's end block is in a different "
6599579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash								   "block group than start block. did you change fs params?");
6609579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				}
6619579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				block_range = strtok_r(NULL, ",", &end_string);
662d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash				int bg_first_block = bgs[block_group].first_block;
663afb52975c3b60b32cf08a3ab270400defccd81f6Colin Cross				int min_bg_bound = bgs[block_group].chunks[0].block + bgs[block_group].chunks[0].len;
664afb52975c3b60b32cf08a3ab270400defccd81f6Colin Cross				int max_bg_bound = bgs[block_group].chunks[bgs[block_group].chunk_count - 1].block;
665d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash
666d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash				if (min_bg_bound >= start_block - bg_first_block ||
667d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash					max_bg_bound <= end_block - bg_first_block) {
668d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash					continue;
669d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash				}
670d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash				block_file_size = end_block - start_block + 1;
671d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash				if (block_file_size > real_file_block_size) {
672d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash					block_file_size = real_file_block_size;
673d2ed02a94086e1221041bc59825add3d0a657e19Mohamad Ayyash				}
6749579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				append_region(fs_alloc, start_block, block_file_size, block_group);
6759579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				reserve_bg_chunk(block_group, start_block - bgs[block_group].first_block, block_file_size);
6769579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				real_file_block_size -= block_file_size;
6779579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			}
6789579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			if (reserve_blocks_for_allocation(fs_alloc) < 0)
6799579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash				critical_error("failed to reserve base fs allocation");
6809579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			fs_alloc->next = create_allocation();
6819579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			fs_alloc = fs_alloc->next;
6829579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		}
6839579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
6849579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6859579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	for (i = 0; i < aux_info.groups; i++) {
6869579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		qsort(bgs[i].chunks, bgs[i].chunk_count, sizeof(struct region), compare_chunks);
6879579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
6889579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6899579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	free(base_file_line);
6909579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
691ef24424e32921f509f98aae429b6efd9b0e4eae6Mohamad Ayyash#else
692ef24424e32921f509f98aae429b6efd9b0e4eae6Mohamad Ayyash    return;
693ef24424e32921f509f98aae429b6efd9b0e4eae6Mohamad Ayyash#endif
6949579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash#undef err_msg
6959579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash}
6969579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
6979579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyashvoid generate_base_alloc_file_out(FILE* base_alloc_file_out, char* dir, char* mountpoint,
6989579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash								  struct block_allocation* p)
6999579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash{
7009579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	size_t dirlen = dir ? strlen(dir) : 0;
7019579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	fprintf(base_alloc_file_out, blk_file_header_fmt, blk_file_major_ver, blk_file_minor_ver);
7029579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	fputc('\n', base_alloc_file_out);
7039579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	while (p) {
7049579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		if (dir && strncmp(p->filename, dir, dirlen) == 0) {
7059579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			// substitute mountpoint for the leading directory in the filename, in the output file
7069579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			fprintf(base_alloc_file_out, "%s%s", mountpoint, p->filename + dirlen);
7079579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		} else {
7089579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			fprintf(base_alloc_file_out, "%s", p->filename);
7099579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		}
7109579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		print_blocks(base_alloc_file_out, p, ',');
7119579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		struct block_allocation* pn = p->next;
7129579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		p = pn;
7139579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
7149579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash}
7159579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
716b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudelint make_ext4fs_internal(int fd, const char *_directory, const char *_target_out_directory,
7179526680de97e2bc963a70d1fabffe165a688bb1eDoug Zongker						 const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
718f965968e1912553939e7cf1afc9ff39d306ada54Jeff Sharkey						 int sparse, int crc, int wipe, int real_uuid,
719bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker						 struct selabel_handle *sehnd, int verbose, time_t fixed_time,
7209579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash						 FILE* block_list_file, FILE* base_alloc_file_in, FILE* base_alloc_file_out)
721ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross{
7220349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	u32 root_inode_num;
7230349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau	u16 root_mode;
724a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	char *mountpoint;
725a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	char *directory = NULL;
726b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel	char *target_out_directory = NULL;
7279579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	struct block_allocation* p;
728ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
7292ae7663e1e064000356ee9e49ebd08bdddc545f9Ken Sumrall	if (setjmp(setjmp_env))
7302ae7663e1e064000356ee9e49ebd08bdddc545f9Ken Sumrall		return EXIT_FAILURE; /* Handle a call to longjmp() */
7312ae7663e1e064000356ee9e49ebd08bdddc545f9Ken Sumrall
732aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao	info.block_device = is_block_device_fd(fd);
733aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao
734aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao	if (info.block_device && (sparse || gzip || crc)) {
735aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao		fprintf(stderr, "No sparse/gzip/crc allowed for block device\n");
736aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao		return EXIT_FAILURE;
737aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao	}
738aaf32ea5166b6b86023dc283311228cdebb3dc02Eric Miao
739a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	if (_mountpoint == NULL) {
740a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross		mountpoint = strdup("");
741a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	} else {
7425b89a4a6003d429343e608d78a97f552b13894deColin Cross		mountpoint = canonicalize_abs_slashes(_mountpoint);
743a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	}
744a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross
745a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	if (_directory) {
7465b89a4a6003d429343e608d78a97f552b13894deColin Cross		directory = canonicalize_rel_slashes(_directory);
747a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	}
748a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross
749b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel	if (_target_out_directory) {
750b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel		target_out_directory = canonicalize_rel_slashes(_target_out_directory);
751b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel	}
752b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel
753435a8b61e925e3efb22fce08612efe210e83f791Ken Sumrall	if (info.len <= 0)
7540349bd9f14d252673a7a25767da4a80121aaaaf2Anatol Pomazau		info.len = get_file_size(fd);
755ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
756ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.block_size <= 0)
757ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		info.block_size = compute_block_size();
758ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
75988833a6277f305b6a03ff29d8e9ffe717ddb4045Ken Sumrall	/* Round down the filesystem length to be a multiple of the block size */
76088833a6277f305b6a03ff29d8e9ffe717ddb4045Ken Sumrall	info.len &= ~((u64)info.block_size - 1);
76188833a6277f305b6a03ff29d8e9ffe717ddb4045Ken Sumrall
76263362e153f799f41d3e0dd256d8b8281da3f2672Jin Qian	if (info.len <= 0) {
76363362e153f799f41d3e0dd256d8b8281da3f2672Jin Qian		fprintf(stderr, "filesystem size too small\n");
76463362e153f799f41d3e0dd256d8b8281da3f2672Jin Qian		return EXIT_FAILURE;
76563362e153f799f41d3e0dd256d8b8281da3f2672Jin Qian	}
76663362e153f799f41d3e0dd256d8b8281da3f2672Jin Qian
767e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	if (info.journal_blocks == 0)
768e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross		info.journal_blocks = compute_journal_blocks();
769e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross
770e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	if (info.no_journal == 0)
771e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross		info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
772e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	else
773e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross		info.journal_blocks = 0;
774e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross
775ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.blocks_per_group <= 0)
776ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		info.blocks_per_group = compute_blocks_per_group();
777ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
778ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.inodes <= 0)
779ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		info.inodes = compute_inodes();
780ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
781ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.inode_size <= 0)
782ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		info.inode_size = 256;
783ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
784ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.label == NULL)
785ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		info.label = "";
786ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
787ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	info.inodes_per_group = compute_inodes_per_group();
788ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
789ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	info.feat_compat |=
7904df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			EXT4_FEATURE_COMPAT_RESIZE_INODE |
7914df62f342dbbe2f5cca831ce789dc0426d32ec03Nick Kralevich			EXT4_FEATURE_COMPAT_EXT_ATTR;
792ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
793ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	info.feat_ro_compat |=
794ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
795dedf8f9705df13e1fd07d3f754216d34725bb269Mohamad Ayyash			EXT4_FEATURE_RO_COMPAT_LARGE_FILE |
796dedf8f9705df13e1fd07d3f754216d34725bb269Mohamad Ayyash			EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
797ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
798ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	info.feat_incompat |=
799ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			EXT4_FEATURE_INCOMPAT_EXTENTS |
800ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			EXT4_FEATURE_INCOMPAT_FILETYPE;
801ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
802ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
80322742ce739a046a079b2e1b03342a25472dfa352Colin Cross	info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
80422742ce739a046a079b2e1b03342a25472dfa352Colin Cross
805ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("Creating filesystem with parameters:\n");
806af0723439af552c170425416ee8e35f4f20bbe67Colin Cross	printf("    Size: %"PRIu64"\n", info.len);
807ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("    Block size: %d\n", info.block_size);
808ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("    Blocks per group: %d\n", info.blocks_per_group);
809ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("    Inodes per group: %d\n", info.inodes_per_group);
810ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("    Inode size: %d\n", info.inode_size);
811e4b5ae8ab07e698b95f004c9226000b02f853abcColin Cross	printf("    Journal blocks: %d\n", info.journal_blocks);
812ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("    Label: %s\n", info.label);
813ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
814ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	ext4_create_fs_aux_info();
815ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
816af0723439af552c170425416ee8e35f4f20bbe67Colin Cross	printf("    Blocks: %"PRIu64"\n", aux_info.len_blocks);
817ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("    Block groups: %d\n", aux_info.groups);
81822742ce739a046a079b2e1b03342a25472dfa352Colin Cross	printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
819ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
820782879ab61fe825835a9c6a701f91aa7d305acefColin Cross	ext4_sparse_file = sparse_file_new(info.block_size, info.len);
821f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
822ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	block_allocator_init();
823ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
824f965968e1912553939e7cf1afc9ff39d306ada54Jeff Sharkey	ext4_fill_in_sb(real_uuid);
825ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
8269579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	if (base_alloc_file_in) {
8279579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		extract_base_fs_allocations(directory, mountpoint, base_alloc_file_in);
8289579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
829ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
830ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		error("failed to reserve first 10 inodes");
831ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
832ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
833ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		ext4_create_journal_inode();
834ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
835ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
836ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross		ext4_create_resize_inode();
837ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
8381eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifdef _WIN32
8394605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll	// Windows needs only 'create an empty fs image' functionality
8404605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll	assert(!directory);
8417907ac7c811670643c3606125657a39226507ea1Stephen Smalley	root_inode_num = build_default_directory_structure(mountpoint, sehnd);
8424605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#else
843ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	if (directory)
844b89e81dcb9bfa707912d9e370949b250367b0998Thierry Strudel		root_inode_num = build_directory_structure(directory, mountpoint, target_out_directory, 0,
845bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker			fs_config_func, sehnd, verbose, fixed_time);
846ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	else
8477907ac7c811670643c3606125657a39226507ea1Stephen Smalley		root_inode_num = build_default_directory_structure(mountpoint, sehnd);
8484605b3fb8a00fa37f617a8d0fe3a095d0503a845Raphael Moll#endif
849263eefd9fb9608432636c903423e43848e69f39dDoug Zongker
850ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
851de61f980c7b034eefac6e0ace718b3c1eb3f6252Colin Cross	inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
852ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
8531eb2f5433461ad437e7dfedca32ce7bf5f09fd21Elliott Hughes#ifndef _WIN32
854b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	if (sehnd) {
855b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		char *secontext = NULL;
8566ece70806883534d29a74b9785871505f71ecc1fStephen Smalley
857a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross		if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) {
858a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross			error("cannot lookup security context for %s", mountpoint);
859b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		}
8602929313c66014bce5d53cf4323a9db507ca5b139Robert Craig		if (secontext) {
8612929313c66014bce5d53cf4323a9db507ca5b139Robert Craig			if (verbose) {
8622929313c66014bce5d53cf4323a9db507ca5b139Robert Craig				printf("Labeling %s as %s\n", mountpoint, secontext);
8632929313c66014bce5d53cf4323a9db507ca5b139Robert Craig			}
864b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley			inode_set_selinux(root_inode_num, secontext);
865b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		}
866b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley		freecon(secontext);
867b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley	}
868b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley#endif
869b4eca4b24af9c80ebb2a7fa2ba539a48096b7576Stephen Smalley
870ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	ext4_update_free();
871ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
8729579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	// TODO: Consider migrating the OTA tools to the new base alloc file format
8739579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	// used for generating incremental images (see go/incremental-ext4)
874bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker	if (block_list_file) {
87518785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash		size_t dirlen = directory ? strlen(directory) : 0;
876bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker		struct block_allocation* p = get_saved_allocation_chain();
87718785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash		while (p) {
87818785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash			if (directory && strncmp(p->filename, directory, dirlen) == 0) {
87918785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash				// substitute mountpoint for the leading directory in the filename, in the output file
88018785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash				fprintf(block_list_file, "%s%s", mountpoint, p->filename + dirlen);
88118785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash			} else {
88218785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash				fprintf(block_list_file, "%s", p->filename);
88318785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash			}
8849579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash			print_blocks(block_list_file, p, ' ');
88518785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash			struct block_allocation* pn = p->next;
88618785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash			p = pn;
88718785a86a30135ac65b88db9886bfc22d6608849Mohamad Ayyash		}
888bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker	}
889bec598e982301bf2714d37b14e312c9845c7cc0cDoug Zongker
8909579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	if (base_alloc_file_out) {
8919579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		struct block_allocation* p = get_saved_allocation_chain();
8929579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		generate_base_alloc_file_out(base_alloc_file_out, directory, mountpoint, p);
8939579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
8949579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
895ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
896ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
897ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			aux_info.sb->s_inodes_count,
898ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
899ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross			aux_info.sb->s_blocks_count_lo);
900ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
901eb5fcc3e932a8ccac1b580788a213c7782aff31bDavid 'Digit' Turner	if (wipe && WIPE_IS_SUPPORTED) {
902dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross		wipe_block_device(fd, info.len);
903eb5fcc3e932a8ccac1b580788a213c7782aff31bDavid 'Digit' Turner	}
904dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross
905dc5abeee1e6fc4827ee0d5ece12aaed2dd56f4c7Colin Cross	write_ext4_image(fd, gzip, sparse, crc);
906ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross
907782879ab61fe825835a9c6a701f91aa7d305acefColin Cross	sparse_file_destroy(ext4_sparse_file);
908782879ab61fe825835a9c6a701f91aa7d305acefColin Cross	ext4_sparse_file = NULL;
909f0ee37ffded79afdb03e15ae3a69969d2b7e6079Colin Cross
9109579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	p = get_saved_allocation_chain();
9119579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	while (p) {
9129579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		struct block_allocation* pn = p->next;
9139579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		free_alloc(p);
9149579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash		p = pn;
9159579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash	}
9169579198cd7d5b88b3508f1b00ddd77bd8da60682Mohamad Ayyash
917a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	free(mountpoint);
918a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross	free(directory);
919a4460149a5fadc639dbb708c332a75f9717c12d6Colin Cross
920ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross	return 0;
921ec0a2e83dc66d67addeb90e83144187691852a3eColin Cross}
922