Linux-kernel mailing list archive 2000-40,: [PATCH] Endianness-aware mkcramfs

# [PATCH] Endianness-aware mkcramfs

Daniel Marmier (daniel.marmier@lightning.ch)
Tue, 03 Oct 2000 13:51:56 +0200

- Messages sorted by: [ date ][ thread ][ subject ][ author ]
- Next message: Chip Salzenberg: "Re: 2.2.18pre13: Small patches"
- Previous message: Anton Blanchard: "Re: Bottom Handles/soft irqs/timer interrupts/SMP ....."

Hi all,

Here is a small patch that makes mkcramfs endianness-aware.
I simply added a "-e" command line option that takes one of
the following arguments :

b makes a _b_ig endian image
l makes a _l_ittle endian image
h makes a _h_ost-like image (big on big, little on little)
r makes a _r_everse-host image (big on little and vice versa)

The default behaviour (if -e unspecified) is to make a host-like image
for backwards compatibility.

Oh, and yes, it IS ugly :-)

Have a nice day,

Daniel Marmier

------------------------------------------------------------------------
--- work/linux/scripts/cramfs/mkcramfs.c Mon Jun 26 08:02:14 2000
+++ ppc/soft/kernel/scripts/cramfs/mkcramfs.c Tue Oct 3 13:49:36 2000
@@ -25,7 +25,7 @@
static void usage(void)
{
- fprintf(stderr, "Usage: '%s dirname outfile'\n"
+ fprintf(stderr, "Usage: '%s [-e{b,l,h,r}] dirname outfile'\n"
" where <dirname> is the root of the\n"
" filesystem to be compressed.\n", progname);
exit(1);
@@ -47,6 +47,8 @@
static int warn_dev, warn_gid, warn_namelen, warn_size, warn_uid;
+static int reverse_endian;
+
#ifndef MIN
# define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
#endif
@@ -87,6 +89,17 @@
*/
#define MAX_INPUT_NAMELEN 255
+static unsigned long htocl(unsigned long x)
+{
+ if (reverse_endian)
+ return ((x << 24) & 0xff000000) |
+ ((x << 8) & 0x00ff0000) |
+ ((x >> 8) & 0x0000ff00) |
+ ((x >> 24) & 0x000000ff);
+ else
+ return x;
+}
+
static int find_identical_file(struct entry *orig,struct entry *newfile)
{
if(orig==newfile) return 1;
@@ -273,41 +286,59 @@
memset(area, 0x00, size);
}
+static unsigned int write_entry(struct entry *entry, char *base)
+{
+ unsigned long *p = (unsigned long *)base;
+
+ p[0] = htocl((entry->mode << 16) | (entry->uid & 0xffff));
+ p[1] = htocl((entry->size << 8) | (entry->gid & 0xff));
+ p[2] = htocl(entry->offset & 0x03ffffff);
+ return sizeof(struct entry);
+}
+
/* Returns sizeof(struct cramfs_super), which includes the root inode. */
static unsigned int write_superblock(struct entry *root, char *base)
{
struct cramfs_super *super = (struct cramfs_super *) base;
unsigned int offset = sizeof(struct cramfs_super);
- super->magic = CRAMFS_MAGIC;
- super->flags = 0;
+ super->magic = htocl(CRAMFS_MAGIC);
+ super->flags = htocl(0);
/* Note: 0x10000 is meaningless, which is a bug; but
super->size is never used anyway. */
- super->size = 0x10000;
+ super->size = htocl(0x10000);
+ super->future = htocl(0);
memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature));
set_random(super->fsid, sizeof(super->fsid));
strncpy(super->name, "Compressed", sizeof(super->name));
- super->root.mode = root->mode;
- super->root.uid = root->uid;
- super->root.gid = root->gid;
- super->root.size = root->size;
- super->root.offset = offset >> 2;
-
+ root->offset = offset >> 2;
+ write_entry(root, (char *)&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);
+ unsigned long *p = (unsigned long *)(base + entry->dir_offset);
+ unsigned long value;
assert ((offset & 3) == 0);
if (offset >= (1 << (2 + OFFSET_WIDTH))) {
fprintf(stderr, "filesystem too big. Exiting.\n");
exit(1);
}
- inode->offset = (offset >> 2);
+ value = (htocl(p[2]) & 0xfc000000) | ((offset >> 2) & 0x03ffffff);
+ p[2] = htocl(value);
}
+static unsigned int write_inode(struct cramfs_inode *inode, char *base)
+{
+ unsigned long *p = (unsigned long *)base;
+
+ p[0] = htocl((inode->mode << 16) | (inode->uid & 0xffff));
+ p[1] = htocl((inode->size << 8) | (inode->gid & 0xff));
+ p[2] = htocl((inode->namelen << 26) | (inode->offset & 0x03ffffff));
+ return sizeof(struct cramfs_inode);
+}
/*
* We do a width-first printout of the directory
@@ -323,27 +354,27 @@
for (;;) {
int dir_start = stack_entries;
while (entry) {
- struct cramfs_inode *inode = (struct cramfs_inode *) (base + offset);
+ struct cramfs_inode inode;
size_t len = strlen(entry->name);
entry->dir_offset = offset;
- inode->mode = entry->mode;
- inode->uid = entry->uid;
- inode->gid = entry->gid;
- inode->size = entry->size;
- inode->offset = 0;
+ inode.mode = entry->mode;
+ inode.uid = entry->uid;
+ inode.gid = entry->gid;
+ inode.size = entry->size;
+ inode.offset = 0;
+ inode.namelen = (len + 3) >> 2;
+ offset += write_inode(&inode, base + offset);
/* Non-empty directories, regfiles and symlinks will
write over inode->offset later. */
- offset += sizeof(struct cramfs_inode);
memcpy(base + offset, entry->name, len);
/* Pad up the name to a 4-byte boundary */
while (len & 3) {
*(base + offset + len) = '\0';
len++;
}
- inode->namelen = len >> 2;
offset += len;
/* TODO: this may get it wrong for chars >= 0x80.
@@ -451,7 +482,7 @@
exit(1);
}
- *(u32 *) (base + offset) = curr;
+ *(u32 *) (base + offset) = htocl(curr);
offset += 4;
} while (size);
@@ -517,6 +548,11 @@
*/
int main(int argc, char **argv)
{
+ int opt;
+ const char optstring[] = "e:";
+ char endian = 'h';
+ int big_endian;
+ unsigned char test_endian[] = { 0x12, 0x34 };
struct stat st;
struct entry *root_entry;
char *rom_image;
@@ -529,14 +565,47 @@
if (argc)
progname = argv[0];
- if (argc != 3)
+ if (argc < 3)
usage();
- if (stat(dirname = argv[1], &st) < 0) {
- perror(argv[1]);
+ while ((opt = getopt(argc, argv, optstring)) != -1)
+ switch(opt) {
+ case 'e':
+ endian = *optarg;
+ break;
+ default:
+ usage();
+ }
+
+ /* find out host endianness */
+ big_endian = *(unsigned short *)test_endian == 0x1234;
+ /* find out (from host endianness and user's wish) if we need to swap words */
+ switch(endian) {
+ case 'b':
+ /* big endian image */
+ reverse_endian = !big_endian;
+ break;
+ case 'h':
+ /* host-like image (default) */
+ reverse_endian = 0;
+ break;
+ case 'l':
+ /* little endian image */
+ reverse_endian = big_endian;
+ break;
+ case 'r':
+ /* reverse-host image (big on little and vice versa) */
+ reverse_endian = 1;
+ break;
+ default:
+ usage();
+ }
+
+ if (stat(dirname = argv[argc - 2], &st) < 0) {
+ perror(argv[argc - 2]);
exit(1);
}
- fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ fd = open(argv[argc - 1], O_WRONLY | O_CREAT | O_TRUNC, 0666);
root_entry = calloc(1, sizeof(struct entry));
if (!root_entry) {
@@ -547,7 +616,7 @@
root_entry->uid = st.st_uid;
root_entry->gid = st.st_gid;
- root_entry->size = parse_directory(root_entry, argv[1], &root_entry->child, &fslen_ub);
+ root_entry->size = parse_directory(root_entry, argv[argc - 2], &root_entry->child, &fslen_ub);
if (fslen_ub > MAXFSLEN) {
fprintf(stderr,
"warning: guestimate of required size (upper bound) is %luMB, but maximum image size is %uMB. We might die prematurely.\n",
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/

- Next message: Chip Salzenberg: "Re: 2.2.18pre13: Small patches"
- Previous message: Anton Blanchard: "Re: Bottom Handles/soft irqs/timer interrupts/SMP ....."