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