[FS] Added support for ROMFS
diff --git a/fs/romfs/romfs.c b/fs/romfs/romfs.c
new file mode 100644
index 0000000..b7d9696
--- /dev/null
+++ b/fs/romfs/romfs.c
@@ -0,0 +1,270 @@
+/*
+ * (C) Copyright 2007 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+
+#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
+
+#include <asm/byteorder.h>
+#include <linux/stat.h>
+#include <jffs2/jffs2.h>
+#include <jffs2/load_kernel.h>
+
+#undef DEBUG_ROMFS
+
+/* ROMFS superblock */
+struct romfs_super {
+	u32 word0;
+	u32 word1;
+	u32 size;
+	u32 checksum;
+	char name[0];
+};
+
+struct romfs_inode {
+	u32 next;
+	u32 spec;
+	u32 size;
+	u32 checksum;
+	char name[0];
+};
+
+extern flash_info_t flash_info[];
+#define PART_OFFSET(x)	(x->offset + flash_info[x->dev->id->num].start[0])
+#define ALIGN(x)	(((x) & 0xfffffff0))
+#define HEADERSIZE(name)	(0x20 + ALIGN(strlen(name)))
+
+static unsigned long romfs_resolve (unsigned long begin, unsigned long offset,
+				unsigned long size, int raw, char *filename)
+{
+	unsigned long inodeoffset = 0, nextoffset;
+	struct romfs_inode *inode;
+#ifdef DEBUG_ROMFS
+	printf ("ROMFS_resolve: begin 0x%x, offset 0x%x, size 0x%x, raw 0x%x, \
+		filename %s\n", begin, offset, size, raw, filename);
+#endif
+
+	while (inodeoffset < size) {
+		inode = (struct romfs_inode *)(begin + offset + inodeoffset);
+		offset = 0;
+		nextoffset = ALIGN (inode->next);
+#ifdef DEBUG_ROMFS
+		printf("inode 0x%x, name %s - len 0x%x, next inode 0x%x, \
+			compare names 0x%x\n",
+			inode, inode->name, strlen (inode->name), nextoffset,
+			strncmp (filename, inode->name, strlen (filename)));
+#endif
+		if (!strncmp (filename, inode->name, strlen (inode->name))) {
+			char *p = strtok (NULL, "/");
+			if (raw && (p == NULL || *p == '\0')) {
+				return offset + inodeoffset;
+			}
+			return romfs_resolve (begin,
+					inodeoffset + HEADERSIZE (inode->name),
+					size, raw, p);
+		}
+		inodeoffset = nextoffset;
+	}
+
+	printf ("can't find corresponding entry\n");
+	return 0;
+}
+
+int romfs_load (char *loadoffset, struct part_info *info, char *filename)
+{
+	struct romfs_inode *inode;
+	struct romfs_super *sb;
+	char *data;
+	int pocet;
+	sb = (struct romfs_super *) PART_OFFSET (info);
+
+	unsigned long offset;
+
+	offset = romfs_resolve (PART_OFFSET (info), HEADERSIZE (sb->name),
+				sb->size, 1, strtok (filename, "/"));
+	if (offset <= 0)
+		return offset;
+
+	inode = (struct romfs_inode *)(PART_OFFSET (info) + offset);
+	data = (char *)((int)inode + HEADERSIZE (inode->name));
+	pocet = inode->size;
+	while (pocet--) {
+		*loadoffset++ = *data++;
+	}
+	return inode->size;
+}
+
+static int romfs_list_inode (struct part_info *info, unsigned long offset)
+{
+	struct romfs_inode *inode =
+			(struct romfs_inode *)(PART_OFFSET (info) + offset);
+	struct romfs_inode *hardlink = NULL;
+	char str[3], *data;
+
+/*	mapping		spec.info means
+ * 0	hard link	link destination [file header]
+ * 1	directory	first file's header
+ * 2	regular file	unused, must be zero [MBZ]
+ * 3	symbolic link	unused, MBZ (file data is the link content)
+ * 4	block device	16/16 bits major/minor number
+ * 5	char device		- " -
+ * 6	socket		unused, MBZ
+ * 7	fifo		unused, MBZ
+ */
+	switch (inode->next & 0x7) {
+	case 0:
+		str[0] = 'h';
+		break;
+	case 1:
+		str[0] = 'd';
+		break;
+	case 2:
+		str[0] = 'f';
+		break;
+	case 3:
+		str[0] = 'l';
+		break;
+	case 4:
+		str[0] = 'b';
+		break;
+	case 5:
+		str[0] = 'c';
+		break;
+	case 6:
+		str[0] = 's';
+		break;
+	case 7:
+		str[0] = 'p';
+		break;
+	default:
+		str[0] = '?';
+	}
+
+	if (inode->next & 0x8) {
+		str[1] = 'x';
+	} else {
+		str[1] = '-';
+	}
+	str[2] = '\0';
+
+	if ((str[0] == 'b') || (str[0] == 'c')) {
+#ifdef DEBUG_ROMFS
+		printf (" %s  %3d,%3d %12s 0x%08x 0x%08x", str,
+			(inode->spec & 0xffff0000) >> 16,
+			inode->spec & 0x0000ffff, inode->name, inode,
+			inode->spec);
+#else
+		printf (" %s  %3d,%3d %12s", str,
+			(inode->spec & 0xffff0000) >> 16,
+			inode->spec & 0x0000ffff);
+#endif
+	} else {
+#ifdef DEBUG_ROMFS
+		printf (" %s  %7d %12s 0x%08x 0x%08x", str, inode->size,
+			inode->name, inode, inode->spec);
+#else
+		printf (" %s  %7d %12s", str, inode->size, inode->name);
+#endif
+		if (str[0] == 'l') {
+			data = (char *)((int)inode + HEADERSIZE (inode->name));
+			puts (" -> ");
+			puts (data);
+		}
+		if (str[0] == 'h') {
+			hardlink = (struct romfs_inode *)(PART_OFFSET (info) +
+						inode->spec);
+			puts (" -> ");
+			puts (hardlink->name);
+		}
+	}
+	puts ("\n");
+	return ALIGN (inode->next);
+}
+
+int romfs_ls (struct part_info *info, char *filename)
+{
+	struct romfs_inode *inode;
+	unsigned long inodeoffset = 0, nextoffset;
+	unsigned long offset, size;
+	struct romfs_super *sb;
+	sb = (struct romfs_super *)PART_OFFSET (info);
+
+	if (strlen (filename) == 0 || !strcmp (filename, "/")) {
+		offset = HEADERSIZE (sb->name);
+		size = sb->size;
+	} else {
+		offset = romfs_resolve (PART_OFFSET (info),
+			HEADERSIZE (sb->name), sb->size, 1,
+			strtok (filename, "/"));
+
+		if (offset == 0) {
+			return offset;
+		}
+		inode = (struct romfs_inode *)(PART_OFFSET (info) + offset);
+		if ((inode->next & 0x7) != 1) {
+			return (romfs_list_inode (info, offset) > 0);
+		}
+
+		size = sb->size;
+		offset = offset + HEADERSIZE (inode->name);
+	}
+
+	inodeoffset = offset + inodeoffset;
+	while (inodeoffset < size) {
+		nextoffset = romfs_list_inode (info, inodeoffset);
+		if (nextoffset == 0)
+			break;
+		inodeoffset = nextoffset;
+	}
+	return 1;
+}
+
+int romfs_info (struct part_info *info)
+{
+	struct romfs_super *sb;
+	sb = (struct romfs_super *)PART_OFFSET (info);
+
+	printf ("name: \t\t%s, len %d B\n", sb->name, strlen (sb->name));
+	printf ("size of SB:\t%d B\n", HEADERSIZE (sb->name));
+	printf ("full size:\t%d B\n", sb->size);
+	printf ("checksum:\t0x%x\n", sb->checksum);
+	return 0;
+}
+
+int romfs_check (struct part_info *info)
+{
+	struct romfs_super *sb;
+	if (info->dev->id->type != MTD_DEV_TYPE_NOR)
+		return 0;
+
+	sb = (struct romfs_super *)PART_OFFSET (info);
+	if ((sb->word0 != 0x2D726F6D) || (sb->word1 != 0x3166732D)) {
+		return 0;
+	}
+	return 1;
+}
+
+#endif