@ -1,3 +1,4 @@
/* vi: set sw=4 ts=4: */
/*
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Filename : jffs2 . c
@ -75,6 +76,42 @@
*
*/
/*
* Bugfixing by Kai - Uwe Bloem < kai - uwe . bloem @ auerswald . de > , ( C ) Mar / 2003
*
* - overhaul of the memory management . Removed much of the " paper-bagging "
* in that part of the code , fixed several bugs , now frees memory when
* partition is changed .
* It ' s still ugly : - (
* - fixed a bug in jffs2_1pass_read_inode where the file length calculation
* was incorrect . Removed a bit of the paper - bagging as well .
* - removed double crc calculation for fragment headers in jffs2_private . h
* for speedup .
* - scan_empty rewritten in a more " standard " manner ( non - paperbag , that is ) .
* - spinning wheel now spins depending on how much memory has been scanned
* - lots of small changes all over the place to " improve " readability .
* - implemented fragment sorting to ensure that the newest data is copied
* if there are multiple copies of fragments for a certain file offset .
*
* The fragment sorting feature must be enabled by CFG_JFFS2_SORT_FRAGMENTS .
* Sorting is done while adding fragments to the lists , which is more or less a
* bubble sort . This takes a lot of time , and is most probably not an issue if
* the boot filesystem is always mounted readonly .
*
* You should define it if the boot filesystem is mounted writable , and updates
* to the boot files are done by copying files to that filesystem .
*
*
* There ' s a big issue left : endianess is completely ignored in this code . Duh !
*
*
* You still should have paper bags at hand : - ( . The code lacks more or less
* any comment , and is still arcane and difficult to read in places . As this
* is incompatible with any new code from the jffs2 maintainers anyway , it
* should probably be dumped and replaced by something like jffs2reader !
*/
# include <common.h>
# include <config.h>
# include <malloc.h>
@ -88,124 +125,197 @@
# include "jffs2_private.h"
/* Compression names */
static char * compr_names [ ] = {
" NONE " ,
" ZERO " ,
" RTIME " ,
" RUBINMIPS " ,
" COPY " ,
" DYNRUBIN " ,
" ZLIB " } ;
static char spinner [ ] = { ' | ' , ' \\ ' , ' - ' , ' / ' } ;
# define NODE_CHUNK 1024 /* size of memory allocation chunk in b_nodes */
# define SPIN_BLKSIZE 18 /* spin after having scanned 1<<BLKSIZE bytes */
/* Debugging switches */
# undef DEBUG_DIRENTS /* print directory entry list after scan */
# undef DEBUG_FRAGMENTS /* print fragment list after scan */
# undef DEBUG /* enable debugging messages */
# define DEBUG
# ifdef DEBUG
# define DEBUGF(fmt,args...) printf(fmt ,##args)
# else
# define DEBUGF(fmt,args...)
# endif
# define MALLOC_CHUNK (10*1024)
/* Compression names */
static char * compr_names [ ] = {
" NONE " ,
" ZERO " ,
" RTIME " ,
" RUBINMIPS " ,
" COPY " ,
" DYNRUBIN " ,
" ZLIB "
} ;
/* Spinning wheel */
static char spinner [ ] = { ' | ' , ' / ' , ' - ' , ' \\ ' } ;
/* Memory management */
struct mem_block {
u32 index ;
struct mem_block * next ;
struct b_node nodes [ NODE_CHUNK ] ;
} ;
static void
free_nodes ( struct b_list * list )
{
while ( list - > listMemBase ! = NULL ) {
struct mem_block * next = list - > listMemBase - > next ;
free ( list - > listMemBase ) ;
list - > listMemBase = next ;
}
}
static struct b_node *
add_node ( struct b_node * tail , u32 * count , u32 * memBase )
add_node ( struct b_list * list )
{
u32 index ;
u32 memLimit ;
u32 index = 0 ;
struct mem_block * memBase ;
struct b_node * b ;
index = ( * count ) * sizeof ( struct b_node ) % MALLOC_CHUNK ;
memLimit = MALLOC_CHUNK ;
memBase = list - > listMemBase ;
if ( memBase ! = NULL )
index = memBase - > index ;
#if 0
putLabeledWord ( " add_node: index = " , index ) ;
putLabeledWord ( " add_node: memLimit = " , memLimit ) ;
putLabeledWord ( " add_node: memBase = " , * memBase ) ;
putLabeledWord ( " add_node: memBase = " , list - > listMemBase ) ;
# 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 ) {
if ( memBase = = NULL | | index > = NODE_CHUNK ) {
/* we need more space before we continue */
memBase = mmalloc ( sizeof ( struct mem_block ) ) ;
if ( memBase = = NULL ) {
putstr ( " add_node: malloc failed \n " ) ;
return NULL ;
}
memBase - > next = list - > listMemBase ;
index = 0 ;
#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 ;
b = & memBase - > nodes [ index ] ;
index + + ;
#if 0
putLabeledWord ( " add_node: tail = " , ( u32 ) tail ) ;
if ( tail )
putLabeledWord ( " add_node: tail->next = " , ( u32 ) tail - > next ) ;
memBase - > index = index ;
list - > listMemBase = memBase ;
list - > listCount + + ;
return b ;
}
static struct b_node *
insert_node ( struct b_list * list , u32 offset )
{
struct b_node * new ;
# ifdef CFG_JFFS2_SORT_FRAGMENTS
struct b_node * b , * prev ;
# endif
#if 0
putLabeledWord ( " add_node: mb+i = " , ( u32 ) ( * memBase + index ) ) ;
putLabeledWord ( " add_node: b = " , ( u32 ) b ) ;
if ( ! ( new = add_node ( list ) ) ) {
putstr ( " add_node failed! \r \n " ) ;
return NULL ;
}
new - > offset = offset ;
# ifdef CFG_JFFS2_SORT_FRAGMENTS
if ( list - > listTail ! = NULL & & list - > listCompare ( new , list - > listTail ) )
prev = list - > listTail ;
else if ( list - > listLast ! = NULL & & list - > listCompare ( new , list - > listLast ) )
prev = list - > listLast ;
else
prev = NULL ;
for ( b = ( prev ? prev - > next : list - > listHead ) ;
b ! = NULL & & list - > listCompare ( new , b ) ;
prev = b , b = b - > next ) {
list - > listLoops + + ;
}
if ( b ! = NULL )
list - > listLast = prev ;
if ( b ! = NULL ) {
new - > next = b ;
if ( prev ! = NULL )
prev - > next = new ;
else
list - > listHead = new ;
} else
# endif
( * count ) + + ;
b - > next = ( struct b_node * ) NULL ;
return b ;
{
new - > next = ( struct b_node * ) NULL ;
if ( list - > listTail ! = NULL ) {
list - > listTail - > next = new ;
list - > listTail = new ;
} else {
list - > listTail = list - > listHead = new ;
}
}
return new ;
}
/* 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 ;
} ;
# ifdef CFG_JFFS2_SORT_FRAGMENTS
static int compare_inodes ( struct b_node * new , struct b_node * old )
{
struct jffs2_raw_inode * jNew = ( struct jffs2_raw_inode * ) new - > offset ;
struct jffs2_raw_inode * jOld = ( struct jffs2_raw_inode * ) old - > offset ;
return jNew - > version < jOld - > version ;
}
static int compare_dirents ( struct b_node * new , struct b_node * old )
{
struct jffs2_raw_dirent * jNew = ( struct jffs2_raw_dirent * ) new - > offset ;
struct jffs2_raw_dirent * jOld = ( struct jffs2_raw_dirent * ) old - > offset ;
return jNew - > version > jOld - > version ;
}
# endif
static u32
jffs2_scan_empty ( u32 start_offset , struct part_info * part )
{
u32 max = part - > size - sizeof ( struct jffs2_raw_inode ) ;
char * max = part - > offset + part - > size - sizeof ( struct jffs2_raw_inode ) ;
char * offset = part - > offset + start_offset ;
/* 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 ;
}
while ( offset < max & & * ( u32 * ) offset = = 0xFFFFFFFF ) {
offset + = sizeof ( u32 ) ;
/* return if spinning is due */
if ( ( ( u32 ) offset & ( ( 1 < < SPIN_BLKSIZE ) - 1 ) ) = = 0 ) break ;
}
return start_offset ;
return offset - part - > offset ;
}
static u32
jffs_init_1pass_list ( struct part_info * part )
{
if ( 0 ! = ( part - > jffs2_priv = malloc ( sizeof ( struct b_lists ) ) ) ) {
struct b_lists * pL = ( struct b_lists * ) part - > jffs2_priv ;
struct b_lists * pL ;
pL - > dirListHead = pL - > dirListTail = NULL ;
pL - > fragListHead = pL - > fragListTail = NULL ;
pL - > dirListCount = 0 ;
pL - > dirListMemBase = 0 ;
pL - > fragListCount = 0 ;
pL - > fragListMemBase = 0 ;
pL - > partOffset = 0x0 ;
if ( part - > jffs2_priv ! = NULL ) {
pL = ( struct b_lists * ) part - > jffs2_priv ;
free_nodes ( & pL - > frag ) ;
free_nodes ( & pL - > dir ) ;
free ( pL ) ;
}
if ( NULL ! = ( part - > jffs2_priv = malloc ( sizeof ( struct b_lists ) ) ) ) {
pL = ( struct b_lists * ) part - > jffs2_priv ;
memset ( pL , 0 , sizeof ( * pL ) ) ;
# ifdef CFG_JFFS2_SORT_FRAGMENTS
pL - > dir . listCompare = compare_dirents ;
pL - > frag . listCompare = compare_inodes ;
# endif
}
return 0 ;
}
@ -216,21 +326,18 @@ jffs2_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 ;
u32 totalSize = 0 ;
u16 latestVersion = 0 ;
char * lDest ;
char * src ;
long ret ;
int i ;
u32 counter = 0 ;
char totalSizeSet = 0 ;
#if 0
b = pL - > fragListHead ;
while ( b ) {
for ( b = pL - > frag . listHead ; b ! = NULL ; b = b - > next ) {
jNode = ( struct jffs2_raw_inode * ) ( b - > offset ) ;
if ( ( inode = = jNode - > ino ) ) {
#if 0
putLabeledWord ( " \r \n \r \n read_inode: totlen = " , jNode - > totlen ) ;
putLabeledWord ( " read_inode: inode = " , jNode - > ino ) ;
putLabeledWord ( " read_inode: version = " , jNode - > version ) ;
@ -241,58 +348,26 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
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 */
/* get actual file length from the newest node */
if ( jNode - > version > = latestVersion ) {
totalSize = jNode - > isize ;
totalSizeSet = 1 ;
} else if ( ! totalSizeSet ) {
totalSize = size + jNode - > dsize + 1 ;
latestVersion = jNode - > version ;
}
oldTotalSize = jNode - > isize ;
if ( dest ) {
src = ( ( char * ) jNode ) + sizeof ( struct jffs2_raw_inode ) ;
/* lDest = (char *) (dest + (jNode->offset & ~3)); */
/* ignore data behind latest known EOF */
if ( jNode - > offset > totalSize )
continue ;
lDest = ( char * ) ( dest + jNode - > offset ) ;
#if 0
putLabeledWord ( " \r \n \r \n read_inode: src = " , src ) ;
putLabeledWord ( " read_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 ( " \t COMPR_NONE: src = " , src + i ) ;
putLabeledWord ( " \t COMPR_NONE: length = " , first - > length ) ;
putLabeledWord ( " \t COMPR_NONE: dest = " , dest + i ) ;
putLabeledWord ( " \t COMPR_NONE: data = " , ( unsigned char ) * ( src + i ) ) ;
}
}
# endif
ret = ( unsigned long ) ldr_memcpy ( lDest , src , jNode - > dsize ) ;
break ;
case JFFS2_COMPR_ZERO :
@ -320,22 +395,18 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
}
}
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 = " , s ize) ;
putLabeledWord ( " read_inode: returning = " , totalS ize) ;
# endif
return s ize;
return totalS ize;
}
/* find the inode from the slashless name given a parent */
@ -354,18 +425,19 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
counter = 0 ;
/* we need to search all and return the inode with the highest version */
for ( b = pL - > dirListHead ; b ; b = b - > next , counter + + ) {
for ( b = pL - > dir . listHead ; b ; b = b - > next , counter + + ) {
jDir = ( struct jffs2_raw_dirent * ) ( b - > offset ) ;
if ( ( pino = = jDir - > pino ) & & ( len = = jDir - > nsize ) & & ( jDir - > ino ) & & /* 0 for unlink */
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 ) {
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 ) {
} else if ( jDir - > version = = version ) {
/* Im pretty sure this isn't ... */
putstr ( " ** ERROR ** " ) ;
putnstr ( jDir - > name , jDir - > nsize ) ;
@ -389,53 +461,53 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
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 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 ;
char str [ 20 ] ;
char s [ 64 ] , * p ;
if ( st - > st_mtime = = ( time_t ) ( - 1 ) ) /* some ctimes really hate -1 */
st - > st_mtime = 1 ;
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 */
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 ' ;
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 ( " %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 ) ;
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 )
@ -446,16 +518,16 @@ static inline u32 dump_inode(struct b_lists * pL, struct jffs2_raw_dirent *d, st
if ( ! d | | ! i ) return - 1 ;
strncpy ( fname , d - > name , d - > nsize ) ;
fname [ d - > nsize ] = ' \0 ' ;
fname [ d - > nsize ] = ' \0 ' ;
memset ( & st , 0 , sizeof ( st ) ) ;
st . st_mtime = i - > mtime ;
st . st_mode = i - > mode ;
st . st_ino = i - > ino ;
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 ) ;
st . st_size = jffs2_1pass_read_inode ( pL , i - > ino , NULL ) ;
dump_stat ( & st , fname ) ;
@ -477,18 +549,18 @@ jffs2_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 ) {
for ( b = pL - > dir . listHead ; 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 - > fragL istHead ;
if ( ( pino = = jDir - > pino ) & & ( jDir - > ino ) ) { /* ino=0 -> unlink */
u32 i_version = 0 ;
struct jffs2_raw_inode * jNode , * i = NULL ;
struct b_node * b2 = pL - > frag . l istHead;
while ( b2 ) {
jNode = ( struct jffs2_raw_inode * ) ( b2 - > offset ) ;
if ( jNode - > ino = = jDir - > ino
& & jNode - > version > = i_version )
i = jNode ;
& & jNode - > version > = i_version )
i = jNode ;
b2 = b2 - > next ;
}
@ -568,7 +640,7 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
unsigned char * src ;
/* we need to search all and return the inode with the highest version */
for ( b = pL - > dirL istHead ; b ; b = b - > next ) {
for ( b = pL - > dir . l istHead; b ; b = b - > next ) {
jDir = ( struct jffs2_raw_dirent * ) ( b - > offset ) ;
if ( ino = = jDir - > ino ) {
if ( jDir - > version < version ) continue ;
@ -593,8 +665,9 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
/* now we found the right entry again. (shoulda returned inode*) */
if ( jDirFound - > type ! = DT_LNK )
return jDirFound - > ino ;
/* so its a soft link so we follow it again. */
b2 = pL - > fragListHead ;
/* it's a soft link so we follow it again. */
b2 = pL - > frag . listHead ;
while ( b2 ) {
jNode = ( struct jffs2_raw_inode * ) ( b2 - > offset ) ;
if ( jNode - > ino = = jDirFound - > ino ) {
@ -644,7 +717,8 @@ jffs2_1pass_search_list_inodes(struct b_lists * pL, const char *fname, u32 pino)
tmp [ i ] = c [ i + 1 ] ;
tmp [ i ] = ' \0 ' ;
/* only a failure if we arent looking at top level */
if ( ! ( pino = jffs2_1pass_find_inode ( pL , working_tmp , pino ) ) & & ( working_tmp [ 0 ] ) ) {
if ( ! ( pino = jffs2_1pass_find_inode ( pL , working_tmp , pino ) ) & &
( working_tmp [ 0 ] ) ) {
putstr ( " find_inode failed for name= " ) ;
putstr ( working_tmp ) ;
putstr ( " \r \n " ) ;
@ -674,29 +748,30 @@ jffs2_1pass_rescan_needed(struct part_info *part)
{
struct b_node * b ;
struct jffs2_unknown_node * node ;
struct b_lists * pL = ( struct b_lists * ) part - > jffs2_priv ;
struct b_lists * pL = ( struct b_lists * ) part - > jffs2_priv ;
if ( part - > jffs2_priv = = 0 ) {
DEBUGF ( " rescan: First time in use \n " ) ;
return 1 ;
}
/* if we have no list, we need to rescan */
if ( pL - > fragL istCount = = 0 ) {
if ( pL - > frag . l istCount = = 0 ) {
DEBUGF ( " rescan: fraglist zero \n " ) ;
return 1 ;
}
/* or if we are scanninga new partition */
/* or if we are scanning a new partition */
if ( pL - > partOffset ! = part - > offset ) {
DEBUGF ( " rescan: different partition \n " ) ;
return 1 ;
}
/* but suppose someone reflashed the root partition at the same offset... */
b = pL - > dirL istHead ;
/* but suppose someone reflashed a partition at the same offset... */
b = pL - > dir . l istHead;
while ( b ) {
node = ( struct jffs2_unknown_node * ) ( b - > offset ) ;
if ( node - > nodetype ! = JFFS2_NODETYPE_DIRENT ) {
DEBUGF ( " rescan: fs changed beneath me? (%lx) \n " , ( unsigned long ) b - > offset ) ;
DEBUGF ( " rescan: fs changed beneath me? (%lx) \n " ,
( unsigned long ) b - > offset ) ;
return 1 ;
}
b = b - > next ;
@ -704,12 +779,71 @@ jffs2_1pass_rescan_needed(struct part_info *part)
return 0 ;
}
# ifdef DEBUG_FRAGMENTS
static void
dump_fragments ( struct b_lists * pL )
{
struct b_node * b ;
struct jffs2_raw_inode * jNode ;
putstr ( " \r \n \r \n ******The fragment Entries****** \r \n " ) ;
b = pL - > frag . listHead ;
while ( b ) {
jNode = ( struct jffs2_raw_inode * ) ( b - > offset ) ;
putLabeledWord ( " \r \n \t build_list: FLASH_OFFSET = " , b - > offset ) ;
putLabeledWord ( " \t build_list: totlen = " , jNode - > totlen ) ;
putLabeledWord ( " \t build_list: inode = " , jNode - > ino ) ;
putLabeledWord ( " \t build_list: version = " , jNode - > version ) ;
putLabeledWord ( " \t build_list: isize = " , jNode - > isize ) ;
putLabeledWord ( " \t build_list: atime = " , jNode - > atime ) ;
putLabeledWord ( " \t build_list: offset = " , jNode - > offset ) ;
putLabeledWord ( " \t build_list: csize = " , jNode - > csize ) ;
putLabeledWord ( " \t build_list: dsize = " , jNode - > dsize ) ;
putLabeledWord ( " \t build_list: compr = " , jNode - > compr ) ;
putLabeledWord ( " \t build_list: usercompr = " , jNode - > usercompr ) ;
putLabeledWord ( " \t build_list: flags = " , jNode - > flags ) ;
putLabeledWord ( " \t build_list: offset = " , b - > offset ) ; // FIXME: ? [RS]
b = b - > next ;
}
}
# endif
# ifdef DEBUG_DIRENTS
static void
dump_dirents ( struct b_lists * pL )
{
struct b_node * b ;
struct jffs2_raw_dirent * jDir ;
putstr ( " \r \n \r \n ******The directory Entries****** \r \n " ) ;
b = pL - > dir . listHead ;
while ( b ) {
jDir = ( struct jffs2_raw_dirent * ) ( b - > offset ) ;
putstr ( " \r \n " ) ;
putnstr ( jDir - > name , jDir - > nsize ) ;
putLabeledWord ( " \r \n \t build_list: magic = " , jDir - > magic ) ;
putLabeledWord ( " \t build_list: nodetype = " , jDir - > nodetype ) ;
putLabeledWord ( " \t build_list: hdr_crc = " , jDir - > hdr_crc ) ;
putLabeledWord ( " \t build_list: pino = " , jDir - > pino ) ;
putLabeledWord ( " \t build_list: version = " , jDir - > version ) ;
putLabeledWord ( " \t build_list: ino = " , jDir - > ino ) ;
putLabeledWord ( " \t build_list: mctime = " , jDir - > mctime ) ;
putLabeledWord ( " \t build_list: nsize = " , jDir - > nsize ) ;
putLabeledWord ( " \t build_list: type = " , jDir - > type ) ;
putLabeledWord ( " \t build_list: node_crc = " , jDir - > node_crc ) ;
putLabeledWord ( " \t build_list: name_crc = " , jDir - > name_crc ) ;
putLabeledWord ( " \t build_list: offset = " , b - > offset ) ; // FIXME: ? [RS]
b = b - > next ;
}
}
# endif
static u32
jffs2_1pass_build_lists ( struct part_info * part )
{
struct b_lists * pL ;
struct jffs2_unknown_node * node ;
u32 offset ;
u32 offset , oldoffset = 0 ;
u32 max = part - > size - sizeof ( struct jffs2_raw_inode ) ;
u32 counter = 0 ;
u32 counter4 = 0 ;
@ -722,71 +856,52 @@ jffs2_1pass_build_lists(struct part_info * part)
/* lcd_off(); */
/* if we are building a list we need to refresh the cache. */
/* note that since we don't free our memory, eventually this will be bad. */
/* but we're a bootldr so what the hell. */
jffs_init_1pass_list ( part ) ;
pL = ( struct b_lists * ) part - > jffs2_priv ;
pL = ( struct b_lists * ) part - > jffs2_priv ;
pL - > partOffset = part - > offset ;
offset = 0 ;
printf ( " Scanning JFFS2 FS: " ) ;
/* start at the beginning of the partition */
while ( offset < max ) {
if ( ! ( + + counter % 10000 ) )
printf ( " \b \b %c " , spinner [ ( counter / 10000 ) % 4 ] ) ;
if ( ( oldoffset > > SPIN_BLKSIZE ) ! = ( offset > > SPIN_BLKSIZE ) ) {
printf ( " \b \b %c " , spinner [ counter + + % sizeof ( spinner ) ] ) ;
oldoffset = offset ;
}
node = ( struct jffs2_unknown_node * ) ( part - > offset + offset ) ;
if ( node - > magic = = JFFS2_MAGIC_BITMASK & & hdr_crc ( node ) ) {
/* if its a fragment add it */
if ( node - > nodetype = = JFFS2_NODETYPE_INODE & & inode_crc ( ( struct jffs2_raw_inode * ) node ) ) {
if ( ! ( pL - > fragListTail = add_node ( pL - > fragListTail , & ( pL - > fragListCount ) ,
& ( pL - > fragListMemBase ) ) ) ) {
putstr ( " add_node failed! \r \n " ) ;
if ( node - > nodetype = = JFFS2_NODETYPE_INODE & &
inode_crc ( ( struct jffs2_raw_inode * ) node ) ) {
if ( insert_node ( & pL - > frag , ( u32 ) part - > offset +
offset ) = = NULL )
return 0 ;
}
pL - > fragListTail - > offset = ( u32 ) ( part - > offset + offset ) ;
if ( ! pL - > fragListHead )
pL - > fragListHead = pL - > fragListTail ;
} else if ( node - > nodetype = = JFFS2_NODETYPE_DIRENT & &
dirent_crc ( ( struct jffs2_raw_dirent * ) node ) & &
dirent_name_crc ( ( struct jffs2_raw_dirent * ) node ) ) {
if ( ! ( counterN % 100 ) )
printf ( " \b \b . " ) ;
#if 0
printf ( " Found DIRENT @ 0x%lx \n " , offset ) ;
putstr ( " \r \n build_lists:p&l -> " ) ;
putnstr ( ( ( struct jffs2_raw_dirent * ) node ) - > name , ( ( struct jffs2_raw_dirent * ) node ) - > nsize ) ;
putstr ( " \r \n " ) ;
putLabeledWord ( " \t pino = " , ( ( struct jffs2_raw_dirent * ) node ) - > pino ) ;
putLabeledWord ( " \t nsize = " , ( ( struct jffs2_raw_dirent * ) node ) - > nsize ) ;
# endif
if ( ! ( pL - > dirListTail = add_node ( pL - > dirListTail , & ( pL - > dirListCount ) , & ( pL - > dirListMemBase ) ) ) ) {
putstr ( " add_node failed! \r \n " ) ;
if ( insert_node ( & pL - > dir , ( u32 ) part - > offset +
offset ) = = NULL )
return 0 ;
}
pL - > dirListTail - > offset = ( u32 ) ( part - > offset + offset ) ;
#if 0
putLabeledWord ( " \t tail = " , ( u32 ) pL - > dirListTail ) ;
putstr ( " \t tailName -> " ) ;
putnstr ( ( ( struct jffs2_raw_dirent * ) ( pL - > dirListTail - > offset ) ) - > name ,
( ( struct jffs2_raw_dirent * ) ( pL - > dirListTail - > offset ) ) - > nsize ) ;
putstr ( " \r \n " ) ;
# endif
if ( ! pL - > dirListHead )
pL - > dirListHead = pL - > dirListTail ;
counterN + + ;
} else if ( node - > nodetype = = JFFS2_NODETYPE_CLEANMARKER ) {
if ( node - > totlen ! = sizeof ( struct jffs2_unknown_node ) )
printf ( " OOPS Cleanmarker has bad size %d != %d \n " , node - > totlen , sizeof ( struct jffs2_unknown_node ) ) ;
printf ( " OOPS Cleanmarker has bad size "
" %d != %d \n " , node - > totlen ,
sizeof ( struct jffs2_unknown_node ) ) ;
} else {
printf ( " Unknown node type: %x len %d offset 0x%x \n " , node - > nodetype , node - > totlen , offset ) ;
printf ( " Unknown node type: %x len %d "
" offset 0x%x \n " , node - > nodetype ,
node - > totlen , offset ) ;
}
offset + = ( ( node - > totlen + 3 ) & ~ 3 ) ;
counterF + + ;
} else if ( node - > magic = = JFFS2_EMPTY_BITMASK & & node - > nodetype = = JFFS2_EMPTY_BITMASK ) {
} else if ( node - > magic = = JFFS2_EMPTY_BITMASK & &
node - > nodetype = = JFFS2_EMPTY_BITMASK ) {
offset = jffs2_scan_empty ( offset , part ) ;
} else { /* if we know nothing of the filesystem , we just step and look. */
} else { /* if we know nothing, we just step and look. */
offset + = 4 ;
counter4 + + ;
}
@ -799,66 +914,21 @@ jffs2_1pass_build_lists(struct part_info * part)
/* splash(); */
#if 0
putLabeledWord ( " dir entries = " , pL - > dirL istCount ) ;
putLabeledWord ( " frag entries = " , pL - > fragL istCount ) ;
putLabeledWord ( " dir entries = " , pL - > dir . l istCount) ;
putLabeledWord ( " frag entries = " , pL - > frag . l istCount) ;
putLabeledWord ( " +4 increments = " , counter4 ) ;
putLabeledWord ( " +file_offset increments = " , counterF ) ;
# endif
# undef SHOW_ALL
# undef SHOW_ALL_FRAGMENTS
# ifdef SHOW_ALL
{
struct b_node * b ;
struct b_node * b2 ;
struct jffs2_raw_dirent * jDir ;
struct jffs2_raw_inode * jNode ;
putstr ( " \r \n \r \n ******The directory Entries****** \r \n " ) ;
b = pL - > dirListHead ;
while ( b ) {
jDir = ( struct jffs2_raw_dirent * ) ( b - > offset ) ;
putstr ( " \r \n " ) ;
putnstr ( jDir - > name , jDir - > nsize ) ;
putLabeledWord ( " \r \n \t build_list: magic = " , jDir - > magic ) ;
putLabeledWord ( " \t build_list: nodetype = " , jDir - > nodetype ) ;
putLabeledWord ( " \t build_list: hdr_crc = " , jDir - > hdr_crc ) ;
putLabeledWord ( " \t build_list: pino = " , jDir - > pino ) ;
putLabeledWord ( " \t build_list: version = " , jDir - > version ) ;
putLabeledWord ( " \t build_list: ino = " , jDir - > ino ) ;
putLabeledWord ( " \t build_list: mctime = " , jDir - > mctime ) ;
putLabeledWord ( " \t build_list: nsize = " , jDir - > nsize ) ;
putLabeledWord ( " \t build_list: type = " , jDir - > type ) ;
putLabeledWord ( " \t build_list: node_crc = " , jDir - > node_crc ) ;
putLabeledWord ( " \t build_list: name_crc = " , jDir - > name_crc ) ;
b = b - > next ;
}
# ifdef DEBUG_DIRENTS
dump_dirents ( pL ) ;
# endif
# ifdef SHOW_ALL_FRAGMENTS
putstr ( " \r \n \r \n ******The fragment Entries****** \r \n " ) ;
b = pL - > fragListHead ;
while ( b ) {
jNode = ( struct jffs2_raw_inode * ) ( b - > offset ) ;
putLabeledWord ( " \r \n \t build_list: FLASH_OFFSET = " , b - > offset ) ;
putLabeledWord ( " \t build_list: totlen = " , jNode - > totlen ) ;
putLabeledWord ( " \t build_list: inode = " , jNode - > ino ) ;
putLabeledWord ( " \t build_list: version = " , jNode - > version ) ;
putLabeledWord ( " \t build_list: isize = " , jNode - > isize ) ;
putLabeledWord ( " \t build_list: atime = " , jNode - > atime ) ;
putLabeledWord ( " \t build_list: offset = " , jNode - > offset ) ;
putLabeledWord ( " \t build_list: csize = " , jNode - > csize ) ;
putLabeledWord ( " \t build_list: dsize = " , jNode - > dsize ) ;
putLabeledWord ( " \t build_list: compr = " , jNode - > compr ) ;
putLabeledWord ( " \t build_list: usercompr = " , jNode - > usercompr ) ;
putLabeledWord ( " \t build_list: flags = " , jNode - > flags ) ;
b = b - > next ;
}
# endif /* SHOW_ALL_FRAGMENTS */
}
# ifdef DEBUG_FRAGMENTS
dump_fragments ( pL ) ;
# endif
# endif /* SHOW_ALL */
/* give visual feedback that we are done scanning the flash */
led_blink ( 0x0 , 0x0 , 0x1 , 0x1 ) ; /* off, forever, on 100ms, off 100ms */
return 1 ;
@ -875,13 +945,13 @@ jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL)
struct jffs2_raw_inode * jNode ;
int i ;
b = pL - > fragListHead ;
for ( i = 0 ; i < JFFS2_NUM_COMPR ; i + + ) {
piL - > compr_info [ i ] . num_frags = 0 ;
piL - > compr_info [ i ] . compr_sum = 0 ;
piL - > compr_info [ i ] . decompr_sum = 0 ;
}
b = pL - > frag . listHead ;
while ( b ) {
jNode = ( struct jffs2_raw_inode * ) ( b - > offset ) ;
if ( jNode - > compr < JFFS2_NUM_COMPR ) {
@ -917,7 +987,7 @@ jffs2_1pass_ls(struct part_info * part, const char *fname)
long ret = 0 ;
u32 inode ;
if ( ! ( pl = jffs2_get_list ( part , " ls " ) ) )
if ( ! ( pl = jffs2_get_list ( part , " ls " ) ) )
return 0 ;
if ( ! ( inode = jffs2_1pass_search_list_inodes ( pl , fname , 1 ) ) ) {
@ -983,7 +1053,7 @@ jffs2_1pass_info(struct part_info * part)
return 0 ;
jffs2_1pass_fill_info ( pl , & info ) ;
for ( i = 0 ; i < JFFS2_NUM_COMPR ; i + + ) {
for ( i = 0 ; i < JFFS2_NUM_COMPR ; i + + ) {
printf ( " Compression: %s \n " , compr_names [ i ] ) ;
printf ( " \t frag count: %d \n " , info . compr_info [ i ] . num_frags ) ;
printf ( " \t compressed sum: %d \n " , info . compr_info [ i ] . compr_sum ) ;