summaryrefslogtreecommitdiffstats
path: root/target/cramfs/cramfs-02-endian.patch
blob: 4c28b8397a1bcd94d848c78ba73fd738129e4b1b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
--- cramfs-1.1/mkcramfs.c.orig	2005-04-13 05:55:57.000000000 -0600
+++ cramfs-1.1/mkcramfs.c	2005-04-13 16:19:57.000000000 -0600
@@ -117,6 +117,7 @@
 static int opt_squash = 0;
 static char *opt_image = NULL;
 static char *opt_name = NULL;
+static int swap_endian = 0;
 
 static int warn_dev, warn_gid, warn_namelen, warn_skip, warn_size, warn_uid;
 static const char *const memory_exhausted = "memory exhausted";
@@ -155,6 +156,8 @@
 		" -i file    insert a file image into the filesystem (requires >= 2.4.0)\n"
 		" -n name    set name of cramfs filesystem\n"
 		" -p         pad by %d bytes for boot code\n"
+		" -l         litte endian filesystem\n"
+		" -b         big endian filesystem\n"
 		" -s         sort directory entries (old option, ignored)\n"
 		" -v         be more verbose\n"
 		" -z         make explicit holes (requires >= 2.3.39)\n"
@@ -504,6 +506,50 @@
 	return totalsize;
 }
 
+/* routines to swap endianness/bitfields in inode/superblock block data */
+static void fix_inode(struct cramfs_inode *inode)
+{
+#define wswap(x)    (((x)>>24) | (((x)>>8)&0xff00) | (((x)&0xff00)<<8) | (((x)&0xff)<<24))
+	/* attempt #2 */
+	inode->mode = (inode->mode >> 8) | ((inode->mode&0xff)<<8);
+	inode->uid = (inode->uid >> 8) | ((inode->uid&0xff)<<8);
+	inode->size = (inode->size >> 16) | (inode->size&0xff00) |
+		((inode->size&0xff)<<16);
+	((u32*)inode)[2] = wswap(inode->offset | (inode->namelen<<26));
+}
+
+static void fix_offset(struct cramfs_inode *inode, u32 offset)
+{
+	u32 tmp = wswap(((u32*)inode)[2]);
+	((u32*)inode)[2] = wswap((offset >> 2) | (tmp&0xfc000000));
+}
+
+static void fix_block_pointer(u32 *p)
+{
+	*p = wswap(*p);
+}
+
+static void fix_super(struct cramfs_super *super)
+{
+	u32 *p = (u32*)super;
+
+	/* fix superblock fields */
+	p[0] = wswap(p[0]);	/* magic */
+	p[1] = wswap(p[1]);	/* size */
+	p[2] = wswap(p[2]);	/* flags */
+	p[3] = wswap(p[3]);	/* future */
+
+	/* fix filesystem info fields */
+	p = (u32*)&super->fsid;
+	p[0] = wswap(p[0]);	/* crc */
+	p[1] = wswap(p[1]);	/* edition */
+	p[2] = wswap(p[2]);	/* blocks */
+	p[3] = wswap(p[3]);	/* files */
+
+	fix_inode(&super->root);
+#undef wswap
+}
+
 /* Returns sizeof(struct cramfs_super), which includes the root inode. */
 static unsigned int write_superblock(struct entry *root, char *base, int size)
 {
@@ -539,6 +585,7 @@
 	super->root.gid = root->gid;
 	super->root.size = root->size;
 	super->root.offset = offset >> 2;
+	if (swap_endian) fix_super(super);
 
 	return offset;
 }
@@ -553,7 +600,10 @@
 	if (offset >= (1 << (2 + CRAMFS_OFFSET_WIDTH))) {
 		error_msg_and_die("filesystem too big");
 	}
-	inode->offset = (offset >> 2);
+	if (swap_endian)
+		fix_offset(inode, offset);
+	else
+		inode->offset = (offset >> 2);
 }
 
 /*
@@ -638,6 +688,7 @@
 				stack_entries++;
 			}
 			entry = entry->next;
+			if (swap_endian) fix_inode(inode);
 		}
 
 		/*
@@ -734,6 +785,7 @@
 		}
 
 		*(u32 *) (base + offset) = curr;
+		if (swap_endian) fix_block_pointer((u32*)(base + offset));
 		offset += 4;
 	} while (size);
 
@@ -1146,7 +1198,7 @@
 		progname = argv[0];
 
 	/* command line options */
-	while ((c = getopt(argc, argv, "hEe:i:n:psvzD:q")) != EOF) {
+	while ((c = getopt(argc, argv, "hEe:i:n:psvzD:qlb")) != EOF) {
 		switch (c) {
 		case 'h':
 			usage(MKFS_OK);
@@ -1174,6 +1227,18 @@
 			opt_pad = PAD_SIZE;
 			fslen_ub += PAD_SIZE;
 			break;
+		case 'b':
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+			swap_endian = 1;
+			printf("Swapping filesystem endian-ness\n");
+#endif
+			break;
+		case 'l':
+#if __BYTE_ORDER == __BIG_ENDIAN
+			swap_endian = 1;
+			printf("Swapping filesystem endian-ness\n");
+#endif
+			break;
 		case 's':
 			/* old option, ignored */
 			break;