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