2 * SPDX-License-Identifier: GPL-2.0-or-later
4 * mkcramfs - make a cramfs file system
6 * Copyright (C) 1999-2002 Transmeta Corporation
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * Old version would die on largish filesystems. Change to mmap the
25 * files one by one instead of all simultaneously. - aeb, 2002-11-01
28 #include <sys/types.h>
42 /* We don't use our include/crc32.h, but crc32 from zlib!
44 * The zlib implementation performs pre/post-conditioning. The util-linux
45 * imlemenation requires post-conditioning (xor) in the applications.
54 #include "exitcodes.h"
57 #define CLOSE_EXIT_CODE MKFS_EX_ERROR
58 #include "closestream.h"
60 #define XALLOC_EXIT_CODE MKFS_EX_ERROR
63 /* The kernel only supports PAD_SIZE of 0 and 512. */
66 static int verbose
= 0;
68 static unsigned int blksize
= 0; /* settable via -b option, default page size */
69 static long total_blocks
= 0, total_nodes
= 1; /* pre-count the root node */
70 static int image_length
= 0;
71 static int cramfs_is_big_endian
= 0; /* target is big endian */
74 * If opt_holes is set, then mkcramfs can create explicit holes in the
75 * data, which saves 26 bytes per hole (which is a lot smaller a
76 * saving than for most filesystems).
78 * Note that kernels up to at least 2.3.39 don't support cramfs holes,
79 * which is why this is turned off by default.
81 static unsigned int opt_edition
= 0;
82 static int opt_errors
= 0;
83 static int opt_holes
= 0;
84 static int opt_pad
= 0;
85 static char *opt_image
= NULL
;
86 static char *opt_name
= NULL
;
88 static int warn_dev
= 0;
89 static int warn_gid
= 0;
90 static int warn_namelen
= 0;
91 static int warn_skip
= 0;
92 static int warn_size
= 0;
93 static int warn_uid
= 0;
96 #define CRAMFS_EFLAG_MD5 1
97 #define CRAMFS_EFLAG_INVALID 2
99 /* In-core version of inode / directory entry. */
103 unsigned int mode
, size
, uid
, gid
;
104 unsigned char md5sum
[UL_MD5LENGTH
];
105 unsigned char flags
; /* CRAMFS_EFLAG_* */
109 int fd
; /* temporarily open files while mmapped */
110 struct entry
*same
; /* points to other identical file */
111 unsigned int offset
; /* pointer to compressed data in archive */
112 unsigned int dir_offset
; /* offset of directory entry in archive */
115 struct entry
*child
; /* NULL for non-directory and empty dir */
120 * Width of various bitfields in struct cramfs_inode.
121 * Used only to generate warnings.
123 #define CRAMFS_SIZE_WIDTH 24
124 #define CRAMFS_UID_WIDTH 16
125 #define CRAMFS_GID_WIDTH 8
126 #define CRAMFS_OFFSET_WIDTH 26
128 static void __attribute__((__noreturn__
)) usage(void)
130 fputs(USAGE_HEADER
, stdout
);
131 fprintf(stdout
, _(" %s [-h] [-v] [-b blksize] [-e edition] [-N endian] [-i file] [-n name] dirname outfile\n"),
132 program_invocation_short_name
);
133 fputs(USAGE_SEPARATOR
, stdout
);
134 fputs(_("Make compressed ROM file system."), stdout
);
135 fputs(USAGE_OPTIONS
, stdout
);
136 fputs(_( " -v be verbose"), stdout
);
137 fputs(_( " -E make all warnings errors (non-zero exit status)"), stdout
);
138 fputs(_( " -b blksize use this blocksize, must equal page size"), stdout
);
139 fputs(_( " -e edition set edition number (part of fsid)"), stdout
);
140 fprintf(stdout
, _(" -N endian set cramfs endianness (%s|%s|%s), default %s\n"), "big", "little", "host", "host");
141 fputs(_( " -i file insert a file image into the filesystem"), stdout
);
142 fputs(_( " -n name set name of cramfs filesystem"), stdout
);
143 fprintf(stdout
, _(" -p pad by %d bytes for boot code\n"), PAD_SIZE
);
144 fputs(_( " -s sort directory entries (old option, ignored)"), stdout
);
145 fputs(_( " -z make explicit holes"), stdout
);
146 fputs(_( " -l[=<mode>] use exclusive device lock (yes, no or nonblock)"), stdout
);
147 fputs(_( " dirname root of the filesystem to be compressed"), stdout
);
148 fputs(_( " outfile output file"), stdout
);
149 fputs(USAGE_SEPARATOR
, stdout
);
150 fprintf(stdout
, USAGE_HELP_OPTIONS(16));
151 fprintf(stdout
, USAGE_MAN_TAIL("mkfs.cramfs(8)"));
156 do_mmap(char *path
, unsigned int size
, unsigned int mode
){
164 /* The link buffer is unnecessary to terminate by null as it's
165 * always used as buffer rather than a string */
166 start
= xmalloc(size
);
167 if (readlink(path
, start
, size
) < 0) {
168 warn(_("readlink failed: %s"), path
);
175 fd
= open(path
, O_RDONLY
);
177 warn(_("cannot open %s"), path
);
182 start
= mmap(NULL
, size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
184 if (start
== MAP_FAILED
)
185 err(MKFS_EX_ERROR
, "mmap");
193 do_munmap(char *start
, unsigned int size
, unsigned int mode
){
200 /* compute md5sums, so that we do not have to compare every pair of files */
202 mdfile(struct entry
*e
) {
205 start
= do_mmap(e
->path
, e
->size
, e
->mode
);
207 e
->flags
|= CRAMFS_EFLAG_INVALID
;
212 ul_MD5Update(&ctx
, (unsigned char *) start
, e
->size
);
213 ul_MD5Final(e
->md5sum
, &ctx
);
215 do_munmap(start
, e
->size
, e
->mode
);
217 e
->flags
|= CRAMFS_EFLAG_MD5
;
221 /* md5 digests are equal; files are almost certainly the same,
222 but just to be sure, do the comparison */
224 identical_file(struct entry
*e1
, struct entry
*e2
){
225 char *start1
, *start2
;
228 start1
= do_mmap(e1
->path
, e1
->size
, e1
->mode
);
231 start2
= do_mmap(e2
->path
, e2
->size
, e2
->mode
);
233 do_munmap(start1
, e1
->size
, e1
->mode
);
236 equal
= !memcmp(start1
, start2
, e1
->size
);
237 do_munmap(start1
, e1
->size
, e1
->mode
);
238 do_munmap(start2
, e2
->size
, e2
->mode
);
243 * The longest file name component to allow for in the input directory tree.
244 * Ext2fs (and many others) allow up to 255 bytes. A couple of filesystems
245 * allow longer (e.g. smbfs 1024), but there isn't much use in supporting
246 * >255-byte names in the input directory tree given that such names get
247 * truncated to 255 bytes when written to cramfs.
249 #define MAX_INPUT_NAMELEN 255
251 static int find_identical_file(struct entry
*orig
, struct entry
*new, loff_t
*fslen_ub
)
257 if (orig
->size
== new->size
&& orig
->path
) {
263 if ((orig
->flags
& CRAMFS_EFLAG_MD5
) &&
264 (new->flags
& CRAMFS_EFLAG_MD5
) &&
265 !memcmp(orig
->md5sum
, new->md5sum
, UL_MD5LENGTH
) &&
266 identical_file(orig
, new)) {
268 *fslen_ub
-= new->size
;
272 return find_identical_file(orig
->child
, new, fslen_ub
) ||
273 find_identical_file(orig
->next
, new, fslen_ub
);
276 static void eliminate_doubles(struct entry
*root
, struct entry
*orig
, loff_t
*fslen_ub
) {
278 if (orig
->size
&& orig
->path
)
279 find_identical_file(root
,orig
, fslen_ub
);
280 eliminate_doubles(root
,orig
->child
, fslen_ub
);
281 eliminate_doubles(root
,orig
->next
, fslen_ub
);
286 * We define our own sorting function instead of using alphasort which
287 * uses strcoll and changes ordering based on locale information.
289 static int cramsort (const struct dirent
**a
, const struct dirent
**b
)
291 return strcmp((*a
)->d_name
, (*b
)->d_name
);
294 static unsigned int parse_directory(struct entry
*root_entry
, const char *name
, struct entry
**prev
, loff_t
*fslen_ub
)
296 struct dirent
**dirlist
;
297 int totalsize
= 0, dircount
, dirindex
;
298 char *path
, *endpath
;
299 size_t len
= strlen(name
);
301 /* Set up the path. */
302 /* TODO: Reuse the parent's buffer to save memcpy'ing and duplication. */
303 path
= xmalloc(len
+ 1 + MAX_INPUT_NAMELEN
+ 1);
304 memcpy(path
, name
, len
);
305 endpath
= path
+ len
;
309 /* read in the directory and sort */
310 dircount
= scandir(name
, &dirlist
, NULL
, cramsort
);
313 err(MKFS_EX_ERROR
, _("could not read directory %s"), name
);
315 /* process directory */
316 for (dirindex
= 0; dirindex
< dircount
; dirindex
++) {
317 struct dirent
*dirent
;
323 dirent
= dirlist
[dirindex
];
325 /* Ignore "." and ".." - we won't be adding them
327 if (dirent
->d_name
[0] == '.') {
328 if (dirent
->d_name
[1] == '\0')
330 if (dirent
->d_name
[1] == '.' &&
331 dirent
->d_name
[2] == '\0')
334 namelen
= strlen(dirent
->d_name
);
335 if (namelen
> MAX_INPUT_NAMELEN
) {
336 namelen
= MAX_INPUT_NAMELEN
;
340 memcpy(endpath
, dirent
->d_name
, namelen
+ 1);
342 if (lstat(path
, &st
) < 0) {
343 warn(_("stat of %s failed"), endpath
);
347 entry
= xcalloc(1, sizeof(struct entry
));
348 entry
->name
= (unsigned char *)xstrndup(dirent
->d_name
, namelen
);
349 entry
->mode
= st
.st_mode
;
350 entry
->size
= st
.st_size
;
351 entry
->uid
= st
.st_uid
;
352 if (entry
->uid
>= 1 << CRAMFS_UID_WIDTH
)
354 entry
->gid
= st
.st_gid
;
355 if (entry
->gid
>= 1 << CRAMFS_GID_WIDTH
)
356 /* TODO: We ought to replace with a default
357 gid instead of truncating; otherwise there
358 are security problems. Maybe mode should
359 be &= ~070. Same goes for uid once Linux
360 supports >16-bit uids. */
362 size
= sizeof(struct cramfs_inode
) + ((namelen
+ 3) & ~3);
364 if (S_ISDIR(st
.st_mode
)) {
365 entry
->size
= parse_directory(root_entry
, path
, &entry
->child
, fslen_ub
);
366 } else if (S_ISREG(st
.st_mode
)) {
367 entry
->path
= xstrdup(path
);
368 if (entry
->size
>= (1 << CRAMFS_SIZE_WIDTH
)) {
370 entry
->size
= (1 << CRAMFS_SIZE_WIDTH
) - 1;
372 } else if (S_ISLNK(st
.st_mode
)) {
373 entry
->path
= xstrdup(path
);
374 } else if (S_ISFIFO(st
.st_mode
) || S_ISSOCK(st
.st_mode
)) {
375 /* maybe we should skip sockets */
378 entry
->size
= st
.st_rdev
;
379 if (entry
->size
& -(1<<CRAMFS_SIZE_WIDTH
))
383 if (S_ISREG(st
.st_mode
) || S_ISLNK(st
.st_mode
)) {
384 int blocks
= ((entry
->size
- 1) / blksize
+ 1);
386 /* block pointers & data expansion allowance + data */
388 *fslen_ub
+= (4+26)*blocks
+ entry
->size
+ 3;
391 /* Link it into the list */
397 free(dirlist
); /* allocated by scandir() with malloc() */
401 /* Returns sizeof(struct cramfs_super), which includes the root inode. */
402 static unsigned int write_superblock(struct entry
*root
, char *base
, int size
)
404 struct cramfs_super
*super
= (struct cramfs_super
*) base
;
405 unsigned int offset
= sizeof(struct cramfs_super
) + image_length
;
411 super
->magic
= CRAMFS_MAGIC
;
412 super
->flags
= CRAMFS_FLAG_FSID_VERSION_2
| CRAMFS_FLAG_SORTED_DIRS
;
414 super
->flags
|= CRAMFS_FLAG_HOLES
;
415 if (image_length
> 0)
416 super
->flags
|= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET
;
418 memcpy(super
->signature
, CRAMFS_SIGNATURE
, sizeof(super
->signature
));
420 super
->fsid
.crc
= crc32(0L, NULL
, 0);
421 super
->fsid
.edition
= opt_edition
;
422 super
->fsid
.blocks
= total_blocks
;
423 super
->fsid
.files
= total_nodes
;
425 memset(super
->name
, 0x00, sizeof(super
->name
));
427 str2memcpy((char *)super
->name
, opt_name
, sizeof(super
->name
));
429 str2memcpy((char *)super
->name
, "Compressed", sizeof(super
->name
));
431 super
->root
.mode
= root
->mode
;
432 super
->root
.uid
= root
->uid
;
433 super
->root
.gid
= root
->gid
;
434 super
->root
.size
= root
->size
;
435 super
->root
.offset
= offset
>> 2;
437 super_toggle_endianness(cramfs_is_big_endian
, super
);
438 inode_from_host(cramfs_is_big_endian
, &super
->root
, &super
->root
);
443 static void set_data_offset(struct entry
*entry
, char *base
, unsigned long offset
)
445 struct cramfs_inode
*inode
= (struct cramfs_inode
*) (base
+ entry
->dir_offset
);
446 inode_to_host(cramfs_is_big_endian
, inode
, inode
);
447 if (offset
>= (1 << (2 + CRAMFS_OFFSET_WIDTH
)))
448 errx(MKFS_EX_ERROR
, _("filesystem too big. Exiting."));
449 inode
->offset
= (offset
>> 2);
450 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
455 * We do a width-first printout of the directory
456 * entries, using a stack to remember the directories
459 static unsigned int write_directory_structure(struct entry
*entry
, char *base
, unsigned int offset
)
461 int stack_entries
= 0;
463 struct entry
**entry_stack
;
465 entry_stack
= xmalloc(stack_size
* sizeof(struct entry
*));
468 int dir_start
= stack_entries
;
470 struct cramfs_inode
*inode
=
471 (struct cramfs_inode
*) (base
+ offset
);
472 size_t len
= strlen((const char *)entry
->name
);
474 entry
->dir_offset
= offset
;
476 inode
->mode
= entry
->mode
;
477 inode
->uid
= entry
->uid
;
478 inode
->gid
= entry
->gid
;
479 inode
->size
= entry
->size
;
481 /* Non-empty directories, regfiles and symlinks will
482 write over inode->offset later. */
484 offset
+= sizeof(struct cramfs_inode
);
485 total_nodes
++; /* another node */
486 memcpy(base
+ offset
, entry
->name
, len
);
487 /* Pad up the name to a 4-byte boundary */
489 *(base
+ offset
+ len
) = '\0';
492 inode
->namelen
= len
>> 2;
496 printf(" %s\n", entry
->name
);
498 if (stack_entries
>= stack_size
) {
500 entry_stack
= xreallocarray(entry_stack
, stack_size
, sizeof(struct entry
*));
502 entry_stack
[stack_entries
] = entry
;
505 inode_from_host(cramfs_is_big_endian
, inode
, inode
);
510 * Reverse the order the stack entries pushed during
511 * this directory, for a small optimization of disk
512 * access in the created fs. This change makes things
516 struct entry
**lo
= entry_stack
+ dir_start
;
517 struct entry
**hi
= entry_stack
+ stack_entries
;
527 /* Pop a subdirectory entry from the stack, and recurse. */
531 entry
= entry_stack
[stack_entries
];
533 set_data_offset(entry
, base
, offset
);
535 printf("'%s':\n", entry
->name
);
536 entry
= entry
->child
;
542 static int is_zero(unsigned char const *begin
, unsigned len
)
545 /* Returns non-zero iff the first LEN bytes from BEGIN are
547 return (len
-- == 0 ||
555 memcmp(begin
, begin
+ 4, len
) == 0))))))));
557 /* Never create holes. */
562 * One 4-byte pointer per block and then the actual blocked
563 * output. The first block does not need an offset pointer,
564 * as it will start immediately after the pointer block;
565 * so the i'th pointer points to the end of the i'th block
566 * (i.e. the start of the (i+1)'th block or past EOF).
568 * Note that size > 0, as a zero-sized file wouldn't ever
569 * have gotten here in the first place.
572 do_compress(char *base
, unsigned int offset
, unsigned char const *name
,
573 char *path
, unsigned int size
, unsigned int mode
)
575 unsigned long original_size
, original_offset
, new_size
, blocks
, curr
;
580 /* get uncompressed data */
581 start
= do_mmap(path
, size
, mode
);
586 original_size
= size
;
587 original_offset
= offset
;
588 blocks
= (size
- 1) / blksize
+ 1;
589 curr
= offset
+ 4 * blocks
;
591 total_blocks
+= blocks
;
594 uLongf len
= 2 * blksize
;
599 if (!is_zero (p
, input
)) {
600 compress((Bytef
*)(base
+ curr
), &len
, p
, input
);
605 if (len
> blksize
*2) {
606 /* (I don't think this can happen with zlib.) */
607 printf(_("AIEEE: block \"compressed\" to > "
608 "2*blocklength (%ld)\n"),
613 *(uint32_t *) (base
+ offset
) = u32_toggle_endianness(cramfs_is_big_endian
, curr
);
617 do_munmap(start
, original_size
, mode
);
619 curr
= (curr
+ 3) & ~3;
620 new_size
= curr
- original_offset
;
621 /* TODO: Arguably, original_size in these 2 lines should be
622 st_blocks * 512. But if you say that, then perhaps
623 administrative data should also be included in both. */
624 change
= new_size
- original_size
;
626 printf(_("%6.2f%% (%+ld bytes)\t%s\n"),
627 (change
* 100) / (double) original_size
, change
, name
);
634 * Traverse the entry tree, writing data for every item that has
635 * non-null entry->path (i.e. every symlink and non-empty
639 write_data(struct entry
*entry
, char *base
, unsigned int offset
) {
642 for (e
= entry
; e
; e
= e
->next
) {
645 set_data_offset(e
, base
, e
->same
->offset
);
646 e
->offset
= e
->same
->offset
;
647 } else if (e
->size
) {
648 set_data_offset(e
, base
, offset
);
650 offset
= do_compress(base
, offset
, e
->name
,
651 e
->path
, e
->size
,e
->mode
);
654 offset
= write_data(e
->child
, base
, offset
);
659 static unsigned int write_file(char *file
, char *base
, unsigned int offset
)
664 fd
= open(file
, O_RDONLY
);
666 err(MKFS_EX_ERROR
, _("cannot open %s"), file
);
667 buf
= mmap(NULL
, image_length
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
668 memcpy(base
+ offset
, buf
, image_length
);
669 munmap(buf
, image_length
);
671 err(MKFS_EX_ERROR
, _("cannot close file %s"), file
);
672 /* Pad up the image_length to a 4-byte boundary */
673 while (image_length
& 3) {
674 *(base
+ offset
+ image_length
) = '\0';
677 return (offset
+ image_length
);
681 * Maximum size fs you can create is roughly 256MB. (The last file's
682 * data must begin within 256MB boundary but can extend beyond that.)
684 * Note that if you want it to fit in a ROM then you're limited to what the
685 * hardware and kernel can support (64MB?).
689 return (((1 << CRAMFS_OFFSET_WIDTH
) - 1) << 2) /* offset */
690 + (1 << CRAMFS_SIZE_WIDTH
) - 1 /* filesize */
691 + (1 << CRAMFS_SIZE_WIDTH
) * 4 / blksize
; /* block pointers */
697 * mkcramfs directory-name outfile
699 * where "directory-name" is simply the root of the directory
700 * tree that we want to generate a compressed filesystem out
703 int main(int argc
, char **argv
)
705 struct stat st
; /* used twice... */
706 struct entry
*root_entry
;
708 ssize_t offset
, written
;
710 /* initial guess (upper-bound) of required filesystem size */
711 loff_t fslen_ub
= sizeof(struct cramfs_super
);
712 unsigned int fslen_max
;
713 char const *dirname
, *outfile
;
715 uint32_t crc
= crc32(0L, NULL
, 0);
717 cramfs_is_big_endian
= HOST_IS_BIG_ENDIAN
; /* default is to use host order */
721 setlocale(LC_ALL
, "");
722 bindtextdomain(PACKAGE
, LOCALEDIR
);
724 close_stdout_atexit();
727 /* first arg may be one of our standard longopts */
728 if (!strcmp(argv
[1], "--help"))
730 if (!strcmp(argv
[1], "--version")) {
731 print_version(EXIT_SUCCESS
);
735 strutils_set_exitcode(MKFS_EX_USAGE
);
737 /* command line options */
738 while ((c
= getopt(argc
, argv
, "hb:Ee:i:n:N:l::psVvz")) != EOF
) {
743 blksize
= strtou32_or_err(optarg
, _("invalid blocksize argument"));
749 opt_edition
= strtou32_or_err(optarg
, _("invalid edition number argument"));
752 if (strcmp(optarg
, "big") == 0)
753 cramfs_is_big_endian
= 1;
754 else if (strcmp(optarg
, "little") == 0)
755 cramfs_is_big_endian
= 0;
756 else if (strcmp(optarg
, "host") == 0)
759 errx(MKFS_EX_USAGE
, _("invalid endianness given;"
760 " must be 'big', 'little', or 'host'"));
764 if (lstat(opt_image
, &st
) < 0)
765 err(MKFS_EX_USAGE
, _("stat of %s failed"), opt_image
);
766 image_length
= st
.st_size
; /* may be padded later */
767 fslen_ub
+= (image_length
+ 3); /* 3 is for padding */
782 fslen_ub
+= PAD_SIZE
;
785 /* old option, ignored */
788 print_version(MKFS_EX_OK
);
796 errtryhelp(MKFS_EX_USAGE
);
800 if ((argc
- optind
) != 2) {
801 warnx(_("bad usage"));
802 errtryhelp(MKFS_EX_USAGE
);
804 dirname
= argv
[optind
];
805 outfile
= argv
[optind
+ 1];
808 blksize
= getpagesize();
810 if (stat(dirname
, &st
) < 0)
811 err(MKFS_EX_USAGE
, _("stat of %s failed"), dirname
);
812 fd
= open(outfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0666);
814 err(MKFS_EX_USAGE
, _("cannot open %s"), outfile
);
816 if (blkdev_lock(fd
, outfile
, lockmode
) != 0)
819 root_entry
= xcalloc(1, sizeof(struct entry
));
820 root_entry
->mode
= st
.st_mode
;
821 root_entry
->uid
= st
.st_uid
;
822 root_entry
->gid
= st
.st_gid
;
824 root_entry
->size
= parse_directory(root_entry
, dirname
, &root_entry
->child
, &fslen_ub
);
826 /* find duplicate files */
827 eliminate_doubles(root_entry
,root_entry
, &fslen_ub
);
829 /* always allocate a multiple of blksize bytes because that's
830 what we're going to write later on */
831 fslen_ub
= ((fslen_ub
- 1) | (blksize
- 1)) + 1;
832 fslen_max
= maxfslen();
834 if (fslen_ub
> fslen_max
) {
835 warnx( _("warning: guestimate of required size (upper bound) "
836 "is %lldMB, but maximum image size is %uMB. "
837 "We might die prematurely."),
838 (long long)fslen_ub
>> 20,
840 fslen_ub
= fslen_max
;
843 /* TODO: Why do we use a private/anonymous mapping here
844 followed by a write below, instead of just a shared mapping
845 and a couple of ftruncate calls? Is it just to save us
846 having to deal with removing the file afterwards? If we
847 really need this huge anonymous mapping, we ought to mmap
848 in smaller chunks, so that the user doesn't need nn MB of
849 RAM free. If the reason is to be able to write to
850 un-mmappable block devices, then we could try shared mmap
851 and revert to anonymous mmap if the shared mmap fails. */
852 rom_image
= mmap(NULL
,
854 PROT_READ
| PROT_WRITE
,
855 MAP_PRIVATE
| MAP_ANONYMOUS
,
858 if (-1 == (int) (long) rom_image
)
859 err(MKFS_EX_ERROR
, _("ROM image map"));
861 /* Skip the first opt_pad bytes for boot loader code */
863 memset(rom_image
, 0x00, opt_pad
);
865 /* Skip the superblock and come back to write it later. */
866 offset
+= sizeof(struct cramfs_super
);
868 /* Insert a file image. */
871 printf(_("Including: %s\n"), opt_image
);
872 offset
= write_file(opt_image
, rom_image
, offset
);
875 offset
= write_directory_structure(root_entry
->child
, rom_image
, offset
);
877 printf(_("Directory data: %zd bytes\n"), offset
);
879 offset
= write_data(root_entry
, rom_image
, offset
);
881 /* We always write a multiple of blksize bytes, so that
883 offset
= ((offset
- 1) | (blksize
- 1)) + 1;
885 printf(_("Everything: %zd kilobytes\n"), offset
>> 10);
887 /* Write the superblock now that we can fill in all of the fields. */
888 write_superblock(root_entry
, rom_image
+opt_pad
, offset
);
890 printf(_("Super block: %zd bytes\n"),
891 sizeof(struct cramfs_super
));
893 /* Put the checksum in. */
894 crc
= crc32(crc
, (unsigned char *) (rom_image
+opt_pad
), (offset
-opt_pad
));
895 ((struct cramfs_super
*) (rom_image
+opt_pad
))->fsid
.crc
= u32_toggle_endianness(cramfs_is_big_endian
, crc
);
897 printf(_("CRC: %x\n"), crc
);
899 /* Check to make sure we allocated enough space. */
900 if (fslen_ub
< offset
)
902 _("not enough space allocated for ROM image "
903 "(%lld allocated, %zu used)"),
904 (long long) fslen_ub
, offset
);
906 written
= write(fd
, rom_image
, offset
);
907 if (offset
!= written
)
908 errx(MKFS_EX_ERROR
, _("ROM image write failed (%zd %zd)"),
910 if (close_fd(fd
) != 0)
911 err(MKFS_EX_ERROR
, _("ROM image"));
914 * (These warnings used to come at the start, but they scroll off
915 * the screen too quickly.)
918 /* Can't happen when reading from ext2fs. */
919 /* Bytes, not chars: think UTF8. */
920 warnx(_("warning: filenames truncated to %u bytes."), MAX_INPUT_NAMELEN
);
922 warnx(_("warning: files were skipped due to errors."));
924 warnx(_("warning: file sizes truncated to %luMB "
925 "(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH
- 20));
927 /* (not possible with current Linux versions) */
928 warnx(_("warning: uids truncated to %u bits. "
929 "(This may be a security concern.)"), CRAMFS_UID_WIDTH
);
931 warnx(_("warning: gids truncated to %u bits. "
932 "(This may be a security concern.)"), CRAMFS_GID_WIDTH
);
934 warnx(_("WARNING: device numbers truncated to %u bits. "
935 "This almost certainly means\n"
936 "that some device files will be wrong."),
937 CRAMFS_OFFSET_WIDTH
);
939 (warn_namelen
|warn_skip
|warn_size
|warn_uid
|warn_gid
|warn_dev
))