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>
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
= 0; /* settable via -b option, default page size */
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) {
155 warn(_("readlink failed: %s"), path
);
162 fd
= open(path
, O_RDONLY
);
164 warn(_("cannot open %s"), path
);
169 start
= mmap(NULL
, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
171 if (start
== MAP_FAILED
)
172 err(MKFS_EX_ERROR
, "mmap");
180 do_munmap(char *start
, unsigned int size
, unsigned int mode
){
187 /* compute md5sums, so that we do not have to compare every pair of files */
189 mdfile(struct entry
*e
) {
193 start
= do_mmap(e
->path
, e
->size
, e
->mode
);
195 e
->flags
|= CRAMFS_EFLAG_INVALID
;
198 MD5Update(&ctx
, (unsigned char *) start
, e
->size
);
199 MD5Final(e
->md5sum
, &ctx
);
201 do_munmap(start
, e
->size
, e
->mode
);
203 e
->flags
|= CRAMFS_EFLAG_MD5
;
207 /* md5 digests are equal; files are almost certainly the same,
208 but just to be sure, do the comparison */
210 identical_file(struct entry
*e1
, struct entry
*e2
){
211 char *start1
, *start2
;
214 start1
= do_mmap(e1
->path
, e1
->size
, e1
->mode
);
217 start2
= do_mmap(e2
->path
, e2
->size
, e2
->mode
);
219 do_munmap(start1
, e1
->size
, e1
->mode
);
222 equal
= !memcmp(start1
, start2
, e1
->size
);
223 do_munmap(start1
, e1
->size
, e1
->mode
);
224 do_munmap(start2
, e2
->size
, e2
->mode
);
229 * The longest file name component to allow for in the input directory tree.
230 * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems
231 * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
232 * >255-byte names in the input directory tree given that such names get
233 * truncated to 255 bytes when written to cramfs.
235 #define MAX_INPUT_NAMELEN 255
237 static int find_identical_file(struct entry
*orig
, struct entry
*new, loff_t
*fslen_ub
)
243 if (orig
->size
== new->size
&& orig
->path
) {
249 if ((orig
->flags
& CRAMFS_EFLAG_MD5
) &&
250 (new->flags
& CRAMFS_EFLAG_MD5
) &&
251 !memcmp(orig
->md5sum
, new->md5sum
, MD5LENGTH
) &&
252 identical_file(orig
, new)) {
254 *fslen_ub
-= new->size
;
258 return find_identical_file(orig
->child
, new, fslen_ub
) ||
259 find_identical_file(orig
->next
, new, fslen_ub
);
262 static void eliminate_doubles(struct entry
*root
, struct entry
*orig
, loff_t
*fslen_ub
) {
264 if (orig
->size
&& orig
->path
)
265 find_identical_file(root
,orig
, fslen_ub
);
266 eliminate_doubles(root
,orig
->child
, fslen_ub
);
267 eliminate_doubles(root
,orig
->next
, fslen_ub
);
272 * We define our own sorting function instead of using alphasort which
273 * uses strcoll and changes ordering based on locale information.
275 static int cramsort (const struct dirent
**a
, const struct dirent
**b
)
277 return strcmp((*a
)->d_name
, (*b
)->d_name
);
280 static unsigned int parse_directory(struct entry
*root_entry
, const char *name
, struct entry
**prev
, loff_t
*fslen_ub
)
282 struct dirent
**dirlist
;
283 int totalsize
= 0, dircount
, dirindex
;
284 char *path
, *endpath
;
285 size_t len
= strlen(name
);
287 /* Set up the path. */
288 /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
289 path
= xmalloc(len
+ 1 + MAX_INPUT_NAMELEN
+ 1);
290 memcpy(path
, name
, len
);
291 endpath
= path
+ len
;
295 /* read in the directory and sort */
296 dircount
= scandir(name
, &dirlist
, 0, cramsort
);
299 err(MKFS_EX_ERROR
, _("could not read directory %s"), name
);
301 /* process directory */
302 for (dirindex
= 0; dirindex
< dircount
; dirindex
++) {
303 struct dirent
*dirent
;
309 dirent
= dirlist
[dirindex
];
311 /* Ignore "." and ".." - we won't be adding them
313 if (dirent
->d_name
[0] == '.') {
314 if (dirent
->d_name
[1] == '\0')
316 if (dirent
->d_name
[1] == '.') {
317 if (dirent
->d_name
[2] == '\0')
321 namelen
= strlen(dirent
->d_name
);
322 if (namelen
> MAX_INPUT_NAMELEN
) {
323 namelen
= MAX_INPUT_NAMELEN
;
327 memcpy(endpath
, dirent
->d_name
, namelen
+ 1);
329 if (lstat(path
, &st
) < 0) {
330 warn(_("stat of %s failed"), endpath
);
334 entry
= xcalloc(1, sizeof(struct entry
));
335 entry
->name
= (unsigned char *)xstrndup(dirent
->d_name
, namelen
);
336 entry
->mode
= st
.st_mode
;
337 entry
->size
= st
.st_size
;
338 entry
->uid
= st
.st_uid
;
339 if (entry
->uid
>= 1 << CRAMFS_UID_WIDTH
)
341 entry
->gid
= st
.st_gid
;
342 if (entry
->gid
>= 1 << CRAMFS_GID_WIDTH
)
343 /* TODO: We ought to replace with a default
344 gid instead of truncating; otherwise there
345 are security problems. Maybe mode should
346 be &= ~070. Same goes for uid once Linux
347 supports >16-bit uids. */
349 size
= sizeof(struct cramfs_inode
) + ((namelen
+ 3) & ~3);
351 if (S_ISDIR(st
.st_mode
)) {
352 entry
->size
= parse_directory(root_entry
, path
, &entry
->child
, fslen_ub
);
353 } else if (S_ISREG(st
.st_mode
)) {
354 entry
->path
= xstrdup(path
);
356 if (entry
->size
>= (1 << CRAMFS_SIZE_WIDTH
)) {
358 entry
->size
= (1 << CRAMFS_SIZE_WIDTH
) - 1;
361 } else if (S_ISLNK(st
.st_mode
)) {
362 entry
->path
= xstrdup(path
);
363 } else if (S_ISFIFO(st
.st_mode
) || S_ISSOCK(st
.st_mode
)) {
364 /* maybe we should skip sockets */
367 entry
->size
= st
.st_rdev
;
368 if (entry
->size
& -(1<<CRAMFS_SIZE_WIDTH
))
372 if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
373 int blocks
= ((entry
->size
- 1) / blksize
+ 1);
375 /* block pointers & data expansion allowance + data */
377 *fslen_ub
+= (4+26)*blocks
+ entry
->size
+ 3;
380 /* Link it into the list */
386 free(dirlist
); /* allocated by scandir() with malloc() */
390 /* Returns sizeof(struct cramfs_super), which includes the root inode. */
391 static unsigned int write_superblock(struct entry
*root
, char *base
, int size
)
393 struct cramfs_super
*super
= (struct cramfs_super
*) base
;
394 unsigned int offset
= sizeof(struct cramfs_super
) + image_length
;
400 super
->magic
= CRAMFS_MAGIC
;
401 super
->flags
= CRAMFS_FLAG_FSID_VERSION_2
| CRAMFS_FLAG_SORTED_DIRS
;
403 super
->flags
|= CRAMFS_FLAG_HOLES
;
404 if (image_length
> 0)
405 super
->flags
|= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET
;
407 memcpy(super
->signature
, CRAMFS_SIGNATURE
, sizeof(super
->signature
));
409 super
->fsid
.crc
= crc32(0L, Z_NULL
, 0);
410 super
->fsid
.edition
= opt_edition
;
411 super
->fsid
.blocks
= total_blocks
;
412 super
->fsid
.files
= total_nodes
;
414 memset(super
->name
, 0x00, sizeof(super
->name
));
416 strncpy((char *)super
->name
, opt_name
, sizeof(super
->name
));
418 strncpy((char *)super
->name
, "Compressed", sizeof(super
->name
));
420 super
->root
.mode
= root
->mode
;
421 super
->root
.uid
= root
->uid
;
422 super
->root
.gid
= root
->gid
;
423 super
->root
.size
= root
->size
;
424 super
->root
.offset
= offset
>> 2;
426 super_toggle_endianness(cramfs_is_big_endian
, super
);
427 inode_from_host(cramfs_is_big_endian
, &super
->root
, &super
->root
);
432 static void set_data_offset(struct entry
*entry
, char *base
, unsigned long offset
)
434 struct cramfs_inode
*inode
= (struct cramfs_inode
*) (base
+ entry
->dir_offset
);
435 inode_to_host(cramfs_is_big_endian
, inode
, inode
);
436 if (offset
>= (1 << (2 + CRAMFS_OFFSET_WIDTH
)))
437 errx(MKFS_EX_ERROR
, _("filesystem too big. Exiting."));
438 inode
->offset
= (offset
>> 2);
439 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
444 * We do a width-first printout of the directory
445 * entries, using a stack to remember the directories
448 static unsigned int write_directory_structure(struct entry
*entry
, char *base
, unsigned int offset
)
450 int stack_entries
= 0;
452 struct entry
**entry_stack
;
454 entry_stack
= xmalloc(stack_size
* sizeof(struct entry
*));
457 int dir_start
= stack_entries
;
459 struct cramfs_inode
*inode
=
460 (struct cramfs_inode
*) (base
+ offset
);
461 size_t len
= strlen((const char *)entry
->name
);
463 entry
->dir_offset
= offset
;
465 inode
->mode
= entry
->mode
;
466 inode
->uid
= entry
->uid
;
467 inode
->gid
= entry
->gid
;
468 inode
->size
= entry
->size
;
470 /* Non-empty directories, regfiles and symlinks will
471 write over inode->offset later. */
473 offset
+= sizeof(struct cramfs_inode
);
474 total_nodes
++; /* another node */
475 memcpy(base
+ offset
, entry
->name
, len
);
476 /* Pad up the name to a 4-byte boundary */
478 *(base
+ offset
+ len
) = '\0';
481 inode
->namelen
= len
>> 2;
485 printf(" %s\n", entry
->name
);
487 if (stack_entries
>= stack_size
) {
489 entry_stack
= xrealloc(entry_stack
, stack_size
* sizeof(struct entry
*));
491 entry_stack
[stack_entries
] = entry
;
494 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
499 * Reverse the order the stack entries pushed during
500 * this directory, for a small optimization of disk
501 * access in the created fs. This change makes things
505 struct entry
**lo
= entry_stack
+ dir_start
;
506 struct entry
**hi
= entry_stack
+ stack_entries
;
516 /* Pop a subdirectory entry from the stack, and recurse. */
520 entry
= entry_stack
[stack_entries
];
522 set_data_offset(entry
, base
, offset
);
524 printf("'%s':\n", entry
->name
);
525 entry
= entry
->child
;
531 static int is_zero(unsigned char const *begin
, unsigned len
)
534 /* Returns non-zero iff the first LEN bytes from BEGIN are
536 return (len
-- == 0 ||
544 memcmp(begin
, begin
+ 4, len
) == 0))))))));
546 /* Never create holes. */
551 * One 4-byte pointer per block and then the actual blocked
552 * output. The first block does not need an offset pointer,
553 * as it will start immediately after the pointer block;
554 * so the i'th pointer points to the end of the i'th block
555 * (i.e. the start of the (i+1)'th block or past EOF).
557 * Note that size > 0, as a zero-sized file wouldn't ever
558 * have gotten here in the first place.
561 do_compress(char *base
, unsigned int offset
, unsigned char const *name
,
562 char *path
, unsigned int size
, unsigned int mode
)
564 unsigned long original_size
, original_offset
, new_size
, blocks
, curr
;
569 /* get uncompressed data */
570 start
= do_mmap(path
, size
, mode
);
575 original_size
= size
;
576 original_offset
= offset
;
577 blocks
= (size
- 1) / blksize
+ 1;
578 curr
= offset
+ 4 * blocks
;
580 total_blocks
+= blocks
;
583 uLongf len
= 2 * blksize
;
588 if (!is_zero (p
, input
)) {
589 compress((Bytef
*)(base
+ curr
), &len
, p
, input
);
594 if (len
> blksize
*2) {
595 /* (I don't think this can happen with zlib.) */
596 printf(_("AIEEE: block \"compressed\" to > "
597 "2*blocklength (%ld)\n"),
602 *(uint32_t *) (base
+ offset
) = u32_toggle_endianness(cramfs_is_big_endian
, curr
);
606 do_munmap(start
, original_size
, mode
);
608 curr
= (curr
+ 3) & ~3;
609 new_size
= curr
- original_offset
;
610 /* TODO: Arguably, original_size in these 2 lines should be
611 st_blocks * 512. But if you say that, then perhaps
612 administrative data should also be included in both. */
613 change
= new_size
- original_size
;
615 printf(_("%6.2f%% (%+ld bytes)\t%s\n"),
616 (change
* 100) / (double) original_size
, change
, name
);
623 * Traverse the entry tree, writing data for every item that has
624 * non-null entry->path (i.e. every symlink and non-empty
628 write_data(struct entry
*entry
, char *base
, unsigned int offset
) {
631 for (e
= entry
; e
; e
= e
->next
) {
634 set_data_offset(e
, base
, e
->same
->offset
);
635 e
->offset
= e
->same
->offset
;
636 } else if (e
->size
) {
637 set_data_offset(e
, base
, offset
);
639 offset
= do_compress(base
, offset
, e
->name
,
640 e
->path
, e
->size
,e
->mode
);
643 offset
= write_data(e
->child
, base
, offset
);
648 static unsigned int write_file(char *file
, char *base
, unsigned int offset
)
653 fd
= open(file
, O_RDONLY
);
655 err(MKFS_EX_ERROR
, _("cannot open %s"), file
);
656 buf
= mmap(NULL
, image_length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
657 memcpy(base
+ offset
, buf
, image_length
);
658 munmap(buf
, image_length
);
660 err(MKFS_EX_ERROR
, _("cannot close file %s"), file
);
661 /* Pad up the image_length to a 4-byte boundary */
662 while (image_length
& 3) {
663 *(base
+ offset
+ image_length
) = '\0';
666 return (offset
+ image_length
);
670 * Maximum size fs you can create is roughly 256MB. (The last file's
671 * data must begin within 256MB boundary but can extend beyond that.)
673 * Note that if you want it to fit in a ROM then you're limited to what the
674 * hardware and kernel can support (64MB?).
678 return (((1 << CRAMFS_OFFSET_WIDTH
) - 1) << 2) /* offset */
679 + (1 << CRAMFS_SIZE_WIDTH
) - 1 /* filesize */
680 + (1 << CRAMFS_SIZE_WIDTH
) * 4 / blksize
; /* block pointers */
686 * mkcramfs directory-name outfile
688 * where "directory-name" is simply the root of the directory
689 * tree that we want to generate a compressed filesystem out
692 int main(int argc
, char **argv
)
694 struct stat st
; /* used twice... */
695 struct entry
*root_entry
;
697 ssize_t offset
, written
;
699 /* initial guess (upper-bound) of required filesystem size */
700 loff_t fslen_ub
= sizeof(struct cramfs_super
);
701 unsigned int fslen_max
;
702 char const *dirname
, *outfile
;
703 uint32_t crc
= crc32(0L, Z_NULL
, 0);
705 cramfs_is_big_endian
= HOST_IS_BIG_ENDIAN
; /* default is to use host order */
709 setlocale(LC_ALL
, "");
710 bindtextdomain(PACKAGE
, LOCALEDIR
);
712 atexit(close_stdout
);
714 /* command line options */
715 while ((c
= getopt(argc
, argv
, "hb:Ee:i:n:N:psVvz")) != EOF
) {
720 blksize
= strtou32_or_err(optarg
, _("invalid blocksize argument"));
726 opt_edition
= strtou32_or_err(optarg
, _("invalid edition number argument"));
729 if (strcmp(optarg
, "big") == 0)
730 cramfs_is_big_endian
= 1;
731 else if (strcmp(optarg
, "little") == 0)
732 cramfs_is_big_endian
= 0;
733 else if (strcmp(optarg
, "host") == 0)
736 errx(MKFS_EX_USAGE
, _("invalid endianness given;"
737 " must be 'big', 'little', or 'host'"));
741 if (lstat(opt_image
, &st
) < 0)
742 err(MKFS_EX_USAGE
, _("stat of %s failed"), opt_image
);
743 image_length
= st
.st_size
; /* may be padded later */
744 fslen_ub
+= (image_length
+ 3); /* 3 is for padding */
751 fslen_ub
+= PAD_SIZE
;
754 /* old option, ignored */
757 printf(UTIL_LINUX_VERSION
);
766 usage(FSCK_EX_USAGE
);
770 if ((argc
- optind
) != 2)
771 usage(MKFS_EX_USAGE
);
772 dirname
= argv
[optind
];
773 outfile
= argv
[optind
+ 1];
776 blksize
= getpagesize();
778 if (stat(dirname
, &st
) < 0)
779 err(MKFS_EX_USAGE
, _("stat of %s failed"), dirname
);
780 fd
= open(outfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
782 err(MKFS_EX_USAGE
, _("cannot open %s"), outfile
);
784 root_entry
= xcalloc(1, sizeof(struct entry
));
785 root_entry
->mode
= st
.st_mode
;
786 root_entry
->uid
= st
.st_uid
;
787 root_entry
->gid
= st
.st_gid
;
789 root_entry
->size
= parse_directory(root_entry
, dirname
, &root_entry
->child
, &fslen_ub
);
791 /* find duplicate files */
792 eliminate_doubles(root_entry
,root_entry
, &fslen_ub
);
794 /* always allocate a multiple of blksize bytes because that's
795 what we're going to write later on */
796 fslen_ub
= ((fslen_ub
- 1) | (blksize
- 1)) + 1;
797 fslen_max
= maxfslen();
799 if (fslen_ub
> fslen_max
) {
800 warnx( _("warning: guestimate of required size (upper bound) "
801 "is %lldMB, but maximum image size is %uMB. "
802 "We might die prematurely."),
803 (long long)fslen_ub
>> 20,
805 fslen_ub
= fslen_max
;
808 /* TODO: Why do we use a private/anonymous mapping here
809 followed by a write below, instead of just a shared mapping
810 and a couple of ftruncate calls? Is it just to save us
811 having to deal with removing the file afterwards? If we
812 really need this huge anonymous mapping, we ought to mmap
813 in smaller chunks, so that the user doesn't need nn MB of
814 RAM free. If the reason is to be able to write to
815 un-mmappable block devices, then we could try shared mmap
816 and revert to anonymous mmap if the shared mmap fails. */
817 rom_image
= mmap(NULL
,
819 PROT_READ
| PROT_WRITE
,
820 MAP_PRIVATE
| MAP_ANONYMOUS
,
823 if (-1 == (int) (long) rom_image
)
824 err(MKFS_EX_ERROR
, _("ROM image map"));
826 /* Skip the first opt_pad bytes for boot loader code */
828 memset(rom_image
, 0x00, opt_pad
);
830 /* Skip the superblock and come back to write it later. */
831 offset
+= sizeof(struct cramfs_super
);
833 /* Insert a file image. */
836 printf(_("Including: %s\n"), opt_image
);
837 offset
= write_file(opt_image
, rom_image
, offset
);
840 offset
= write_directory_structure(root_entry
->child
, rom_image
, offset
);
842 printf(_("Directory data: %zd bytes\n"), offset
);
844 offset
= write_data(root_entry
, rom_image
, offset
);
846 /* We always write a multiple of blksize bytes, so that
848 offset
= ((offset
- 1) | (blksize
- 1)) + 1;
850 printf(_("Everything: %zd kilobytes\n"), offset
>> 10);
852 /* Write the superblock now that we can fill in all of the fields. */
853 write_superblock(root_entry
, rom_image
+opt_pad
, offset
);
855 printf(_("Super block: %zd bytes\n"),
856 sizeof(struct cramfs_super
));
858 /* Put the checksum in. */
859 crc
= crc32(crc
, (unsigned char *) (rom_image
+opt_pad
), (offset
-opt_pad
));
860 ((struct cramfs_super
*) (rom_image
+opt_pad
))->fsid
.crc
= u32_toggle_endianness(cramfs_is_big_endian
, crc
);
862 printf(_("CRC: %x\n"), crc
);
864 /* Check to make sure we allocated enough space. */
865 if (fslen_ub
< offset
)
867 _("not enough space allocated for ROM image "
868 "(%lld allocated, %zu used)"),
869 (long long) fslen_ub
, offset
);
871 written
= write(fd
, rom_image
, offset
);
872 if (offset
!= written
)
873 errx(MKFS_EX_ERROR
, _("ROM image write failed (%zd %zd)"),
875 if (close_fd(fd
) != 0)
876 err(MKFS_EX_ERROR
, _("ROM image"));
879 * (These warnings used to come at the start, but they scroll off
880 * the screen too quickly.)
883 /* Can't happen when reading from ext2fs. */
884 /* Bytes, not chars: think UTF8. */
885 warnx(_("warning: filenames truncated to %u bytes."), MAX_INPUT_NAMELEN
);
887 warnx(_("warning: files were skipped due to errors."));
889 warnx(_("warning: file sizes truncated to %luMB "
890 "(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH
- 20));
892 /* (not possible with current Linux versions) */
893 warnx(_("warning: uids truncated to %u bits. "
894 "(This may be a security concern.)"), CRAMFS_UID_WIDTH
);
896 warnx(_("warning: gids truncated to %u bits. "
897 "(This may be a security concern.)"), CRAMFS_GID_WIDTH
);
899 warnx(_("WARNING: device numbers truncated to %u bits. "
900 "This almost certainly means\n"
901 "that some device files will be wrong."),
902 CRAMFS_OFFSET_WIDTH
);
904 (warn_namelen
|warn_skip
|warn_size
|warn_uid
|warn_gid
|warn_dev
))