AC_PROG_CC_STDC
AC_GNU_SOURCE
AC_CANONICAL_HOST
+AC_C_BIGENDIAN
linux_os=no
case ${host_os} in
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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
#include <sys/sysmacros.h> /* for major, minor */
#include "cramfs.h"
+#include "cramfs_common.h"
#include "nls.h"
#include "blkdev.h"
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) */
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;
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))) {
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"));
}
if (!inode) {
die(FSCK_ERROR, 1, _("malloc failed"));
}
- *inode = *i;
+ inode_to_host(cramfs_is_big_endian, i, inode);
return 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)) &&
{
die(FSCK_UNCORRECTED, 0, _("bad root offset (%lu)"), offset);
}
- return cramfs_iget(&super.root);
+ return root;
}
static int uncompress_block(void *src, int len)
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;
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;
{
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) {
#include <zlib.h>
#include "cramfs.h"
+#include "cramfs_common.h"
#include "md5.h"
#include "nls.h"
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
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"
"(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"
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);
}
entry_stack[stack_entries] = entry;
stack_entries++;
}
+ inode_from_host(cramfs_is_big_endian, inode, inode);
entry = entry->next;
}
exit(8);
}
- *(u32 *) (base + offset) = curr;
+ *(u32 *) (base + offset) = u32_toggle_endianness(cramfs_is_big_endian, curr);
offset += 4;
} while (size);
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;
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);
break;
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;
/* 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);
ts-cal-y \
ts-col-multibyte \
ts-cramfs-mkfs \
+ ts-cramfs-endianness-mkfs \
+ ts-cramfs-endianness-fsck \
ts-fstab-devname \
ts-fstab-devname2label \
ts-fstab-devname2uuid \
TS_CMD_MKSWAP=${TS_CMD_MKSWAP:-"$TOPDIR/disk-utils/mkswap"}
TS_CMD_MKCRAMFS=${TS_CMD_MKCRAMFS:-"$TOPDIR/disk-utils/mkfs.cramfs"}
+TS_CMD_FSCKCRAMFS=${TS_CMD_FSCKCRAMFS:-"$TOPDIR/disk-utils/fsck.cramfs"}
TS_CMD_IPCS=${TS_CMD_IPCS:-"$TOPDIR/sys-utils/ipcs"}
--- /dev/null
+extract from little endian
+little
+create big endian
+bc0b7bbef02765d32e07faa735d2e0c6
+extract from big endian
+big
+create little endian
+4666f0d2b661f9f3962877edabadb210
--- /dev/null
+create little endian
+4666f0d2b661f9f3962877edabadb210
+create big endian
+bc0b7bbef02765d32e07faa735d2e0c6
--- /dev/null
+#!/bin/bash
+
+#
+# Copyright (C) 2007 Karel Zak <kzak@redhat.com>
+#
+# This file is part of util-linux-ng.
+#
+# This file 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 file 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.
+#
+. ./commands.sh
+. ./functions.sh
+
+TS_COMPONENT="mkfs.cramfs"
+TS_DESC="endianness-fsck"
+
+ts_init "$*"
+ts_skip_nonroot
+
+set -o pipefail
+
+($TS_CMD_FSCKCRAMFS -x TEST_X_FLAG 2>&1 || true) \
+ | grep -q "compiled without -x support" && ts_skip "fsck: compiled without -x support"
+
+IMAGE_LITTLE="$TS_INPUTDIR/cramfs-little.img" #Known good little endian image
+IMAGE_BIG="$TS_INPUTDIR/cramfs-big.img" #Known good big endian image
+
+IMAGE_CREATED="$TS_OUTDIR/cramfs.img" #Image created during the test and compared against the known images.
+IMAGE_DATA="$TS_OUTDIR/cramfs-endianness-data"
+
+test_image() {
+ local FROM_ENDIANNESS="$1"; shift
+ local TO_ENDIANNESS="$1"; shift
+ local FROM_IMAGE="$1"; shift
+
+ rm -rf "$IMAGE_DATA"
+ ts_log "extract from $FROM_ENDIANNESS endian"
+ $TS_CMD_FSCKCRAMFS -v -x $IMAGE_DATA $FROM_IMAGE | head -n1 | cut -d" " -f4 2>&1 >> $TS_OUTPUT
+
+ ts_log "create $TO_ENDIANNESS endian"
+ $TS_CMD_MKCRAMFS -N "$TO_ENDIANNESS" "$IMAGE_DATA" "$IMAGE_CREATED" 2>&1 >> $TS_OUTPUT
+
+ md5sum $IMAGE_CREATED | cut -d" " -f1 >> $TS_OUTPUT
+
+ rm "$IMAGE_CREATED"
+}
+
+test_image "little" "big" "$IMAGE_LITTLE"
+test_image "big" "little" "$IMAGE_BIG"
+
+ts_finalize
+
--- /dev/null
+#!/bin/bash
+
+#
+# Copyright (C) 2007 Karel Zak <kzak@redhat.com>
+#
+# This file is part of util-linux-ng.
+#
+# This file 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 file 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.
+#
+. ./commands.sh
+. ./functions.sh
+
+TS_COMPONENT="mkfs.cramfs"
+TS_DESC="endianness-mkfs"
+
+ts_init "$*"
+ts_skip_nonroot
+
+set -o pipefail
+
+IMAGE_DATA="$TS_OUTDIR/cramfs-endianness-data"
+IMAGE_CREATED="$TS_OUTDIR/cramfs.img" #Image created during the test and compared against the known images.
+
+test_image() {
+ local TO_ENDIANNESS="$1"; shift
+ ts_log "create $TO_ENDIANNESS endian"
+
+ $TS_CMD_MKCRAMFS -N "$TO_ENDIANNESS" "$IMAGE_DATA" "$IMAGE_CREATED" 2>&1 >> $TS_OUTPUT
+
+ md5sum $IMAGE_CREATED | cut -d" " -f1 >> $TS_OUTPUT
+
+ rm "$IMAGE_CREATED"
+}
+
+#generate test data
+mkdir -p $IMAGE_DATA/dirA/dirB
+yes "Testing cramfs 1234567890 Endianness check 1234567890 Endianness check" \
+ | dd of=$IMAGE_DATA/dirA/dirB/a bs=512 count=1 &> /dev/null
+yes "Testing cramfs 1234567890 Endianness check 1234567890 Endianness check" \
+ | dd of=$IMAGE_DATA/dirA/dirB/b bs=512 count=30 &> /dev/null
+
+#perform tests for both endians
+test_image "little"
+test_image "big"
+
+ts_finalize
+