30
30
#include <sys/mman.h>
32
32
#include <dirent.h>
33
34
#include <stdlib.h>
35
36
#include <string.h>
36
37
#include <getopt.h>
40
42
#include "cramfs.h"
41
#include "cramfs_common.h"
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 */
45
#include "exitcodes.h"
47
#define XALLOC_EXIT_CODE MKFS_ERROR
50
50
/* The kernel only supports PAD_SIZE of 0 and 512. */
51
51
#define PAD_SIZE 512
53
static const char *progname = "mkcramfs";
54
53
static int verbose = 0;
56
55
static unsigned int blksize; /* settable via -b option */
94
93
unsigned char *name;
95
94
unsigned int mode, size, uid, gid;
96
unsigned char md5sum[16];
95
unsigned char md5sum[MD5LENGTH];
97
96
unsigned char flags; /* CRAMFS_EFLAG_* */
101
100
int fd; /* temporarily open files while mmapped */
102
struct entry *same; /* points to other identical file */
103
unsigned int offset; /* pointer to compressed data in archive */
101
struct entry *same; /* points to other identical file */
102
unsigned int offset; /* pointer to compressed data in archive */
104
103
unsigned int dir_offset; /* offset of directory entry in archive */
106
105
/* organization */
140
139
" -z make explicit holes (requires >= 2.3.39)\n"
141
140
" dirname root of the filesystem to be compressed\n"
142
141
" outfile output file\n"),
142
program_invocation_short_name, PAD_SIZE);
150
xmalloc (size_t size) {
151
void *t = malloc(size);
154
exit(MKFS_ERROR); /* out of memory */
160
148
do_mmap(char *path, unsigned int size, unsigned int mode){
262
248
if ((orig->flags & CRAMFS_EFLAG_MD5) &&
263
249
(new->flags & CRAMFS_EFLAG_MD5) &&
264
!memcmp(orig->md5sum, new->md5sum, 16) &&
250
!memcmp(orig->md5sum, new->md5sum, MD5LENGTH) &&
265
251
identical_file(orig, new)) {
266
252
new->same = orig;
267
253
*fslen_ub -= new->size;
271
return find_identical_file(orig->child, new, fslen_ub) ||
272
find_identical_file(orig->next, new, fslen_ub);
257
return find_identical_file(orig->child, new, fslen_ub) ||
258
find_identical_file(orig->next, new, fslen_ub);
275
261
static void eliminate_doubles(struct entry *root, struct entry *orig, loff_t *fslen_ub) {
277
if (orig->size && orig->path)
263
if (orig->size && orig->path)
278
264
find_identical_file(root,orig, fslen_ub);
279
eliminate_doubles(root,orig->child, fslen_ub);
280
eliminate_doubles(root,orig->next, fslen_ub);
265
eliminate_doubles(root,orig->child, fslen_ub);
266
eliminate_doubles(root,orig->next, fslen_ub);
308
/* read in the directory and sort */
309
dircount = scandir(name, &dirlist, 0, cramsort);
294
/* read in the directory and sort */
295
dircount = scandir(name, &dirlist, 0, cramsort);
298
err(MKFS_ERROR, _("could not read directory %s"), name);
316
300
/* process directory */
317
301
for (dirindex = 0; dirindex < dircount; dirindex++) {
336
320
namelen = strlen(dirent->d_name);
337
if (namelen > MAX_INPUT_NAMELEN) {
321
if (namelen > MAX_INPUT_NAMELEN)
339
323
_("Very long (%zu bytes) filename `%s' found.\n"
340
324
" Please increase MAX_INPUT_NAMELEN in "
341
"mkcramfs.c and recompile. Exiting.\n"),
325
"mkcramfs.c and recompile. Exiting."),
342
326
namelen, dirent->d_name);
345
327
memcpy(endpath, dirent->d_name, namelen + 1);
347
329
if (lstat(path, &st) < 0) {
375
349
entry->gid = st.st_gid;
376
350
if (entry->gid >= 1 << CRAMFS_GID_WIDTH)
377
351
/* TODO: We ought to replace with a default
378
gid instead of truncating; otherwise there
379
are security problems. Maybe mode should
380
be &= ~070. Same goes for uid once Linux
381
supports >16-bit uids. */
352
gid instead of truncating; otherwise there
353
are security problems. Maybe mode should
354
be &= ~070. Same goes for uid once Linux
355
supports >16-bit uids. */
383
357
size = sizeof(struct cramfs_inode) + ((namelen + 3) & ~3);
384
358
*fslen_ub += size;
385
359
if (S_ISDIR(st.st_mode)) {
386
360
entry->size = parse_directory(root_entry, path, &entry->child, fslen_ub);
387
361
} else if (S_ISREG(st.st_mode)) {
388
entry->path = strdup(path);
362
entry->path = xstrdup(path);
389
363
if (entry->size) {
390
364
if (entry->size >= (1 << CRAMFS_SIZE_WIDTH)) {
468
442
struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset);
469
443
inode_to_host(cramfs_is_big_endian, inode, inode);
470
if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
471
fprintf(stderr, _("filesystem too big. Exiting.\n"));
444
if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH)))
445
errx(MKFS_ERROR, _("filesystem too big. Exiting."));
474
446
inode->offset = (offset >> 2);
475
447
inode_from_host(cramfs_is_big_endian, inode, inode);
671
639
for (e = entry; e; e = e->next) {
674
set_data_offset(e, base, e->same->offset);
675
e->offset = e->same->offset;
676
} else if (e->size) {
677
set_data_offset(e, base, offset);
679
offset = do_compress(base, offset, e->name,
642
set_data_offset(e, base, e->same->offset);
643
e->offset = e->same->offset;
644
} else if (e->size) {
645
set_data_offset(e, base, offset);
647
offset = do_compress(base, offset, e->name,
680
648
e->path, e->size,e->mode);
682
650
} else if (e->child)
683
651
offset = write_data(e->child, base, offset);
693
661
fd = open(file, O_RDONLY);
663
err(MKFS_ERROR, _("cannot open file %s"), file);
698
664
buf = mmap(NULL, image_length, PROT_READ, MAP_PRIVATE, fd, 0);
699
665
memcpy(base + offset, buf, image_length);
700
666
munmap(buf, image_length);
668
err(MKFS_ERROR, _("cannot close file %s"), file);
702
669
/* Pad up the image_length to a 4-byte boundary */
703
670
while (image_length & 3) {
704
671
*(base + offset + image_length) = '\0';
741
708
loff_t fslen_ub = sizeof(struct cramfs_super);
742
709
unsigned int fslen_max;
743
710
char const *dirname, *outfile;
744
u32 crc = crc32(0L, Z_NULL, 0);
711
uint32_t crc = crc32(0L, Z_NULL, 0);
746
713
cramfs_is_big_endian = HOST_IS_BIG_ENDIAN; /* default is to use host order */
748
715
blksize = getpagesize();
749
716
total_blocks = 0;
754
if ((p = strrchr(progname, '/')) != NULL)
758
718
setlocale(LC_ALL, "");
759
719
bindtextdomain(PACKAGE, LOCALEDIR);
760
720
textdomain(PACKAGE);
763
723
while ((c = getopt(argc, argv, "hb:Ee:i:n:N:psVvz")) != EOF) {
768
blksize = atoi(optarg);
728
blksize = strtoll_or_err(optarg, _("failed to parse blocksize argument"));
769
729
if (blksize <= 0)
776
opt_edition = atoi(optarg);
736
opt_edition = strtoll_or_err(optarg, _("edition number argument failed"));
779
if (strcmp(optarg, "big") == 0) {
739
if (strcmp(optarg, "big") == 0)
780
740
cramfs_is_big_endian = 1;
782
else if (strcmp(optarg, "little") == 0) {
741
else if (strcmp(optarg, "little") == 0)
783
742
cramfs_is_big_endian = 0;
785
else if (strcmp(optarg, "host") == 0); /* default */
787
perror("invalid endianness given. Must be 'big', 'little', or 'host'");
743
else if (strcmp(optarg, "host") == 0)
746
errx(MKFS_USAGE, _("invalid endianness given."
747
" Must be 'big', 'little', or 'host'"));
793
750
opt_image = optarg;
794
if (lstat(opt_image, &st) < 0) {
751
if (lstat(opt_image, &st) < 0)
752
err(MKFS_USAGE, _("cannot stat %s"), opt_image);
798
753
image_length = st.st_size; /* may be padded later */
799
754
fslen_ub += (image_length + 3); /* 3 is for padding */
824
779
if ((argc - optind) != 2)
826
781
dirname = argv[optind];
827
782
outfile = argv[optind + 1];
829
if (stat(dirname, &st) < 0) {
784
if (stat(dirname, &st) < 0)
785
err(MKFS_USAGE, _("cannot stat %s"), dirname);
833
786
fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
788
err(MKFS_USAGE, _("cannot open %s"), outfile);
835
root_entry = calloc(1, sizeof(struct entry));
790
root_entry = xcalloc(1, sizeof(struct entry));
840
791
root_entry->mode = st.st_mode;
841
792
root_entry->uid = st.st_uid;
842
793
root_entry->gid = st.st_gid;
844
795
root_entry->size = parse_directory(root_entry, dirname, &root_entry->child, &fslen_ub);
846
797
/* always allocate a multiple of blksize bytes because that's
847
what we're going to write later on */
798
what we're going to write later on */
848
799
fslen_ub = ((fslen_ub - 1) | (blksize - 1)) + 1;
849
800
fslen_max = maxfslen();
851
802
if (fslen_ub > fslen_max) {
853
_("warning: guestimate of required size (upper bound) "
803
warnx( _("warning: guestimate of required size (upper bound) "
854
804
"is %lldMB, but maximum image size is %uMB. "
855
"We might die prematurely.\n"),
805
"We might die prematurely."),
856
806
(long long)fslen_ub >> 20,
857
807
fslen_max >> 20);
858
808
fslen_ub = fslen_max;
861
/* find duplicate files */
862
eliminate_doubles(root_entry,root_entry, &fslen_ub);
811
/* find duplicate files */
812
eliminate_doubles(root_entry,root_entry, &fslen_ub);
864
814
/* TODO: Why do we use a private/anonymous mapping here
865
followed by a write below, instead of just a shared mapping
866
and a couple of ftruncate calls? Is it just to save us
867
having to deal with removing the file afterwards? If we
868
really need this huge anonymous mapping, we ought to mmap
869
in smaller chunks, so that the user doesn't need nn MB of
870
RAM free. If the reason is to be able to write to
871
un-mmappable block devices, then we could try shared mmap
872
and revert to anonymous mmap if the shared mmap fails. */
815
followed by a write below, instead of just a shared mapping
816
and a couple of ftruncate calls? Is it just to save us
817
having to deal with removing the file afterwards? If we
818
really need this huge anonymous mapping, we ought to mmap
819
in smaller chunks, so that the user doesn't need nn MB of
820
RAM free. If the reason is to be able to write to
821
un-mmappable block devices, then we could try shared mmap
822
and revert to anonymous mmap if the shared mmap fails. */
873
823
rom_image = mmap(NULL,
874
824
fslen_ub?fslen_ub:1,
875
825
PROT_READ | PROT_WRITE,
876
826
MAP_PRIVATE | MAP_ANONYMOUS,
879
if (-1 == (int) (long) rom_image) {
880
perror(_("ROM image map"));
829
if (-1 == (int) (long) rom_image)
830
err(MKFS_ERROR, _("ROM image map"));
884
832
/* Skip the first opt_pad bytes for boot loader code */
885
833
offset = opt_pad;
920
868
printf(_("CRC: %x\n"), crc);
922
870
/* Check to make sure we allocated enough space. */
923
if (fslen_ub < offset) {
871
if (fslen_ub < offset)
925
873
_("not enough space allocated for ROM image "
926
"(%lld allocated, %zu used)\n"),
874
"(%lld allocated, %zu used)"),
927
875
(long long) fslen_ub, offset);
931
877
written = write(fd, rom_image, offset);
933
perror(_("ROM image"));
936
if (offset != written) {
937
fprintf(stderr, _("ROM image write failed (%zd %zd)\n"),
879
err(MKFS_ERROR, _("ROM image"));
880
if (offset != written)
881
errx(MKFS_ERROR, _("ROM image write failed (%zd %zd)"),
938
882
written, offset);
942
/* (These warnings used to come at the start, but they scroll off the
943
screen too quickly.) */
944
if (warn_namelen) /* (can't happen when reading from ext2fs) */
945
fprintf(stderr, /* bytes, not chars: think UTF8. */
946
_("warning: filenames truncated to 255 bytes.\n"));
885
* (These warnings used to come at the start, but they scroll off
886
* the screen too quickly.)
889
/* Can't happen when reading from ext2fs. */
890
/* Bytes, not chars: think UTF8. */
891
warnx(_("warning: filenames truncated to 255 bytes."));
949
_("warning: files were skipped due to errors.\n"));
893
warnx(_("warning: files were skipped due to errors."));
952
_("warning: file sizes truncated to %luMB "
953
"(minus 1 byte).\n"),
954
1L << (CRAMFS_SIZE_WIDTH - 20));
955
if (warn_uid) /* (not possible with current Linux versions) */
957
_("warning: uids truncated to %u bits. "
958
"(This may be a security concern.)\n"),
895
warnx(_("warning: file sizes truncated to %luMB "
896
"(minus 1 byte)."), 1L << (CRAMFS_SIZE_WIDTH - 20));
898
/* (not possible with current Linux versions) */
899
warnx(_("warning: uids truncated to %u bits. "
900
"(This may be a security concern.)"), CRAMFS_UID_WIDTH);
962
_("warning: gids truncated to %u bits. "
963
"(This may be a security concern.)\n"),
902
warnx(_("warning: gids truncated to %u bits. "
903
"(This may be a security concern.)"), CRAMFS_GID_WIDTH);
967
_("WARNING: device numbers truncated to %u bits. "
968
"This almost certainly means\n"
969
"that some device files will be wrong.\n"),
970
CRAMFS_OFFSET_WIDTH);
905
warnx(_("WARNING: device numbers truncated to %u bits. "
906
"This almost certainly means\n"
907
"that some device files will be wrong."),
908
CRAMFS_OFFSET_WIDTH);
971
909
if (opt_errors &&
972
910
(warn_namelen|warn_skip|warn_size|warn_uid|warn_gid|warn_dev))
973
911
exit(MKFS_ERROR);