File: /usr/src/linux/scripts/cramfs/mkcramfs.c

1     /*
2      * mkcramfs - make a cramfs file system
3      *
4      * Copyright (C) 1999-2001 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
17      * along with this program; if not, write to the Free Software
18      * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19      */
20     
21     #include <sys/types.h>
22     #include <stdio.h>
23     #include <sys/stat.h>
24     #include <unistd.h>
25     #include <sys/mman.h>
26     #include <sys/fcntl.h>
27     #include <dirent.h>
28     #include <stdlib.h>
29     #include <errno.h>
30     #include <string.h>
31     #include <assert.h>
32     #include <getopt.h>
33     #include <linux/cramfs_fs.h>
34     #include <zlib.h>
35     
36     #define PAD_SIZE 512		/* only 0 and 512 supported by kernel */
37     
38     static const char *progname = "mkcramfs";
39     
40     /* N.B. If you change the disk format of cramfs, please update fs/cramfs/README. */
41     
42     /* Input status of 0 to print help and exit without an error. */
43     static void usage(int status)
44     {
45     	FILE *stream = status ? stderr : stdout;
46     
47     	fprintf(stream, "usage: %s [-h] [-e edition] [-i file] [-n name] dirname outfile\n"
48     		" -h         print this help\n"
49     		" -E         make all warnings errors (non-zero exit status)\n"
50     		" -e edition set edition number (part of fsid)\n"
51     		" -i file    insert a file image into the filesystem (requires >= 2.4.0)\n"
52     		" -n name    set name of cramfs filesystem\n"
53     		" -p         pad by %d bytes for boot code\n"
54     		" -s         sort directory entries (old option, ignored)\n"
55     		" -z         make explicit holes (requires >= 2.3.39)\n"
56     		" dirname    root of the filesystem to be compressed\n"
57     		" outfile    output file\n", progname, PAD_SIZE);
58     
59     	exit(status);
60     }
61     
62     #define PAGE_CACHE_SIZE (4096)
63     /* The kernel assumes PAGE_CACHE_SIZE as block size. */
64     static unsigned int blksize = PAGE_CACHE_SIZE;
65     static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */
66     static int image_length = 0;
67     
68     /*
69      * If opt_holes is set, then mkcramfs can create explicit holes in the
70      * data, which saves 26 bytes per hole (which is a lot smaller a
71      * saving than most most filesystems).
72      *
73      * Note that kernels up to at least 2.3.39 don't support cramfs holes,
74      * which is why this is turned off by default.
75      */
76     static int opt_edition = 0;
77     static int opt_errors = 0;
78     static int opt_holes = 0;
79     static int opt_pad = 0;
80     static char *opt_image = NULL;
81     static char *opt_name = NULL;
82     
83     static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
84     
85     #ifndef MIN
86     # define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
87     #endif
88     
89     /* In-core version of inode / directory entry. */
90     struct entry {
91     	/* stats */
92     	char *name;
93     	unsigned int mode, size, uid, gid;
94     
95     	/* FS data */
96     	void *uncompressed;
97             /* points to other identical file */
98             struct entry *same;
99             unsigned int offset;            /* pointer to compressed data in archive */
100     	unsigned int dir_offset;	/* Where in the archive is the directory entry? */
101     
102     	/* organization */
103     	struct entry *child; /* null for non-directories and empty directories */
104     	struct entry *next;
105     };
106     
107     /*
108      * The longest file name component to allow for in the input directory tree.
109      * Ext2fs (and many others) allow up to 255 bytes.  A couple of filesystems
110      * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
111      * >255-byte names in the input directory tree given that such names get
112      * truncated to 255 bytes when written to cramfs.
113      */
114     #define MAX_INPUT_NAMELEN 255
115     
116     static int find_identical_file(struct entry *orig,struct entry *newfile)
117     {
118             if(orig==newfile) return 1;
119             if(!orig) return 0;
120             if(orig->size==newfile->size && orig->uncompressed && !memcmp(orig->uncompressed,newfile->uncompressed,orig->size)) {
121                     newfile->same=orig;
122                     return 1;
123             }
124             return find_identical_file(orig->child,newfile) ||
125                        find_identical_file(orig->next,newfile);
126     }
127     
128     static void eliminate_doubles(struct entry *root,struct entry *orig) {
129             if(orig) {
130                     if(orig->size && orig->uncompressed)
131     			find_identical_file(root,orig);
132                     eliminate_doubles(root,orig->child);
133                     eliminate_doubles(root,orig->next);
134             }
135     }
136     
137     /*
138      * We define our own sorting function instead of using alphasort which
139      * uses strcoll and changes ordering based on locale information.
140      */
141     static int cramsort (const void *a, const void *b)
142     {
143     	return strcmp ((*(const struct dirent **) a)->d_name,
144     		       (*(const struct dirent **) b)->d_name);
145     }
146     
147     static unsigned int parse_directory(struct entry *root_entry, const char *name, struct entry **prev, loff_t *fslen_ub)
148     {
149     	struct dirent **dirlist;
150     	int totalsize = 0, dircount, dirindex;
151     	char *path, *endpath;
152     	size_t len = strlen(name);
153     
154     	/* Set up the path. */
155     	/* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
156     	path = malloc(len + 1 + MAX_INPUT_NAMELEN + 1);
157     	if (!path) {
158     		perror(NULL);
159     		exit(8);
160     	}
161     	memcpy(path, name, len);
162     	endpath = path + len;
163     	*endpath = '/';
164     	endpath++;
165     
166             /* read in the directory and sort */
167             dircount = scandir(name, &dirlist, 0, cramsort);
168     
169     	if (dircount < 0) {
170     		perror(name);
171     		exit(8);
172     	}
173     
174     	/* process directory */
175     	for (dirindex = 0; dirindex < dircount; dirindex++) {
176     		struct dirent *dirent;
177     		struct entry *entry;
178     		struct stat st;
179     		int size;
180     		size_t namelen;
181     
182     		dirent = dirlist[dirindex];
183     
184     		/* Ignore "." and ".." - we won't be adding them to the archive */
185     		if (dirent->d_name[0] == '.') {
186     			if (dirent->d_name[1] == '\0')
187     				continue;
188     			if (dirent->d_name[1] == '.') {
189     				if (dirent->d_name[2] == '\0')
190     					continue;
191     			}
192     		}
193     		namelen = strlen(dirent->d_name);
194     		if (namelen > MAX_INPUT_NAMELEN) {
195     			fprintf(stderr,
196     				"Very long (%u bytes) filename `%s' found.\n"
197     				" Please increase MAX_INPUT_NAMELEN in mkcramfs.c and recompile.  Exiting.\n",
198     				namelen, dirent->d_name);
199     			exit(8);
200     		}
201     		memcpy(endpath, dirent->d_name, namelen + 1);
202     
203     		if (lstat(path, &st) < 0) {
204     			perror(endpath);
205     			warn_skip = 1;
206     			continue;
207     		}
208     		entry = calloc(1, sizeof(struct entry));
209     		if (!entry) {
210     			perror(NULL);
211     			exit(8);
212     		}
213     		entry->name = strdup(dirent->d_name);
214     		if (!entry->name) {
215     			perror(NULL);
216     			exit(8);
217     		}
218     		if (namelen > 255) {
219     			/* Can't happen when reading from ext2fs. */
220     
221     			/* TODO: we ought to avoid chopping in half
222     			   multi-byte UTF8 characters. */
223     			entry->name[namelen = 255] = '\0';
224     			warn_namelen = 1;
225     		}
226     		entry->mode = st.st_mode;
227     		entry->size = st.st_size;
228     		entry->uid = st.st_uid;
229     		if (entry->uid >= 1 << CRAMFS_UID_WIDTH)
230     			warn_uid = 1;
231     		entry->gid = st.st_gid;
232     		if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
233     			/* TODO: We ought to replace with a default
234                                gid instead of truncating; otherwise there
235                                are security problems.  Maybe mode should
236                                be &= ~070.  Same goes for uid once Linux
237                                supports >16-bit uids. */
238     			warn_gid = 1;
239     		size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
240     		*fslen_ub += size;
241     		if (S_ISDIR(st.st_mode)) {
242     			entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
243     		} else if (S_ISREG(st.st_mode)) {
244     			/* TODO: We ought to open files in do_compress, one
245     			   at a time, instead of amassing all these memory
246     			   maps during parse_directory (which don't get used
247     			   until do_compress anyway).  As it is, we tend to
248     			   get EMFILE errors (especially if mkcramfs is run
249     			   by non-root).
250     
251     			   While we're at it, do analagously for symlinks
252     			   (which would just save a little memory). */
253     			int fd = open(path, O_RDONLY);
254     			if (fd < 0) {
255     				perror(path);
256     				warn_skip = 1;
257     				continue;
258     			}
259     			if (entry->size) {
260     				if ((entry->size >= 1 << CRAMFS_SIZE_WIDTH)) {
261     					warn_size = 1;
262     					entry->size = (1 << CRAMFS_SIZE_WIDTH) - 1;
263     				}
264     
265     				entry->uncompressed = mmap(NULL, entry->size, PROT_READ, MAP_PRIVATE, fd, 0);
266     				if (-1 == (int) (long) entry->uncompressed) {
267     					perror("mmap");
268     					exit(8);
269     				}
270     			}
271     			close(fd);
272     		} else if (S_ISLNK(st.st_mode)) {
273     			entry->uncompressed = malloc(entry->size);
274     			if (!entry->uncompressed) {
275     				perror(NULL);
276     				exit(8);
277     			}
278     			if (readlink(path, entry->uncompressed, entry->size) < 0) {
279     				perror(path);
280     				warn_skip = 1;
281     				continue;
282     			}
283     		} else if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode)) {
284     			/* maybe we should skip sockets */
285     			entry->size = 0;
286     		} else {
287     			entry->size = st.st_rdev;
288     			if (entry->size & -(1<<CRAMFS_SIZE_WIDTH))
289     				warn_dev = 1;
290     		}
291     
292     		if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
293     			int blocks = ((entry->size - 1) / blksize + 1);
294     
295     			/* block pointers & data expansion allowance + data */
296     			if(entry->size)
297     				*fslen_ub += (4+26)*blocks + entry->size + 3;
298                     }
299     
300     		/* Link it into the list */
301     		*prev = entry;
302     		prev = &entry->next;
303     		totalsize += size;
304     	}
305     	free(path);
306     	free(dirlist);		/* allocated by scandir() with malloc() */
307     	return totalsize;
308     }
309     
310     /* Returns sizeof(struct cramfs_super), which includes the root inode. */
311     static unsigned int write_superblock(struct entry *root, char *base, int size)
312     {
313     	struct cramfs_super *super = (struct cramfs_super *) base;
314     	unsigned int offset = sizeof(struct cramfs_super) + image_length;
315     
316     	if (opt_pad) {
317     		offset += opt_pad;
318     	}
319     
320     	super->magic = CRAMFS_MAGIC;
321     	super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS;
322     	if (opt_holes)
323     		super->flags |= CRAMFS_FLAG_HOLES;
324     	if (image_length > 0)
325     		super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET;
326     	super->size = size;
327     	memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
328     
329     	super->fsid.crc = crc32(0L, Z_NULL, 0);
330     	super->fsid.edition = opt_edition;
331     	super->fsid.blocks = total_blocks;
332     	super->fsid.files = total_nodes;
333     
334     	memset(super->name, 0x00, sizeof(super->name));
335     	if (opt_name)
336     		strncpy(super->name, opt_name, sizeof(super->name));
337     	else
338     		strncpy(super->name, "Compressed", sizeof(super->name));
339     
340     	super->root.mode = root->mode;
341     	super->root.uid = root->uid;
342     	super->root.gid = root->gid;
343     	super->root.size = root->size;
344     	super->root.offset = offset >> 2;
345     
346     	return offset;
347     }
348     
349     static void set_data_offset(struct entry *entry, char *base, unsigned long offset)
350     {
351     	struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
352     #ifdef DEBUG
353     	assert ((offset & 3) == 0);
354     #endif /* DEBUG */
355     	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
356     		fprintf(stderr, "filesystem too big.  Exiting.\n");
357     		exit(8);
358     	}
359     	inode->offset = (offset >> 2);
360     }
361     
362     
363     /*
364      * We do a width-first printout of the directory
365      * entries, using a stack to remember the directories
366      * we've seen.
367      */
368     #define MAXENTRIES (100)
369     static unsigned int write_directory_structure(struct entry *entry, char *base, unsigned int offset)
370     {
371     	int stack_entries = 0;
372     	struct entry *entry_stack[MAXENTRIES];
373     
374     	for (;;) {
375     		int dir_start = stack_entries;
376     		while (entry) {
377     			struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
378     			size_t len = strlen(entry->name);
379     
380     			entry->dir_offset = offset;
381     
382     			inode->mode = entry->mode;
383     			inode->uid = entry->uid;
384     			inode->gid = entry->gid;
385     			inode->size = entry->size;
386     			inode->offset = 0;
387     			/* Non-empty directories, regfiles and symlinks will
388     			   write over inode->offset later. */
389     
390     			offset += sizeof(struct cramfs_inode);
391     			total_nodes++;	/* another node */
392     			memcpy(base + offset, entry->name, len);
393     			/* Pad up the name to a 4-byte boundary */
394     			while (len & 3) {
395     				*(base + offset + len) = '\0';
396     				len++;
397     			}
398     			inode->namelen = len >> 2;
399     			offset += len;
400     
401     			/* TODO: this may get it wrong for chars >= 0x80.
402     			   Most filesystems use UTF8 encoding for filenames,
403     			   whereas the console is a single-byte character
404     			   set like iso-latin-1. */
405     			printf("  %s\n", entry->name);
406     			if (entry->child) {
407     				if (stack_entries >= MAXENTRIES) {
408     					fprintf(stderr, "Exceeded MAXENTRIES.  Raise this value in mkcramfs.c and recompile.  Exiting.\n");
409     					exit(8);
410     				}
411     				entry_stack[stack_entries] = entry;
412     				stack_entries++;
413     			}
414     			entry = entry->next;
415     		}
416     
417     		/*
418     		 * Reverse the order the stack entries pushed during
419                      * this directory, for a small optimization of disk
420                      * access in the created fs.  This change makes things
421                      * `ls -UR' order.
422     		 */
423     		{
424     			struct entry **lo = entry_stack + dir_start;
425     			struct entry **hi = entry_stack + stack_entries;
426     			struct entry *tmp;
427     
428     			while (lo < --hi) {
429     				tmp = *lo;
430     				*lo++ = *hi;
431     				*hi = tmp;
432     			}
433     		}
434     
435     		/* Pop a subdirectory entry from the stack, and recurse. */
436     		if (!stack_entries)
437     			break;
438     		stack_entries--;
439     		entry = entry_stack[stack_entries];
440     
441     		set_data_offset(entry, base, offset);
442     		printf("'%s':\n", entry->name);
443     		entry = entry->child;
444     	}
445     	return offset;
446     }
447     
448     static int is_zero(char const *begin, unsigned len)
449     {
450     	if (opt_holes)
451     		/* Returns non-zero iff the first LEN bytes from BEGIN are
452     		   all NULs. */
453     		return (len-- == 0 ||
454     			(begin[0] == '\0' &&
455     			 (len-- == 0 ||
456     			  (begin[1] == '\0' &&
457     			   (len-- == 0 ||
458     			    (begin[2] == '\0' &&
459     			     (len-- == 0 ||
460     			      (begin[3] == '\0' &&
461     			       memcmp(begin, begin + 4, len) == 0))))))));
462     	else
463     		/* Never create holes. */
464     		return 0;
465     }
466     
467     /*
468      * One 4-byte pointer per block and then the actual blocked
469      * output. The first block does not need an offset pointer,
470      * as it will start immediately after the pointer block;
471      * so the i'th pointer points to the end of the i'th block
472      * (i.e. the start of the (i+1)'th block or past EOF).
473      *
474      * Note that size > 0, as a zero-sized file wouldn't ever
475      * have gotten here in the first place.
476      */
477     static unsigned int do_compress(char *base, unsigned int offset, char const *name, char *uncompressed, unsigned int size)
478     {
479     	unsigned long original_size = size;
480     	unsigned long original_offset = offset;
481     	unsigned long new_size;
482     	unsigned long blocks = (size - 1) / blksize + 1;
483     	unsigned long curr = offset + 4 * blocks;
484     	int change;
485     
486     	total_blocks += blocks;
487     
488     	do {
489     		unsigned long len = 2 * blksize;
490     		unsigned int input = size;
491     		if (input > blksize)
492     			input = blksize;
493     		size -= input;
494     		if (!is_zero (uncompressed, input)) {
495     			compress(base + curr, &len, uncompressed, input);
496     			curr += len;
497     		}
498     		uncompressed += input;
499     
500     		if (len > blksize*2) {
501     			/* (I don't think this can happen with zlib.) */
502     			printf("AIEEE: block \"compressed\" to > 2*blocklength (%ld)\n", len);
503     			exit(8);
504     		}
505     
506     		*(u32 *) (base + offset) = curr;
507     		offset += 4;
508     	} while (size);
509     
510     	curr = (curr + 3) & ~3;
511     	new_size = curr - original_offset;
512     	/* TODO: Arguably, original_size in these 2 lines should be
513     	   st_blocks * 512.  But if you say that then perhaps
514     	   administrative data should also be included in both. */
515     	change = new_size - original_size;
516     	printf("%6.2f%% (%+d bytes)\t%s\n",
517     	       (change * 100) / (double) original_size, change, name);
518     
519     	return curr;
520     }
521     
522     
523     /*
524      * Traverse the entry tree, writing data for every item that has
525      * non-null entry->compressed (i.e. every symlink and non-empty
526      * regfile).
527      */
528     static unsigned int write_data(struct entry *entry, char *base, unsigned int offset)
529     {
530     	do {
531     		if (entry->uncompressed) {
532                             if(entry->same) {
533                                     set_data_offset(entry, base, entry->same->offset);
534                                     entry->offset=entry->same->offset;
535                             } else {
536                                     set_data_offset(entry, base, offset);
537                                     entry->offset=offset;
538                                     offset = do_compress(base, offset, entry->name, entry->uncompressed, entry->size);
539                             }
540     		}
541     		else if (entry->child)
542     			offset = write_data(entry->child, base, offset);
543                     entry=entry->next;
544     	} while (entry);
545     	return offset;
546     }
547     
548     static unsigned int write_file(char *file, char *base, unsigned int offset)
549     {
550     	int fd;
551     	char *buf;
552     
553     	fd = open(file, O_RDONLY);
554     	if (fd < 0) {
555     		perror(file);
556     		exit(8);
557     	}
558     	buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
559     	memcpy(base + offset, buf, image_length);
560     	munmap(buf, image_length);
561     	close (fd);
562     	/* Pad up the image_length to a 4-byte boundary */
563     	while (image_length & 3) {
564     		*(base + offset + image_length) = '\0';
565     		image_length++;
566     	}
567     	return (offset + image_length);
568     }
569     
570     /*
571      * Maximum size fs you can create is roughly 256MB.  (The last file's
572      * data must begin within 256MB boundary but can extend beyond that.)
573      *
574      * Note that if you want it to fit in a ROM then you're limited to what the
575      * hardware and kernel can support (64MB?).
576      */
577     #define MAXFSLEN ((((1 << CRAMFS_OFFSET_WIDTH) - 1) << 2) /* offset */ \
578     		  + (1 << CRAMFS_SIZE_WIDTH) - 1 /* filesize */ \
579     		  + (1 << CRAMFS_SIZE_WIDTH) * 4 / PAGE_CACHE_SIZE /* block pointers */ )
580     
581     
582     /*
583      * Usage:
584      *
585      *      mkcramfs directory-name outfile
586      *
587      * where "directory-name" is simply the root of the directory
588      * tree that we want to generate a compressed filesystem out
589      * of.
590      */
591     int main(int argc, char **argv)
592     {
593     	struct stat st;		/* used twice... */
594     	struct entry *root_entry;
595     	char *rom_image;
596     	ssize_t offset, written;
597     	int fd;
598     	/* initial guess (upper-bound) of required filesystem size */
599     	loff_t fslen_ub = sizeof(struct cramfs_super);
600     	char const *dirname, *outfile;
601     	u32 crc = crc32(0L, Z_NULL, 0);
602     	int c;			/* for getopt */
603     
604     	total_blocks = 0;
605     
606     	if (argc)
607     		progname = argv[0];
608     
609     	/* command line options */
610     	while ((c = getopt(argc, argv, "hEe:i:n:psz")) != EOF) {
611     		switch (c) {
612     		case 'h':
613     			usage(0);
614     		case 'E':
615     			opt_errors = 1;
616     			break;
617     		case 'e':
618     			opt_edition = atoi(optarg);
619     			break;
620     		case 'i':
621     			opt_image = optarg;
622     			if (lstat(opt_image, &st) < 0) {
623     				perror(opt_image);
624     				exit(16);
625     			}
626     			image_length = st.st_size; /* may be padded later */
627     			fslen_ub += (image_length + 3); /* 3 is for padding */
628     			break;
629     		case 'n':
630     			opt_name = optarg;
631     			break;
632     		case 'p':
633     			opt_pad = PAD_SIZE;
634     			fslen_ub += PAD_SIZE;
635     			break;
636     		case 's':
637     			/* old option, ignored */
638     			break;
639     		case 'z':
640     			opt_holes = 1;
641     			break;
642     		}
643     	}
644     
645     	if ((argc - optind) != 2)
646     		usage(16);
647     	dirname = argv[optind];
648     	outfile = argv[optind + 1];
649     
650     	if (stat(dirname, &st) < 0) {
651     		perror(dirname);
652     		exit(16);
653     	}
654     	fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
655     
656     	root_entry = calloc(1, sizeof(struct entry));
657     	if (!root_entry) {
658     		perror(NULL);
659     		exit(8);
660     	}
661     	root_entry->mode = st.st_mode;
662     	root_entry->uid = st.st_uid;
663     	root_entry->gid = st.st_gid;
664     
665     	root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
666     
667     	/* always allocate a multiple of blksize bytes because that's
668                what we're going to write later on */
669     	fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
670     
671     	if (fslen_ub > MAXFSLEN) {
672     		fprintf(stderr,
673     			"warning: guestimate of required size (upper bound) is %LdMB, but maximum image size is %uMB.  We might die prematurely.\n",
674     			fslen_ub >> 20,
675     			MAXFSLEN >> 20);
676     		fslen_ub = MAXFSLEN;
677     	}
678     
679             /* find duplicate files. TODO: uses the most inefficient algorithm
680                possible. */
681             eliminate_doubles(root_entry,root_entry);
682     
683     	/* TODO: Why do we use a private/anonymous mapping here
684                followed by a write below, instead of just a shared mapping
685                and a couple of ftruncate calls?  Is it just to save us
686                having to deal with removing the file afterwards?  If we
687                really need this huge anonymous mapping, we ought to mmap
688                in smaller chunks, so that the user doesn't need nn MB of
689                RAM free.  If the reason is to be able to write to
690                un-mmappable block devices, then we could try shared mmap
691                and revert to anonymous mmap if the shared mmap fails. */
692     	rom_image = mmap(NULL, fslen_ub?fslen_ub:1, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
693     
694     	if (-1 == (int) (long) rom_image) {
695     		perror("ROM image map");
696     		exit(8);
697     	}
698     
699     	/* Skip the first opt_pad bytes for boot loader code */
700     	offset = opt_pad;
701     	memset(rom_image, 0x00, opt_pad);
702     
703     	/* Skip the superblock and come back to write it later. */
704     	offset += sizeof(struct cramfs_super);
705     
706     	/* Insert a file image. */
707     	if (opt_image) {
708     		printf("Including: %s\n", opt_image);
709     		offset = write_file(opt_image, rom_image, offset);
710     	}
711     
712     	offset = write_directory_structure(root_entry->child, rom_image, offset);
713     	printf("Directory data: %d bytes\n", offset);
714     
715     	offset = write_data(root_entry, rom_image, offset);
716     
717     	/* We always write a multiple of blksize bytes, so that
718                losetup works. */
719     	offset = ((offset - 1) | (blksize - 1)) + 1;
720     	printf("Everything: %d kilobytes\n", offset >> 10);
721     
722     	/* Write the superblock now that we can fill in all of the fields. */
723     	write_superblock(root_entry, rom_image+opt_pad, offset);
724     	printf("Super block: %d bytes\n", sizeof(struct cramfs_super));
725     
726     	/* Put the checksum in. */
727     	crc = crc32(crc, (rom_image+opt_pad), (offset-opt_pad));
728     	((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc;
729     	printf("CRC: %x\n", crc);
730     
731     	/* Check to make sure we allocated enough space. */
732     	if (fslen_ub < offset) {
733     		fprintf(stderr, "not enough space allocated for ROM image (%Ld allocated, %d used)\n",
734     			fslen_ub, offset);
735     		exit(8);
736     	}
737     
738     	written = write(fd, rom_image, offset);
739     	if (written < 0) {
740     		perror("ROM image");
741     		exit(8);
742     	}
743     	if (offset != written) {
744     		fprintf(stderr, "ROM image write failed (%d %d)\n", written, offset);
745     		exit(8);
746     	}
747     
748     	/* (These warnings used to come at the start, but they scroll off the
749                screen too quickly.) */
750     	if (warn_namelen) /* (can't happen when reading from ext2fs) */
751     		fprintf(stderr, /* bytes, not chars: think UTF8. */
752     			"warning: filenames truncated to 255 bytes.\n");
753     	if (warn_skip)
754     		fprintf(stderr, "warning: files were skipped due to errors.\n");
755     	if (warn_size)
756     		fprintf(stderr,
757     			"warning: file sizes truncated to %luMB (minus 1 byte).\n",
758     			1L << (CRAMFS_SIZE_WIDTH - 20));
759     	if (warn_uid) /* (not possible with current Linux versions) */
760     		fprintf(stderr,
761     			"warning: uids truncated to %u bits.  (This may be a security concern.)\n",
762     			CRAMFS_UID_WIDTH);
763     	if (warn_gid)
764     		fprintf(stderr,
765     			"warning: gids truncated to %u bits.  (This may be a security concern.)\n",
766     			CRAMFS_GID_WIDTH);
767     	if (warn_dev)
768     		fprintf(stderr,
769     			"WARNING: device numbers truncated to %u bits.  This almost certainly means\n"
770     			"that some device files will be wrong.\n",
771     			CRAMFS_OFFSET_WIDTH);
772     	if (opt_errors &&
773     	    (warn_namelen||warn_skip||warn_size||warn_uid||warn_gid||warn_dev))
774     		exit(8);
775     	return 0;
776     }
777