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 instaed of all simultaneously. - aeb, 2002-11-01
26 #include <sys/types.h>
43 #include "closestream.h"
46 #include "exitcodes.h"
48 #define XALLOC_EXIT_CODE MKFS_EX_ERROR
51 /* The kernel only supports PAD_SIZE of 0 and 512. */
54 static int verbose
= 0;
56 static unsigned int blksize
; /* settable via -b option */
57 static long total_blocks
= 0, total_nodes
= 1; /* pre-count the root node */
58 static int image_length
= 0;
59 static int cramfs_is_big_endian
= 0; /* target is big endian */
62 * If opt_holes is set, then mkcramfs can create explicit holes in the
63 * data, which saves 26 bytes per hole (which is a lot smaller a
64 * saving than for most filesystems).
66 * Note that kernels up to at least 2.3.39 don't support cramfs holes,
67 * which is why this is turned off by default.
69 static unsigned int opt_edition
= 0;
70 static int opt_errors
= 0;
71 static int opt_holes
= 0;
72 static int opt_pad
= 0;
73 static char *opt_image
= NULL
;
74 static char *opt_name
= NULL
;
76 static int warn_dev
= 0;
77 static int warn_gid
= 0;
78 static int warn_namelen
= 0;
79 static int warn_skip
= 0;
80 static int warn_size
= 0;
81 static int warn_uid
= 0;
84 #define CRAMFS_EFLAG_MD5 1
85 #define CRAMFS_EFLAG_INVALID 2
87 /* In-core version of inode / directory entry. */
91 unsigned int mode
, size
, uid
, gid
;
92 unsigned char md5sum
[MD5LENGTH
];
93 unsigned char flags
; /* CRAMFS_EFLAG_* */
97 int fd
; /* temporarily open files while mmapped */
98 struct entry
*same
; /* points to other identical file */
99 unsigned int offset
; /* pointer to compressed data in archive */
100 unsigned int dir_offset
; /* offset of directory entry in archive */
103 struct entry
*child
; /* NULL for non-directory and empty dir */
108 * Width of various bitfields in struct cramfs_inode.
109 * Used only to generate warnings.
111 #define CRAMFS_SIZE_WIDTH 24
112 #define CRAMFS_UID_WIDTH 16
113 #define CRAMFS_GID_WIDTH 8
114 #define CRAMFS_OFFSET_WIDTH 26
116 /* Input status of 0 to print help and exit without an error. */
119 FILE *stream
= status
? stderr
: stdout
;
122 _("usage: %s [-h] [-v] [-b blksize] [-e edition] [-N endian] [-i file] "
123 "[-n name] dirname outfile\n"
124 " -h print this help\n"
126 " -E make all warnings errors "
127 "(non-zero exit status)\n"
128 " -b blksize use this blocksize, must equal page size\n"
129 " -e edition set edition number (part of fsid)\n"
130 " -N endian set cramfs endianness (big|little|host), default host\n"
131 " -i file insert a file image into the filesystem "
132 "(requires >= 2.4.0)\n"
133 " -n name set name of cramfs filesystem\n"
134 " -p pad by %d bytes for boot code\n"
135 " -s sort directory entries (old option, ignored)\n"
136 " -z make explicit holes (requires >= 2.3.39)\n"
137 " dirname root of the filesystem to be compressed\n"
138 " outfile output file\n"),
139 program_invocation_short_name
, PAD_SIZE
);
145 do_mmap(char *path
, unsigned int size
, unsigned int mode
){
153 start
= xmalloc(size
);
154 if (readlink(path
, start
, size
) < 0) {
162 fd
= open(path
, O_RDONLY
);
169 start
= mmap(NULL
, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
170 if (-1 == (int) (long) start
)
171 err(MKFS_EX_ERROR
, "mmap");
178 do_munmap(char *start
, unsigned int size
, unsigned int mode
){
185 /* compute md5sums, so that we do not have to compare every pair of files */
187 mdfile(struct entry
*e
) {
191 start
= do_mmap(e
->path
, e
->size
, e
->mode
);
193 e
->flags
|= CRAMFS_EFLAG_INVALID
;
196 MD5Update(&ctx
, (unsigned char *) start
, e
->size
);
197 MD5Final(e
->md5sum
, &ctx
);
199 do_munmap(start
, e
->size
, e
->mode
);
201 e
->flags
|= CRAMFS_EFLAG_MD5
;
205 /* md5 digests are equal; files are almost certainly the same,
206 but just to be sure, do the comparison */
208 identical_file(struct entry
*e1
, struct entry
*e2
){
209 char *start1
, *start2
;
212 start1
= do_mmap(e1
->path
, e1
->size
, e1
->mode
);
215 start2
= do_mmap(e2
->path
, e2
->size
, e2
->mode
);
218 equal
= !memcmp(start1
, start2
, e1
->size
);
219 do_munmap(start1
, e1
->size
, e1
->mode
);
220 do_munmap(start2
, e2
->size
, e2
->mode
);
225 * The longest file name component to allow for in the input directory tree.
226 * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems
227 * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
228 * >255-byte names in the input directory tree given that such names get
229 * truncated to 255 bytes when written to cramfs.
231 #define MAX_INPUT_NAMELEN 255
233 static int find_identical_file(struct entry
*orig
, struct entry
*new, loff_t
*fslen_ub
)
239 if (orig
->size
== new->size
&& orig
->path
) {
245 if ((orig
->flags
& CRAMFS_EFLAG_MD5
) &&
246 (new->flags
& CRAMFS_EFLAG_MD5
) &&
247 !memcmp(orig
->md5sum
, new->md5sum
, MD5LENGTH
) &&
248 identical_file(orig
, new)) {
250 *fslen_ub
-= new->size
;
254 return find_identical_file(orig
->child
, new, fslen_ub
) ||
255 find_identical_file(orig
->next
, new, fslen_ub
);
258 static void eliminate_doubles(struct entry
*root
, struct entry
*orig
, loff_t
*fslen_ub
) {
260 if (orig
->size
&& orig
->path
)
261 find_identical_file(root
,orig
, fslen_ub
);
262 eliminate_doubles(root
,orig
->child
, fslen_ub
);
263 eliminate_doubles(root
,orig
->next
, fslen_ub
);
268 * We define our own sorting function instead of using alphasort which
269 * uses strcoll and changes ordering based on locale information.
271 static int cramsort (const struct dirent
**a
, const struct dirent
**b
)
273 return strcmp((*a
)->d_name
, (*b
)->d_name
);
276 static unsigned int parse_directory(struct entry
*root_entry
, const char *name
, struct entry
**prev
, loff_t
*fslen_ub
)
278 struct dirent
**dirlist
;
279 int totalsize
= 0, dircount
, dirindex
;
280 char *path
, *endpath
;
281 size_t len
= strlen(name
);
283 /* Set up the path. */
284 /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
285 path
= xmalloc(len
+ 1 + MAX_INPUT_NAMELEN
+ 1);
286 memcpy(path
, name
, len
);
287 endpath
= path
+ len
;
291 /* read in the directory and sort */
292 dircount
= scandir(name
, &dirlist
, 0, cramsort
);
295 err(MKFS_EX_ERROR
, _("could not read directory %s"), name
);
297 /* process directory */
298 for (dirindex
= 0; dirindex
< dircount
; dirindex
++) {
299 struct dirent
*dirent
;
305 dirent
= dirlist
[dirindex
];
307 /* Ignore "." and ".." - we won't be adding them
309 if (dirent
->d_name
[0] == '.') {
310 if (dirent
->d_name
[1] == '\0')
312 if (dirent
->d_name
[1] == '.') {
313 if (dirent
->d_name
[2] == '\0')
317 namelen
= strlen(dirent
->d_name
);
318 if (namelen
> MAX_INPUT_NAMELEN
)
320 _("Very long (%zu bytes) filename `%s' found.\n"
321 " Please increase MAX_INPUT_NAMELEN in "
322 "mkcramfs.c and recompile. Exiting."),
323 namelen
, dirent
->d_name
);
324 memcpy(endpath
, dirent
->d_name
, namelen
+ 1);
326 if (lstat(path
, &st
) < 0) {
331 entry
= xcalloc(1, sizeof(struct entry
));
332 entry
->name
= (unsigned char *)xstrdup(dirent
->d_name
);
334 /* Can't happen when reading from ext2fs. */
336 /* TODO: we ought to avoid chopping in half
337 multi-byte UTF8 characters. */
338 entry
->name
[namelen
= 255] = '\0';
341 entry
->mode
= st
.st_mode
;
342 entry
->size
= st
.st_size
;
343 entry
->uid
= st
.st_uid
;
344 if (entry
->uid
>= 1 << CRAMFS_UID_WIDTH
)
346 entry
->gid
= st
.st_gid
;
347 if (entry
->gid
>= 1 << CRAMFS_GID_WIDTH
)
348 /* TODO: We ought to replace with a default
349 gid instead of truncating; otherwise there
350 are security problems. Maybe mode should
351 be &= ~070. Same goes for uid once Linux
352 supports >16-bit uids. */
354 size
= sizeof(struct cramfs_inode
) + ((namelen
+ 3) & ~3);
356 if (S_ISDIR(st
.st_mode
)) {
357 entry
->size
= parse_directory(root_entry
, path
, &entry
->child
, fslen_ub
);
358 } else if (S_ISREG(st
.st_mode
)) {
359 entry
->path
= xstrdup(path
);
361 if (entry
->size
>= (1 << CRAMFS_SIZE_WIDTH
)) {
363 entry
->size
= (1 << CRAMFS_SIZE_WIDTH
) - 1;
366 } else if (S_ISLNK(st
.st_mode
)) {
367 entry
->path
= xstrdup(path
);
368 } else if (S_ISFIFO(st
.st_mode
) || S_ISSOCK(st
.st_mode
)) {
369 /* maybe we should skip sockets */
372 entry
->size
= st
.st_rdev
;
373 if (entry
->size
& -(1<<CRAMFS_SIZE_WIDTH
))
377 if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
378 int blocks
= ((entry
->size
- 1) / blksize
+ 1);
380 /* block pointers & data expansion allowance + data */
382 *fslen_ub
+= (4+26)*blocks
+ entry
->size
+ 3;
385 /* Link it into the list */
391 free(dirlist
); /* allocated by scandir() with malloc() */
395 /* Returns sizeof(struct cramfs_super), which includes the root inode. */
396 static unsigned int write_superblock(struct entry
*root
, char *base
, int size
)
398 struct cramfs_super
*super
= (struct cramfs_super
*) base
;
399 unsigned int offset
= sizeof(struct cramfs_super
) + image_length
;
405 super
->magic
= CRAMFS_MAGIC
;
406 super
->flags
= CRAMFS_FLAG_FSID_VERSION_2
| CRAMFS_FLAG_SORTED_DIRS
;
408 super
->flags
|= CRAMFS_FLAG_HOLES
;
409 if (image_length
> 0)
410 super
->flags
|= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET
;
412 memcpy(super
->signature
, CRAMFS_SIGNATURE
, sizeof(super
->signature
));
414 super
->fsid
.crc
= crc32(0L, Z_NULL
, 0);
415 super
->fsid
.edition
= opt_edition
;
416 super
->fsid
.blocks
= total_blocks
;
417 super
->fsid
.files
= total_nodes
;
419 memset(super
->name
, 0x00, sizeof(super
->name
));
421 strncpy((char *)super
->name
, opt_name
, sizeof(super
->name
));
423 strncpy((char *)super
->name
, "Compressed", sizeof(super
->name
));
425 super
->root
.mode
= root
->mode
;
426 super
->root
.uid
= root
->uid
;
427 super
->root
.gid
= root
->gid
;
428 super
->root
.size
= root
->size
;
429 super
->root
.offset
= offset
>> 2;
431 super_toggle_endianness(cramfs_is_big_endian
, super
);
432 inode_from_host(cramfs_is_big_endian
, &super
->root
, &super
->root
);
437 static void set_data_offset(struct entry
*entry
, char *base
, unsigned long offset
)
439 struct cramfs_inode
*inode
= (struct cramfs_inode
*) (base
+ entry
->dir_offset
);
440 inode_to_host(cramfs_is_big_endian
, inode
, inode
);
441 if (offset
>= (1 << (2 + CRAMFS_OFFSET_WIDTH
)))
442 errx(MKFS_EX_ERROR
, _("filesystem too big. Exiting."));
443 inode
->offset
= (offset
>> 2);
444 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
449 * We do a width-first printout of the directory
450 * entries, using a stack to remember the directories
453 static unsigned int write_directory_structure(struct entry
*entry
, char *base
, unsigned int offset
)
455 int stack_entries
= 0;
457 struct entry
**entry_stack
;
459 entry_stack
= xmalloc(stack_size
* sizeof(struct entry
*));
462 int dir_start
= stack_entries
;
464 struct cramfs_inode
*inode
=
465 (struct cramfs_inode
*) (base
+ offset
);
466 size_t len
= strlen((const char *)entry
->name
);
468 entry
->dir_offset
= offset
;
470 inode
->mode
= entry
->mode
;
471 inode
->uid
= entry
->uid
;
472 inode
->gid
= entry
->gid
;
473 inode
->size
= entry
->size
;
475 /* Non-empty directories, regfiles and symlinks will
476 write over inode->offset later. */
478 offset
+= sizeof(struct cramfs_inode
);
479 total_nodes
++; /* another node */
480 memcpy(base
+ offset
, entry
->name
, len
);
481 /* Pad up the name to a 4-byte boundary */
483 *(base
+ offset
+ len
) = '\0';
486 inode
->namelen
= len
>> 2;
490 printf(" %s\n", entry
->name
);
492 if (stack_entries
>= stack_size
) {
494 entry_stack
= xrealloc(entry_stack
, stack_size
* sizeof(struct entry
*));
496 entry_stack
[stack_entries
] = entry
;
499 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
504 * Reverse the order the stack entries pushed during
505 * this directory, for a small optimization of disk
506 * access in the created fs. This change makes things
510 struct entry
**lo
= entry_stack
+ dir_start
;
511 struct entry
**hi
= entry_stack
+ stack_entries
;
521 /* Pop a subdirectory entry from the stack, and recurse. */
525 entry
= entry_stack
[stack_entries
];
527 set_data_offset(entry
, base
, offset
);
529 printf("'%s':\n", entry
->name
);
530 entry
= entry
->child
;
536 static int is_zero(unsigned char const *begin
, unsigned len
)
539 /* Returns non-zero iff the first LEN bytes from BEGIN are
541 return (len
-- == 0 ||
549 memcmp(begin
, begin
+ 4, len
) == 0))))))));
551 /* Never create holes. */
556 * One 4-byte pointer per block and then the actual blocked
557 * output. The first block does not need an offset pointer,
558 * as it will start immediately after the pointer block;
559 * so the i'th pointer points to the end of the i'th block
560 * (i.e. the start of the (i+1)'th block or past EOF).
562 * Note that size > 0, as a zero-sized file wouldn't ever
563 * have gotten here in the first place.
566 do_compress(char *base
, unsigned int offset
, unsigned char const *name
,
567 char *path
, unsigned int size
, unsigned int mode
)
569 unsigned long original_size
, original_offset
, new_size
, blocks
, curr
;
574 /* get uncompressed data */
575 start
= do_mmap(path
, size
, mode
);
580 original_size
= size
;
581 original_offset
= offset
;
582 blocks
= (size
- 1) / blksize
+ 1;
583 curr
= offset
+ 4 * blocks
;
585 total_blocks
+= blocks
;
588 uLongf len
= 2 * blksize
;
593 if (!is_zero (p
, input
)) {
594 compress((Bytef
*)(base
+ curr
), &len
, p
, input
);
599 if (len
> blksize
*2) {
600 /* (I don't think this can happen with zlib.) */
601 printf(_("AIEEE: block \"compressed\" to > "
602 "2*blocklength (%ld)\n"),
607 *(uint32_t *) (base
+ offset
) = u32_toggle_endianness(cramfs_is_big_endian
, curr
);
611 do_munmap(start
, original_size
, mode
);
613 curr
= (curr
+ 3) & ~3;
614 new_size
= curr
- original_offset
;
615 /* TODO: Arguably, original_size in these 2 lines should be
616 st_blocks * 512. But if you say that, then perhaps
617 administrative data should also be included in both. */
618 change
= new_size
- original_size
;
620 printf(_("%6.2f%% (%+ld bytes)\t%s\n"),
621 (change
* 100) / (double) original_size
, change
, name
);
628 * Traverse the entry tree, writing data for every item that has
629 * non-null entry->path (i.e. every symlink and non-empty
633 write_data(struct entry
*entry
, char *base
, unsigned int offset
) {
636 for (e
= entry
; e
; e
= e
->next
) {
639 set_data_offset(e
, base
, e
->same
->offset
);
640 e
->offset
= e
->same
->offset
;
641 } else if (e
->size
) {
642 set_data_offset(e
, base
, offset
);
644 offset
= do_compress(base
, offset
, e
->name
,
645 e
->path
, e
->size
,e
->mode
);
648 offset
= write_data(e
->child
, base
, offset
);
653 static unsigned int write_file(char *file
, char *base
, unsigned int offset
)
658 fd
= open(file
, O_RDONLY
);
660 err(MKFS_EX_ERROR
, _("cannot open file %s"), file
);
661 buf
= mmap(NULL
, image_length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
662 memcpy(base
+ offset
, buf
, image_length
);
663 munmap(buf
, image_length
);
665 err(MKFS_EX_ERROR
, _("cannot close file %s"), file
);
666 /* Pad up the image_length to a 4-byte boundary */
667 while (image_length
& 3) {
668 *(base
+ offset
+ image_length
) = '\0';
671 return (offset
+ image_length
);
675 * Maximum size fs you can create is roughly 256MB. (The last file's
676 * data must begin within 256MB boundary but can extend beyond that.)
678 * Note that if you want it to fit in a ROM then you're limited to what the
679 * hardware and kernel can support (64MB?).
683 return (((1 << CRAMFS_OFFSET_WIDTH
) - 1) << 2) /* offset */
684 + (1 << CRAMFS_SIZE_WIDTH
) - 1 /* filesize */
685 + (1 << CRAMFS_SIZE_WIDTH
) * 4 / blksize
; /* block pointers */
691 * mkcramfs directory-name outfile
693 * where "directory-name" is simply the root of the directory
694 * tree that we want to generate a compressed filesystem out
697 int main(int argc
, char **argv
)
699 struct stat st
; /* used twice... */
700 struct entry
*root_entry
;
702 ssize_t offset
, written
;
704 /* initial guess (upper-bound) of required filesystem size */
705 loff_t fslen_ub
= sizeof(struct cramfs_super
);
706 unsigned int fslen_max
;
707 char const *dirname
, *outfile
;
708 uint32_t crc
= crc32(0L, Z_NULL
, 0);
710 cramfs_is_big_endian
= HOST_IS_BIG_ENDIAN
; /* default is to use host order */
712 blksize
= getpagesize();
715 setlocale(LC_ALL
, "");
716 bindtextdomain(PACKAGE
, LOCALEDIR
);
718 atexit(close_stdout
);
720 /* command line options */
721 while ((c
= getopt(argc
, argv
, "hb:Ee:i:n:N:psVvz")) != EOF
) {
726 blksize
= strtou32_or_err(optarg
, _("invalid blocksize argument"));
732 opt_edition
= strtou32_or_err(optarg
, _("edition number argument failed"));
735 if (strcmp(optarg
, "big") == 0)
736 cramfs_is_big_endian
= 1;
737 else if (strcmp(optarg
, "little") == 0)
738 cramfs_is_big_endian
= 0;
739 else if (strcmp(optarg
, "host") == 0)
742 errx(MKFS_EX_USAGE
, _("invalid endianness given."
743 " Must be 'big', 'little', or 'host'"));
747 if (lstat(opt_image
, &st
) < 0)
748 err(MKFS_EX_USAGE
, _("cannot stat %s"), opt_image
);
749 image_length
= st
.st_size
; /* may be padded later */
750 fslen_ub
+= (image_length
+ 3); /* 3 is for padding */
757 fslen_ub
+= PAD_SIZE
;
760 /* old option, ignored */
763 printf(_("%s from %s\n"),
764 program_invocation_short_name
, PACKAGE_STRING
);
775 if ((argc
- optind
) != 2)
776 usage(MKFS_EX_USAGE
);
777 dirname
= argv
[optind
];
778 outfile
= argv
[optind
+ 1];
780 if (stat(dirname
, &st
) < 0)
781 err(MKFS_EX_USAGE
, _("cannot stat %s"), dirname
);
782 fd
= open(outfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
784 err(MKFS_EX_USAGE
, _("cannot open %s"), outfile
);
786 root_entry
= xcalloc(1, sizeof(struct entry
));
787 root_entry
->mode
= st
.st_mode
;
788 root_entry
->uid
= st
.st_uid
;
789 root_entry
->gid
= st
.st_gid
;
791 root_entry
->size
= parse_directory(root_entry
, dirname
, &root_entry
->child
, &fslen_ub
);
793 /* find duplicate files */
794 eliminate_doubles(root_entry
,root_entry
, &fslen_ub
);
796 /* always allocate a multiple of blksize bytes because that's
797 what we're going to write later on */
798 fslen_ub
= ((fslen_ub
- 1) | (blksize
- 1)) + 1;
799 fslen_max
= maxfslen();
801 if (fslen_ub
> fslen_max
) {
802 warnx( _("warning: guestimate of required size (upper bound) "
803 "is %lldMB, but maximum image size is %uMB. "
804 "We might die prematurely."),
805 (long long)fslen_ub
>> 20,
807 fslen_ub
= fslen_max
;
810 /* TODO: Why do we use a private/anonymous mapping here
811 followed by a write below, instead of just a shared mapping
812 and a couple of ftruncate calls? Is it just to save us
813 having to deal with removing the file afterwards? If we
814 really need this huge anonymous mapping, we ought to mmap
815 in smaller chunks, so that the user doesn't need nn MB of
816 RAM free. If the reason is to be able to write to
817 un-mmappable block devices, then we could try shared mmap
818 and revert to anonymous mmap if the shared mmap fails. */
819 rom_image
= mmap(NULL
,
821 PROT_READ
| PROT_WRITE
,
822 MAP_PRIVATE
| MAP_ANONYMOUS
,
825 if (-1 == (int) (long) rom_image
)
826 err(MKFS_EX_ERROR
, _("ROM image map"));
828 /* Skip the first opt_pad bytes for boot loader code */
830 memset(rom_image
, 0x00, opt_pad
);
832 /* Skip the superblock and come back to write it later. */
833 offset
+= sizeof(struct cramfs_super
);
835 /* Insert a file image. */
838 printf(_("Including: %s\n"), opt_image
);
839 offset
= write_file(opt_image
, rom_image
, offset
);
842 offset
= write_directory_structure(root_entry
->child
, rom_image
, offset
);
844 printf(_("Directory data: %zd bytes\n"), offset
);
846 offset
= write_data(root_entry
, rom_image
, offset
);
848 /* We always write a multiple of blksize bytes, so that
850 offset
= ((offset
- 1) | (blksize
- 1)) + 1;
852 printf(_("Everything: %zd kilobytes\n"), offset
>> 10);
854 /* Write the superblock now that we can fill in all of the fields. */
855 write_superblock(root_entry
, rom_image
+opt_pad
, offset
);
857 printf(_("Super block: %zd bytes\n"),
858 sizeof(struct cramfs_super
));
860 /* Put the checksum in. */
861 crc
= crc32(crc
, (unsigned char *) (rom_image
+opt_pad
), (offset
-opt_pad
));
862 ((struct cramfs_super
*) (rom_image
+opt_pad
))->fsid
.crc
= u32_toggle_endianness(cramfs_is_big_endian
, crc
);
864 printf(_("CRC: %x\n"), crc
);
866 /* Check to make sure we allocated enough space. */
867 if (fslen_ub
< offset
)
869 _("not enough space allocated for ROM image "
870 "(%lld allocated, %zu used)"),
871 (long long) fslen_ub
, offset
);
873 written
= write(fd
, rom_image
, offset
);
876 err(MKFS_EX_ERROR
, _("ROM image"));
877 if (offset
!= written
)
878 errx(MKFS_EX_ERROR
, _("ROM image write failed (%zd %zd)"),
882 * (These warnings used to come at the start, but they scroll off
883 * the screen too quickly.)
886 /* Can't happen when reading from ext2fs. */
887 /* Bytes, not chars: think UTF8. */
888 warnx(_("warning: filenames truncated to 255 bytes."));
890 warnx(_("warning: files were skipped due to errors."));
892 warnx(_("warning: file sizes truncated to %luMB "
893 "(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH
- 20));
895 /* (not possible with current Linux versions) */
896 warnx(_("warning: uids truncated to %u bits. "
897 "(This may be a security concern.)"), CRAMFS_UID_WIDTH
);
899 warnx(_("warning: gids truncated to %u bits. "
900 "(This may be a security concern.)"), CRAMFS_GID_WIDTH
);
902 warnx(_("WARNING: device numbers truncated to %u bits. "
903 "This almost certainly means\n"
904 "that some device files will be wrong."),
905 CRAMFS_OFFSET_WIDTH
);
907 (warn_namelen
|warn_skip
|warn_size
|warn_uid
|warn_gid
|warn_dev
))