]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - fs/romfs/romfs.c
[FS] Added support for ROMFS
[karo-tx-uboot.git] / fs / romfs / romfs.c
1 /*
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
29 #if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
30
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 */
39 struct romfs_super {
40         u32 word0;
41         u32 word1;
42         u32 size;
43         u32 checksum;
44         char name[0];
45 };
46
47 struct romfs_inode {
48         u32 next;
49         u32 spec;
50         u32 size;
51         u32 checksum;
52         char name[0];
53 };
54
55 extern 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
60 static 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
96 int 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
120 static 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
127 /*      mapping         spec.info means
128  * 0    hard link       link destination [file header]
129  * 1    directory       first file's header
130  * 2    regular file    unused, must be zero [MBZ]
131  * 3    symbolic link   unused, MBZ (file data is the link content)
132  * 4    block device    16/16 bits major/minor number
133  * 5    char device             - " -
134  * 6    socket          unused, MBZ
135  * 7    fifo            unused, MBZ
136  */
137         switch (inode->next & 0x7) {
138         case 0:
139                 str[0] = 'h';
140                 break;
141         case 1:
142                 str[0] = 'd';
143                 break;
144         case 2:
145                 str[0] = 'f';
146                 break;
147         case 3:
148                 str[0] = 'l';
149                 break;
150         case 4:
151                 str[0] = 'b';
152                 break;
153         case 5:
154                 str[0] = 'c';
155                 break;
156         case 6:
157                 str[0] = 's';
158                 break;
159         case 7:
160                 str[0] = 'p';
161                 break;
162         default:
163                 str[0] = '?';
164         }
165
166         if (inode->next & 0x8) {
167                 str[1] = 'x';
168         } else {
169                 str[1] = '-';
170         }
171         str[2] = '\0';
172
173         if ((str[0] == 'b') || (str[0] == 'c')) {
174 #ifdef DEBUG_ROMFS
175                 printf (" %s  %3d,%3d %12s 0x%08x 0x%08x", str,
176                         (inode->spec & 0xffff0000) >> 16,
177                         inode->spec & 0x0000ffff, inode->name, inode,
178                         inode->spec);
179 #else
180                 printf (" %s  %3d,%3d %12s", str,
181                         (inode->spec & 0xffff0000) >> 16,
182                         inode->spec & 0x0000ffff);
183 #endif
184         } else {
185 #ifdef DEBUG_ROMFS
186                 printf (" %s  %7d %12s 0x%08x 0x%08x", str, inode->size,
187                         inode->name, inode, inode->spec);
188 #else
189                 printf (" %s  %7d %12s", str, inode->size, inode->name);
190 #endif
191                 if (str[0] == 'l') {
192                         data = (char *)((int)inode + HEADERSIZE (inode->name));
193                         puts (" -> ");
194                         puts (data);
195                 }
196                 if (str[0] == 'h') {
197                         hardlink = (struct romfs_inode *)(PART_OFFSET (info) +
198                                                 inode->spec);
199                         puts (" -> ");
200                         puts (hardlink->name);
201                 }
202         }
203         puts ("\n");
204         return ALIGN (inode->next);
205 }
206
207 int romfs_ls (struct part_info *info, char *filename)
208 {
209         struct romfs_inode *inode;
210         unsigned long inodeoffset = 0, nextoffset;
211         unsigned long offset, size;
212         struct romfs_super *sb;
213         sb = (struct romfs_super *)PART_OFFSET (info);
214
215         if (strlen (filename) == 0 || !strcmp (filename, "/")) {
216                 offset = HEADERSIZE (sb->name);
217                 size = sb->size;
218         } else {
219                 offset = romfs_resolve (PART_OFFSET (info),
220                         HEADERSIZE (sb->name), sb->size, 1,
221                         strtok (filename, "/"));
222
223                 if (offset == 0) {
224                         return offset;
225                 }
226                 inode = (struct romfs_inode *)(PART_OFFSET (info) + offset);
227                 if ((inode->next & 0x7) != 1) {
228                         return (romfs_list_inode (info, offset) > 0);
229                 }
230
231                 size = sb->size;
232                 offset = offset + HEADERSIZE (inode->name);
233         }
234
235         inodeoffset = offset + inodeoffset;
236         while (inodeoffset < size) {
237                 nextoffset = romfs_list_inode (info, inodeoffset);
238                 if (nextoffset == 0)
239                         break;
240                 inodeoffset = nextoffset;
241         }
242         return 1;
243 }
244
245 int romfs_info (struct part_info *info)
246 {
247         struct romfs_super *sb;
248         sb = (struct romfs_super *)PART_OFFSET (info);
249
250         printf ("name: \t\t%s, len %d B\n", sb->name, strlen (sb->name));
251         printf ("size of SB:\t%d B\n", HEADERSIZE (sb->name));
252         printf ("full size:\t%d B\n", sb->size);
253         printf ("checksum:\t0x%x\n", sb->checksum);
254         return 0;
255 }
256
257 int romfs_check (struct part_info *info)
258 {
259         struct romfs_super *sb;
260         if (info->dev->id->type != MTD_DEV_TYPE_NOR)
261                 return 0;
262
263         sb = (struct romfs_super *)PART_OFFSET (info);
264         if ((sb->word0 != 0x2D726F6D) || (sb->word1 != 0x3166732D)) {
265                 return 0;
266         }
267         return 1;
268 }
269
270 #endif