[FIX] Correction command definition
[platform/kernel/u-boot.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 defined(CONFIG_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 /*
128  *      mapping         spec.info means
129  * 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  */
138         char attributes[] = "hdflbcsp";
139         str[0] = attributes[inode->next & 0x7];
140         str[1] = (inode->next & 0x8) ? 'x' : '-';
141         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
177 int 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
215 int 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
227 int 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