2 * mkcramfs - make a cramfs file system
4 * Copyright (C) 1999-2002 Transmeta Corporation
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.
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.
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.
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
26 #include <sys/types.h>
40 /* We don't use our include/crc32.h, but crc32 from zlib!
42 * The zlib implementation performs pre/post-conditioning. The util-linux
43 * imlemenation requires post-conditioning (xor) in the applications.
52 #include "exitcodes.h"
55 #define CLOSE_EXIT_CODE MKFS_EX_ERROR
56 #include "closestream.h"
58 #define XALLOC_EXIT_CODE MKFS_EX_ERROR
61 /* The kernel only supports PAD_SIZE of 0 and 512. */
64 static int verbose
= 0;
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 */
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).
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.
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
;
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;
94 #define CRAMFS_EFLAG_MD5 1
95 #define CRAMFS_EFLAG_INVALID 2
97 /* In-core version of inode / directory entry. */
101 unsigned int mode
, size
, uid
, gid
;
102 unsigned char md5sum
[UL_MD5LENGTH
];
103 unsigned char flags
; /* CRAMFS_EFLAG_* */
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 */
113 struct entry
*child
; /* NULL for non-directory and empty dir */
118 * Width of various bitfields in struct cramfs_inode.
119 * Used only to generate warnings.
121 #define CRAMFS_SIZE_WIDTH 24
122 #define CRAMFS_UID_WIDTH 16
123 #define CRAMFS_GID_WIDTH 8
124 #define CRAMFS_OFFSET_WIDTH 26
126 static void __attribute__((__noreturn__
)) usage(void)
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)"));
154 do_mmap(char *path
, unsigned int size
, unsigned int 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
);
173 fd
= open(path
, O_RDONLY
);
175 warn(_("cannot open %s"), path
);
180 start
= mmap(NULL
, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
182 if (start
== MAP_FAILED
)
183 err(MKFS_EX_ERROR
, "mmap");
191 do_munmap(char *start
, unsigned int size
, unsigned int mode
){
198 /* compute md5sums, so that we do not have to compare every pair of files */
200 mdfile(struct entry
*e
) {
203 start
= do_mmap(e
->path
, e
->size
, e
->mode
);
205 e
->flags
|= CRAMFS_EFLAG_INVALID
;
210 ul_MD5Update(&ctx
, (unsigned char *) start
, e
->size
);
211 ul_MD5Final(e
->md5sum
, &ctx
);
213 do_munmap(start
, e
->size
, e
->mode
);
215 e
->flags
|= CRAMFS_EFLAG_MD5
;
219 /* md5 digests are equal; files are almost certainly the same,
220 but just to be sure, do the comparison */
222 identical_file(struct entry
*e1
, struct entry
*e2
){
223 char *start1
, *start2
;
226 start1
= do_mmap(e1
->path
, e1
->size
, e1
->mode
);
229 start2
= do_mmap(e2
->path
, e2
->size
, e2
->mode
);
231 do_munmap(start1
, e1
->size
, e1
->mode
);
234 equal
= !memcmp(start1
, start2
, e1
->size
);
235 do_munmap(start1
, e1
->size
, e1
->mode
);
236 do_munmap(start2
, e2
->size
, e2
->mode
);
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.
247 #define MAX_INPUT_NAMELEN 255
249 static int find_identical_file(struct entry
*orig
, struct entry
*new, loff_t
*fslen_ub
)
255 if (orig
->size
== new->size
&& orig
->path
) {
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)) {
266 *fslen_ub
-= new->size
;
270 return find_identical_file(orig
->child
, new, fslen_ub
) ||
271 find_identical_file(orig
->next
, new, fslen_ub
);
274 static void eliminate_doubles(struct entry
*root
, struct entry
*orig
, loff_t
*fslen_ub
) {
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
);
284 * We define our own sorting function instead of using alphasort which
285 * uses strcoll and changes ordering based on locale information.
287 static int cramsort (const struct dirent
**a
, const struct dirent
**b
)
289 return strcmp((*a
)->d_name
, (*b
)->d_name
);
292 static unsigned int parse_directory(struct entry
*root_entry
, const char *name
, struct entry
**prev
, loff_t
*fslen_ub
)
294 struct dirent
**dirlist
;
295 int totalsize
= 0, dircount
, dirindex
;
296 char *path
, *endpath
;
297 size_t len
= strlen(name
);
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
;
307 /* read in the directory and sort */
308 dircount
= scandir(name
, &dirlist
, NULL
, cramsort
);
311 err(MKFS_EX_ERROR
, _("could not read directory %s"), name
);
313 /* process directory */
314 for (dirindex
= 0; dirindex
< dircount
; dirindex
++) {
315 struct dirent
*dirent
;
321 dirent
= dirlist
[dirindex
];
323 /* Ignore "." and ".." - we won't be adding them
325 if (dirent
->d_name
[0] == '.') {
326 if (dirent
->d_name
[1] == '\0')
328 if (dirent
->d_name
[1] == '.' &&
329 dirent
->d_name
[2] == '\0')
332 namelen
= strlen(dirent
->d_name
);
333 if (namelen
> MAX_INPUT_NAMELEN
) {
334 namelen
= MAX_INPUT_NAMELEN
;
338 memcpy(endpath
, dirent
->d_name
, namelen
+ 1);
340 if (lstat(path
, &st
) < 0) {
341 warn(_("stat of %s failed"), endpath
);
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
)
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. */
360 size
= sizeof(struct cramfs_inode
) + ((namelen
+ 3) & ~3);
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
)) {
368 entry
->size
= (1 << CRAMFS_SIZE_WIDTH
) - 1;
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 */
376 entry
->size
= st
.st_rdev
;
377 if (entry
->size
& -(1<<CRAMFS_SIZE_WIDTH
))
381 if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
382 int blocks
= ((entry
->size
- 1) / blksize
+ 1);
384 /* block pointers & data expansion allowance + data */
386 *fslen_ub
+= (4+26)*blocks
+ entry
->size
+ 3;
389 /* Link it into the list */
395 free(dirlist
); /* allocated by scandir() with malloc() */
399 /* Returns sizeof(struct cramfs_super), which includes the root inode. */
400 static unsigned int write_superblock(struct entry
*root
, char *base
, int size
)
402 struct cramfs_super
*super
= (struct cramfs_super
*) base
;
403 unsigned int offset
= sizeof(struct cramfs_super
) + image_length
;
409 super
->magic
= CRAMFS_MAGIC
;
410 super
->flags
= CRAMFS_FLAG_FSID_VERSION_2
| CRAMFS_FLAG_SORTED_DIRS
;
412 super
->flags
|= CRAMFS_FLAG_HOLES
;
413 if (image_length
> 0)
414 super
->flags
|= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET
;
416 memcpy(super
->signature
, CRAMFS_SIGNATURE
, sizeof(super
->signature
));
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
;
423 memset(super
->name
, 0x00, sizeof(super
->name
));
425 str2memcpy((char *)super
->name
, opt_name
, sizeof(super
->name
));
427 str2memcpy((char *)super
->name
, "Compressed", sizeof(super
->name
));
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;
435 super_toggle_endianness(cramfs_is_big_endian
, super
);
436 inode_from_host(cramfs_is_big_endian
, &super
->root
, &super
->root
);
441 static void set_data_offset(struct entry
*entry
, char *base
, unsigned long offset
)
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
);
453 * We do a width-first printout of the directory
454 * entries, using a stack to remember the directories
457 static unsigned int write_directory_structure(struct entry
*entry
, char *base
, unsigned int offset
)
459 int stack_entries
= 0;
461 struct entry
**entry_stack
;
463 entry_stack
= xmalloc(stack_size
* sizeof(struct entry
*));
466 int dir_start
= stack_entries
;
468 struct cramfs_inode
*inode
=
469 (struct cramfs_inode
*) (base
+ offset
);
470 size_t len
= strlen((const char *)entry
->name
);
472 entry
->dir_offset
= offset
;
474 inode
->mode
= entry
->mode
;
475 inode
->uid
= entry
->uid
;
476 inode
->gid
= entry
->gid
;
477 inode
->size
= entry
->size
;
479 /* Non-empty directories, regfiles and symlinks will
480 write over inode->offset later. */
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 */
487 *(base
+ offset
+ len
) = '\0';
490 inode
->namelen
= len
>> 2;
494 printf(" %s\n", entry
->name
);
496 if (stack_entries
>= stack_size
) {
498 entry_stack
= xrealloc(entry_stack
, stack_size
* sizeof(struct entry
*));
500 entry_stack
[stack_entries
] = entry
;
503 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
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
514 struct entry
**lo
= entry_stack
+ dir_start
;
515 struct entry
**hi
= entry_stack
+ stack_entries
;
525 /* Pop a subdirectory entry from the stack, and recurse. */
529 entry
= entry_stack
[stack_entries
];
531 set_data_offset(entry
, base
, offset
);
533 printf("'%s':\n", entry
->name
);
534 entry
= entry
->child
;
540 static int is_zero(unsigned char const *begin
, unsigned len
)
543 /* Returns non-zero iff the first LEN bytes from BEGIN are
545 return (len
-- == 0 ||
553 memcmp(begin
, begin
+ 4, len
) == 0))))))));
555 /* Never create holes. */
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).
566 * Note that size > 0, as a zero-sized file wouldn't ever
567 * have gotten here in the first place.
570 do_compress(char *base
, unsigned int offset
, unsigned char const *name
,
571 char *path
, unsigned int size
, unsigned int mode
)
573 unsigned long original_size
, original_offset
, new_size
, blocks
, curr
;
578 /* get uncompressed data */
579 start
= do_mmap(path
, size
, mode
);
584 original_size
= size
;
585 original_offset
= offset
;
586 blocks
= (size
- 1) / blksize
+ 1;
587 curr
= offset
+ 4 * blocks
;
589 total_blocks
+= blocks
;
592 uLongf len
= 2 * blksize
;
597 if (!is_zero (p
, input
)) {
598 compress((Bytef
*)(base
+ curr
), &len
, p
, input
);
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"),
611 *(uint32_t *) (base
+ offset
) = u32_toggle_endianness(cramfs_is_big_endian
, curr
);
615 do_munmap(start
, original_size
, mode
);
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
;
624 printf(_("%6.2f%% (%+ld bytes)\t%s\n"),
625 (change
* 100) / (double) original_size
, change
, name
);
632 * Traverse the entry tree, writing data for every item that has
633 * non-null entry->path (i.e. every symlink and non-empty
637 write_data(struct entry
*entry
, char *base
, unsigned int offset
) {
640 for (e
= entry
; e
; e
= e
->next
) {
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
);
648 offset
= do_compress(base
, offset
, e
->name
,
649 e
->path
, e
->size
,e
->mode
);
652 offset
= write_data(e
->child
, base
, offset
);
657 static unsigned int write_file(char *file
, char *base
, unsigned int offset
)
662 fd
= open(file
, O_RDONLY
);
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
);
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';
675 return (offset
+ image_length
);
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.)
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?).
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 */
695 * mkcramfs directory-name outfile
697 * where "directory-name" is simply the root of the directory
698 * tree that we want to generate a compressed filesystem out
701 int main(int argc
, char **argv
)
703 struct stat st
; /* used twice... */
704 struct entry
*root_entry
;
706 ssize_t offset
, written
;
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
;
713 uint32_t crc
= crc32(0L, NULL
, 0);
715 cramfs_is_big_endian
= HOST_IS_BIG_ENDIAN
; /* default is to use host order */
719 setlocale(LC_ALL
, "");
720 bindtextdomain(PACKAGE
, LOCALEDIR
);
722 close_stdout_atexit();
725 /* first arg may be one of our standard longopts */
726 if (!strcmp(argv
[1], "--help"))
728 if (!strcmp(argv
[1], "--version")) {
729 print_version(EXIT_SUCCESS
);
733 strutils_set_exitcode(MKFS_EX_USAGE
);
735 /* command line options */
736 while ((c
= getopt(argc
, argv
, "hb:Ee:i:n:N:l::psVvz")) != EOF
) {
741 blksize
= strtou32_or_err(optarg
, _("invalid blocksize argument"));
747 opt_edition
= strtou32_or_err(optarg
, _("invalid edition number argument"));
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)
757 errx(MKFS_EX_USAGE
, _("invalid endianness given;"
758 " must be 'big', 'little', or 'host'"));
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 */
780 fslen_ub
+= PAD_SIZE
;
783 /* old option, ignored */
786 print_version(MKFS_EX_OK
);
794 errtryhelp(MKFS_EX_USAGE
);
798 if ((argc
- optind
) != 2) {
799 warnx(_("bad usage"));
800 errtryhelp(MKFS_EX_USAGE
);
802 dirname
= argv
[optind
];
803 outfile
= argv
[optind
+ 1];
806 blksize
= getpagesize();
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);
812 err(MKFS_EX_USAGE
, _("cannot open %s"), outfile
);
814 if (blkdev_lock(fd
, outfile
, lockmode
) != 0)
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
;
822 root_entry
->size
= parse_directory(root_entry
, dirname
, &root_entry
->child
, &fslen_ub
);
824 /* find duplicate files */
825 eliminate_doubles(root_entry
,root_entry
, &fslen_ub
);
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();
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,
838 fslen_ub
= fslen_max
;
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
,
852 PROT_READ
| PROT_WRITE
,
853 MAP_PRIVATE
| MAP_ANONYMOUS
,
856 if (-1 == (int) (long) rom_image
)
857 err(MKFS_EX_ERROR
, _("ROM image map"));
859 /* Skip the first opt_pad bytes for boot loader code */
861 memset(rom_image
, 0x00, opt_pad
);
863 /* Skip the superblock and come back to write it later. */
864 offset
+= sizeof(struct cramfs_super
);
866 /* Insert a file image. */
869 printf(_("Including: %s\n"), opt_image
);
870 offset
= write_file(opt_image
, rom_image
, offset
);
873 offset
= write_directory_structure(root_entry
->child
, rom_image
, offset
);
875 printf(_("Directory data: %zd bytes\n"), offset
);
877 offset
= write_data(root_entry
, rom_image
, offset
);
879 /* We always write a multiple of blksize bytes, so that
881 offset
= ((offset
- 1) | (blksize
- 1)) + 1;
883 printf(_("Everything: %zd kilobytes\n"), offset
>> 10);
885 /* Write the superblock now that we can fill in all of the fields. */
886 write_superblock(root_entry
, rom_image
+opt_pad
, offset
);
888 printf(_("Super block: %zd bytes\n"),
889 sizeof(struct cramfs_super
));
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
);
895 printf(_("CRC: %x\n"), crc
);
897 /* Check to make sure we allocated enough space. */
898 if (fslen_ub
< offset
)
900 _("not enough space allocated for ROM image "
901 "(%lld allocated, %zu used)"),
902 (long long) fslen_ub
, offset
);
904 written
= write(fd
, rom_image
, offset
);
905 if (offset
!= written
)
906 errx(MKFS_EX_ERROR
, _("ROM image write failed (%zd %zd)"),
908 if (close_fd(fd
) != 0)
909 err(MKFS_EX_ERROR
, _("ROM image"));
912 * (These warnings used to come at the start, but they scroll off
913 * the screen too quickly.)
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
);
920 warnx(_("warning: files were skipped due to errors."));
922 warnx(_("warning: file sizes truncated to %luMB "
923 "(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH
- 20));
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
);
929 warnx(_("warning: gids truncated to %u bits. "
930 "(This may be a security concern.)"), CRAMFS_GID_WIDTH
);
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
);
937 (warn_namelen
|warn_skip
|warn_size
|warn_uid
|warn_gid
|warn_dev
))