diff options
Diffstat (limited to 'mkfs.ubifs/mkfs.ubifs.c')
-rw-r--r-- | mkfs.ubifs/mkfs.ubifs.c | 2324 |
1 files changed, 0 insertions, 2324 deletions
diff --git a/mkfs.ubifs/mkfs.ubifs.c b/mkfs.ubifs/mkfs.ubifs.c deleted file mode 100644 index ca17e2b..0000000 --- a/mkfs.ubifs/mkfs.ubifs.c +++ /dev/null @@ -1,2324 +0,0 @@ -/* - * Copyright (C) 2008 Nokia Corporation. - * Copyright (C) 2008 University of Szeged, Hungary - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 51 - * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Authors: Adrian Hunter - * Artem Bityutskiy - * Zoltan Sogor - */ - -#define _XOPEN_SOURCE 500 /* For realpath() */ - -#include "mkfs.ubifs.h" -#include <crc32.h> -#include "common.h" - -/* Size (prime number) of hash table for link counting */ -#define HASH_TABLE_SIZE 10099 - -/* The node buffer must allow for worst case compression */ -#define NODE_BUFFER_SIZE (UBIFS_DATA_NODE_SZ + \ - UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR) - -/* Default time granularity in nanoseconds */ -#define DEFAULT_TIME_GRAN 1000000000 - -/** - * struct idx_entry - index entry. - * @next: next index entry (NULL at end of list) - * @prev: previous index entry (NULL at beginning of list) - * @key: key - * @name: directory entry name used for sorting colliding keys by name - * @lnum: LEB number - * @offs: offset - * @len: length - * - * The index is recorded as a linked list which is sorted and used to create - * the bottom level of the on-flash index tree. The remaining levels of the - * index tree are each built from the level below. - */ -struct idx_entry { - struct idx_entry *next; - struct idx_entry *prev; - union ubifs_key key; - char *name; - int lnum; - int offs; - int len; -}; - -/** - * struct inum_mapping - inode number mapping for link counting. - * @next: next inum_mapping (NULL at end of list) - * @prev: previous inum_mapping (NULL at beginning of list) - * @dev: source device on which the source inode number resides - * @inum: source inode number of the file - * @use_inum: target inode number of the file - * @use_nlink: number of links - * @path_name: a path name of the file - * @st: struct stat object containing inode attributes which have to be used - * when the inode is being created (actually only UID, GID, access - * mode, major and minor device numbers) - * - * If a file has more than one hard link, then the number of hard links that - * exist in the source directory hierarchy must be counted to exclude the - * possibility that the file is linked from outside the source directory - * hierarchy. - * - * The inum_mappings are stored in a hash_table of linked lists. - */ -struct inum_mapping { - struct inum_mapping *next; - struct inum_mapping *prev; - dev_t dev; - ino_t inum; - ino_t use_inum; - unsigned int use_nlink; - char *path_name; - struct stat st; -}; - -/* - * Because we copy functions from the kernel, we use a subset of the UBIFS - * file-system description object struct ubifs_info. - */ -struct ubifs_info info_; -static struct ubifs_info *c = &info_; -static libubi_t ubi; - -/* Debug levels are: 0 (none), 1 (statistics), 2 (files) ,3 (more details) */ -int debug_level; -int verbose; -int yes; - -static char *root; -static int root_len; -static struct stat root_st; -static char *output; -static int out_fd; -static int out_ubi; -static int squash_owner; - -/* The 'head' (position) which nodes are written */ -static int head_lnum; -static int head_offs; -static int head_flags; - -/* The index list */ -static struct idx_entry *idx_list_first; -static struct idx_entry *idx_list_last; -static size_t idx_cnt; - -/* Global buffers */ -static void *leb_buf; -static void *node_buf; -static void *block_buf; - -/* Hash table for inode link counting */ -static struct inum_mapping **hash_table; - -/* Inode creation sequence number */ -static unsigned long long creat_sqnum; - -static const char *optstring = "d:r:m:o:D:yh?vVe:c:g:f:Fp:k:x:X:j:R:l:j:UQq"; - -static const struct option longopts[] = { - {"root", 1, NULL, 'r'}, - {"min-io-size", 1, NULL, 'm'}, - {"leb-size", 1, NULL, 'e'}, - {"max-leb-cnt", 1, NULL, 'c'}, - {"output", 1, NULL, 'o'}, - {"devtable", 1, NULL, 'D'}, - {"yes", 0, NULL, 'y'}, - {"help", 0, NULL, 'h'}, - {"verbose", 0, NULL, 'v'}, - {"version", 0, NULL, 'V'}, - {"debug-level", 1, NULL, 'g'}, - {"jrn-size", 1, NULL, 'j'}, - {"reserved", 1, NULL, 'R'}, - {"compr", 1, NULL, 'x'}, - {"favor-percent", 1, NULL, 'X'}, - {"fanout", 1, NULL, 'f'}, - {"space-fixup", 0, NULL, 'F'}, - {"keyhash", 1, NULL, 'k'}, - {"log-lebs", 1, NULL, 'l'}, - {"orph-lebs", 1, NULL, 'p'}, - {"squash-uids" , 0, NULL, 'U'}, - {NULL, 0, NULL, 0} -}; - -static const char *helptext = -"Usage: mkfs.ubifs [OPTIONS] target\n" -"Make a UBIFS file system image from an existing directory tree\n\n" -"Examples:\n" -"Build file system from directory /opt/img, writting the result in the ubifs.img file\n" -"\tmkfs.ubifs -m 512 -e 128KiB -c 100 -r /opt/img ubifs.img\n" -"The same, but writting directly to an UBI volume\n" -"\tmkfs.ubifs -r /opt/img /dev/ubi0_0\n" -"Creating an empty UBIFS filesystem on an UBI volume\n" -"\tmkfs.ubifs /dev/ubi0_0\n\n" -"Options:\n" -"-r, -d, --root=DIR build file system from directory DIR\n" -"-m, --min-io-size=SIZE minimum I/O unit size\n" -"-e, --leb-size=SIZE logical erase block size\n" -"-c, --max-leb-cnt=COUNT maximum logical erase block count\n" -"-o, --output=FILE output to FILE\n" -"-j, --jrn-size=SIZE journal size\n" -"-R, --reserved=SIZE how much space should be reserved for the super-user\n" -"-x, --compr=TYPE compression type - \"lzo\", \"favor_lzo\", \"zlib\" or\n" -" \"none\" (default: \"lzo\")\n" -"-X, --favor-percent may only be used with favor LZO compression and defines\n" -" how many percent better zlib should compress to make\n" -" mkfs.ubifs use zlib instead of LZO (default 20%)\n" -"-f, --fanout=NUM fanout NUM (default: 8)\n" -"-F, --space-fixup file-system free space has to be fixed up on first mount\n" -" (requires kernel version 3.0 or greater)\n" -"-k, --keyhash=TYPE key hash type - \"r5\" or \"test\" (default: \"r5\")\n" -"-p, --orph-lebs=COUNT count of erase blocks for orphans (default: 1)\n" -"-D, --devtable=FILE use device table FILE\n" -"-U, --squash-uids squash owners making all files owned by root\n" -"-l, --log-lebs=COUNT count of erase blocks for the log (used only for\n" -" debugging)\n" -"-y, --yes assume the answer is \"yes\" for all questions\n" -"-v, --verbose verbose operation\n" -"-V, --version display version information\n" -"-g, --debug=LEVEL display debug information (0 - none, 1 - statistics,\n" -" 2 - files, 3 - more details)\n" -"-h, --help display this help text\n\n" -"Note, SIZE is specified in bytes, but it may also be specified in Kilobytes,\n" -"Megabytes, and Gigabytes if a KiB, MiB, or GiB suffix is used.\n\n" -"If you specify \"lzo\" or \"zlib\" compressors, mkfs.ubifs will use this compressor\n" -"for all data. The \"none\" disables any data compression. The \"favor_lzo\" is not\n" -"really a separate compressor. It is just a method of combining \"lzo\" and \"zlib\"\n" -"compressors. Namely, mkfs.ubifs tries to compress data with both \"lzo\" and \"zlib\"\n" -"compressors, then it compares which compressor is better. If \"zlib\" compresses 20\n" -"or more percent better than \"lzo\", mkfs.ubifs chooses \"lzo\", otherwise it chooses\n" -"\"zlib\". The \"--favor-percent\" may specify arbitrary threshold instead of the\n" -"default 20%.\n\n" -"The -F parameter is used to set the \"fix up free space\" flag in the superblock,\n" -"which forces UBIFS to \"fixup\" all the free space which it is going to use. This\n" -"option is useful to work-around the problem of double free space programming: if the\n" -"flasher program which flashes the UBI image is unable to skip NAND pages containing\n" -"only 0xFF bytes, the effect is that some NAND pages are written to twice - first time\n" -"when flashing the image and the second time when UBIFS is mounted and writes useful\n" -"data there. A proper UBI-aware flasher should skip such NAND pages, though. Note, this\n" -"flag may make the first mount very slow, because the \"free space fixup\" procedure\n" -"takes time. This feature is supported by the Linux kernel starting from version 3.0.\n"; - -/** - * make_path - make a path name from a directory and a name. - * @dir: directory path name - * @name: name - */ -static char *make_path(const char *dir, const char *name) -{ - char *s; - - s = malloc(strlen(dir) + strlen(name) + 2); - if (!s) - return NULL; - strcpy(s, dir); - if (dir[strlen(dir) - 1] != '/') - strcat(s, "/"); - strcat(s, name); - return s; -} - -/** - * is_contained - determine if a file is beneath a directory. - * @file: file path name - * @dir: directory path name - * - * This function returns %1 if @file is accessible from the @dir directory and - * %0 otherwise. In case of error, returns %-1. - */ -static int is_contained(const char *file, const char *dir) -{ - char *real_file = NULL; - char *real_dir = NULL; - char *file_base, *copy; - int ret = -1; - - /* Make a copy of the file path because 'dirname()' can modify it */ - copy = strdup(file); - if (!copy) - return -1; - file_base = dirname(copy); - - /* Turn the paths into the canonical form */ - real_file = malloc(PATH_MAX); - if (!real_file) - goto out_free; - - real_dir = malloc(PATH_MAX); - if (!real_dir) - goto out_free; - - if (!realpath(file_base, real_file)) { - perror("Could not canonicalize file path"); - goto out_free; - } - if (!realpath(dir, real_dir)) { - perror("Could not canonicalize directory"); - goto out_free; - } - - ret = !!strstr(real_file, real_dir); - -out_free: - free(copy); - free(real_file); - free(real_dir); - return ret; -} - -/** - * calc_min_log_lebs - calculate the minimum number of log LEBs needed. - * @max_bud_bytes: journal size (buds only) - */ -static int calc_min_log_lebs(unsigned long long max_bud_bytes) -{ - int buds, log_lebs; - unsigned long long log_size; - - buds = (max_bud_bytes + c->leb_size - 1) / c->leb_size; - log_size = ALIGN(UBIFS_REF_NODE_SZ, c->min_io_size); - log_size *= buds; - log_size += ALIGN(UBIFS_CS_NODE_SZ + - UBIFS_REF_NODE_SZ * (c->jhead_cnt + 2), - c->min_io_size); - log_lebs = (log_size + c->leb_size - 1) / c->leb_size; - log_lebs += 1; - return log_lebs; -} - -/** - * add_space_overhead - add UBIFS overhead. - * @size: flash space which should be visible to the user - * - * UBIFS has overhead, and if we need to reserve @size bytes for the user data, - * we have to reserve more flash space, to compensate the overhead. This - * function calculates and returns the amount of physical flash space which - * should be reserved to provide @size bytes for the user. - */ -static long long add_space_overhead(long long size) -{ - int divisor, factor, f, max_idx_node_sz; - - /* - * Do the opposite to what the 'ubifs_reported_space()' kernel UBIFS - * function does. - */ - max_idx_node_sz = ubifs_idx_node_sz(c, c->fanout); - f = c->fanout > 3 ? c->fanout >> 1 : 2; - divisor = UBIFS_BLOCK_SIZE; - factor = UBIFS_MAX_DATA_NODE_SZ; - factor += (max_idx_node_sz * 3) / (f - 1); - size *= factor; - return size / divisor; -} - -static int validate_options(void) -{ - int tmp; - - if (!output) - return err_msg("no output file or UBI volume specified"); - if (root) { - tmp = is_contained(output, root); - if (tmp < 0) - return err_msg("failed to perform output file root check"); - else if (tmp) - return err_msg("output file cannot be in the UBIFS root " - "directory"); - } - if (!is_power_of_2(c->min_io_size)) - return err_msg("min. I/O unit size should be power of 2"); - if (c->leb_size < c->min_io_size) - return err_msg("min. I/O unit cannot be larger than LEB size"); - if (c->leb_size < UBIFS_MIN_LEB_SZ) - return err_msg("too small LEB size %d, minimum is %d", - c->leb_size, UBIFS_MIN_LEB_SZ); - if (c->leb_size % c->min_io_size) - return err_msg("LEB should be multiple of min. I/O units"); - if (c->leb_size % 8) - return err_msg("LEB size has to be multiple of 8"); - if (c->leb_size > UBIFS_MAX_LEB_SZ) - return err_msg("too large LEB size %d, maximum is %d", - c->leb_size, UBIFS_MAX_LEB_SZ); - if (c->max_leb_cnt < UBIFS_MIN_LEB_CNT) - return err_msg("too low max. count of LEBs, minimum is %d", - UBIFS_MIN_LEB_CNT); - if (c->fanout < UBIFS_MIN_FANOUT) - return err_msg("too low fanout, minimum is %d", - UBIFS_MIN_FANOUT); - tmp = c->leb_size - UBIFS_IDX_NODE_SZ; - tmp /= UBIFS_BRANCH_SZ + UBIFS_MAX_KEY_LEN; - if (c->fanout > tmp) - return err_msg("too high fanout, maximum is %d", tmp); - if (c->log_lebs < UBIFS_MIN_LOG_LEBS) - return err_msg("too few log LEBs, minimum is %d", - UBIFS_MIN_LOG_LEBS); - if (c->log_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT) - return err_msg("too many log LEBs, maximum is %d", - c->max_leb_cnt - UBIFS_MIN_LEB_CNT); - if (c->orph_lebs < UBIFS_MIN_ORPH_LEBS) - return err_msg("too few orphan LEBs, minimum is %d", - UBIFS_MIN_ORPH_LEBS); - if (c->orph_lebs >= c->max_leb_cnt - UBIFS_MIN_LEB_CNT) - return err_msg("too many orphan LEBs, maximum is %d", - c->max_leb_cnt - UBIFS_MIN_LEB_CNT); - tmp = UBIFS_SB_LEBS + UBIFS_MST_LEBS + c->log_lebs + c->lpt_lebs; - tmp += c->orph_lebs + 4; - if (tmp > c->max_leb_cnt) - return err_msg("too low max. count of LEBs, expected at " - "least %d", tmp); - tmp = calc_min_log_lebs(c->max_bud_bytes); - if (c->log_lebs < calc_min_log_lebs(c->max_bud_bytes)) - return err_msg("too few log LEBs, expected at least %d", tmp); - if (c->rp_size >= ((long long)c->leb_size * c->max_leb_cnt) / 2) - return err_msg("too much reserved space %lld", c->rp_size); - return 0; -} - -/** - * get_multiplier - convert size specifier to an integer multiplier. - * @str: the size specifier string - * - * This function parses the @str size specifier, which may be one of - * 'KiB', 'MiB', or 'GiB' into an integer multiplier. Returns positive - * size multiplier in case of success and %-1 in case of failure. - */ -static int get_multiplier(const char *str) -{ - if (!str) - return 1; - - /* Remove spaces before the specifier */ - while (*str == ' ' || *str == '\t') - str += 1; - - if (!strcmp(str, "KiB")) - return 1024; - if (!strcmp(str, "MiB")) - return 1024 * 1024; - if (!strcmp(str, "GiB")) - return 1024 * 1024 * 1024; - - return -1; -} - -/** - * get_bytes - convert a string containing amount of bytes into an - * integer. - * @str: string to convert - * - * This function parses @str which may have one of 'KiB', 'MiB', or 'GiB' size - * specifiers. Returns positive amount of bytes in case of success and %-1 in - * case of failure. - */ -static long long get_bytes(const char *str) -{ - char *endp; - long long bytes = strtoull(str, &endp, 0); - - if (endp == str || bytes < 0) - return err_msg("incorrect amount of bytes: \"%s\"", str); - - if (*endp != '\0') { - int mult = get_multiplier(endp); - - if (mult == -1) - return err_msg("bad size specifier: \"%s\" - " - "should be 'KiB', 'MiB' or 'GiB'", endp); - bytes *= mult; - } - - return bytes; -} -/** - * open_ubi - open the UBI volume. - * @node: name of the UBI volume character device to fetch information about - * - * Returns %0 in case of success and %-1 in case of failure - */ -static int open_ubi(const char *node) -{ - struct stat st; - - if (stat(node, &st) || !S_ISCHR(st.st_mode)) - return -1; - - ubi = libubi_open(); - if (!ubi) - return -1; - if (ubi_get_vol_info(ubi, node, &c->vi)) - return -1; - if (ubi_get_dev_info1(ubi, c->vi.dev_num, &c->di)) - return -1; - return 0; -} - -static int get_options(int argc, char**argv) -{ - int opt, i; - const char *tbl_file = NULL; - struct stat st; - char *endp; - - c->fanout = 8; - c->orph_lebs = 1; - c->key_hash = key_r5_hash; - c->key_len = UBIFS_SK_LEN; - c->default_compr = UBIFS_COMPR_LZO; - c->favor_percent = 20; - c->lsave_cnt = 256; - c->leb_size = -1; - c->min_io_size = -1; - c->max_leb_cnt = -1; - c->max_bud_bytes = -1; - c->log_lebs = -1; - - while (1) { - opt = getopt_long(argc, argv, optstring, longopts, &i); - if (opt == -1) - break; - switch (opt) { - case 'r': - case 'd': - root_len = strlen(optarg); - root = malloc(root_len + 2); - if (!root) - return err_msg("cannot allocate memory"); - - /* - * The further code expects '/' at the end of the root - * UBIFS directory on the host. - */ - memcpy(root, optarg, root_len); - if (root[root_len - 1] != '/') - root[root_len++] = '/'; - root[root_len] = 0; - - /* Make sure the root directory exists */ - if (stat(root, &st)) - return sys_err_msg("bad root directory '%s'", - root); - break; - case 'm': - c->min_io_size = get_bytes(optarg); - if (c->min_io_size <= 0) - return err_msg("bad min. I/O size"); - break; - case 'e': - c->leb_size = get_bytes(optarg); - if (c->leb_size <= 0) - return err_msg("bad LEB size"); - break; - case 'c': - c->max_leb_cnt = get_bytes(optarg); - if (c->max_leb_cnt <= 0) - return err_msg("bad maximum LEB count"); - break; - case 'o': - output = xstrdup(optarg); - break; - case 'D': - tbl_file = optarg; - if (stat(tbl_file, &st) < 0) - return sys_err_msg("bad device table file '%s'", - tbl_file); - break; - case 'y': - yes = 1; - break; - case 'h': - case '?': - printf("%s", helptext); - exit(0); - case 'v': - verbose = 1; - break; - case 'V': - common_print_version(); - exit(0); - case 'g': - debug_level = strtol(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - debug_level < 0 || debug_level > 3) - return err_msg("bad debugging level '%s'", - optarg); - break; - case 'f': - c->fanout = strtol(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || c->fanout <= 0) - return err_msg("bad fanout %s", optarg); - break; - case 'F': - c->space_fixup = 1; - break; - case 'l': - c->log_lebs = strtol(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || c->log_lebs <= 0) - return err_msg("bad count of log LEBs '%s'", - optarg); - break; - case 'p': - c->orph_lebs = strtol(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - c->orph_lebs <= 0) - return err_msg("bad orphan LEB count '%s'", - optarg); - break; - case 'k': - if (strcmp(optarg, "r5") == 0) { - c->key_hash = key_r5_hash; - c->key_hash_type = UBIFS_KEY_HASH_R5; - } else if (strcmp(optarg, "test") == 0) { - c->key_hash = key_test_hash; - c->key_hash_type = UBIFS_KEY_HASH_TEST; - } else - return err_msg("bad key hash"); - break; - case 'x': - if (strcmp(optarg, "favor_lzo") == 0) - c->favor_lzo = 1; - else if (strcmp(optarg, "zlib") == 0) - c->default_compr = UBIFS_COMPR_ZLIB; - else if (strcmp(optarg, "none") == 0) - c->default_compr = UBIFS_COMPR_NONE; - else if (strcmp(optarg, "lzo") != 0) - return err_msg("bad compressor name"); - break; - case 'X': - c->favor_percent = strtol(optarg, &endp, 0); - if (*endp != '\0' || endp == optarg || - c->favor_percent <= 0 || c->favor_percent >= 100) - return err_msg("bad favor LZO percent '%s'", - optarg); - break; - case 'j': - c->max_bud_bytes = get_bytes(optarg); - if (c->max_bud_bytes <= 0) - return err_msg("bad maximum amount of buds"); - break; - case 'R': - c->rp_size = get_bytes(optarg); - if (c->rp_size < 0) - return err_msg("bad reserved bytes count"); - break; - case 'U': - squash_owner = 1; - break; - } - } - - if (optind != argc && !output) - output = xstrdup(argv[optind]); - - if (!output) - return err_msg("not output device or file specified"); - - out_ubi = !open_ubi(output); - - if (out_ubi) { - c->min_io_size = c->di.min_io_size; - c->leb_size = c->vi.leb_size; - if (c->max_leb_cnt == -1) - c->max_leb_cnt = c->vi.rsvd_lebs; - } - - if (c->min_io_size == -1) - return err_msg("min. I/O unit was not specified " - "(use -h for help)"); - - if (c->leb_size == -1) - return err_msg("LEB size was not specified (use -h for help)"); - - if (c->max_leb_cnt == -1) - return err_msg("Maximum count of LEBs was not specified " - "(use -h for help)"); - - if (c->max_bud_bytes == -1) { - int lebs; - - lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS; - lebs -= c->orph_lebs; - if (c->log_lebs != -1) - lebs -= c->log_lebs; - else - lebs -= UBIFS_MIN_LOG_LEBS; - /* - * We do not know lprops geometry so far, so assume minimum - * count of lprops LEBs. - */ - lebs -= UBIFS_MIN_LPT_LEBS; - /* Make the journal about 12.5% of main area lebs */ - c->max_bud_bytes = (lebs / 8) * (long long)c->leb_size; - /* Make the max journal size 8MiB */ - if (c->max_bud_bytes > 8 * 1024 * 1024) - c->max_bud_bytes = 8 * 1024 * 1024; - if (c->max_bud_bytes < 4 * c->leb_size) - c->max_bud_bytes = 4 * c->leb_size; - } - - if (c->log_lebs == -1) { - c->log_lebs = calc_min_log_lebs(c->max_bud_bytes); - c->log_lebs += 2; - } - - if (c->min_io_size < 8) - c->min_io_size = 8; - c->rp_size = add_space_overhead(c->rp_size); - - if (verbose) { - printf("mkfs.ubifs\n"); - printf("\troot: %s\n", root); - printf("\tmin_io_size: %d\n", c->min_io_size); - printf("\tleb_size: %d\n", c->leb_size); - printf("\tmax_leb_cnt: %d\n", c->max_leb_cnt); - printf("\toutput: %s\n", output); - printf("\tjrn_size: %llu\n", c->max_bud_bytes); - printf("\treserved: %llu\n", c->rp_size); - switch (c->default_compr) { - case UBIFS_COMPR_LZO: - printf("\tcompr: lzo\n"); - break; - case UBIFS_COMPR_ZLIB: - printf("\tcompr: zlib\n"); - break; - case UBIFS_COMPR_NONE: - printf("\tcompr: none\n"); - break; - } - printf("\tkeyhash: %s\n", (c->key_hash == key_r5_hash) ? - "r5" : "test"); - printf("\tfanout: %d\n", c->fanout); - printf("\torph_lebs: %d\n", c->orph_lebs); - printf("\tspace_fixup: %d\n", c->space_fixup); - } - - if (validate_options()) - return -1; - - if (tbl_file && parse_devtable(tbl_file)) - return err_msg("cannot parse device table file '%s'", tbl_file); - - return 0; -} - -/** - * prepare_node - fill in the common header. - * @node: node - * @len: node length - */ -static void prepare_node(void *node, int len) -{ - uint32_t crc; - struct ubifs_ch *ch = node; - - ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); - ch->len = cpu_to_le32(len); - ch->group_type = UBIFS_NO_NODE_GROUP; - ch->sqnum = cpu_to_le64(++c->max_sqnum); - ch->padding[0] = ch->padding[1] = 0; - crc = mtd_crc32(UBIFS_CRC32_INIT, node + 8, len - 8); - ch->crc = cpu_to_le32(crc); -} - -/** - * write_leb - copy the image of a LEB to the output target. - * @lnum: LEB number - * @len: length of data in the buffer - * @buf: buffer (must be at least c->leb_size bytes) - */ -int write_leb(int lnum, int len, void *buf) -{ - off_t pos = (off_t)lnum * c->leb_size; - - dbg_msg(3, "LEB %d len %d", lnum, len); - memset(buf + len, 0xff, c->leb_size - len); - if (out_ubi) - if (ubi_leb_change_start(ubi, out_fd, lnum, c->leb_size)) - return sys_err_msg("ubi_leb_change_start failed"); - - if (lseek(out_fd, pos, SEEK_SET) != pos) - return sys_err_msg("lseek failed seeking %"PRIdoff_t, pos); - - if (write(out_fd, buf, c->leb_size) != c->leb_size) - return sys_err_msg("write failed writing %d bytes at pos %"PRIdoff_t, - c->leb_size, pos); - - return 0; -} - -/** - * write_empty_leb - copy the image of an empty LEB to the output target. - * @lnum: LEB number - */ -static int write_empty_leb(int lnum) -{ - return write_leb(lnum, 0, leb_buf); -} - -/** - * do_pad - pad a buffer to the minimum I/O size. - * @buf: buffer - * @len: buffer length - */ -static int do_pad(void *buf, int len) -{ - int pad_len, alen = ALIGN(len, 8), wlen = ALIGN(alen, c->min_io_size); - uint32_t crc; - - memset(buf + len, 0xff, alen - len); - pad_len = wlen - alen; - dbg_msg(3, "len %d pad_len %d", len, pad_len); - buf += alen; - if (pad_len >= (int)UBIFS_PAD_NODE_SZ) { - struct ubifs_ch *ch = buf; - struct ubifs_pad_node *pad_node = buf; - - ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC); - ch->node_type = UBIFS_PAD_NODE; - ch->group_type = UBIFS_NO_NODE_GROUP; - ch->padding[0] = ch->padding[1] = 0; - ch->sqnum = cpu_to_le64(0); - ch->len = cpu_to_le32(UBIFS_PAD_NODE_SZ); - - pad_len -= UBIFS_PAD_NODE_SZ; - pad_node->pad_len = cpu_to_le32(pad_len); - - crc = mtd_crc32(UBIFS_CRC32_INIT, buf + 8, - UBIFS_PAD_NODE_SZ - 8); - ch->crc = cpu_to_le32(crc); - - memset(buf + UBIFS_PAD_NODE_SZ, 0, pad_len); - } else if (pad_len > 0) - memset(buf, UBIFS_PADDING_BYTE, pad_len); - - return wlen; -} - -/** - * write_node - write a node to a LEB. - * @node: node - * @len: node length - * @lnum: LEB number - */ -static int write_node(void *node, int len, int lnum) -{ - prepare_node(node, len); - - memcpy(leb_buf, node, len); - - len = do_pad(leb_buf, len); - - return write_leb(lnum, len, leb_buf); -} - -/** - * calc_dark - calculate LEB dark space size. - * @c: the UBIFS file-system description object - * @spc: amount of free and dirty space in the LEB - * - * This function calculates amount of dark space in an LEB which has @spc bytes - * of free and dirty space. Returns the calculations result. - * - * Dark space is the space which is not always usable - it depends on which - * nodes are written in which order. E.g., if an LEB has only 512 free bytes, - * it is dark space, because it cannot fit a large data node. So UBIFS cannot - * count on this LEB and treat these 512 bytes as usable because it is not true - * if, for example, only big chunks of uncompressible data will be written to - * the FS. - */ -static int calc_dark(struct ubifs_info *c, int spc) -{ - if (spc < c->dark_wm) - return spc; - - /* - * If we have slightly more space then the dark space watermark, we can - * anyway safely assume it we'll be able to write a node of the - * smallest size there. - */ - if (spc - c->dark_wm < (int)MIN_WRITE_SZ) - return spc - MIN_WRITE_SZ; - - return c->dark_wm; -} - -/** - * set_lprops - set the LEB property values for a LEB. - * @lnum: LEB number - * @offs: end offset of data in the LEB - * @flags: LEB property flags - */ -static void set_lprops(int lnum, int offs, int flags) -{ - int i = lnum - c->main_first, free, dirty; - int a = max_t(int, c->min_io_size, 8); - - free = c->leb_size - ALIGN(offs, a); - dirty = c->leb_size - free - ALIGN(offs, 8); - dbg_msg(3, "LEB %d free %d dirty %d flags %d", lnum, free, dirty, - flags); - if (i < c->main_lebs) { - c->lpt[i].free = free; - c->lpt[i].dirty = dirty; - c->lpt[i].flags = flags; - } - c->lst.total_free += free; - c->lst.total_dirty += dirty; - if (flags & LPROPS_INDEX) - c->lst.idx_lebs += 1; - else { - int spc; - - spc = free + dirty; - if (spc < c->dead_wm) - c->lst.total_dead += spc; - else - c->lst.total_dark += calc_dark(c, spc); - c->lst.total_used += c->leb_size - spc; - } -} - -/** - * add_to_index - add a node key and position to the index. - * @key: node key - * @lnum: node LEB number - * @offs: node offset - * @len: node length - */ -static int add_to_index(union ubifs_key *key, char *name, int lnum, int offs, - int len) -{ - struct idx_entry *e; - - dbg_msg(3, "LEB %d offs %d len %d", lnum, offs, len); - e = malloc(sizeof(struct idx_entry)); - if (!e) - return err_msg("out of memory"); - e->next = NULL; - e->prev = idx_list_last; - e->key = *key; - e->name = name; - e->lnum = lnum; - e->offs = offs; - e->len = len; - if (!idx_list_first) - idx_list_first = e; - if (idx_list_last) - idx_list_last->next = e; - idx_list_last = e; - idx_cnt += 1; - return 0; -} - -/** - * flush_nodes - write the current head and move the head to the next LEB. - */ -static int flush_nodes(void) -{ - int len, err; - - if (!head_offs) - return 0; - len = do_pad(leb_buf, head_offs); - err = write_leb(head_lnum, len, leb_buf); - if (err) - return err; - set_lprops(head_lnum, head_offs, head_flags); - head_lnum += 1; - head_offs = 0; - return 0; -} - -/** - * reserve_space - reserve space for a node on the head. - * @len: node length - * @lnum: LEB number is returned here - * @offs: offset is returned here - */ -static int reserve_space(int len, int *lnum, int *offs) -{ - int err; - - if (len > c->leb_size - head_offs) { - err = flush_nodes(); - if (err) - return err; - } - *lnum = head_lnum; - *offs = head_offs; - head_offs += ALIGN(len, 8); - return 0; -} - -/** - * add_node - write a node to the head. - * @key: node key - * @node: node - * @len: node length - */ -static int add_node(union ubifs_key *key, char *name, void *node, int len) -{ - int err, lnum, offs; - - prepare_node(node, len); - - err = reserve_space(len, &lnum, &offs); - if (err) - return err; - - memcpy(leb_buf + offs, node, len); - memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len); - - add_to_index(key, name, lnum, offs, len); - - return 0; -} - -/** - * add_inode_with_data - write an inode. - * @st: stat information of source inode - * @inum: target inode number - * @data: inode data (for special inodes e.g. symlink path etc) - * @data_len: inode data length - * @flags: source inode flags - */ -static int add_inode_with_data(struct stat *st, ino_t inum, void *data, - unsigned int data_len, int flags) -{ - struct ubifs_ino_node *ino = node_buf; - union ubifs_key key; - int len, use_flags = 0; - - if (c->default_compr != UBIFS_COMPR_NONE) - use_flags |= UBIFS_COMPR_FL; - if (flags & FS_COMPR_FL) - use_flags |= UBIFS_COMPR_FL; - if (flags & FS_SYNC_FL) - use_flags |= UBIFS_SYNC_FL; - if (flags & FS_IMMUTABLE_FL) - use_flags |= UBIFS_IMMUTABLE_FL; - if (flags & FS_APPEND_FL) - use_flags |= UBIFS_APPEND_FL; - if (flags & FS_DIRSYNC_FL && S_ISDIR(st->st_mode)) - use_flags |= UBIFS_DIRSYNC_FL; - - memset(ino, 0, UBIFS_INO_NODE_SZ); - - ino_key_init(&key, inum); - ino->ch.node_type = UBIFS_INO_NODE; - key_write(&key, &ino->key); - ino->creat_sqnum = cpu_to_le64(creat_sqnum); - ino->size = cpu_to_le64(st->st_size); - ino->nlink = cpu_to_le32(st->st_nlink); - /* - * The time fields are updated assuming the default time granularity - * of 1 second. To support finer granularities, utime() would be needed. - */ - ino->atime_sec = cpu_to_le64(st->st_atime); - ino->ctime_sec = cpu_to_le64(st->st_ctime); - ino->mtime_sec = cpu_to_le64(st->st_mtime); - ino->atime_nsec = 0; - ino->ctime_nsec = 0; - ino->mtime_nsec = 0; - ino->uid = cpu_to_le32(st->st_uid); - ino->gid = cpu_to_le32(st->st_gid); - ino->mode = cpu_to_le32(st->st_mode); - ino->flags = cpu_to_le32(use_flags); - ino->data_len = cpu_to_le32(data_len); - ino->compr_type = cpu_to_le16(c->default_compr); - if (data_len) - memcpy(&ino->data, data, data_len); - - len = UBIFS_INO_NODE_SZ + data_len; - - return add_node(&key, NULL, ino, len); -} - -/** - * add_inode - write an inode. - * @st: stat information of source inode - * @inum: target inode number - * @flags: source inode flags - */ -static int add_inode(struct stat *st, ino_t inum, int flags) -{ - return add_inode_with_data(st, inum, NULL, 0, flags); -} - -/** - * add_dir_inode - write an inode for a directory. - * @dir: source directory - * @inum: target inode number - * @size: target directory size - * @nlink: target directory link count - * @st: struct stat object describing attributes (except size and nlink) of the - * target inode to create - * - * Note, this function may be called with %NULL @dir, when the directory which - * is being created does not exist at the host file system, but is defined by - * the device table. - */ -static int add_dir_inode(DIR *dir, ino_t inum, loff_t size, unsigned int nlink, - struct stat *st) -{ - int fd, flags = 0; - - st->st_size = size; - st->st_nlink = nlink; - - if (dir) { - fd = dirfd(dir); - if (fd == -1) - return sys_err_msg("dirfd failed"); - if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) - flags = 0; - } - - return add_inode(st, inum, flags); -} - -/** - * add_dev_inode - write an inode for a character or block device. - * @st: stat information of source inode - * @inum: target inode number - * @flags: source inode flags - */ -static int add_dev_inode(struct stat *st, ino_t inum, int flags) -{ - union ubifs_dev_desc dev; - - dev.huge = cpu_to_le64(makedev(major(st->st_rdev), minor(st->st_rdev))); - return add_inode_with_data(st, inum, &dev, 8, flags); -} - -/** - * add_symlink_inode - write an inode for a symbolic link. - * @path_name: path name of symbolic link inode itself (not the link target) - * @st: stat information of source inode - * @inum: target inode number - * @flags: source inode flags - */ -static int add_symlink_inode(const char *path_name, struct stat *st, ino_t inum, - int flags) -{ - char buf[UBIFS_MAX_INO_DATA + 2]; - ssize_t len; - - /* Take the symlink as is */ - len = readlink(path_name, buf, UBIFS_MAX_INO_DATA + 1); - if (len <= 0) - return sys_err_msg("readlink failed for %s", path_name); - if (len > UBIFS_MAX_INO_DATA) - return err_msg("symlink too long for %s", path_name); - - return add_inode_with_data(st, inum, buf, len, flags); -} - -/** - * add_dent_node - write a directory entry node. - * @dir_inum: target inode number of directory - * @name: directory entry name - * @inum: target inode number of the directory entry - * @type: type of the target inode - */ -static int add_dent_node(ino_t dir_inum, const char *name, ino_t inum, - unsigned char type) -{ - struct ubifs_dent_node *dent = node_buf; - union ubifs_key key; - struct qstr dname; - char *kname; - int len; - - dbg_msg(3, "%s ino %lu type %u dir ino %lu", name, (unsigned long)inum, - (unsigned int)type, (unsigned long)dir_inum); - memset(dent, 0, UBIFS_DENT_NODE_SZ); - - dname.name = (void *)name; - dname.len = strlen(name); - - dent->ch.node_type = UBIFS_DENT_NODE; - - dent_key_init(c, &key, dir_inum, &dname); - key_write(&key, dent->key); - dent->inum = cpu_to_le64(inum); - dent->padding1 = 0; - dent->type = type; - dent->nlen = cpu_to_le16(dname.len); - memcpy(dent->name, dname.name, dname.len); - dent->name[dname.len] = '\0'; - - len = UBIFS_DENT_NODE_SZ + dname.len + 1; - - kname = strdup(name); - if (!kname) - return err_msg("cannot allocate memory"); - - return add_node(&key, kname, dent, len); -} - -/** - * lookup_inum_mapping - add an inode mapping for link counting. - * @dev: source device on which source inode number resides - * @inum: source inode number - */ -static struct inum_mapping *lookup_inum_mapping(dev_t dev, ino_t inum) -{ - struct inum_mapping *im; - unsigned int k; - - k = inum % HASH_TABLE_SIZE; - im = hash_table[k]; - while (im) { - if (im->dev == dev && im->inum == inum) - return im; - im = im->next; - } - im = malloc(sizeof(struct inum_mapping)); - if (!im) - return NULL; - im->next = hash_table[k]; - im->prev = NULL; - im->dev = dev; - im->inum = inum; - im->use_inum = 0; - im->use_nlink = 0; - if (hash_table[k]) - hash_table[k]->prev = im; - hash_table[k] = im; - return im; -} - -/** - * all_zero - does a buffer contain only zero bytes. - * @buf: buffer - * @len: buffer length - */ -static int all_zero(void *buf, int len) -{ - unsigned char *p = buf; - - while (len--) - if (*p++ != 0) - return 0; - return 1; -} - -/** - * add_file - write the data of a file and its inode to the output file. - * @path_name: source path name - * @st: source inode stat information - * @inum: target inode number - * @flags: source inode flags - */ -static int add_file(const char *path_name, struct stat *st, ino_t inum, - int flags) -{ - struct ubifs_data_node *dn = node_buf; - void *buf = block_buf; - loff_t file_size = 0; - ssize_t ret, bytes_read; - union ubifs_key key; - int fd, dn_len, err, compr_type, use_compr; - unsigned int block_no = 0; - size_t out_len; - - fd = open(path_name, O_RDONLY | O_LARGEFILE); - if (fd == -1) - return sys_err_msg("failed to open file '%s'", path_name); - do { - /* Read next block */ - bytes_read = 0; - do { - ret = read(fd, buf + bytes_read, - UBIFS_BLOCK_SIZE - bytes_read); - if (ret == -1) { - sys_err_msg("failed to read file '%s'", - path_name); - close(fd); - return 1; - } - bytes_read += ret; - } while (ret != 0 && bytes_read != UBIFS_BLOCK_SIZE); - if (bytes_read == 0) - break; - file_size += bytes_read; - /* Skip holes */ - if (all_zero(buf, bytes_read)) { - block_no += 1; - continue; - } - /* Make data node */ - memset(dn, 0, UBIFS_DATA_NODE_SZ); - data_key_init(&key, inum, block_no++); - dn->ch.node_type = UBIFS_DATA_NODE; - key_write(&key, &dn->key); - dn->size = cpu_to_le32(bytes_read); - out_len = NODE_BUFFER_SIZE - UBIFS_DATA_NODE_SZ; - if (c->default_compr == UBIFS_COMPR_NONE && - (flags & FS_COMPR_FL)) - use_compr = UBIFS_COMPR_LZO; - else - use_compr = c->default_compr; - compr_type = compress_data(buf, bytes_read, &dn->data, - &out_len, use_compr); - dn->compr_type = cpu_to_le16(compr_type); - dn_len = UBIFS_DATA_NODE_SZ + out_len; - /* Add data node to file system */ - err = add_node(&key, NULL, dn, dn_len); - if (err) { - close(fd); - return err; - } - } while (ret != 0); - if (close(fd) == -1) - return sys_err_msg("failed to close file '%s'", path_name); - if (file_size != st->st_size) - return err_msg("file size changed during writing file '%s'", - path_name); - return add_inode(st, inum, flags); -} - -/** - * add_non_dir - write a non-directory to the output file. - * @path_name: source path name - * @inum: target inode number is passed and returned here (due to link counting) - * @nlink: number of links if known otherwise zero - * @type: UBIFS inode type is returned here - * @st: struct stat object containing inode attributes which should be use when - * creating the UBIFS inode - */ -static int add_non_dir(const char *path_name, ino_t *inum, unsigned int nlink, - unsigned char *type, struct stat *st) -{ - int fd, flags = 0; - - dbg_msg(2, "%s", path_name); - - if (S_ISREG(st->st_mode)) { - fd = open(path_name, O_RDONLY); - if (fd == -1) - return sys_err_msg("failed to open file '%s'", - path_name); - if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) - flags = 0; - if (close(fd) == -1) - return sys_err_msg("failed to close file '%s'", - path_name); - *type = UBIFS_ITYPE_REG; - } else if (S_ISCHR(st->st_mode)) - *type = UBIFS_ITYPE_CHR; - else if (S_ISBLK(st->st_mode)) - *type = UBIFS_ITYPE_BLK; - else if (S_ISLNK(st->st_mode)) - *type = UBIFS_ITYPE_LNK; - else if (S_ISSOCK(st->st_mode)) - *type = UBIFS_ITYPE_SOCK; - else if (S_ISFIFO(st->st_mode)) - *type = UBIFS_ITYPE_FIFO; - else - return err_msg("file '%s' has unknown inode type", path_name); - - if (nlink) - st->st_nlink = nlink; - else if (st->st_nlink > 1) { - /* - * If the number of links is greater than 1, then add this file - * later when we know the number of links that we actually have. - * For now, we just put the inode mapping in the hash table. - */ - struct inum_mapping *im; - - im = lookup_inum_mapping(st->st_dev, st->st_ino); - if (!im) - return err_msg("out of memory"); - if (im->use_nlink == 0) { - /* New entry */ - im->use_inum = *inum; - im->use_nlink = 1; - im->path_name = malloc(strlen(path_name) + 1); - if (!im->path_name) - return err_msg("out of memory"); - strcpy(im->path_name, path_name); - } else { - /* Existing entry */ - *inum = im->use_inum; - im->use_nlink += 1; - /* Return unused inode number */ - c->highest_inum -= 1; - } - - memcpy(&im->st, st, sizeof(struct stat)); - return 0; - } else - st->st_nlink = 1; - - creat_sqnum = ++c->max_sqnum; - - if (S_ISREG(st->st_mode)) - return add_file(path_name, st, *inum, flags); - if (S_ISCHR(st->st_mode)) - return add_dev_inode(st, *inum, flags); - if (S_ISBLK(st->st_mode)) - return add_dev_inode(st, *inum, flags); - if (S_ISLNK(st->st_mode)) - return add_symlink_inode(path_name, st, *inum, flags); - if (S_ISSOCK(st->st_mode)) - return add_inode(st, *inum, flags); - if (S_ISFIFO(st->st_mode)) - return add_inode(st, *inum, flags); - - return err_msg("file '%s' has unknown inode type", path_name); -} - -/** - * add_directory - write a directory tree to the output file. - * @dir_name: directory path name - * @dir_inum: UBIFS inode number of directory - * @st: directory inode statistics - * @non_existing: non-zero if this function is called for a directory which - * does not exist on the host file-system and it is being - * created because it is defined in the device table file. - */ -static int add_directory(const char *dir_name, ino_t dir_inum, struct stat *st, - int non_existing) -{ - struct dirent *entry; - DIR *dir = NULL; - int err = 0; - loff_t size = UBIFS_INO_NODE_SZ; - char *name = NULL; - unsigned int nlink = 2; - struct path_htbl_element *ph_elt; - struct name_htbl_element *nh_elt = NULL; - struct hashtable_itr *itr; - ino_t inum; - unsigned char type; - unsigned long long dir_creat_sqnum = ++c->max_sqnum; - - dbg_msg(2, "%s", dir_name); - if (!non_existing) { - dir = opendir(dir_name); - if (dir == NULL) - return sys_err_msg("cannot open directory '%s'", - dir_name); - } - - /* - * Check whether this directory contains files which should be - * added/changed because they were specified in the device table. - * @ph_elt will be non-zero if yes. - */ - ph_elt = devtbl_find_path(dir_name + root_len - 1); - - /* - * Before adding the directory itself, we have to iterate over all the - * entries the device table adds to this directory and create them. - */ - for (; !non_existing;) { - struct stat dent_st; - - errno = 0; - entry = readdir(dir); - if (!entry) { - if (errno == 0) - break; - sys_err_msg("error reading directory '%s'", dir_name); - err = -1; - break; - } - - if (strcmp(".", entry->d_name) == 0) - continue; - if (strcmp("..", entry->d_name) == 0) - continue; - - if (ph_elt) - /* - * This directory was referred to at the device table - * file. Check if this directory entry is referred at - * too. - */ - nh_elt = devtbl_find_name(ph_elt, entry->d_name); - - /* - * We are going to create the file corresponding to this - * directory entry (@entry->d_name). We use 'struct stat' - * object to pass information about file attributes (actually - * only about UID, GID, mode, major, and minor). Get attributes - * for this file from the UBIFS rootfs on the host. - */ - free(name); - name = make_path(dir_name, entry->d_name); - if (lstat(name, &dent_st) == -1) { - sys_err_msg("lstat failed for file '%s'", name); - goto out_free; - } - - if (squash_owner) - /* - * Squash UID/GID. But the device table may override - * this. - */ - dent_st.st_uid = dent_st.st_gid = 0; - - /* - * And if the device table describes the same file, override - * the attributes. However, this is not allowed for device node - * files. - */ - if (nh_elt && override_attributes(&dent_st, ph_elt, nh_elt)) - goto out_free; - - inum = ++c->highest_inum; - - if (S_ISDIR(dent_st.st_mode)) { - err = add_directory(name, inum, &dent_st, 0); - if (err) - goto out_free; - nlink += 1; - type = UBIFS_ITYPE_DIR; - } else { - err = add_non_dir(name, &inum, 0, &type, &dent_st); - if (err) - goto out_free; - } - - err = add_dent_node(dir_inum, entry->d_name, inum, type); - if (err) - goto out_free; - size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(entry->d_name) + 1, - 8); - } - - /* - * OK, we have created all files in this directory (recursively), let's - * also create all files described in the device table. All t - */ - nh_elt = first_name_htbl_element(ph_elt, &itr); - while (nh_elt) { - struct stat fake_st; - - /* - * We prohibit creating regular files using the device table, - * the device table may only re-define attributes of regular - * files. - */ - if (S_ISREG(nh_elt->mode)) { - err_msg("Bad device table entry %s/%s - it is " - "prohibited to create regular files " - "via device table", - strcmp(ph_elt->path, "/") ? ph_elt->path : "", - nh_elt->name); - goto out_free; - } - - memcpy(&fake_st, &root_st, sizeof(struct stat)); - fake_st.st_uid = nh_elt->uid; - fake_st.st_uid = nh_elt->uid; - fake_st.st_mode = nh_elt->mode; - fake_st.st_rdev = nh_elt->dev; - fake_st.st_nlink = 1; - - free(name); - name = make_path(dir_name, nh_elt->name); - inum = ++c->highest_inum; - - if (S_ISDIR(nh_elt->mode)) { - err = add_directory(name, inum, &fake_st, 1); - if (err) - goto out_free; - nlink += 1; - type = UBIFS_ITYPE_DIR; - } else { - err = add_non_dir(name, &inum, 0, &type, &fake_st); - if (err) - goto out_free; - } - - err = add_dent_node(dir_inum, nh_elt->name, inum, type); - if (err) - goto out_free; - size += ALIGN(UBIFS_DENT_NODE_SZ + strlen(nh_elt->name) + 1, 8); - - nh_elt = next_name_htbl_element(ph_elt, &itr); - } - - creat_sqnum = dir_creat_sqnum; - - err = add_dir_inode(dir, dir_inum, size, nlink, st); - if (err) - goto out_free; - - free(name); - if (!non_existing && closedir(dir) == -1) - return sys_err_msg("error closing directory '%s'", dir_name); - - return 0; - -out_free: - free(name); - if (!non_existing) - closedir(dir); - return -1; -} - -/** - * add_multi_linked_files - write all the files for which we counted links. - */ -static int add_multi_linked_files(void) -{ - int i, err; - - for (i = 0; i < HASH_TABLE_SIZE; i++) { - struct inum_mapping *im; - unsigned char type = 0; - - for (im = hash_table[i]; im; im = im->next) { - dbg_msg(2, "%s", im->path_name); - err = add_non_dir(im->path_name, &im->use_inum, - im->use_nlink, &type, &im->st); - if (err) - return err; - } - } - return 0; -} - -/** - * write_data - write the files and directories. - */ -static int write_data(void) -{ - int err; - mode_t mode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; - - if (root) { - err = stat(root, &root_st); - if (err) - return sys_err_msg("bad root file-system directory '%s'", - root); - } else { - root_st.st_mtime = time(NULL); - root_st.st_atime = root_st.st_ctime = root_st.st_mtime; - root_st.st_mode = mode; - } - - head_flags = 0; - err = add_directory(root, UBIFS_ROOT_INO, &root_st, !root); - if (err) - return err; - err = add_multi_linked_files(); - if (err) - return err; - return flush_nodes(); -} - -static int namecmp(const char *name1, const char *name2) -{ - size_t len1 = strlen(name1), len2 = strlen(name2); - size_t clen = (len1 < len2) ? len1 : len2; - int cmp; - - cmp = memcmp(name1, name2, clen); - if (cmp) - return cmp; - return (len1 < len2) ? -1 : 1; -} - -static int cmp_idx(const void *a, const void *b) -{ - const struct idx_entry *e1 = *(const struct idx_entry **)a; - const struct idx_entry *e2 = *(const struct idx_entry **)b; - int cmp; - - cmp = keys_cmp(&e1->key, &e2->key); - if (cmp) - return cmp; - return namecmp(e1->name, e2->name); -} - -/** - * add_idx_node - write an index node to the head. - * @node: index node - * @child_cnt: number of children of this index node - */ -static int add_idx_node(void *node, int child_cnt) -{ - int err, lnum, offs, len; - - len = ubifs_idx_node_sz(c, child_cnt); - - prepare_node(node, len); - - err = reserve_space(len, &lnum, &offs); - if (err) - return err; - - memcpy(leb_buf + offs, node, len); - memset(leb_buf + offs + len, 0xff, ALIGN(len, 8) - len); - - c->old_idx_sz += ALIGN(len, 8); - - dbg_msg(3, "at %d:%d len %d index size %llu", lnum, offs, len, - c->old_idx_sz); - - /* The last index node written will be the root */ - c->zroot.lnum = lnum; - c->zroot.offs = offs; - c->zroot.len = len; - - return 0; -} - -/** - * write_index - write out the index. - */ -static int write_index(void) -{ - size_t sz, i, cnt, idx_sz, pstep, bcnt; - struct idx_entry **idx_ptr, **p; - struct ubifs_idx_node *idx; - struct ubifs_branch *br; - int child_cnt = 0, j, level, blnum, boffs, blen, blast_len, err; - - dbg_msg(1, "leaf node count: %zd", idx_cnt); - - /* Reset the head for the index */ - head_flags = LPROPS_INDEX; - /* Allocate index node */ - idx_sz = ubifs_idx_node_sz(c, c->fanout); - idx = malloc(idx_sz); - if (!idx) - return err_msg("out of memory"); - /* Make an array of pointers to sort the index list */ - sz = idx_cnt * sizeof(struct idx_entry *); - if (sz / sizeof(struct idx_entry *) != idx_cnt) { - free(idx); - return err_msg("index is too big (%zu entries)", idx_cnt); - } - idx_ptr = malloc(sz); - if (!idx_ptr) { - free(idx); - return err_msg("out of memory - needed %zu bytes for index", - sz); - } - idx_ptr[0] = idx_list_first; - for (i = 1; i < idx_cnt; i++) - idx_ptr[i] = idx_ptr[i - 1]->next; - qsort(idx_ptr, idx_cnt, sizeof(struct idx_entry *), cmp_idx); - /* Write level 0 index nodes */ - cnt = idx_cnt / c->fanout; - if (idx_cnt % c->fanout) - cnt += 1; - p = idx_ptr; - blnum = head_lnum; - boffs = head_offs; - for (i = 0; i < cnt; i++) { - /* - * Calculate the child count. All index nodes are created full - * except for the last index node on each row. - */ - if (i == cnt - 1) { - child_cnt = idx_cnt % c->fanout; - if (child_cnt == 0) - child_cnt = c->fanout; - } else - child_cnt = c->fanout; - memset(idx, 0, idx_sz); - idx->ch.node_type = UBIFS_IDX_NODE; - idx->child_cnt = cpu_to_le16(child_cnt); - idx->level = cpu_to_le16(0); - for (j = 0; j < child_cnt; j++, p++) { - br = ubifs_idx_branch(c, idx, j); - key_write_idx(&(*p)->key, &br->key); - br->lnum = cpu_to_le32((*p)->lnum); - br->offs = cpu_to_le32((*p)->offs); - br->len = cpu_to_le32((*p)->len); - } - add_idx_node(idx, child_cnt); - } - /* Write level 1 index nodes and above */ - level = 0; - pstep = 1; - while (cnt > 1) { - /* - * 'blast_len' is the length of the last index node in the level - * below. - */ - blast_len = ubifs_idx_node_sz(c, child_cnt); - /* 'bcnt' is the number of index nodes in the level below */ - bcnt = cnt; - /* 'cnt' is the number of index nodes in this level */ - cnt = (cnt + c->fanout - 1) / c->fanout; - if (cnt == 0) - cnt = 1; - level += 1; - /* - * The key of an index node is the same as the key of its first - * child. Thus we can get the key by stepping along the bottom - * level 'p' with an increasing large step 'pstep'. - */ - p = idx_ptr; - pstep *= c->fanout; - for (i = 0; i < cnt; i++) { - /* - * Calculate the child count. All index nodes are - * created full except for the last index node on each - * row. - */ - if (i == cnt - 1) { - child_cnt = bcnt % c->fanout; - if (child_cnt == 0) - child_cnt = c->fanout; - } else - child_cnt = c->fanout; - memset(idx, 0, idx_sz); - idx->ch.node_type = UBIFS_IDX_NODE; - idx->child_cnt = cpu_to_le16(child_cnt); - idx->level = cpu_to_le16(level); - for (j = 0; j < child_cnt; j++) { - size_t bn = i * c->fanout + j; - - /* - * The length of the index node in the level - * below is 'idx_sz' except when it is the last - * node on the row. i.e. all the others on the - * row are full. - */ - if (bn == bcnt - 1) - blen = blast_len; - else - blen = idx_sz; - /* - * 'blnum' and 'boffs' hold the position of the - * index node on the level below. - */ - if (boffs + blen > c->leb_size) { - blnum += 1; - boffs = 0; - } - /* - * Fill in the branch with the key and position - * of the index node from the level below. - */ - br = ubifs_idx_branch(c, idx, j); - key_write_idx(&(*p)->key, &br->key); - br->lnum = cpu_to_le32(blnum); - br->offs = cpu_to_le32(boffs); - br->len = cpu_to_le32(blen); - /* - * Step to the next index node on the level - * below. - */ - boffs += ALIGN(blen, 8); - p += pstep; - } - add_idx_node(idx, child_cnt); - } - } - - /* Free stuff */ - for (i = 0; i < idx_cnt; i++) - free(idx_ptr[i]); - free(idx_ptr); - free(idx); - - dbg_msg(1, "zroot is at %d:%d len %d", c->zroot.lnum, c->zroot.offs, - c->zroot.len); - - /* Set the index head */ - c->ihead_lnum = head_lnum; - c->ihead_offs = ALIGN(head_offs, c->min_io_size); - dbg_msg(1, "ihead is at %d:%d", c->ihead_lnum, c->ihead_offs); - - /* Flush the last index LEB */ - err = flush_nodes(); - if (err) - return err; - - return 0; -} - -/** - * set_gc_lnum - set the LEB number reserved for the garbage collector. - */ -static int set_gc_lnum(void) -{ - int err; - - c->gc_lnum = head_lnum++; - err = write_empty_leb(c->gc_lnum); - if (err) - return err; - set_lprops(c->gc_lnum, 0, 0); - c->lst.empty_lebs += 1; - return 0; -} - -/** - * finalize_leb_cnt - now that we know how many LEBs we used. - */ -static int finalize_leb_cnt(void) -{ - c->leb_cnt = head_lnum; - if (c->leb_cnt > c->max_leb_cnt) - return err_msg("max_leb_cnt too low (%d needed)", c->leb_cnt); - c->main_lebs = c->leb_cnt - c->main_first; - if (verbose) { - printf("\tsuper lebs: %d\n", UBIFS_SB_LEBS); - printf("\tmaster lebs: %d\n", UBIFS_MST_LEBS); - printf("\tlog_lebs: %d\n", c->log_lebs); - printf("\tlpt_lebs: %d\n", c->lpt_lebs); - printf("\torph_lebs: %d\n", c->orph_lebs); - printf("\tmain_lebs: %d\n", c->main_lebs); - printf("\tgc lebs: %d\n", 1); - printf("\tindex lebs: %d\n", c->lst.idx_lebs); - printf("\tleb_cnt: %d\n", c->leb_cnt); - } - dbg_msg(1, "total_free: %llu", c->lst.total_free); - dbg_msg(1, "total_dirty: %llu", c->lst.total_dirty); - dbg_msg(1, "total_used: %llu", c->lst.total_used); - dbg_msg(1, "total_dead: %llu", c->lst.total_dead); - dbg_msg(1, "total_dark: %llu", c->lst.total_dark); - dbg_msg(1, "index size: %llu", c->old_idx_sz); - dbg_msg(1, "empty_lebs: %d", c->lst.empty_lebs); - return 0; -} - -/** - * write_super - write the super block. - */ -static int write_super(void) -{ - struct ubifs_sb_node sup; - - memset(&sup, 0, UBIFS_SB_NODE_SZ); - - sup.ch.node_type = UBIFS_SB_NODE; - sup.key_hash = c->key_hash_type; - sup.min_io_size = cpu_to_le32(c->min_io_size); - sup.leb_size = cpu_to_le32(c->leb_size); - sup.leb_cnt = cpu_to_le32(c->leb_cnt); - sup.max_leb_cnt = cpu_to_le32(c->max_leb_cnt); - sup.max_bud_bytes = cpu_to_le64(c->max_bud_bytes); - sup.log_lebs = cpu_to_le32(c->log_lebs); - sup.lpt_lebs = cpu_to_le32(c->lpt_lebs); - sup.orph_lebs = cpu_to_le32(c->orph_lebs); - sup.jhead_cnt = cpu_to_le32(c->jhead_cnt); - sup.fanout = cpu_to_le32(c->fanout); - sup.lsave_cnt = cpu_to_le32(c->lsave_cnt); - sup.fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION); - sup.default_compr = cpu_to_le16(c->default_compr); - sup.rp_size = cpu_to_le64(c->rp_size); - sup.time_gran = cpu_to_le32(DEFAULT_TIME_GRAN); - uuid_generate_random(sup.uuid); - if (verbose) { - char s[40]; - - uuid_unparse_upper(sup.uuid, s); - printf("\tUUID: %s\n", s); - } - if (c->big_lpt) - sup.flags |= cpu_to_le32(UBIFS_FLG_BIGLPT); - if (c->space_fixup) - sup.flags |= cpu_to_le32(UBIFS_FLG_SPACE_FIXUP); - - return write_node(&sup, UBIFS_SB_NODE_SZ, UBIFS_SB_LNUM); -} - -/** - * write_master - write the master node. - */ -static int write_master(void) -{ - struct ubifs_mst_node mst; - int err; - - memset(&mst, 0, UBIFS_MST_NODE_SZ); - - mst.ch.node_type = UBIFS_MST_NODE; - mst.log_lnum = cpu_to_le32(UBIFS_LOG_LNUM); - mst.highest_inum = cpu_to_le64(c->highest_inum); - mst.cmt_no = cpu_to_le64(0); - mst.flags = cpu_to_le32(UBIFS_MST_NO_ORPHS); - mst.root_lnum = cpu_to_le32(c->zroot.lnum); - mst.root_offs = cpu_to_le32(c->zroot.offs); - mst.root_len = cpu_to_le32(c->zroot.len); - mst.gc_lnum = cpu_to_le32(c->gc_lnum); - mst.ihead_lnum = cpu_to_le32(c->ihead_lnum); - mst.ihead_offs = cpu_to_le32(c->ihead_offs); - mst.index_size = cpu_to_le64(c->old_idx_sz); - mst.lpt_lnum = cpu_to_le32(c->lpt_lnum); - mst.lpt_offs = cpu_to_le32(c->lpt_offs); - mst.nhead_lnum = cpu_to_le32(c->nhead_lnum); - mst.nhead_offs = cpu_to_le32(c->nhead_offs); - mst.ltab_lnum = cpu_to_le32(c->ltab_lnum); - mst.ltab_offs = cpu_to_le32(c->ltab_offs); - mst.lsave_lnum = cpu_to_le32(c->lsave_lnum); - mst.lsave_offs = cpu_to_le32(c->lsave_offs); - mst.lscan_lnum = cpu_to_le32(c->lscan_lnum); - mst.empty_lebs = cpu_to_le32(c->lst.empty_lebs); - mst.idx_lebs = cpu_to_le32(c->lst.idx_lebs); - mst.total_free = cpu_to_le64(c->lst.total_free); - mst.total_dirty = cpu_to_le64(c->lst.total_dirty); - mst.total_used = cpu_to_le64(c->lst.total_used); - mst.total_dead = cpu_to_le64(c->lst.total_dead); - mst.total_dark = cpu_to_le64(c->lst.total_dark); - mst.leb_cnt = cpu_to_le32(c->leb_cnt); - - err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM); - if (err) - return err; - - err = write_node(&mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1); - if (err) - return err; - - return 0; -} - -/** - * write_log - write an empty log. - */ -static int write_log(void) -{ - struct ubifs_cs_node cs; - int err, i, lnum; - - lnum = UBIFS_LOG_LNUM; - - cs.ch.node_type = UBIFS_CS_NODE; - cs.cmt_no = cpu_to_le64(0); - - err = write_node(&cs, UBIFS_CS_NODE_SZ, lnum); - if (err) - return err; - - lnum += 1; - - for (i = 1; i < c->log_lebs; i++, lnum++) { - err = write_empty_leb(lnum); - if (err) - return err; - } - - return 0; -} - -/** - * write_lpt - write the LEB properties tree. - */ -static int write_lpt(void) -{ - int err, lnum; - - err = create_lpt(c); - if (err) - return err; - - lnum = c->nhead_lnum + 1; - while (lnum <= c->lpt_last) { - err = write_empty_leb(lnum++); - if (err) - return err; - } - - return 0; -} - -/** - * write_orphan_area - write an empty orphan area. - */ -static int write_orphan_area(void) -{ - int err, i, lnum; - - lnum = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs; - for (i = 0; i < c->orph_lebs; i++, lnum++) { - err = write_empty_leb(lnum); - if (err) - return err; - } - return 0; -} - -/** - * check_volume_empty - check if the UBI volume is empty. - * - * This function checks if the UBI volume is empty by looking if its LEBs are - * mapped or not. - * - * Returns %0 in case of success, %1 is the volume is not empty, - * and a negative error code in case of failure. - */ -static int check_volume_empty(void) -{ - int lnum, err; - - for (lnum = 0; lnum < c->vi.rsvd_lebs; lnum++) { - err = ubi_is_mapped(out_fd, lnum); - if (err < 0) - return err; - if (err == 1) - return 1; - } - return 0; -} - -/** - * open_target - open the output target. - * - * Open the output target. The target can be an UBI volume - * or a file. - * - * Returns %0 in case of success and %-1 in case of failure. - */ -static int open_target(void) -{ - if (out_ubi) { - out_fd = open(output, O_RDWR | O_EXCL); - - if (out_fd == -1) - return sys_err_msg("cannot open the UBI volume '%s'", - output); - if (ubi_set_property(out_fd, UBI_VOL_PROP_DIRECT_WRITE, 1)) - return sys_err_msg("ubi_set_property failed"); - - if (!yes && check_volume_empty()) { - if (!prompt("UBI volume is not empty. Format anyways?", false)) - return err_msg("UBI volume is not empty"); - } - } else { - out_fd = open(output, O_CREAT | O_RDWR | O_TRUNC, - S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH); - if (out_fd == -1) - return sys_err_msg("cannot create output file '%s'", - output); - } - return 0; -} - - -/** - * close_target - close the output target. - * - * Close the output target. If the target was an UBI - * volume, also close libubi. - * - * Returns %0 in case of success and %-1 in case of failure. - */ -static int close_target(void) -{ - if (ubi) - libubi_close(ubi); - if (out_fd >= 0 && close(out_fd) == -1) - return sys_err_msg("cannot close the target '%s'", output); - if (output) - free(output); - return 0; -} - -/** - * init - initialize things. - */ -static int init(void) -{ - int err, i, main_lebs, big_lpt = 0, sz; - - c->highest_inum = UBIFS_FIRST_INO; - - c->jhead_cnt = 1; - - main_lebs = c->max_leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS; - main_lebs -= c->log_lebs + c->orph_lebs; - - err = calc_dflt_lpt_geom(c, &main_lebs, &big_lpt); - if (err) - return err; - - c->main_first = UBIFS_LOG_LNUM + c->log_lebs + c->lpt_lebs + - c->orph_lebs; - head_lnum = c->main_first; - head_offs = 0; - - c->lpt_first = UBIFS_LOG_LNUM + c->log_lebs; - c->lpt_last = c->lpt_first + c->lpt_lebs - 1; - - c->lpt = malloc(c->main_lebs * sizeof(struct ubifs_lprops)); - if (!c->lpt) - return err_msg("unable to allocate LPT"); - - c->ltab = malloc(c->lpt_lebs * sizeof(struct ubifs_lprops)); - if (!c->ltab) - return err_msg("unable to allocate LPT ltab"); - - /* Initialize LPT's own lprops */ - for (i = 0; i < c->lpt_lebs; i++) { - c->ltab[i].free = c->leb_size; - c->ltab[i].dirty = 0; - } - - c->dead_wm = ALIGN(MIN_WRITE_SZ, c->min_io_size); - c->dark_wm = ALIGN(UBIFS_MAX_NODE_SZ, c->min_io_size); - dbg_msg(1, "dead_wm %d dark_wm %d", c->dead_wm, c->dark_wm); - - leb_buf = malloc(c->leb_size); - if (!leb_buf) - return err_msg("out of memory"); - - node_buf = malloc(NODE_BUFFER_SIZE); - if (!node_buf) - return err_msg("out of memory"); - - block_buf = malloc(UBIFS_BLOCK_SIZE); - if (!block_buf) - return err_msg("out of memory"); - - sz = sizeof(struct inum_mapping *) * HASH_TABLE_SIZE; - hash_table = malloc(sz); - if (!hash_table) - return err_msg("out of memory"); - memset(hash_table, 0, sz); - - err = init_compression(); - if (err) - return err; - - return 0; -} - -static void destroy_hash_table(void) -{ - int i; - - for (i = 0; i < HASH_TABLE_SIZE; i++) { - struct inum_mapping *im, *q; - - for (im = hash_table[i]; im; ) { - q = im; - im = im->next; - free(q->path_name); - free(q); - } - } -} - -/** - * deinit - deinitialize things. - */ -static void deinit(void) -{ - free(c->lpt); - free(c->ltab); - free(leb_buf); - free(node_buf); - free(block_buf); - destroy_hash_table(); - free(hash_table); - destroy_compression(); - free_devtable_info(); -} - -/** - * mkfs - make the file system. - * - * Each on-flash area has a corresponding function to create it. The order of - * the functions reflects what information must be known to complete each stage. - * As a consequence the output file is not written sequentially. No effort has - * been made to make efficient use of memory or to allow for the possibility of - * incremental updates to the output file. - */ -static int mkfs(void) -{ - int err = 0; - - err = init(); - if (err) - goto out; - - err = write_data(); - if (err) - goto out; - - err = set_gc_lnum(); - if (err) - goto out; - - err = write_index(); - if (err) - goto out; - - err = finalize_leb_cnt(); - if (err) - goto out; - - err = write_lpt(); - if (err) - goto out; - - err = write_super(); - if (err) - goto out; - - err = write_master(); - if (err) - goto out; - - err = write_log(); - if (err) - goto out; - - err = write_orphan_area(); - -out: - deinit(); - return err; -} - -int main(int argc, char *argv[]) -{ - int err; - - err = get_options(argc, argv); - if (err) - return err; - - err = open_target(); - if (err) - return err; - - err = mkfs(); - if (err) { - close_target(); - return err; - } - - err = close_target(); - if (err) - return err; - - if (verbose) - printf("Success!\n"); - - return 0; -} |