[PATCH 1/2] Make mkfs.cramfs little endian only

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux