📄 jffs2_1pass.c
字号:
/*------------------------------------------------------------------------- * Filename: jffs2.c * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill <Russ.Dill@asu.edu> * Description: Module to load kernel from jffs2 *-----------------------------------------------------------------------*//* * some portions of this code are taken from jffs2, and as such, the * following copyright notice is included. * * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by David Woodhouse <dwmw2@cambridge.redhat.com> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. *//* Ok, so anyone who knows the jffs2 code will probably want to get a papar * bag to throw up into before reading this code. I looked through the jffs2 * code, the caching scheme is very elegant. I tried to keep the version * for a bootloader as small and simple as possible. Instead of worring about * unneccesary data copies, node scans, etc, I just optimized for the known * common case, a kernel, which looks like: * (1) most pages are 4096 bytes * (2) version numbers are somewhat sorted in acsending order * (3) multiple compressed blocks making up one page is uncommon * * So I create a linked list of decending version numbers (insertions at the * head), and then for each page, walk down the list, until a matching page * with 4096 bytes is found, and then decompress the watching pages in * reverse order. * *//* * Adapted by Nye Liu <nyet@zumanetworks.com> and * Rex Feany <rfeany@zumanetworks.com> * on Jan/2002 for armboot. * * Clipped out all the non-1pass functions, cleaned up warnings, * wrappers, etc. No major changes to the code. * Please, he really means it when he said have a paper bag * handy. We needed it ;). * */#include <armboot.h>#include <config.h>#include <malloc.h>#include <linux/stat.h>#include <linux/time.h>#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)#include <jffs2/jffs2.h>#include <jffs2/jffs2_1pass.h>#include "jffs2_private.h"/* Compression names */static char *compr_names[] = { "NONE", "ZERO", "RTIME", "RUBINMIPS", "COPY", "DYNRUBIN", "ZLIB" };static char spinner[] = { '|', '\\', '-', '/' };static struct b_lists g_1PassList;#ifdef DEBUG# define DEBUGF(fmt,args...) printf(fmt ,##args)#else# define DEBUGF(fmt,args...)#endif#define MALLOC_CHUNK (10*1024)static struct b_node *add_node(struct b_node *tail, u32 * count, u32 * memBase){ u32 index; u32 memLimit; struct b_node *b; index = (*count) * sizeof(struct b_node) % MALLOC_CHUNK; memLimit = MALLOC_CHUNK;#if 0 putLabeledWord("add_node: index = ", index); putLabeledWord("add_node: memLimit = ", memLimit); putLabeledWord("add_node: memBase = ", *memBase);#endif // we need not keep a list of bases since we'll never free the // memory, just jump the the kernel if ((index == 0) || (index > memLimit)) { // we need mode space before we continue if ((*memBase = (u32) mmalloc(MALLOC_CHUNK)) == (u32) NULL) { putstr("add_node: malloc failed\n"); return NULL; }#if 0 putLabeledWord("add_node: alloced a new membase at ", *memBase);#endif } // now we have room to add it. b = (struct b_node *) (*memBase + index); // null on first call if (tail) tail->next = b;#if 0 putLabeledWord("add_node: tail = ", (u32) tail); if (tail) putLabeledWord("add_node: tail->next = ", (u32) tail->next);#endif#if 0 putLabeledWord("add_node: mb+i = ", (u32) (*memBase + index)); putLabeledWord("add_node: b = ", (u32) b);#endif (*count)++; b->next = (struct b_node *) NULL; return b;}// we know we have empties at the start offset so we will hop// t points that would be non F if there were a node here to speed this up.struct jffs2_empty_node { u32 first; u32 second;};static u32jffs2_scan_empty(u32 start_offset, struct part_info *part){ u32 max = part->size - sizeof(struct jffs2_raw_inode); // this would be either dir node_crc or frag isize u32 offset = start_offset + 32; struct jffs2_empty_node *node; start_offset += 4; while (offset < max) { node = (struct jffs2_empty_node *) (part->offset + offset); if ((node->first == 0xFFFFFFFF) && (node->second == 0xFFFFFFFF)) { // we presume that there were no nodes in between and advance in a hop // putLabeledWord("\t\tjffs2_scan_empty: empty at offset=",offset); start_offset = offset + 4; offset = start_offset + 32; // orig 32 + 4 bytes for the second==0xfffff } else { return start_offset; } } return start_offset;}static u32jffs_init_1pass_list(void){ g_1PassList.dirListHead = g_1PassList.dirListTail = NULL; g_1PassList.fragListHead = g_1PassList.fragListTail = NULL; g_1PassList.dirListCount = 0; g_1PassList.dirListMemBase = 0; g_1PassList.fragListCount = 0; g_1PassList.fragListMemBase = 0; g_1PassList.partOffset = 0x0; return 0;}// find the inode from the slashless name given a parentstatic longjffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest){ struct b_node *b; struct jffs2_raw_inode *jNode; u32 totalSize = 1; u32 oldTotalSize = 0; u32 size = 0; char *lDest = (char *) dest; char *src; long ret; int i; u32 counter = 0; char totalSizeSet = 0;#if 0 b = pL->fragListHead; while (b) { jNode = (struct jffs2_raw_inode *) (b->offset); if ((inode == jNode->ino)) { putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen); putLabeledWord("read_inode: inode = ", jNode->ino); putLabeledWord("read_inode: version = ", jNode->version); putLabeledWord("read_inode: isize = ", jNode->isize); putLabeledWord("read_inode: offset = ", jNode->offset); putLabeledWord("read_inode: csize = ", jNode->csize); putLabeledWord("read_inode: dsize = ", jNode->dsize); putLabeledWord("read_inode: compr = ", jNode->compr); putLabeledWord("read_inode: usercompr = ", jNode->usercompr); putLabeledWord("read_inode: flags = ", jNode->flags); } b = b->next; }#endif#if 1 b = pL->fragListHead; while (b && (size < totalSize)) { jNode = (struct jffs2_raw_inode *) (b->offset); if ((inode == jNode->ino)) { if ((jNode->isize == oldTotalSize) && (jNode->isize > totalSize)) { // 2 consecutive isizes indicate file length totalSize = jNode->isize; totalSizeSet = 1; } else if (!totalSizeSet) { totalSize = size + jNode->dsize + 1; } oldTotalSize = jNode->isize; if(dest) { src = ((char *) jNode) + sizeof(struct jffs2_raw_inode); // lDest = (char *) (dest + (jNode->offset & ~3)); lDest = (char *) (dest + jNode->offset);#if 0 putLabeledWord("\r\n\r\nread_inode: src = ", src); putLabeledWord("read_inode: dest = ", lDest); putLabeledWord("read_inode: dsize = ", jNode->dsize); putLabeledWord("read_inode: csize = ", jNode->csize); putLabeledWord("read_inode: version = ", jNode->version); putLabeledWord("read_inode: isize = ", jNode->isize); putLabeledWord("read_inode: offset = ", jNode->offset); putLabeledWord("read_inode: compr = ", jNode->compr); putLabeledWord("read_inode: flags = ", jNode->flags);#endif switch (jNode->compr) { case JFFS2_COMPR_NONE:#if 0 { int i; if ((dest > 0xc0092ff0) && (dest < 0xc0093000)) for (i = 0; i < first->length; i++) { putLabeledWord("\tCOMPR_NONE: src =", src + i); putLabeledWord("\tCOMPR_NONE: length =", first->length); putLabeledWord("\tCOMPR_NONE: dest =", dest + i); putLabeledWord("\tCOMPR_NONE: data =", (unsigned char) *(src + i)); } }#endif ret = (unsigned long) ldr_memcpy(lDest, src, jNode->dsize); break; case JFFS2_COMPR_ZERO: ret = 0; for (i = 0; i < jNode->dsize; i++) *(lDest++) = 0; break; case JFFS2_COMPR_RTIME: ret = 0; rtime_decompress(src, lDest, jNode->csize, jNode->dsize); break; case JFFS2_COMPR_DYNRUBIN: // this is slow but it works ret = 0; dynrubin_decompress(src, lDest, jNode->csize, jNode->dsize); break; case JFFS2_COMPR_ZLIB: ret = zlib_decompress(src, lDest, jNode->csize, jNode->dsize); break; default: /* unknown */ putLabeledWord("UNKOWN COMPRESSION METHOD = ", jNode->compr); return -1; break; } } size += jNode->dsize;#if 0 putLabeledWord("read_inode: size = ", size); putLabeledWord("read_inode: totalSize = ", totalSize); putLabeledWord("read_inode: compr ret = ", ret);#endif } b = b->next; counter++; }#endif#if 0 putLabeledWord("read_inode: returning = ", size);#endif return size;}// find the inode from the slashless name given a parentstatic u32jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino){ struct b_node *b; struct jffs2_raw_dirent *jDir; int len; u32 counter; u32 version = 0; u32 inode = 0; // name is assumed slash free len = strlen(name); counter = 0; // we need to search all and return the inode with the highest version for(b = pL->dirListHead;b;b=b->next,counter++) { jDir = (struct jffs2_raw_dirent *) (b->offset); if ((pino == jDir->pino) && (len == jDir->nsize) && (jDir->ino) && // 0 for unlink (!strncmp(jDir->name, name, len))) { // a match if (jDir->version < version) continue; if(jDir->version==0) { /* Is this legal? */ putstr(" ** WARNING ** "); putnstr(jDir->name, jDir->nsize); putstr(" is version 0 (in find, ignoring)\r\n"); } else if(jDir->version==version) { /* Im pretty sure this isn't ... */ putstr(" ** ERROR ** "); putnstr(jDir->name, jDir->nsize); putLabeledWord(" has dup version =", version); } inode = jDir->ino; version = jDir->version; }#if 0 putstr("\r\nfind_inode:p&l ->"); putnstr(jDir->name, jDir->nsize); putstr("\r\n"); putLabeledWord("pino = ", jDir->pino); putLabeledWord("nsize = ", jDir->nsize); putLabeledWord("b = ", (u32) b); putLabeledWord("counter = ", counter);#endif } return inode;}static char *mkmodestr(unsigned long mode, char *str){ static const char *l="xwr"; int mask=1, i; char c; switch (mode & S_IFMT) { case S_IFDIR: str[0]='d'; break; case S_IFBLK: str[0]='b'; break; case S_IFCHR: str[0]='c'; break; case S_IFIFO: str[0]='f'; break; case S_IFLNK: str[0]='l'; break; case S_IFSOCK: str[0]='s'; break; case S_IFREG: str[0]='-'; break; default: str[0]='?'; } for(i=0;i<9;i++) { c=l[i%3]; str[9-i]=(mode & mask)?c:'-'; mask=mask<<1; } if(mode & S_ISUID) str[3]=(mode & S_IXUSR)?'s':'S'; if(mode & S_ISGID) str[6]=(mode & S_IXGRP)?'s':'S'; if(mode & S_ISVTX) str[9]=(mode & S_IXOTH)?'t':'T'; str[10]='\0'; return str;}static inline void dump_stat(struct stat *st, const char *name){ char str[20]; char s[64], *p; if (st->st_mtime == (time_t)(-1)) /* some ctimes really hate -1 */ st->st_mtime = 1; ctime_r(&st->st_mtime, s/*, 64*/); /* newlib ctime doesn't have buflen */ if((p=strchr(s,'\n'))!=NULL) *p='\0'; if((p=strchr(s,'\r'))!=NULL) *p='\0';/* printf("%6lo %s %8ld %s %s\n", st->st_mode, mkmodestr(st->st_mode, str), st->st_size, s, name);*/ printf(" %s %8ld %s %s", mkmodestr(st->st_mode,str), st->st_size, s, name);}static inline u32 dump_inode(struct b_lists * pL, struct jffs2_raw_dirent *d, struct jffs2_raw_inode *i){ char fname[256]; struct stat st; if(!d || !i) return -1; strncpy(fname, d->name, d->nsize); fname[d->nsize]='\0'; memset(&st,0,sizeof(st)); st.st_mtime=i->mtime; st.st_mode=i->mode; st.st_ino=i->ino; /* neither dsize nor isize help us.. do it the long way */ st.st_size=jffs2_1pass_read_inode(pL, i->ino, NULL); dump_stat(&st, fname); if (d->type == DT_LNK) { unsigned char *src = (unsigned char *) (&i[1]); putstr(" -> "); putnstr(src, (int)i->dsize); } putstr("\r\n"); return 0;}// list inodes with the given pinostatic u32jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino){ struct b_node *b; struct jffs2_raw_dirent *jDir; for(b = pL->dirListHead;b;b=b->next) { jDir = (struct jffs2_raw_dirent *) (b->offset); if ((pino == jDir->pino) && (jDir->ino)) { // 0 inode for unlink u32 i_version=0; struct jffs2_raw_inode *jNode, *i=NULL; struct b_node *b2 = pL->fragListHead; while (b2) { jNode = (struct jffs2_raw_inode *) (b2->offset); if (jNode->ino == jDir->ino && jNode->version>=i_version) i=jNode; b2 = b2->next; } dump_inode(pL, jDir, i); } } return pino;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -