summaryrefslogtreecommitdiffstats
path: root/disk-utils
diff options
context:
space:
mode:
Diffstat (limited to 'disk-utils')
-rw-r--r--disk-utils/Makefile.am5
-rw-r--r--disk-utils/cramfs_common.c105
-rw-r--r--disk-utils/cramfs_common.h37
-rw-r--r--disk-utils/fsck.cramfs.c49
-rw-r--r--disk-utils/mkfs.cramfs.c32
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);