Michal Simek | 09da925 | 2007-07-14 12:41:23 +0200 | [diff] [blame] | 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 | |
Michal Simek | 79c0611 | 2007-08-15 21:03:41 +0200 | [diff] [blame] | 29 | #if defined(CONFIG_CMD_JFFS2) |
Michal Simek | 09da925 | 2007-07-14 12:41:23 +0200 | [diff] [blame] | 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 | |
Michal Simek | f0018ad | 2007-08-06 23:35:26 +0200 | [diff] [blame] | 127 | /* |
| 128 | * mapping spec.info means |
Michal Simek | 09da925 | 2007-07-14 12:41:23 +0200 | [diff] [blame] | 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 | */ |
Michal Simek | f0018ad | 2007-08-06 23:35:26 +0200 | [diff] [blame] | 138 | char attributes[] = "hdflbcsp"; |
| 139 | str[0] = attributes[inode->next & 0x7]; |
| 140 | str[1] = (inode->next & 0x8) ? 'x' : '-'; |
Michal Simek | 09da925 | 2007-07-14 12:41:23 +0200 | [diff] [blame] | 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 |