|
@@ -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
|