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