This patch modifies mkfs.cramfs in a way that it only produces little endian images. To support the creation of big endian formats, a new option -k ("keep endianness") was added. This option can only be set on big endian machines. A second option called -b (followed by the blocksize) was added, too. It enables the user to specify the desired blocksize (in terms of cramfs). The changes were tested on the following types of machines: An i386 compatible box (little endian) UltraSparc IIi (big endian) Signed-off-by: Andi Drebes <andi@xxxxxxxxxxxxxxxxxxx> --- cramfs.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mkfs.cramfs.c | 82 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 192 insertions(+), 7 deletions(-) diff --git a/disk-utils/cramfs.h b/disk-utils/cramfs.h index 34b32ca..3cb4c51 100644 --- a/disk-utils/cramfs.h +++ b/disk-utils/cramfs.h @@ -6,6 +6,7 @@ typedef unsigned short u16; typedef unsigned int u32; #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ +#define CRAMFS_MAGIC_WEND 0x453dcd28 /* magic number with the wrong endianess */ #define CRAMFS_SIGNATURE "Compressed ROMFS" /* @@ -78,4 +79,120 @@ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); int cramfs_uncompress_init(void); int cramfs_uncompress_exit(void); +#define swab16(x) \ + ((u16)( \ + (((u16)(x) & (u16)0x00ffU) << 8) | \ + (((u16)(x) & (u16)0xff00U) >> 8) )) + +#define swab32(x) \ + ((u32)( \ + (((u32)(x) & (u32)0x000000ffUL) << 24) | \ + (((u32)(x) & (u32)0x0000ff00UL) << 8) | \ + (((u32)(x) & (u32)0x00ff0000UL) >> 8) | \ + (((u32)(x) & (u32)0xff000000UL) >> 24) )) + +/* Converts a cramfs_info from big endian to little endian. */ +static inline void cramfs_convert_info_betole(struct cramfs_info* info) +{ + info->crc = swab32(info->crc); + info->edition = swab32(info->edition); + info->blocks = swab32(info->blocks); + info->files = swab32(info->files); +} + +/* Same function for the inverse way */ +#define cramfs_convert_info_letobe(info) cramfs_convert_info_betole(info) + +/* Converts a cramfs_info from big endian to little endian. */ +static inline void cramfs_convert_inode_betole(struct cramfs_inode* inode) +{ + u8* inode_bytes = (u8*)inode; + u8 old_nloffs[4]; + + inode->mode = swab16(inode->mode); + inode->uid = swab16(inode->uid); + +#if __BYTE_ORDER == __BIG_ENDIAN + inode->size = (inode_bytes[6] << 16) | (inode_bytes[5] << 8) | (inode_bytes[4]); +#elif __BYTE_ORDER == __LITTLE_ENDIAN + inode->size = (inode_bytes[4] << 16) | (inode_bytes[5] << 8) | (inode_bytes[6]); +#endif + + /* Save the old values of the namelength and the offset */ + memcpy(old_nloffs, inode_bytes+8, 4); + + inode_bytes[8] = ((old_nloffs[3] & 0x03) << 6) | ((old_nloffs[0] & 0xfc) >> 2); + inode_bytes[9] = ((old_nloffs[2] & 0x03) << 6) | ((old_nloffs[3] & 0xfc) >> 2); + inode_bytes[10] = ((old_nloffs[1] & 0x03) << 6) | ((old_nloffs[2] & 0xfc) >> 2); + inode_bytes[11] = ((old_nloffs[0] & 0x03) << 6) | ((old_nloffs[1] & 0xfc) >> 2); +} + +/* Converts a cramfs_info from little endian to big endian. + Unfortunately, this is not exact inverse of cramfs_convert_inode_betole + because of the bitfields used in the inode structure. */ +static inline void cramfs_convert_inode_letobe(struct cramfs_inode* inode) +{ + u8* inode_bytes = (u8*)inode; + u8 old_nloffs[4]; + + inode->mode = swab16(inode->mode); + inode->uid = swab16(inode->uid); + inode->size = (inode_bytes[6] << 16) | (inode_bytes[5] << 8) | (inode_bytes[4]); + + /* Save the old values of the namelength and the offset */ + memcpy(old_nloffs, inode_bytes+8, 4); + + /* Convert the namelength and the offset */ + inode_bytes[8] = ((old_nloffs[0] & 0x3f) << 2) | ((old_nloffs[3] & 0xc0) >> 6); + inode_bytes[9] = ((old_nloffs[3] & 0x3f) << 2) | ((old_nloffs[2] & 0xc0) >> 6); + inode_bytes[10] = ((old_nloffs[2] & 0x3f) << 2) | ((old_nloffs[1] & 0xc0) >> 6); + inode_bytes[11] = ((old_nloffs[1] & 0x3f) << 2) | ((old_nloffs[0] & 0xc0) >> 6); +} + +/* Converts a cramfs superblock from big endian to little endian. */ +static inline void cramfs_convert_super_betole(struct cramfs_super* super) +{ + super->magic = swab32(super->magic); + super->size = swab32(super->size); + super->flags = swab32(super->flags); + super->future = swab32(super->future); + cramfs_convert_info_betole(&super->fsid); + cramfs_convert_inode_betole(&super->root); +} + +/* Converts a cramfs superblock from little endian to big endian. */ +static inline void cramfs_convert_super_letobe(struct cramfs_super* super) +{ + super->magic = swab32(super->magic); + super->size = swab32(super->size); + super->flags = swab32(super->flags); + super->future = swab32(super->future); + cramfs_convert_info_letobe(&super->fsid); + cramfs_convert_inode_letobe(&super->root); +} + +/* Converts a 32 bit integer from big endian to little endian */ +static inline u32 cramfs_convert_u32_betole(u32 val) +{ + return swab32(val); +} + +#define cramfs_convert_u32_letobe(val) cramfs_convert_u32_betole(val) + +#if __BYTE_ORDER == __BIG_ENDIAN +#define cramfsck_convert_info(x) cramfs_convert_info_letobe(x) +#define cramfsck_convert_inode(x) cramfs_convert_inode_letobe(x) +#define cramfsck_convert_super(x) cramfs_convert_super_letobe(x) +#define cramfsck_convert_u32(x) cramfs_convert_u32_letobe(x) + +#elif __BYTE_ORDER == __LITTLE_ENDIAN +#define cramfsck_convert_info(x) cramfs_convert_info_betole(x) +#define cramfsck_convert_inode(x) cramfs_convert_inode_betole(x) +#define cramfsck_convert_super(x) cramfs_convert_super_betole(x) +#define cramfsck_convert_u32(x) cramfs_convert_u32_betole(x) + +#else +#error "Neither __BIG_ENDIAN nor __LITTLE_ENDIAN defined." +#endif + #endif diff --git a/disk-utils/mkfs.cramfs.c b/disk-utils/mkfs.cramfs.c index e61ac9e..93466c2 100644 --- a/disk-utils/mkfs.cramfs.c +++ b/disk-utils/mkfs.cramfs.c @@ -23,6 +23,10 @@ * files one by one instaed of all simultaneously. - aeb, 2002-11-01 */ +/* + * Made cramfs little endian only. - Andi Drebes, 11/2007 + */ + #include <sys/types.h> #include <stdio.h> #include <sys/stat.h> @@ -51,6 +55,7 @@ static const char *progname = "mkcramfs"; static int verbose = 0; +static int keep_endianness = 0; static unsigned int blksize; /* settable via -b option */ static long total_blocks = 0, total_nodes = 1; /* pre-count the root node */ @@ -131,6 +136,7 @@ usage(int status) { " -e edition set edition number (part of fsid)\n" " -i file insert a file image into the filesystem " "(requires >= 2.4.0)\n" + " -k keep machine's endianness (for big endian machines only)\n" " -n name set name of cramfs filesystem\n" " -p pad by %d bytes for boot code\n" " -s sort directory entries (old option, ignored)\n" @@ -630,7 +636,13 @@ do_compress(char *base, unsigned int offset, unsigned char const *name, exit(8); } +#if __BYTE_ORDER == __BIG_ENDIAN + if (!keep_endianness) + *(u32 *) (base + offset) = cramfs_convert_u32_betole(curr); + else +#endif *(u32 *) (base + offset) = curr; + offset += 4; } while (size); @@ -712,6 +724,34 @@ maxfslen(void) { + (1 << CRAMFS_SIZE_WIDTH) * 4 / blksize; /* block pointers */ } +#if __BYTE_ORDER == __BIG_ENDIAN +void convert_entry_betole(struct entry *entry, char *base) +{ + struct cramfs_inode *inode; + u32 *startseq; + + if (!entry) + return; + + while (entry) { + if (entry->child) + convert_entry_betole(entry->child, base); + + inode = (struct cramfs_inode*)(base+entry->dir_offset); + cramfs_convert_inode_betole(inode); + entry = entry->next; + } +} + +void convert_image_betole(char *rom_image, struct entry *root_entry) +{ + struct cramfs_super *super = (struct cramfs_super*)(rom_image+opt_pad); + + convert_entry_betole(root_entry->child, rom_image); + cramfs_convert_super_betole(super); +} +#endif /* __BIG_ENDIAN */ + /* * Usage: * @@ -746,7 +786,7 @@ int main(int argc, char **argv) } /* command line options */ - while ((c = getopt(argc, argv, "hb:Ee:i:n:psVvz")) != EOF) { + while ((c = getopt(argc, argv, "hb:Ee:ki:n:psVvz")) != EOF) { switch (c) { case 'h': usage(0); @@ -770,6 +810,9 @@ int main(int argc, char **argv) image_length = st.st_size; /* may be padded later */ fslen_ub += (image_length + 3); /* 3 is for padding */ break; + case 'k': + keep_endianness = 1; + break; case 'n': opt_name = optarg; break; @@ -885,12 +928,6 @@ int main(int argc, char **argv) printf(_("Super block: %zd bytes\n"), sizeof(struct cramfs_super)); - /* 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; - if (verbose) - printf(_("CRC: %x\n"), crc); - /* Check to make sure we allocated enough space. */ if (fslen_ub < offset) { fprintf(stderr, @@ -900,6 +937,37 @@ int main(int argc, char **argv) exit(8); } +#if __BYTE_ORDER == __BIG_ENDIAN + /* Convert everything into little endian */ + if (!keep_endianness) + convert_image_betole(rom_image, root_entry); +#endif + + if (verbose) { + printf(_("Endianness: ")); +#if __BYTE_ORDER == __BIG_ENDIAN + if (!keep_endianness) + printf(_("little endian\n")); + else + printf(_("big endian\n")); +#elif __BYTE_ORDER == __LITTLE_ENDIAN + printf(_("little endian\n")); +#endif + + printf(_("Block size: %d\n"), blksize); + } + + /* Put the checksum in. */ + crc = crc32(crc, (unsigned char *) (rom_image+opt_pad), (offset-opt_pad)); + if (verbose) + printf(_("CRC: %x\n"), crc); + +#if __BYTE_ORDER == __BIG_ENDIAN + if (!keep_endianness) + crc = cramfs_convert_u32_betole(crc); +#endif + ((struct cramfs_super *) (rom_image+opt_pad))->fsid.crc = crc; + written = write(fd, rom_image, offset); if (written < 0) { perror("ROM image"); - To unsubscribe from this list: send the line "unsubscribe util-linux-ng" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html