blob: 15de3e18ff069286d32ece190e47972c4f22323a [file] [log] [blame]
Michal Simek09da9252007-07-14 12:41:23 +02001/*
2 * (C) Copyright 2007 Michal Simek
3 *
4 * Michal SIMEK <monstr@monstr.eu>
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22 * MA 02111-1307 USA
23 */
24
25#include <common.h>
26#include <malloc.h>
27#include <command.h>
28
Michal Simek79c06112007-08-15 21:03:41 +020029#if defined(CONFIG_CMD_JFFS2)
Michal Simek09da9252007-07-14 12:41:23 +020030
31#include <asm/byteorder.h>
32#include <linux/stat.h>
33#include <jffs2/jffs2.h>
34#include <jffs2/load_kernel.h>
35
36#undef DEBUG_ROMFS
37
38/* ROMFS superblock */
39struct romfs_super {
40 u32 word0;
41 u32 word1;
42 u32 size;
43 u32 checksum;
44 char name[0];
45};
46
47struct romfs_inode {
48 u32 next;
49 u32 spec;
50 u32 size;
51 u32 checksum;
52 char name[0];
53};
54
55extern flash_info_t flash_info[];
56#define PART_OFFSET(x) (x->offset + flash_info[x->dev->id->num].start[0])
57#define ALIGN(x) (((x) & 0xfffffff0))
58#define HEADERSIZE(name) (0x20 + ALIGN(strlen(name)))
59
60static unsigned long romfs_resolve (unsigned long begin, unsigned long offset,
61 unsigned long size, int raw, char *filename)
62{
63 unsigned long inodeoffset = 0, nextoffset;
64 struct romfs_inode *inode;
65#ifdef DEBUG_ROMFS
66 printf ("ROMFS_resolve: begin 0x%x, offset 0x%x, size 0x%x, raw 0x%x, \
67 filename %s\n", begin, offset, size, raw, filename);
68#endif
69
70 while (inodeoffset < size) {
71 inode = (struct romfs_inode *)(begin + offset + inodeoffset);
72 offset = 0;
73 nextoffset = ALIGN (inode->next);
74#ifdef DEBUG_ROMFS
75 printf("inode 0x%x, name %s - len 0x%x, next inode 0x%x, \
76 compare names 0x%x\n",
77 inode, inode->name, strlen (inode->name), nextoffset,
78 strncmp (filename, inode->name, strlen (filename)));
79#endif
80 if (!strncmp (filename, inode->name, strlen (inode->name))) {
81 char *p = strtok (NULL, "/");
82 if (raw && (p == NULL || *p == '\0')) {
83 return offset + inodeoffset;
84 }
85 return romfs_resolve (begin,
86 inodeoffset + HEADERSIZE (inode->name),
87 size, raw, p);
88 }
89 inodeoffset = nextoffset;
90 }
91
92 printf ("can't find corresponding entry\n");
93 return 0;
94}
95
96int romfs_load (char *loadoffset, struct part_info *info, char *filename)
97{
98 struct romfs_inode *inode;
99 struct romfs_super *sb;
100 char *data;
101 int pocet;
102 sb = (struct romfs_super *) PART_OFFSET (info);
103
104 unsigned long offset;
105
106 offset = romfs_resolve (PART_OFFSET (info), HEADERSIZE (sb->name),
107 sb->size, 1, strtok (filename, "/"));
108 if (offset <= 0)
109 return offset;
110
111 inode = (struct romfs_inode *)(PART_OFFSET (info) + offset);
112 data = (char *)((int)inode + HEADERSIZE (inode->name));
113 pocet = inode->size;
114 while (pocet--) {
115 *loadoffset++ = *data++;
116 }
117 return inode->size;
118}
119
120static int romfs_list_inode (struct part_info *info, unsigned long offset)
121{
122 struct romfs_inode *inode =
123 (struct romfs_inode *)(PART_OFFSET (info) + offset);
124 struct romfs_inode *hardlink = NULL;
125 char str[3], *data;
126
Michal Simekf0018ad2007-08-06 23:35:26 +0200127/*
128 * mapping spec.info means
Michal Simek09da9252007-07-14 12:41:23 +0200129 * 0 hard link link destination [file header]
130 * 1 directory first file's header
131 * 2 regular file unused, must be zero [MBZ]
132 * 3 symbolic link unused, MBZ (file data is the link content)
133 * 4 block device 16/16 bits major/minor number
134 * 5 char device - " -
135 * 6 socket unused, MBZ
136 * 7 fifo unused, MBZ
137 */
Michal Simekf0018ad2007-08-06 23:35:26 +0200138 char attributes[] = "hdflbcsp";
139 str[0] = attributes[inode->next & 0x7];
140 str[1] = (inode->next & 0x8) ? 'x' : '-';
Michal Simek09da9252007-07-14 12:41:23 +0200141 str[2] = '\0';
142
143 if ((str[0] == 'b') || (str[0] == 'c')) {
144#ifdef DEBUG_ROMFS
145 printf (" %s %3d,%3d %12s 0x%08x 0x%08x", str,
146 (inode->spec & 0xffff0000) >> 16,
147 inode->spec & 0x0000ffff, inode->name, inode,
148 inode->spec);
149#else
150 printf (" %s %3d,%3d %12s", str,
151 (inode->spec & 0xffff0000) >> 16,
152 inode->spec & 0x0000ffff);
153#endif
154 } else {
155#ifdef DEBUG_ROMFS
156 printf (" %s %7d %12s 0x%08x 0x%08x", str, inode->size,
157 inode->name, inode, inode->spec);
158#else
159 printf (" %s %7d %12s", str, inode->size, inode->name);
160#endif
161 if (str[0] == 'l') {
162 data = (char *)((int)inode + HEADERSIZE (inode->name));
163 puts (" -> ");
164 puts (data);
165 }
166 if (str[0] == 'h') {
167 hardlink = (struct romfs_inode *)(PART_OFFSET (info) +
168 inode->spec);
169 puts (" -> ");
170 puts (hardlink->name);
171 }
172 }
173 puts ("\n");
174 return ALIGN (inode->next);
175}
176
177int romfs_ls (struct part_info *info, char *filename)
178{
179 struct romfs_inode *inode;
180 unsigned long inodeoffset = 0, nextoffset;
181 unsigned long offset, size;
182 struct romfs_super *sb;
183 sb = (struct romfs_super *)PART_OFFSET (info);
184
185 if (strlen (filename) == 0 || !strcmp (filename, "/")) {
186 offset = HEADERSIZE (sb->name);
187 size = sb->size;
188 } else {
189 offset = romfs_resolve (PART_OFFSET (info),
190 HEADERSIZE (sb->name), sb->size, 1,
191 strtok (filename, "/"));
192
193 if (offset == 0) {
194 return offset;
195 }
196 inode = (struct romfs_inode *)(PART_OFFSET (info) + offset);
197 if ((inode->next & 0x7) != 1) {
198 return (romfs_list_inode (info, offset) > 0);
199 }
200
201 size = sb->size;
202 offset = offset + HEADERSIZE (inode->name);
203 }
204
205 inodeoffset = offset + inodeoffset;
206 while (inodeoffset < size) {
207 nextoffset = romfs_list_inode (info, inodeoffset);
208 if (nextoffset == 0)
209 break;
210 inodeoffset = nextoffset;
211 }
212 return 1;
213}
214
215int romfs_info (struct part_info *info)
216{
217 struct romfs_super *sb;
218 sb = (struct romfs_super *)PART_OFFSET (info);
219
220 printf ("name: \t\t%s, len %d B\n", sb->name, strlen (sb->name));
221 printf ("size of SB:\t%d B\n", HEADERSIZE (sb->name));
222 printf ("full size:\t%d B\n", sb->size);
223 printf ("checksum:\t0x%x\n", sb->checksum);
224 return 0;
225}
226
227int romfs_check (struct part_info *info)
228{
229 struct romfs_super *sb;
230 if (info->dev->id->type != MTD_DEV_TYPE_NOR)
231 return 0;
232
233 sb = (struct romfs_super *)PART_OFFSET (info);
234 if ((sb->word0 != 0x2D726F6D) || (sb->word1 != 0x3166732D)) {
235 return 0;
236 }
237 return 1;
238}
239
240#endif