[PATCH] Endianness-aware mkcramfs

From: Daniel Marmier (daniel.marmier@lightning.ch)
Date: Tue Oct 03 2000 - 06:51:56 EST


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/



This archive was generated by hypermail 2b29 : Sat Oct 07 2000 - 21:00:11 EST