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