A few people have expressed interest in this, and I needed it as well. Currently, cramfs images aren't shareable between different endian architectures. The documentation states the meta-data should always be stored little endian, as the cost of swabbing would be low, but the code doesn't do it. We needed shareable images, so I modified inode.c, cramfs_fs.h, and mkcramfs.h to enable a big-endian machine to swab meta data when writing (mkcramfs.c) and reading (inode.c). This is done with #defined macros (the 26 bit/6 bit bitfield is kind of ugly to translate), so the code doesn't change for little-endian machines, only big-endian. I tested reading le on be, reading a be-written le image on le, etc... This is a patch against 2.4.10. -Brad Bozarth
--- 2.4.10/include/linux/cramfs_fs.h Thu Jul 19 16:14:53 2001 +++ current/include/linux/cramfs_fs.h Thu Sep 27 17:36:57 2001 @@ -9,7 +9,12 @@ #endif +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) +#define CRAMFS_MAGIC 0x453dcd28 /* endian reversed magic */ +#else #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ +#endif + #define CRAMFS_SIGNATURE "Compressed ROMFS" /* @@ -80,6 +85,40 @@ * changed to test super.future instead. */ #define CRAMFS_SUPPORTED_FLAGS (0x7ff) + +/* + * Since cramfs (according to docs) should always be stored little endian, + * provide macros to swab the bitfields (mkcramfs uses this file too). + */ +#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) + +#define CRAM_SWAB_16(x) ( ( (0x0000FF00 & (x)) >> 8 ) | \ + ( (0x000000FF & (x)) << 8 ) ) +#define CRAM_SWAB_24(x) ( ( (0x00FF0000 & (x)) >> 16 ) | \ + ( (0x0000FF00 & (x)) ) | \ + ( (0x000000FF & (x)) << 16 ) ) +#define CRAM_SWAB_32(x) ( ( (0xFF000000 & (x)) >> 24 ) | \ + ( (0x00FF0000 & (x)) >> 8 ) | \ + ( (0x0000FF00 & (x)) << 8 ) | \ + ( (0x000000FF & (x)) << 24 ) ) +#define GET_CRAM_NAMELEN(x) (((u8*)(x))[8] & 63) +#define GET_CRAM_OFFSET(x) ((CRAM_SWAB_24(((u32*)(x))[2] & 0x00FFFFFF)<<2) | \ + ((((u32*)(x))[2] & 0xC0000000)>>30) ) +#define SET_CRAM_OFFSET(x,y) ( ((u32*)(x))[2] = (((y)&3)<<30) | \ + CRAM_SWAB_24( ( ((y) & 0x03FFFFFF) >> 2) ) | \ + (((u32)(((u8*)(x))[8] & 0x3F)) << 24) ) +#define SET_CRAM_NAMELEN(x,y) ( ((u8*)(x))[8] = ( ((0x3F & (y))) | \ + (0xC0 & ((u8*)(x))[8]) ) ) + +#else +#define CRAM_SWAB_16(x) (x) +#define CRAM_SWAB_24(x) (x) +#define CRAM_SWAB_32(x) (x) +#define GET_CRAM_NAMELEN(x) ((x)->namelen) +#define GET_CRAM_OFFSET(x) ((x)->offset) +#define SET_LE_OFFSET(x,y) ((x)->offset = y) +#define SET_LE_NAMELEN(x,y) ((x)->namelen = y) +#endif /* Uncompression interfaces to the underlying zlib */ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); --- 2.4.10/fs/cramfs/inode.c Mon Aug 27 07:53:49 2001 +++ current/fs/cramfs/inode.c Fri Sep 28 14:01:53 2001 @@ -35,7 +35,7 @@ /* These two macros may change in future, to provide better st_ino semantics. */ -#define CRAMINO(x) ((x)->offset?(x)->offset<<2:1) +#define CRAMINO(x) (GET_CRAM_OFFSET(x) ? GET_CRAM_OFFSET(x)<<2 : 1) #define OFFSET(x) ((x)->i_ino) static struct inode *get_cramfs_inode(struct super_block *sb, struct cramfs_inode * cramfs_inode) @@ -43,9 +43,9 @@ struct inode * inode = new_inode(sb); if (inode) { - inode->i_mode = cramfs_inode->mode; - inode->i_uid = cramfs_inode->uid; - inode->i_size = cramfs_inode->size; + inode->i_mode = CRAM_SWAB_16(cramfs_inode->mode); + inode->i_uid = CRAM_SWAB_16(cramfs_inode->uid); + inode->i_size = CRAM_SWAB_24(cramfs_inode->size); inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_gid = cramfs_inode->gid; @@ -66,7 +66,8 @@ inode->i_data.a_ops = &cramfs_aops; } else { inode->i_size = 0; - init_special_inode(inode, inode->i_mode, cramfs_inode->size); + init_special_inode(inode, inode->i_mode, + CRAM_SWAB_24(cramfs_inode->size)); } } return inode; @@ -219,11 +220,11 @@ } /* Check that the root inode is in a sane state */ - if (!S_ISDIR(super.root.mode)) { + if (!S_ISDIR(CRAM_SWAB_16(super.root.mode))) { printk(KERN_ERR "cramfs: root is not a directory\n"); goto out; } - root_offset = super.root.offset << 2; + root_offset = GET_CRAM_OFFSET(&(super.root)) << 2; if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { sb->CRAMFS_SB_SIZE=super.size; sb->CRAMFS_SB_BLOCKS=super.fsid.blocks; @@ -299,7 +300,7 @@ * and the name padded out to 4-byte boundaries * with zeroes. */ - namelen = de->namelen << 2; + namelen = GET_CRAM_NAMELEN(de) << 2; nextoffset = offset + sizeof(*de) + namelen; for (;;) { if (!namelen) @@ -308,7 +309,8 @@ break; namelen--; } - error = filldir(dirent, name, namelen, offset, CRAMINO(de), de->mode >> 12); + error = filldir(dirent, name, namelen, offset, CRAMINO(de), + CRAM_SWAB_16(de->mode) >> 12); if (error) break; @@ -339,7 +341,7 @@ if (sorted && (dentry->d_name.name[0] < name[0])) break; - namelen = de->namelen << 2; + namelen = GET_CRAM_NAMELEN(de) << 2; offset += sizeof(*de) + namelen; /* Quick check that the name is roughly the right length */ @@ -385,9 +387,10 @@ start_offset = OFFSET(inode) + maxblock*4; if (page->index) - start_offset = *(u32 *) cramfs_read(sb, blkptr_offset-4, 4); - compr_len = (*(u32 *) cramfs_read(sb, blkptr_offset, 4) - - start_offset); + start_offset = CRAM_SWAB_32(*(u32 *) + cramfs_read(sb, blkptr_offset - 4, 4)); + compr_len = CRAM_SWAB_32(*(u32 *) + cramfs_read(sb, blkptr_offset, 4)) - start_offset; pgdata = kmap(page); if (compr_len == 0) ; /* hole */ --- 2.4.10/scripts/cramfs/mkcramfs.c Thu Jul 19 16:14:53 2001 +++ current/scripts/cramfs/mkcramfs.c Fri Sep 28 14:15:37 2001 @@ -317,19 +317,20 @@ offset += opt_pad; } - super->magic = CRAMFS_MAGIC; - super->flags = CRAMFS_FLAG_FSID_VERSION_2 | CRAMFS_FLAG_SORTED_DIRS; + super->magic = CRAMFS_MAGIC; /* #defined correctly on both endians */ + super->flags = CRAM_SWAB_32(CRAMFS_FLAG_FSID_VERSION_2 | + CRAMFS_FLAG_SORTED_DIRS); if (opt_holes) - super->flags |= CRAMFS_FLAG_HOLES; + super->flags |= CRAM_SWAB_32(CRAMFS_FLAG_HOLES); if (image_length > 0) - super->flags |= CRAMFS_FLAG_SHIFTED_ROOT_OFFSET; - super->size = size; + super->flags |= CRAM_SWAB_32(CRAMFS_FLAG_SHIFTED_ROOT_OFFSET); + super->size = CRAM_SWAB_24(size); memcpy(super->signature, CRAMFS_SIGNATURE, sizeof(super->signature)); - super->fsid.crc = crc32(0L, Z_NULL, 0); - super->fsid.edition = opt_edition; - super->fsid.blocks = total_blocks; - super->fsid.files = total_nodes; + super->fsid.crc = CRAM_SWAB_32(crc32(0L, Z_NULL, 0)); + super->fsid.edition = CRAM_SWAB_32(opt_edition); + super->fsid.blocks = CRAM_SWAB_32(total_blocks); + super->fsid.files = CRAM_SWAB_32(total_nodes); memset(super->name, 0x00, sizeof(super->name)); if (opt_name) @@ -337,11 +338,11 @@ else strncpy(super->name, "Compressed", sizeof(super->name)); - super->root.mode = root->mode; - super->root.uid = root->uid; + super->root.mode = CRAM_SWAB_16(root->mode); + super->root.uid = CRAM_SWAB_16(root->uid); super->root.gid = root->gid; - super->root.size = root->size; - super->root.offset = offset >> 2; + super->root.size = CRAM_SWAB_24(root->size); + SET_CRAM_OFFSET(&(super->root), offset >> 2); return offset; } @@ -356,7 +357,7 @@ fprintf(stderr, "filesystem too big. Exiting.\n"); exit(8); } - inode->offset = (offset >> 2); + SET_CRAM_OFFSET(inode, offset >> 2); } @@ -379,10 +380,10 @@ entry->dir_offset = offset; - inode->mode = entry->mode; - inode->uid = entry->uid; + inode->mode = CRAM_SWAB_16(entry->mode); + inode->uid = CRAM_SWAB_16(entry->uid); inode->gid = entry->gid; - inode->size = entry->size; + inode->size = CRAM_SWAB_24(entry->size); inode->offset = 0; /* Non-empty directories, regfiles and symlinks will write over inode->offset later. */ @@ -395,7 +396,7 @@ *(base + offset + len) = '\0'; len++; } - inode->namelen = len >> 2; + SET_CRAM_NAMELEN(inode, len >> 2); offset += len; /* TODO: this may get it wrong for chars >= 0x80. @@ -503,7 +504,7 @@ exit(8); } - *(u32 *) (base + offset) = curr; + *(u32 *) (base + offset) = CRAM_SWAB_32(curr); offset += 4; } while (size);