diff options
Diffstat (limited to 'disk-utils')
-rw-r--r-- | disk-utils/Makefile.am | 5 | ||||
-rw-r--r-- | disk-utils/cramfs_common.c | 105 | ||||
-rw-r--r-- | disk-utils/cramfs_common.h | 37 | ||||
-rw-r--r-- | disk-utils/fsck.cramfs.c | 49 | ||||
-rw-r--r-- | disk-utils/mkfs.cramfs.c | 32 |
5 files changed, 210 insertions, 18 deletions
diff --git a/disk-utils/Makefile.am b/disk-utils/Makefile.am index 2304b2a09..c2cc2f9f0 100644 --- a/disk-utils/Makefile.am +++ b/disk-utils/Makefile.am @@ -38,9 +38,10 @@ endif endif if BUILD_CRAMFS +cramfs_common = $(utils_common) cramfs.h cramfs_common.c cramfs_common.h sbin_PROGRAMS += fsck.cramfs mkfs.cramfs -fsck_cramfs_SOURCES = fsck.cramfs.c cramfs.h $(utils_common) -mkfs_cramfs_SOURCES = mkfs.cramfs.c cramfs.h ../lib/md5.c $(utils_common) +fsck_cramfs_SOURCES = fsck.cramfs.c $(cramfs_common) +mkfs_cramfs_SOURCES = mkfs.cramfs.c $(cramfs_common) ../lib/md5.c fsck_cramfs_LDADD = -lz mkfs_cramfs_LDADD = -lz endif diff --git a/disk-utils/cramfs_common.c b/disk-utils/cramfs_common.c new file mode 100644 index 000000000..ffdad9b09 --- /dev/null +++ b/disk-utils/cramfs_common.c @@ -0,0 +1,105 @@ +/* + * cramfs_common - cramfs common code + * + * Copyright (c) 2008 Roy Peled, the.roy.peled -at- gmail.com + * Copyright (c) 2004-2006 by Michael Holzt, kju -at- fqdn.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <string.h> +#include "cramfs_common.h" +#include "../include/bitops.h" + +u32 u32_toggle_endianness(int big_endian, u32 what) +{ + return big_endian == HOST_IS_BIG_ENDIAN ? what : swab32(what); +} + +void super_toggle_endianness(int big_endian, struct cramfs_super *super) +{ + if (big_endian != HOST_IS_BIG_ENDIAN) { + super->magic = swab32(super->magic); + super->size = swab32(super->size); + super->flags = swab32(super->flags); + super->future = swab32(super->future); + super->fsid.crc = swab32(super->fsid.crc); + super->fsid.edition = swab32(super->fsid.edition); + super->fsid.blocks = swab32(super->fsid.blocks); + super->fsid.files = swab32(super->fsid.files); + } +} + +void inode_toggle_endianness(int input_big_endian, int output_big_endian, struct cramfs_inode *inode_in, struct cramfs_inode *inode_out) +{ + if (input_big_endian == output_big_endian) { + memmove(inode_out, inode_in, sizeof(*inode_out)); + } + else { + unsigned char inode_out_buf[sizeof(*inode_in)]; + unsigned char *inode_in_buf = (unsigned char*)inode_in; + + inode_out_buf[0] = inode_in_buf[1]; /* 16 bit: mode */ + inode_out_buf[1] = inode_in_buf[0]; + + inode_out_buf[2] = inode_in_buf[3]; /* 16 bit: uid */ + inode_out_buf[3] = inode_in_buf[2]; + + inode_out_buf[4] = inode_in_buf[6]; /* 24 bit: size */ + inode_out_buf[5] = inode_in_buf[5]; + inode_out_buf[6] = inode_in_buf[4]; + + inode_out_buf[7] = inode_in_buf[7]; /* 8 bit: gid width */ + + /* Stop the madness! Outlaw C bitfields! They are unportable and nasty! + See for yourself what a mess this is: */ + + if (output_big_endian) { + inode_out_buf[ 8] = ( (inode_in_buf[ 8]&0x3F) << 2 ) | + ( (inode_in_buf[11]&0xC0) >> 6 ); + + inode_out_buf[ 9] = ( (inode_in_buf[11]&0x3F) << 2 ) | + ( (inode_in_buf[10]&0xC0) >> 6 ); + + inode_out_buf[10] = ( (inode_in_buf[10]&0x3F) << 2 ) | + ( (inode_in_buf[ 9]&0xC0) >> 6 ); + + inode_out_buf[11] = ( (inode_in_buf[ 9]&0x3F) << 2 ) | + ( (inode_in_buf[ 8]&0xC0) >> 6 ); + } + else { + inode_out_buf[ 8] = ( (inode_in_buf[ 8]&0xFD) >> 2 ) | + ( (inode_in_buf[11]&0x03) << 6 ); + + inode_out_buf[ 9] = ( (inode_in_buf[11]&0xFD) >> 2 ) | + ( (inode_in_buf[10]&0x03) << 6 ); + + inode_out_buf[10] = ( (inode_in_buf[10]&0xFD) >> 2 ) | + ( (inode_in_buf[ 9]&0x03) << 6 ); + + inode_out_buf[11] = ( (inode_in_buf[ 9]&0xFD) >> 2 ) | + ( (inode_in_buf[ 8]&0x03) << 6 ); + } + + memmove(inode_out, inode_out_buf, sizeof(*inode_out)); + } +} + +void inode_to_host(int from_big_endian, struct cramfs_inode *inode_in, struct cramfs_inode *inode_out) +{ + inode_toggle_endianness(from_big_endian, HOST_IS_BIG_ENDIAN, inode_in, inode_out); +} + +void inode_from_host(int to_big_endian, struct cramfs_inode *inode_in, struct cramfs_inode *inode_out) +{ + inode_toggle_endianness(HOST_IS_BIG_ENDIAN, to_big_endian, inode_in, inode_out); +} diff --git a/disk-utils/cramfs_common.h b/disk-utils/cramfs_common.h new file mode 100644 index 000000000..6311bce25 --- /dev/null +++ b/disk-utils/cramfs_common.h @@ -0,0 +1,37 @@ +/* + * cramfs_common - cramfs common code + * + * Copyright (c) 2008 Roy Peled, the.roy.peled -at- gmail + * Copyright (c) 2004-2006 by Michael Holzt, kju -at- fqdn.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __CRAMFS_COMMON_H +#define __CRAMFS_COMMON_H + +#include "cramfs.h" + +#ifndef HOST_IS_BIG_ENDIAN +#ifdef WORDS_BIGENDIAN +#define HOST_IS_BIG_ENDIAN 1 +#else +#define HOST_IS_BIG_ENDIAN 0 +#endif +#endif + +u32 u32_toggle_endianness(int big_endian, u32 what); +void super_toggle_endianness(int from_big_endian, struct cramfs_super *super); +void inode_to_host(int from_big_endian, struct cramfs_inode *inode_in, struct cramfs_inode *inode_out); +void inode_from_host(int to_big_endian, struct cramfs_inode *inode_in, struct cramfs_inode *inode_out); + +#endif diff --git a/disk-utils/fsck.cramfs.c b/disk-utils/fsck.cramfs.c index 2d11a4071..d388e7874 100644 --- a/disk-utils/fsck.cramfs.c +++ b/disk-utils/fsck.cramfs.c @@ -55,6 +55,7 @@ #include <sys/sysmacros.h> /* for major, minor */ #include "cramfs.h" +#include "cramfs_common.h" #include "nls.h" #include "blkdev.h" @@ -63,6 +64,7 @@ static const char *progname = "cramfsck"; static int fd; /* ROM image file descriptor */ static char *filename; /* ROM image filename */ struct cramfs_super super; /* just find the cramfs superblock once */ +static int cramfs_is_big_endian = 0; /* source is big endian */ static int opt_verbose = 0; /* 1 = verbose (-v), 2+ = very verbose (-vv) */ char *extract_dir = NULL; /* extraction directory (-x) */ @@ -139,6 +141,21 @@ static void die(int status, int syserr, const char *fmt, ...) exit(status); } +int get_superblock_endianness(u32 magic) +{ + if (magic == CRAMFS_MAGIC) { + cramfs_is_big_endian = HOST_IS_BIG_ENDIAN; + return 0; + } + else if (magic == u32_toggle_endianness(!HOST_IS_BIG_ENDIAN, CRAMFS_MAGIC)) { + cramfs_is_big_endian = !HOST_IS_BIG_ENDIAN; + return 0; + } + else { + return -1; + } +} + static void test_super(int *start, size_t *length) { struct stat st; @@ -172,7 +189,7 @@ static void test_super(int *start, size_t *length) { if (read(fd, &super, sizeof(super)) != sizeof(super)) { die(FSCK_ERROR, 1, _("read failed: %s"), filename); } - if (super.magic == CRAMFS_MAGIC) { + if (get_superblock_endianness(super.magic) != -1) { *start = 0; } else if (*length >= (PAD_SIZE + sizeof(super))) { @@ -180,15 +197,22 @@ static void test_super(int *start, size_t *length) { if (read(fd, &super, sizeof(super)) != sizeof(super)) { die(FSCK_ERROR, 1, _("read failed: %s"), filename); } - if (super.magic == CRAMFS_MAGIC) { + if (get_superblock_endianness(super.magic) != -1) { *start = PAD_SIZE; } + else { + die(FSCK_UNCORRECTED, 0, "superblock magic not found"); + } } - - /* superblock tests */ - if (super.magic != CRAMFS_MAGIC) { + else { die(FSCK_UNCORRECTED, 0, _("superblock magic not found")); } + + if (opt_verbose) { + printf("cramfs endianness is %s\n", cramfs_is_big_endian ? "big" : "little"); + } + + super_toggle_endianness(cramfs_is_big_endian, &super); if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { die(FSCK_ERROR, 0, _("unsupported filesystem features")); } @@ -314,7 +338,7 @@ static struct cramfs_inode *cramfs_iget(struct cramfs_inode * i) if (!inode) { die(FSCK_ERROR, 1, _("malloc failed")); } - *inode = *i; + inode_to_host(cramfs_is_big_endian, i, inode); return inode; } @@ -333,9 +357,10 @@ static void iput(struct cramfs_inode *inode) */ static struct cramfs_inode *read_super(void) { - unsigned long offset = super.root.offset << 2; + struct cramfs_inode * root = cramfs_iget(&super.root); + unsigned long offset = root->offset << 2; - if (!S_ISDIR(super.root.mode)) + if (!S_ISDIR(root->mode)) die(FSCK_UNCORRECTED, 0, _("root inode is not directory")); if (!(super.flags & CRAMFS_FLAG_SHIFTED_ROOT_OFFSET) && ((offset != sizeof(struct cramfs_super)) && @@ -343,7 +368,7 @@ static struct cramfs_inode *read_super(void) { die(FSCK_UNCORRECTED, 0, _("bad root offset (%lu)"), offset); } - return cramfs_iget(&super.root); + return root; } static int uncompress_block(void *src, int len) @@ -378,7 +403,7 @@ static void do_uncompress(char *path, int fd, unsigned long offset, unsigned lon do { unsigned long out = page_size; - unsigned long next = *(u32 *) romfs_read(offset); + unsigned long next = u32_toggle_endianness(cramfs_is_big_endian, *(u32 *) romfs_read(offset)); if (next > end_data) { end_data = next; @@ -387,7 +412,7 @@ static void do_uncompress(char *path, int fd, unsigned long offset, unsigned lon offset += 4; if (curr == next) { if (opt_verbose > 1) { - printf(_(" hole at %ld (%d)\n"), curr, page_size); + printf(_(" hole at %ld (%zd)\n"), curr, page_size); } if (size < page_size) out = size; @@ -539,7 +564,7 @@ static void do_symlink(char *path, struct cramfs_inode *i) { unsigned long offset = i->offset << 2; unsigned long curr = offset + 4; - unsigned long next = *(u32 *) romfs_read(offset); + unsigned long next = u32_toggle_endianness(cramfs_is_big_endian, *(u32 *) romfs_read(offset)); unsigned long size; if (offset == 0) { diff --git a/disk-utils/mkfs.cramfs.c b/disk-utils/mkfs.cramfs.c index 1138bfdcc..5ac2c5b97 100644 --- a/disk-utils/mkfs.cramfs.c +++ b/disk-utils/mkfs.cramfs.c @@ -38,6 +38,7 @@ #include <zlib.h> #include "cramfs.h" +#include "cramfs_common.h" #include "md5.h" #include "nls.h" @@ -55,6 +56,7 @@ static int verbose = 0; static unsigned int blksize; /* settable via -b option */ static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ static int image_length = 0; +static int cramfs_is_big_endian = 0; /* target is big endian */ /* * If opt_holes is set, then mkcramfs can create explicit holes in the @@ -121,7 +123,7 @@ usage(int status) { FILE *stream = status ? stderr : stdout; fprintf(stream, - _("usage: %s [-h] [-v] [-b blksize] [-e edition] [-i file] " + _("usage: %s [-h] [-v] [-b blksize] [-e edition] [-N endian] [-i file] " "[-n name] dirname outfile\n" " -h print this help\n" " -v be verbose\n" @@ -129,6 +131,7 @@ usage(int status) { "(non-zero exit status)\n" " -b blksize use this blocksize, must equal page size\n" " -e edition set edition number (part of fsid)\n" + " -N endian set cramfs endianness (big|little|host), default host\n" " -i file insert a file image into the filesystem " "(requires >= 2.4.0)\n" " -n name set name of cramfs filesystem\n" @@ -454,17 +457,22 @@ static unsigned int write_superblock(struct entry *root, char *base, int size) super->root.size = root->size; super->root.offset = offset >> 2; + super_toggle_endianness(cramfs_is_big_endian, super); + inode_from_host(cramfs_is_big_endian, &super->root, &super->root); + return offset; } static void set_data_offset(struct entry *entry, char *base, unsigned long offset) { struct cramfs_inode *inode = (struct cramfs_inode *) (base + entry->dir_offset); + inode_to_host(cramfs_is_big_endian, inode, inode); if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) { fprintf(stderr, _("filesystem too big. Exiting.\n")); exit(8); } inode->offset = (offset >> 2); + inode_from_host(cramfs_is_big_endian, inode, inode); } @@ -523,6 +531,7 @@ static unsigned int write_directory_structure(struct entry *entry, char *base, u entry_stack[stack_entries] = entry; stack_entries++; } + inode_from_host(cramfs_is_big_endian, inode, inode); entry = entry->next; } @@ -630,7 +639,7 @@ do_compress(char *base, unsigned int offset, unsigned char const *name, exit(8); } - *(u32 *) (base + offset) = curr; + *(u32 *) (base + offset) = u32_toggle_endianness(cramfs_is_big_endian, curr); offset += 4; } while (size); @@ -734,6 +743,7 @@ int main(int argc, char **argv) char const *dirname, *outfile; u32 crc = crc32(0L, Z_NULL, 0); int c; + cramfs_is_big_endian = HOST_IS_BIG_ENDIAN; /* default is to use host order */ blksize = getpagesize(); total_blocks = 0; @@ -750,7 +760,7 @@ int main(int argc, char **argv) textdomain(PACKAGE); /* command line options */ - while ((c = getopt(argc, argv, "hb:Ee:i:n:psVvz")) != EOF) { + while ((c = getopt(argc, argv, "hb:Ee:i:n:N:psVvz")) != EOF) { switch (c) { case 'h': usage(0); @@ -765,6 +775,20 @@ int main(int argc, char **argv) case 'e': opt_edition = atoi(optarg); break; + case 'N': + if (strcmp(optarg, "big") == 0) { + cramfs_is_big_endian = 1; + } + else if (strcmp(optarg, "little") == 0) { + cramfs_is_big_endian = 0; + } + else if (strcmp(optarg, "host") == 0); /* default */ + else { + perror("invalid endianness given. Must be 'big', 'little', or 'host'"); + exit(16); + } + + break; case 'i': opt_image = optarg; if (lstat(opt_image, &st) < 0) { @@ -891,7 +915,7 @@ int main(int argc, char **argv) /* Put the checksum in. */ crc = crc32(crc, (unsigned char *) (rom_image+opt_pad), (offset-opt_pad)); - ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc; + ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = u32_toggle_endianness(cramfs_is_big_endian, crc); if (verbose) printf(_("CRC: %x\n"), crc); |