1  /*
       2   * mkcramfs - make a cramfs file system
       3   *
       4   * Copyright (C) 1999-2002 Transmeta Corporation
       5   *
       6   * This program is free software; you can redistribute it and/or modify
       7   * it under the terms of the GNU General Public License as published by
       8   * the Free Software Foundation; either version 2 of the License, or
       9   * (at your option) any later version.
      10   *
      11   * This program is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14   * GNU General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU General Public License along
      17   * with this program; if not, write to the Free Software Foundation, Inc.,
      18   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19   */
      20  
      21  /*
      22   * Old version would die on largish filesystems. Change to mmap the
      23   * files one by one instead of all simultaneously. - aeb, 2002-11-01
      24   */
      25  
      26  #include <sys/types.h>
      27  #include <stdio.h>
      28  #include <sys/stat.h>
      29  #include <unistd.h>
      30  #include <sys/mman.h>
      31  #include <fcntl.h>
      32  #include <dirent.h>
      33  #include <stddef.h>
      34  #include <stdlib.h>
      35  #include <errno.h>
      36  #include <string.h>
      37  #include <getopt.h>
      38  #include <zconf.h>
      39  
      40  /* We don't use our include/crc32.h, but crc32 from zlib!
      41   *
      42   * The zlib implementation performs pre/post-conditioning. The util-linux
      43   * imlemenation requires post-conditioning (xor) in the applications.
      44   */
      45  #include <zlib.h>
      46  
      47  #include "blkdev.h"
      48  #include "c.h"
      49  #include "cramfs.h"
      50  #include "md5.h"
      51  #include "nls.h"
      52  #include "exitcodes.h"
      53  #include "strutils.h"
      54  
      55  #define CLOSE_EXIT_CODE	 MKFS_EX_ERROR
      56  #include "closestream.h"
      57  
      58  #define XALLOC_EXIT_CODE MKFS_EX_ERROR
      59  #include "xalloc.h"
      60  
      61  /* The kernel only supports PAD_SIZE of 0 and 512. */
      62  #define PAD_SIZE 512
      63  
      64  static int verbose = 0;
      65  
      66  static unsigned int blksize = 0; /* settable via -b option, default page size */
      67  static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
      68  static int image_length = 0;
      69  static int cramfs_is_big_endian = 0; /* target is big endian */
      70  
      71  /*
      72   * If opt_holes is set, then mkcramfs can create explicit holes in the
      73   * data, which saves 26 bytes per hole (which is a lot smaller a
      74   * saving than for most filesystems).
      75   *
      76   * Note that kernels up to at least 2.3.39 don't support cramfs holes,
      77   * which is why this is turned off by default.
      78   */
      79  static unsigned int opt_edition = 0;
      80  static int opt_errors = 0;
      81  static int opt_holes = 0;
      82  static int opt_pad = 0;
      83  static char *opt_image = NULL;
      84  static char *opt_name = NULL;
      85  
      86  static int warn_dev = 0;
      87  static int warn_gid = 0;
      88  static int warn_namelen = 0;
      89  static int warn_skip = 0;
      90  static int warn_size = 0;
      91  static int warn_uid = 0;
      92  
      93  /* entry.flags */
      94  #define CRAMFS_EFLAG_MD5	1
      95  #define CRAMFS_EFLAG_INVALID	2
      96  
      97  /* In-core version of inode / directory entry. */
      98  struct entry {
      99  	/* stats */
     100  	unsigned char *name;
     101  	unsigned int mode, size, uid, gid;
     102  	unsigned char md5sum[UL_MD5LENGTH];
     103  	unsigned char flags;	   /* CRAMFS_EFLAG_* */
     104  
     105  	/* FS data */
     106  	char *path;
     107  	int fd;			    /* temporarily open files while mmapped */
     108  	struct entry *same;	    /* points to other identical file */
     109  	unsigned int offset;        /* pointer to compressed data in archive */
     110  	unsigned int dir_offset;    /* offset of directory entry in archive */
     111  
     112  	/* organization */
     113  	struct entry *child;	    /* NULL for non-directory and empty dir */
     114  	struct entry *next;
     115  };
     116  
     117  /*
     118   * Width of various bitfields in struct cramfs_inode.
     119   * Used only to generate warnings.
     120   */
     121  #define CRAMFS_SIZE_WIDTH 24
     122  #define CRAMFS_UID_WIDTH 16
     123  #define CRAMFS_GID_WIDTH 8
     124  #define CRAMFS_OFFSET_WIDTH 26
     125  
     126  static void __attribute__((__noreturn__)) usage(void)
     127  {
     128  	fputs(USAGE_HEADER, stdout);
     129  	printf(_(" %s [-h] [-v] [-b blksize] [-e edition] [-N endian] [-i file] [-n name] dirname outfile\n"),
     130  		program_invocation_short_name);
     131  	fputs(USAGE_SEPARATOR, stdout);
     132  	puts(_("Make compressed ROM file system."));
     133  	fputs(USAGE_OPTIONS, stdout);
     134  	puts(_(  " -v             be verbose"));
     135  	puts(_(  " -E             make all warnings errors (non-zero exit status)"));
     136  	puts(_(  " -b blksize     use this blocksize, must equal page size"));
     137  	puts(_(  " -e edition     set edition number (part of fsid)"));
     138  	printf(_(" -N endian      set cramfs endianness (%s|%s|%s), default %s\n"), "big", "little", "host", "host");
     139  	puts(_(  " -i file        insert a file image into the filesystem"));
     140  	puts(_(  " -n name        set name of cramfs filesystem"));
     141  	printf(_(" -p             pad by %d bytes for boot code\n"), PAD_SIZE);
     142  	puts(_(  " -s             sort directory entries (old option, ignored)"));
     143  	puts(_(  " -z             make explicit holes"));
     144  	puts(_(  " -l[=<mode>]    use exclusive device lock (yes, no or nonblock)"));
     145  	puts(_(  " dirname        root of the filesystem to be compressed"));
     146  	puts(_(  " outfile        output file"));
     147  	fputs(USAGE_SEPARATOR, stdout);
     148  	printf(USAGE_HELP_OPTIONS(16));
     149  	printf(USAGE_MAN_TAIL("mkfs.cramfs(8)"));
     150  	exit(MKFS_EX_OK);
     151  }
     152  
     153  static char *
     154  do_mmap(char *path, unsigned int size, unsigned int mode){
     155  	int fd;
     156  	char *start = NULL;
     157  
     158  	if (!size)
     159  		return NULL;
     160  
     161  	if (S_ISLNK(mode)) {
     162  		/* The link buffer is unnecessary to terminate by null as it's
     163  		 * always used as buffer rather than a string */
     164  		start = xmalloc(size);
     165  		if (readlink(path, start, size) < 0) {
     166  			warn(_("readlink failed: %s"), path);
     167  			warn_skip = 1;
     168  			goto err;
     169  		}
     170  		return start;
     171  	}
     172  
     173  	fd = open(path, O_RDONLY);
     174  	if (fd < 0) {
     175  		warn(_("cannot open %s"), path);
     176  		warn_skip = 1;
     177  		goto err;
     178  	}
     179  
     180  	start = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
     181  	close(fd);
     182  	if (start == MAP_FAILED)
     183  		err(MKFS_EX_ERROR, "mmap");
     184  	return start;
     185  err:
     186  	free(start);
     187  	return NULL;
     188  }
     189  
     190  static void
     191  do_munmap(char *start, unsigned int size, unsigned int mode){
     192  	if (S_ISLNK(mode))
     193  		free(start);
     194  	else
     195  		munmap(start, size);
     196  }
     197  
     198  /* compute md5sums, so that we do not have to compare every pair of files */
     199  static void
     200  mdfile(struct entry *e) {
     201  	char *start;
     202  
     203  	start = do_mmap(e->path, e->size, e->mode);
     204  	if (start == NULL) {
     205  		e->flags |= CRAMFS_EFLAG_INVALID;
     206  	} else {
     207  		UL_MD5_CTX ctx;
     208  
     209  		ul_MD5Init(&ctx);
     210  		ul_MD5Update(&ctx, (unsigned char *) start, e->size);
     211  		ul_MD5Final(e->md5sum, &ctx);
     212  
     213  		do_munmap(start, e->size, e->mode);
     214  
     215  		e->flags |= CRAMFS_EFLAG_MD5;
     216  	}
     217  }
     218  
     219  /* md5 digests are equal; files are almost certainly the same,
     220     but just to be sure, do the comparison */
     221  static int
     222  identical_file(struct entry *e1, struct entry *e2){
     223  	char *start1, *start2;
     224  	int equal;
     225  
     226  	start1 = do_mmap(e1->path, e1->size, e1->mode);
     227  	if (!start1)
     228  		return 0;
     229  	start2 = do_mmap(e2->path, e2->size, e2->mode);
     230  	if (!start2) {
     231  		do_munmap(start1, e1->size, e1->mode);
     232  		return 0;
     233  	}
     234  	equal = !memcmp(start1, start2, e1->size);
     235  	do_munmap(start1, e1->size, e1->mode);
     236  	do_munmap(start2, e2->size, e2->mode);
     237  	return equal;
     238  }
     239  
     240  /*
     241   * The longest file name component to allow for in the input directory tree.
     242   * Ext2fs (and many others) allow up to 255 bytes.  A couple of filesystems
     243   * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
     244   * >255-byte names in the input directory tree given that such names get
     245   * truncated to 255 bytes when written to cramfs.
     246   */
     247  #define MAX_INPUT_NAMELEN 255
     248  
     249  static int find_identical_file(struct entry *orig, struct entry *new, loff_t *fslen_ub)
     250  {
     251  	if (orig == new)
     252  		return 1;
     253  	if (!orig)
     254  		return 0;
     255  	if (orig->size == new->size && orig->path) {
     256  		if (!orig->flags)
     257  			mdfile(orig);
     258  		if (!new->flags)
     259  			mdfile(new);
     260  
     261  		if ((orig->flags & CRAMFS_EFLAG_MD5) &&
     262  		    (new->flags & CRAMFS_EFLAG_MD5) &&
     263  		    !memcmp(orig->md5sum, new->md5sum, UL_MD5LENGTH) &&
     264  		    identical_file(orig, new)) {
     265  			new->same = orig;
     266  			*fslen_ub -= new->size;
     267  			return 1;
     268  		}
     269  	}
     270  	return find_identical_file(orig->child, new, fslen_ub) ||
     271  		   find_identical_file(orig->next, new, fslen_ub);
     272  }
     273  
     274  static void eliminate_doubles(struct entry *root, struct entry *orig, loff_t *fslen_ub) {
     275  	if (orig) {
     276  		if (orig->size && orig->path)
     277  			find_identical_file(root,orig, fslen_ub);
     278  		eliminate_doubles(root,orig->child, fslen_ub);
     279  		eliminate_doubles(root,orig->next, fslen_ub);
     280  	}
     281  }
     282  
     283  /*
     284   * We define our own sorting function instead of using alphasort which
     285   * uses strcoll and changes ordering based on locale information.
     286   */
     287  static int cramsort (const struct dirent **a, const struct dirent **b)
     288  {
     289  	return strcmp((*a)->d_name, (*b)->d_name);
     290  }
     291  
     292  static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub)
     293  {
     294  	struct dirent **dirlist;
     295  	int totalsize = 0, dircount, dirindex;
     296  	char *path, *endpath;
     297  	size_t len = strlen(name);
     298  
     299  	/* Set up the path. */
     300  	/* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
     301  	path = xmalloc(len + 1 + MAX_INPUT_NAMELEN + 1);
     302  	memcpy(path, name, len);
     303  	endpath = path + len;
     304  	*endpath = '/';
     305  	endpath++;
     306  
     307  	/* read in the directory and sort */
     308  	dircount = scandir(name, &dirlist, NULL, cramsort);
     309  
     310  	if (dircount < 0)
     311  		err(MKFS_EX_ERROR, _("could not read directory %s"), name);
     312  
     313  	/* process directory */
     314  	for (dirindex = 0; dirindex < dircount; dirindex++) {
     315  		struct dirent *dirent;
     316  		struct entry *entry;
     317  		struct stat st;
     318  		int size;
     319  		size_t namelen;
     320  
     321  		dirent = dirlist[dirindex];
     322  
     323  		/* Ignore "." and ".." - we won't be adding them
     324  		   to the archive */
     325  		if (dirent->d_name[0] == '.') {
     326  			if (dirent->d_name[1] == '\0')
     327  				continue;
     328  			if (dirent->d_name[1] == '.' &&
     329  			    dirent->d_name[2] == '\0')
     330  				continue;
     331  		}
     332  		namelen = strlen(dirent->d_name);
     333  		if (namelen > MAX_INPUT_NAMELEN) {
     334  			namelen = MAX_INPUT_NAMELEN;
     335  			warn_namelen = 1;
     336  		}
     337  
     338  		memcpy(endpath, dirent->d_name, namelen + 1);
     339  
     340  		if (lstat(path, &st) < 0) {
     341  			warn(_("stat of %s failed"), endpath);
     342  			warn_skip = 1;
     343  			continue;
     344  		}
     345  		entry = xcalloc(1, sizeof(struct entry));
     346  		entry->name = (unsigned char *)xstrndup(dirent->d_name, namelen);
     347  		entry->mode = st.st_mode;
     348  		entry->size = st.st_size;
     349  		entry->uid = st.st_uid;
     350  		if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
     351  			warn_uid = 1;
     352  		entry->gid = st.st_gid;
     353  		if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
     354  			/* TODO: We ought to replace with a default
     355  			   gid instead of truncating; otherwise there
     356  			   are security problems.  Maybe mode should
     357  			   be &= ~070.  Same goes for uid once Linux
     358  			   supports >16-bit uids. */
     359  			warn_gid = 1;
     360  		size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
     361  		*fslen_ub += size;
     362  		if (S_ISDIR(st.st_mode)) {
     363  			entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
     364  		} else if (S_ISREG(st.st_mode)) {
     365  			entry->path = xstrdup(path);
     366  			if (entry->size >= (1 << CRAMFS_SIZE_WIDTH)) {
     367  				warn_size = 1;
     368  				entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
     369  			}
     370  		} else if (S_ISLNK(st.st_mode)) {
     371  			entry->path = xstrdup(path);
     372  		} else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
     373  			/* maybe we should skip sockets */
     374  			entry->size = 0;
     375  		} else {
     376  			entry->size = st.st_rdev;
     377  			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
     378  				warn_dev = 1;
     379  		}
     380  
     381  		if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
     382  			int blocks = ((entry->size - 1) / blksize + 1);
     383  
     384  			/* block pointers & data expansion allowance + data */
     385  			if (entry->size)
     386  				*fslen_ub += (4+26)*blocks + entry->size + 3;
     387  		}
     388  
     389  		/* Link it into the list */
     390  		*prev = entry;
     391  		prev = &entry->next;
     392  		totalsize += size;
     393  	}
     394  	free(path);
     395  	free(dirlist);		/* allocated by scandir() with malloc() */
     396  	return totalsize;
     397  }
     398  
     399  /* Returns sizeof(struct cramfs_super), which includes the root inode. */
     400  static unsigned int write_superblock(struct entry *root, char *base, int size)
     401  {
     402  	struct cramfs_super *super = (struct cramfs_super *) base;
     403  	unsigned int offset = sizeof(struct cramfs_super) + image_length;
     404  
     405  	if (opt_pad) {
     406  		offset += opt_pad;
     407  	}
     408  
     409  	super->magic = CRAMFS_MAGIC;
     410  	super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
     411  	if (opt_holes)
     412  		super->flags |= CRAMFS_FLAG_HOLES;
     413  	if (image_length > 0)
     414  		super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET;
     415  	super->size = size;
     416  	memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
     417  
     418  	super->fsid.crc = crc32(0L, NULL, 0);
     419  	super->fsid.edition = opt_edition;
     420  	super->fsid.blocks = total_blocks;
     421  	super->fsid.files = total_nodes;
     422  
     423  	memset(super->name, 0x00, sizeof(super->name));
     424  	if (opt_name)
     425  		str2memcpy((char *)super->name, opt_name, sizeof(super->name));
     426  	else
     427  		str2memcpy((char *)super->name, "Compressed", sizeof(super->name));
     428  
     429  	super->root.mode = root->mode;
     430  	super->root.uid = root->uid;
     431  	super->root.gid = root->gid;
     432  	super->root.size = root->size;
     433  	super->root.offset = offset >> 2;
     434  
     435  	super_toggle_endianness(cramfs_is_big_endian, super);
     436  	inode_from_host(cramfs_is_big_endian, &super->root, &super->root);
     437  
     438  	return offset;
     439  }
     440  
     441  static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
     442  {
     443  	struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
     444  	inode_to_host(cramfs_is_big_endian, inode, inode);
     445  	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH)))
     446  		errx(MKFS_EX_ERROR, _("filesystem too big.  Exiting."));
     447  	inode->offset = (offset >> 2);
     448  	inode_from_host(cramfs_is_big_endian, inode, inode);
     449  }
     450  
     451  
     452  /*
     453   * We do a width-first printout of the directory
     454   * entries, using a stack to remember the directories
     455   * we've seen.
     456   */
     457  static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
     458  {
     459  	int stack_entries = 0;
     460  	int stack_size = 64;
     461  	struct entry **entry_stack;
     462  
     463  	entry_stack = xmalloc(stack_size * sizeof(struct entry *));
     464  
     465  	for (;;) {
     466  		int dir_start = stack_entries;
     467  		while (entry) {
     468  			struct cramfs_inode *inode =
     469  				(struct cramfs_inode *) (base + offset);
     470  			size_t len = strlen((const char *)entry->name);
     471  
     472  			entry->dir_offset = offset;
     473  
     474  			inode->mode = entry->mode;
     475  			inode->uid = entry->uid;
     476  			inode->gid = entry->gid;
     477  			inode->size = entry->size;
     478  			inode->offset = 0;
     479  			/* Non-empty directories, regfiles and symlinks will
     480  			   write over inode->offset later. */
     481  
     482  			offset += sizeof(struct cramfs_inode);
     483  			total_nodes++;	/* another node */
     484  			memcpy(base + offset, entry->name, len);
     485  			/* Pad up the name to a 4-byte boundary */
     486  			while (len & 3) {
     487  				*(base + offset + len) = '\0';
     488  				len++;
     489  			}
     490  			inode->namelen = len >> 2;
     491  			offset += len;
     492  
     493  			if (verbose)
     494  				printf("  %s\n", entry->name);
     495  			if (entry->child) {
     496  				if (stack_entries >= stack_size) {
     497  					stack_size *= 2;
     498  					entry_stack = xrealloc(entry_stack, stack_size * sizeof(struct entry *));
     499  				}
     500  				entry_stack[stack_entries] = entry;
     501  				stack_entries++;
     502  			}
     503  			inode_from_host(cramfs_is_big_endian, inode, inode);
     504  			entry = entry->next;
     505  		}
     506  
     507  		/*
     508  		 * Reverse the order the stack entries pushed during
     509  		 * this directory, for a small optimization of disk
     510  		 * access in the created fs.  This change makes things
     511  		 * `ls -UR' order.
     512  		 */
     513  		{
     514  			struct entry **lo = entry_stack + dir_start;
     515  			struct entry **hi = entry_stack + stack_entries;
     516  			struct entry *tmp;
     517  
     518  			while (lo < --hi) {
     519  				tmp = *lo;
     520  				*lo++ = *hi;
     521  				*hi = tmp;
     522  			}
     523  		}
     524  
     525  		/* Pop a subdirectory entry from the stack, and recurse. */
     526  		if (!stack_entries)
     527  			break;
     528  		stack_entries--;
     529  		entry = entry_stack[stack_entries];
     530  
     531  		set_data_offset(entry, base, offset);
     532  		if (verbose)
     533  			printf("'%s':\n", entry->name);
     534  		entry = entry->child;
     535  	}
     536  	free(entry_stack);
     537  	return offset;
     538  }
     539  
     540  static int is_zero(unsigned char const *begin, unsigned len)
     541  {
     542  	if (opt_holes)
     543  		/* Returns non-zero iff the first LEN bytes from BEGIN are
     544  		   all NULs. */
     545  		return (len-- == 0 ||
     546  			(begin[0] == '\0' &&
     547  			 (len-- == 0 ||
     548  			  (begin[1] == '\0' &&
     549  			   (len-- == 0 ||
     550  			    (begin[2] == '\0' &&
     551  			     (len-- == 0 ||
     552  			      (begin[3] == '\0' &&
     553  			       memcmp(begin, begin + 4, len) == 0))))))));
     554  
     555  	/* Never create holes. */
     556  	return 0;
     557  }
     558  
     559  /*
     560   * One 4-byte pointer per block and then the actual blocked
     561   * output. The first block does not need an offset pointer,
     562   * as it will start immediately after the pointer block;
     563   * so the i'th pointer points to the end of the i'th block
     564   * (i.e. the start of the (i+1)'th block or past EOF).
     565   *
     566   * Note that size > 0, as a zero-sized file wouldn't ever
     567   * have gotten here in the first place.
     568   */
     569  static unsigned int
     570  do_compress(char *base, unsigned int offset, unsigned char const *name,
     571  	    char *path, unsigned int size, unsigned int mode)
     572  {
     573  	unsigned long original_size, original_offset, new_size, blocks, curr;
     574  	long change;
     575  	char *start;
     576  	Bytef *p;
     577  
     578  	/* get uncompressed data */
     579  	start = do_mmap(path, size, mode);
     580  	if (start == NULL)
     581  		return offset;
     582  	p = (Bytef *) start;
     583  
     584  	original_size = size;
     585  	original_offset = offset;
     586  	blocks = (size - 1) / blksize + 1;
     587  	curr = offset + 4 * blocks;
     588  
     589  	total_blocks += blocks;
     590  
     591  	do {
     592  		uLongf len = 2 * blksize;
     593  		uLongf input = size;
     594  		if (input > blksize)
     595  			input = blksize;
     596  		size -= input;
     597  		if (!is_zero (p, input)) {
     598  			compress((Bytef *)(base + curr), &len, p, input);
     599  			curr += len;
     600  		}
     601  		p += input;
     602  
     603  		if (len > blksize*2) {
     604  			/* (I don't think this can happen with zlib.) */
     605  			printf(_("AIEEE: block \"compressed\" to > "
     606  				 "2*blocklength (%ld)\n"),
     607  			       len);
     608  			exit(MKFS_EX_ERROR);
     609  		}
     610  
     611  		*(uint32_t *) (base + offset) = u32_toggle_endianness(cramfs_is_big_endian, curr);
     612  		offset += 4;
     613  	} while (size);
     614  
     615  	do_munmap(start, original_size, mode);
     616  
     617  	curr = (curr + 3) & ~3;
     618  	new_size = curr - original_offset;
     619  	/* TODO: Arguably, original_size in these 2 lines should be
     620  	   st_blocks * 512.  But if you say that, then perhaps
     621  	   administrative data should also be included in both. */
     622  	change = new_size - original_size;
     623  	if (verbose)
     624  		printf(_("%6.2f%% (%+ld bytes)\t%s\n"),
     625  		       (change * 100) / (double) original_size, change, name);
     626  
     627  	return curr;
     628  }
     629  
     630  
     631  /*
     632   * Traverse the entry tree, writing data for every item that has
     633   * non-null entry->path (i.e. every symlink and non-empty
     634   * regfile).
     635   */
     636  static unsigned int
     637  write_data(struct entry *entry, char *base, unsigned int offset) {
     638  	struct entry *e;
     639  
     640  	for (e = entry; e; e = e->next) {
     641  		if (e->path) {
     642  			if (e->same) {
     643  				set_data_offset(e, base, e->same->offset);
     644  				e->offset = e->same->offset;
     645  			} else if (e->size) {
     646  				set_data_offset(e, base, offset);
     647  				e->offset = offset;
     648  				offset = do_compress(base, offset, e->name,
     649  						     e->path, e->size,e->mode);
     650  			}
     651  		} else if (e->child)
     652  			offset = write_data(e->child, base, offset);
     653  	}
     654  	return offset;
     655  }
     656  
     657  static unsigned int write_file(char *file, char *base, unsigned int offset)
     658  {
     659  	int fd;
     660  	char *buf;
     661  
     662  	fd = open(file, O_RDONLY);
     663  	if (fd < 0)
     664  		err(MKFS_EX_ERROR, _("cannot open %s"), file);
     665  	buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
     666  	memcpy(base + offset, buf, image_length);
     667  	munmap(buf, image_length);
     668  	if (close (fd) < 0)
     669  		err(MKFS_EX_ERROR, _("cannot close file %s"), file);
     670  	/* Pad up the image_length to a 4-byte boundary */
     671  	while (image_length & 3) {
     672  		*(base + offset + image_length) = '\0';
     673  		image_length++;
     674  	}
     675  	return (offset + image_length);
     676  }
     677  
     678  /*
     679   * Maximum size fs you can create is roughly 256MB.  (The last file's
     680   * data must begin within 256MB boundary but can extend beyond that.)
     681   *
     682   * Note that if you want it to fit in a ROM then you're limited to what the
     683   * hardware and kernel can support (64MB?).
     684   */
     685  static unsigned int
     686  maxfslen(void) {
     687  	return (((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2)    /* offset */
     688  		+ (1 << CRAMFS_SIZE_WIDTH) - 1            /* filesize */
     689  		+ (1 << CRAMFS_SIZE_WIDTH) * 4 / blksize; /* block pointers */
     690  }
     691  
     692  /*
     693   * Usage:
     694   *
     695   *      mkcramfs directory-name outfile
     696   *
     697   * where "directory-name" is simply the root of the directory
     698   * tree that we want to generate a compressed filesystem out
     699   * of.
     700   */
     701  int main(int argc, char **argv)
     702  {
     703  	struct stat st;		/* used twice... */
     704  	struct entry *root_entry;
     705  	char *rom_image;
     706  	ssize_t offset, written;
     707  	int fd;
     708  	/* initial guess (upper-bound) of required filesystem size */
     709  	loff_t fslen_ub = sizeof(struct cramfs_super);
     710  	unsigned int fslen_max;
     711  	char const *dirname, *outfile;
     712  	char *lockmode = 0;
     713  	uint32_t crc = crc32(0L, NULL, 0);
     714  	int c;
     715  	cramfs_is_big_endian = HOST_IS_BIG_ENDIAN; /* default is to use host order */
     716  
     717  	total_blocks = 0;
     718  
     719  	setlocale(LC_ALL, "");
     720  	bindtextdomain(PACKAGE, LOCALEDIR);
     721  	textdomain(PACKAGE);
     722  	close_stdout_atexit();
     723  
     724  	if (argc > 1) {
     725  		/* first arg may be one of our standard longopts */
     726  		if (!strcmp(argv[1], "--help"))
     727  			usage();
     728  		if (!strcmp(argv[1], "--version")) {
     729  			print_version(EXIT_SUCCESS);
     730  			exit(MKFS_EX_OK);
     731  		}
     732  	}
     733  	strutils_set_exitcode(MKFS_EX_USAGE);
     734  
     735  	/* command line options */
     736  	while ((c = getopt(argc, argv, "hb:Ee:i:n:N:l::psVvz")) != EOF) {
     737  		switch (c) {
     738  		case 'h':
     739  			usage();
     740  		case 'b':
     741  			blksize = strtou32_or_err(optarg, _("invalid blocksize argument"));
     742  			break;
     743  		case 'E':
     744  			opt_errors = 1;
     745  			break;
     746  		case 'e':
     747  			opt_edition = strtou32_or_err(optarg, _("invalid edition number argument"));
     748  			break;
     749  		case 'N':
     750  			if (strcmp(optarg, "big") == 0)
     751  				cramfs_is_big_endian = 1;
     752  			else if (strcmp(optarg, "little") == 0)
     753  				cramfs_is_big_endian = 0;
     754  			else if (strcmp(optarg, "host") == 0)
     755  				/* default */ ;
     756  			else
     757  				errx(MKFS_EX_USAGE, _("invalid endianness given;"
     758  						   " must be 'big', 'little', or 'host'"));
     759  			break;
     760  		case 'i':
     761  			opt_image = optarg;
     762  			if (lstat(opt_image, &st) < 0)
     763  				err(MKFS_EX_USAGE, _("stat of %s failed"), opt_image);
     764  			image_length = st.st_size; /* may be padded later */
     765  			fslen_ub += (image_length + 3); /* 3 is for padding */
     766  			break;
     767  		case 'l':
     768                          lockmode = "1";
     769  			if (optarg) {
     770                                  if (*optarg == '=')
     771  					optarg++;
     772  				lockmode = optarg;
     773  			}
     774  			break;
     775  		case 'n':
     776  			opt_name = optarg;
     777  			break;
     778  		case 'p':
     779  			opt_pad = PAD_SIZE;
     780  			fslen_ub += PAD_SIZE;
     781  			break;
     782  		case 's':
     783  			/* old option, ignored */
     784  			break;
     785  		case 'V':
     786  			print_version(MKFS_EX_OK);
     787  		case 'v':
     788  			verbose = 1;
     789  			break;
     790  		case 'z':
     791  			opt_holes = 1;
     792  			break;
     793  		default:
     794  			errtryhelp(MKFS_EX_USAGE);
     795  		}
     796  	}
     797  
     798  	if ((argc - optind) != 2) {
     799  		warnx(_("bad usage"));
     800  		errtryhelp(MKFS_EX_USAGE);
     801  	}
     802  	dirname = argv[optind];
     803  	outfile = argv[optind + 1];
     804  
     805  	if (blksize == 0)
     806  		blksize = getpagesize();
     807  
     808  	if (stat(dirname, &st) < 0)
     809  		err(MKFS_EX_USAGE, _("stat of %s failed"), dirname);
     810  	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
     811  	if (fd < 0)
     812  		err(MKFS_EX_USAGE, _("cannot open %s"), outfile);
     813  
     814          if (blkdev_lock(fd, outfile, lockmode) != 0)
     815  		exit(MKFS_EX_ERROR);
     816  
     817  	root_entry = xcalloc(1, sizeof(struct entry));
     818  	root_entry->mode = st.st_mode;
     819  	root_entry->uid = st.st_uid;
     820  	root_entry->gid = st.st_gid;
     821  
     822  	root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
     823  
     824  	/* find duplicate files */
     825  	eliminate_doubles(root_entry,root_entry, &fslen_ub);
     826  
     827  	/* always allocate a multiple of blksize bytes because that's
     828  	   what we're going to write later on */
     829  	fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
     830  	fslen_max = maxfslen();
     831  
     832  	if (fslen_ub > fslen_max) {
     833  		warnx(	_("warning: guestimate of required size (upper bound) "
     834  			  "is %lldMB, but maximum image size is %uMB.  "
     835  			  "We might die prematurely."),
     836  			(long long)fslen_ub >> 20,
     837  			fslen_max >> 20);
     838  		fslen_ub = fslen_max;
     839  	}
     840  
     841  	/* TODO: Why do we use a private/anonymous mapping here
     842  	   followed by a write below, instead of just a shared mapping
     843  	   and a couple of ftruncate calls?  Is it just to save us
     844  	   having to deal with removing the file afterwards?  If we
     845  	   really need this huge anonymous mapping, we ought to mmap
     846  	   in smaller chunks, so that the user doesn't need nn MB of
     847  	   RAM free.  If the reason is to be able to write to
     848  	   un-mmappable block devices, then we could try shared mmap
     849  	   and revert to anonymous mmap if the shared mmap fails. */
     850  	rom_image = mmap(NULL,
     851  			 fslen_ub?fslen_ub:1,
     852  			 PROT_READ | PROT_WRITE,
     853  			 MAP_PRIVATE | MAP_ANONYMOUS,
     854  			 -1, 0);
     855  
     856  	if (-1 == (int) (long) rom_image)
     857  		err(MKFS_EX_ERROR, _("ROM image map"));
     858  
     859  	/* Skip the first opt_pad bytes for boot loader code */
     860  	offset = opt_pad;
     861  	memset(rom_image, 0x00, opt_pad);
     862  
     863  	/* Skip the superblock and come back to write it later. */
     864  	offset += sizeof(struct cramfs_super);
     865  
     866  	/* Insert a file image. */
     867  	if (opt_image) {
     868  		if (verbose)
     869  			printf(_("Including: %s\n"), opt_image);
     870  		offset = write_file(opt_image, rom_image, offset);
     871  	}
     872  
     873  	offset = write_directory_structure(root_entry->child, rom_image, offset);
     874  	if (verbose)
     875  		printf(_("Directory data: %zd bytes\n"), offset);
     876  
     877  	offset = write_data(root_entry, rom_image, offset);
     878  
     879  	/* We always write a multiple of blksize bytes, so that
     880  	   losetup works. */
     881  	offset = ((offset - 1) | (blksize - 1)) + 1;
     882  	if (verbose)
     883  		printf(_("Everything: %zd kilobytes\n"), offset >> 10);
     884  
     885  	/* Write the superblock now that we can fill in all of the fields. */
     886  	write_superblock(root_entry, rom_image+opt_pad, offset);
     887  	if (verbose)
     888  		printf(_("Super block: %zd bytes\n"),
     889  		       sizeof(struct cramfs_super));
     890  
     891  	/* Put the checksum in. */
     892  	crc = crc32(crc, (unsigned char *) (rom_image+opt_pad), (offset-opt_pad));
     893  	((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = u32_toggle_endianness(cramfs_is_big_endian, crc);
     894  	if (verbose)
     895  		printf(_("CRC: %x\n"), crc);
     896  
     897  	/* Check to make sure we allocated enough space. */
     898  	if (fslen_ub < offset)
     899  		errx(MKFS_EX_ERROR,
     900  			_("not enough space allocated for ROM image "
     901  			  "(%lld allocated, %zu used)"),
     902  			(long long) fslen_ub, offset);
     903  
     904  	written = write(fd, rom_image, offset);
     905  	if (offset != written)
     906  		errx(MKFS_EX_ERROR, _("ROM image write failed (%zd %zd)"),
     907  			written, offset);
     908  	if (close_fd(fd) != 0)
     909  		err(MKFS_EX_ERROR, _("ROM image"));
     910  
     911  	/*
     912  	 * (These warnings used to come at the start, but they scroll off
     913  	 * the screen too quickly.)
     914  	 */
     915  	if (warn_namelen)
     916  		/* Can't happen when reading from ext2fs. */
     917  		/* Bytes, not chars: think UTF8. */
     918  		warnx(_("warning: filenames truncated to %u bytes."), MAX_INPUT_NAMELEN);
     919  	if (warn_skip)
     920  		warnx(_("warning: files were skipped due to errors."));
     921  	if (warn_size)
     922  		warnx(_("warning: file sizes truncated to %luMB "
     923  			"(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH - 20));
     924  	if (warn_uid)
     925  		/* (not possible with current Linux versions) */
     926  		warnx(_("warning: uids truncated to %u bits.  "
     927  			"(This may be a security concern.)"), CRAMFS_UID_WIDTH);
     928  	if (warn_gid)
     929  		warnx(_("warning: gids truncated to %u bits.  "
     930  			"(This may be a security concern.)"), CRAMFS_GID_WIDTH);
     931  	if (warn_dev)
     932  		warnx(_("WARNING: device numbers truncated to %u bits.  "
     933  			"This almost certainly means\n"
     934  			"that some device files will be wrong."),
     935  		      CRAMFS_OFFSET_WIDTH);
     936  	if (opt_errors &&
     937  	    (warn_namelen|warn_skip|warn_size|warn_uid|warn_gid|warn_dev))
     938  		exit(MKFS_EX_ERROR);
     939  
     940  	return MKFS_EX_OK;
     941  }