diff options
Diffstat (limited to 'roms/u-boot/fs/jffs2')
| -rw-r--r-- | roms/u-boot/fs/jffs2/LICENCE | 30 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/Makefile | 13 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/compr_lzo.c | 401 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/compr_rtime.c | 87 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/compr_rubin.c | 122 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/compr_zlib.c | 48 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/jffs2_1pass.c | 1865 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/jffs2_nand_1pass.c | 1030 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/jffs2_nand_private.h | 133 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/jffs2_private.h | 101 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/mini_inflate.c | 377 | ||||
| -rw-r--r-- | roms/u-boot/fs/jffs2/summary.h | 163 | 
12 files changed, 4370 insertions, 0 deletions
diff --git a/roms/u-boot/fs/jffs2/LICENCE b/roms/u-boot/fs/jffs2/LICENCE new file mode 100644 index 00000000..56288590 --- /dev/null +++ b/roms/u-boot/fs/jffs2/LICENCE @@ -0,0 +1,30 @@ +The files in this directory and elsewhere which refer to this LICENCE +file are part of JFFS2, the Journalling Flash File System v2. + +	Copyright © 2001-2007 Red Hat, Inc. and others + +JFFS2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 or (at your option) any later  +version. + +JFFS2 is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with JFFS2; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + +As a special exception, if other files instantiate templates or use +macros or inline functions from these files, or you compile these +files and link them with other works to produce a work based on these +files, these files do not by themselves cause the resulting work to be +covered by the GNU General Public License. However the source code for +these files must still be made available in accordance with section (3) +of the GNU General Public License. + +This exception does not invalidate any other reasons why a work based on +this file might be covered by the GNU General Public License. + diff --git a/roms/u-boot/fs/jffs2/Makefile b/roms/u-boot/fs/jffs2/Makefile new file mode 100644 index 00000000..4cb0600c --- /dev/null +++ b/roms/u-boot/fs/jffs2/Makefile @@ -0,0 +1,13 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +obj-$(CONFIG_JFFS2_LZO) += compr_lzo.o +obj-y += compr_rtime.o +obj-y += compr_rubin.o +obj-y += compr_zlib.o +obj-y += jffs2_1pass.o +obj-y += mini_inflate.o diff --git a/roms/u-boot/fs/jffs2/compr_lzo.c b/roms/u-boot/fs/jffs2/compr_lzo.c new file mode 100644 index 00000000..e648ec4f --- /dev/null +++ b/roms/u-boot/fs/jffs2/compr_lzo.c @@ -0,0 +1,401 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2004 Patrik Kluba, + *		      University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + * + * $Id: compr_lzo.c,v 1.3 2004/06/23 16:34:39 havasi Exp $ + * + */ + +/* +   LZO1X-1 (and -999) compression module for jffs2 +   based on the original LZO sources +*/ + +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ + +/* +   Original copyright notice follows: + +   lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm +   lzo_ptr.h -- low-level pointer constructs +   lzo_swd.ch -- sliding window dictionary +   lzoconf.h -- configuration for the LZO real-time data compression library +   lzo_mchw.ch -- matching functions using a window +   minilzo.c -- mini subset of the LZO real-time data compression library +   config1x.h -- configuration for the LZO1X algorithm +   lzo1x.h -- public interface of the LZO1X compression algorithm + +   These files are part of the LZO real-time data compression library. + +   Copyright (C) 1996-2002 Markus Franz Xaver Johannes Oberhumer +   All Rights Reserved. + +   The LZO library is free software; you can redistribute it and/or +   modify it under the terms of the GNU General Public License as +   published by the Free Software Foundation; either version 2 of +   the License, or (at your option) any later version. + +   The LZO library is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with the LZO library; see the file COPYING. +   If not, write to the Free Software Foundation, Inc., +   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +   Markus F.X.J. Oberhumer +   <markus@oberhumer.com> +*/ + +/* + +	2004-02-16  pajko <pajko(AT)halom(DOT)u-szeged(DOT)hu> +				Initial release +					-removed all 16 bit code +					-all sensitive data will be on 4 byte boundary +					-removed check parts for library use +					-removed all but LZO1X-* compression + +*/ + + +#include <config.h> +#include <linux/stddef.h> +#include <jffs2/jffs2.h> +#include <jffs2/compr_rubin.h> + +/* Integral types that have *exactly* the same number of bits as a lzo_voidp */ +typedef unsigned long lzo_ptr_t; +typedef long lzo_sptr_t; + +/* data type definitions */ +#define U32 unsigned long +#define S32 signed long +#define I32 long +#define U16 unsigned short +#define S16 signed short +#define I16 short +#define U8 unsigned char +#define S8 signed char +#define I8 char + +#define M1_MAX_OFFSET	0x0400 +#define M2_MAX_OFFSET	0x0800 +#define M3_MAX_OFFSET	0x4000 +#define M4_MAX_OFFSET	0xbfff + +#define __COPY4(dst,src)  * (lzo_uint32p)(dst) = * (const lzo_uint32p)(src) +#define COPY4(dst,src)	__COPY4((lzo_ptr_t)(dst),(lzo_ptr_t)(src)) + +#define TEST_IP		(ip < ip_end) +#define TEST_OP		(op <= op_end) + +#define NEED_IP(x) \ +	    if ((lzo_uint)(ip_end - ip) < (lzo_uint)(x))  goto input_overrun +#define NEED_OP(x) \ +	    if ((lzo_uint)(op_end - op) < (lzo_uint)(x))  goto output_overrun +#define TEST_LOOKBEHIND(m_pos,out)    if (m_pos < out) goto lookbehind_overrun + +typedef U32 lzo_uint32; +typedef I32 lzo_int32; +typedef U32 lzo_uint; +typedef I32 lzo_int; +typedef int lzo_bool; + +#define lzo_byte		U8 +#define lzo_bytep		U8 * +#define lzo_charp		char * +#define lzo_voidp		void * +#define lzo_shortp		short * +#define lzo_ushortp		unsigned short * +#define lzo_uint32p		lzo_uint32 * +#define lzo_int32p		lzo_int32 * +#define lzo_uintp		lzo_uint * +#define lzo_intp		lzo_int * +#define lzo_voidpp		lzo_voidp * +#define lzo_bytepp		lzo_bytep * +#define lzo_sizeof_dict_t		sizeof(lzo_bytep) + +#define LZO_E_OK		    0 +#define LZO_E_ERROR		    (-1) +#define LZO_E_OUT_OF_MEMORY	    (-2)	/* not used right now */ +#define LZO_E_NOT_COMPRESSIBLE	    (-3)	/* not used right now */ +#define LZO_E_INPUT_OVERRUN	    (-4) +#define LZO_E_OUTPUT_OVERRUN	    (-5) +#define LZO_E_LOOKBEHIND_OVERRUN    (-6) +#define LZO_E_EOF_NOT_FOUND	    (-7) +#define LZO_E_INPUT_NOT_CONSUMED    (-8) + +#define PTR(a)				((lzo_ptr_t) (a)) +#define PTR_LINEAR(a)		PTR(a) +#define PTR_ALIGNED_4(a)	((PTR_LINEAR(a) & 3) == 0) +#define PTR_ALIGNED_8(a)	((PTR_LINEAR(a) & 7) == 0) +#define PTR_ALIGNED2_4(a,b)	(((PTR_LINEAR(a) | PTR_LINEAR(b)) & 3) == 0) +#define PTR_ALIGNED2_8(a,b)	(((PTR_LINEAR(a) | PTR_LINEAR(b)) & 7) == 0) +#define PTR_LT(a,b)			(PTR(a) < PTR(b)) +#define PTR_GE(a,b)			(PTR(a) >= PTR(b)) +#define PTR_DIFF(a,b)		((lzo_ptrdiff_t) (PTR(a) - PTR(b))) +#define pd(a,b)			((lzo_uint) ((a)-(b))) + +typedef ptrdiff_t lzo_ptrdiff_t; + +static int +lzo1x_decompress (const lzo_byte * in, lzo_uint in_len, +		  lzo_byte * out, lzo_uintp out_len, lzo_voidp wrkmem) +{ +	register lzo_byte *op; +	register const lzo_byte *ip; +	register lzo_uint t; + +	register const lzo_byte *m_pos; + +	const lzo_byte *const ip_end = in + in_len; +	lzo_byte *const op_end = out + *out_len; + +	*out_len = 0; + +	op = out; +	ip = in; + +	if (*ip > 17) +	{ +		t = *ip++ - 17; +		if (t < 4) +			goto match_next; +		NEED_OP (t); +		NEED_IP (t + 1); +		do +			*op++ = *ip++; +		while (--t > 0); +		goto first_literal_run; +	} + +	while (TEST_IP && TEST_OP) +	{ +		t = *ip++; +		if (t >= 16) +			goto match; +		if (t == 0) +		{ +			NEED_IP (1); +			while (*ip == 0) +			{ +				t += 255; +				ip++; +				NEED_IP (1); +			} +			t += 15 + *ip++; +		} +		NEED_OP (t + 3); +		NEED_IP (t + 4); +		if (PTR_ALIGNED2_4 (op, ip)) +		{ +			COPY4 (op, ip); + +			op += 4; +			ip += 4; +			if (--t > 0) +			{ +				if (t >= 4) +				{ +					do +					{ +						COPY4 (op, ip); +						op += 4; +						ip += 4; +						t -= 4; +					} +					while (t >= 4); +					if (t > 0) +						do +							*op++ = *ip++; +						while (--t > 0); +				} +				else +					do +						*op++ = *ip++; +					while (--t > 0); +			} +		} +		else +		{ +			*op++ = *ip++; +			*op++ = *ip++; +			*op++ = *ip++; +			do +				*op++ = *ip++; +			while (--t > 0); +		} +	      first_literal_run: + +		t = *ip++; +		if (t >= 16) +			goto match; + +		m_pos = op - (1 + M2_MAX_OFFSET); +		m_pos -= t >> 2; +		m_pos -= *ip++ << 2; +		TEST_LOOKBEHIND (m_pos, out); +		NEED_OP (3); +		*op++ = *m_pos++; +		*op++ = *m_pos++; +		*op++ = *m_pos; + +		goto match_done; + +		while (TEST_IP && TEST_OP) +		{ +		      match: +			if (t >= 64) +			{ +				m_pos = op - 1; +				m_pos -= (t >> 2) & 7; +				m_pos -= *ip++ << 3; +				t = (t >> 5) - 1; +				TEST_LOOKBEHIND (m_pos, out); +				NEED_OP (t + 3 - 1); +				goto copy_match; + +			} +			else if (t >= 32) +			{ +				t &= 31; +				if (t == 0) +				{ +					NEED_IP (1); +					while (*ip == 0) +					{ +						t += 255; +						ip++; +						NEED_IP (1); +					} +					t += 31 + *ip++; +				} + +				m_pos = op - 1; +				m_pos -= (ip[0] >> 2) + (ip[1] << 6); + +				ip += 2; +			} +			else if (t >= 16) +			{ +				m_pos = op; +				m_pos -= (t & 8) << 11; + +				t &= 7; +				if (t == 0) +				{ +					NEED_IP (1); +					while (*ip == 0) +					{ +						t += 255; +						ip++; +						NEED_IP (1); +					} +					t += 7 + *ip++; +				} + +				m_pos -= (ip[0] >> 2) + (ip[1] << 6); + +				ip += 2; +				if (m_pos == op) +					goto eof_found; +				m_pos -= 0x4000; +			} +			else +			{ + +				m_pos = op - 1; +				m_pos -= t >> 2; +				m_pos -= *ip++ << 2; +				TEST_LOOKBEHIND (m_pos, out); +				NEED_OP (2); +				*op++ = *m_pos++; +				*op++ = *m_pos; + +				goto match_done; +			} + +			TEST_LOOKBEHIND (m_pos, out); +			NEED_OP (t + 3 - 1); +			if (t >= 2 * 4 - (3 - 1) +			    && PTR_ALIGNED2_4 (op, m_pos)) +			{ +				COPY4 (op, m_pos); +				op += 4; +				m_pos += 4; +				t -= 4 - (3 - 1); +				do +				{ +					COPY4 (op, m_pos); +					op += 4; +					m_pos += 4; +					t -= 4; +				} +				while (t >= 4); +				if (t > 0) +					do +						*op++ = *m_pos++; +					while (--t > 0); +			} +			else + +			{ +			      copy_match: +				*op++ = *m_pos++; +				*op++ = *m_pos++; +				do +					*op++ = *m_pos++; +				while (--t > 0); +			} + +		      match_done: +			t = ip[-2] & 3; + +			if (t == 0) +				break; + +		      match_next: +			NEED_OP (t); +			NEED_IP (t + 1); +			do +				*op++ = *ip++; +			while (--t > 0); +			t = *ip++; +		} +	} +	*out_len = op - out; +	return LZO_E_EOF_NOT_FOUND; + +      eof_found: +	*out_len = op - out; +	return (ip == ip_end ? LZO_E_OK : +		(ip < +		 ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +      input_overrun: +	*out_len = op - out; +	return LZO_E_INPUT_OVERRUN; + +      output_overrun: +	*out_len = op - out; +	return LZO_E_OUTPUT_OVERRUN; + +      lookbehind_overrun: +	*out_len = op - out; +	return LZO_E_LOOKBEHIND_OVERRUN; +} + +int lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, +		      u32 srclen, u32 destlen) +{ +	lzo_uint outlen = destlen; +	return lzo1x_decompress (data_in, srclen, cpage_out, &outlen, NULL); +} diff --git a/roms/u-boot/fs/jffs2/compr_rtime.c b/roms/u-boot/fs/jffs2/compr_rtime.c new file mode 100644 index 00000000..89b9f2f1 --- /dev/null +++ b/roms/u-boot/fs/jffs2/compr_rtime.c @@ -0,0 +1,87 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001 Red Hat, Inc. + * + * Created by Arjan van de Ven <arjanv@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. + * + * $Id: compr_rtime.c,v 1.2 2002/01/24 22:58:42 rfeany Exp $ + * + * + * Very simple lz77-ish encoder. + * + * Theory of operation: Both encoder and decoder have a list of "last + * occurances" for every possible source-value; after sending the + * first source-byte, the second byte indicated the "run" length of + * matches + * + * The algorithm is intended to only send "whole bytes", no bit-messing. + * + */ + +#include <config.h> +#include <jffs2/jffs2.h> + +void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, +		      u32 srclen, u32 destlen) +{ +	int positions[256]; +	int outpos; +	int pos; +	int i; + +	outpos = pos = 0; + +	for (i = 0; i < 256; positions[i++] = 0); + +	while (outpos<destlen) { +		unsigned char value; +		int backoffs; +		int repeat; + +		value = data_in[pos++]; +		cpage_out[outpos++] = value; /* first the verbatim copied byte */ +		repeat = data_in[pos++]; +		backoffs = positions[value]; + +		positions[value]=outpos; +		if (repeat) { +			if (backoffs + repeat >= outpos) { +				while(repeat) { +					cpage_out[outpos++] = cpage_out[backoffs++]; +					repeat--; +				} +			} else { +				for (i = 0; i < repeat; i++) +					*(cpage_out + outpos + i) = *(cpage_out + backoffs + i); +				outpos+=repeat; +			} +		} +	} +} diff --git a/roms/u-boot/fs/jffs2/compr_rubin.c b/roms/u-boot/fs/jffs2/compr_rubin.c new file mode 100644 index 00000000..9ff22177 --- /dev/null +++ b/roms/u-boot/fs/jffs2/compr_rubin.c @@ -0,0 +1,122 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001 Red Hat, Inc. + * + * Created by Arjan van de Ven <arjanv@redhat.com> + * + * Heavily modified by Russ Dill <Russ.Dill@asu.edu> in an attempt at + * a little more speed. + * + * 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. + * + * $Id: compr_rubin.c,v 1.2 2002/01/24 22:58:42 rfeany Exp $ + * + */ + +#include <config.h> +#include <jffs2/jffs2.h> +#include <jffs2/compr_rubin.h> + + +void rubin_do_decompress(unsigned char *bits, unsigned char *in, +			 unsigned char *page_out, __u32 destlen) +{ +	register char *curr = (char *)page_out; +	char *end = (char *)(page_out + destlen); +	register unsigned long temp; +	register unsigned long result; +	register unsigned long p; +	register unsigned long q; +	register unsigned long rec_q; +	register unsigned long bit; +	register long i0; +	unsigned long i; + +	/* init_pushpull */ +	temp = *(u32 *) in; +	bit = 16; + +	/* init_rubin */ +	q = 0; +	p = (long) (2 * UPPER_BIT_RUBIN); + +	/* init_decode */ +	rec_q = (in[0] << 8) | in[1]; + +	while (curr < end) { +		/* in byte */ + +		result = 0; +		for (i = 0; i < 8; i++) { +			/* decode */ + +			while ((q & UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN)) { +				q &= ~UPPER_BIT_RUBIN; +				q <<= 1; +				p <<= 1; +				rec_q &= ~UPPER_BIT_RUBIN; +				rec_q <<= 1; +				rec_q |= (temp >> (bit++ ^ 7)) & 1; +				if (bit > 31) { +					u32 *p = (u32 *)in; +					bit = 0; +					temp = *(++p); +					in = (unsigned char *)p; +				} +			} +			i0 =  (bits[i] * p) >> 8; + +			if (i0 <= 0) i0 = 1; +			/* if it fails, it fails, we have our crc +			if (i0 >= p) i0 = p - 1; */ + +			result >>= 1; +			if (rec_q < q + i0) { +				/* result |= 0x00; */ +				p = i0; +			} else { +				result |= 0x80; +				p -= i0; +				q += i0; +			} +		} +		*(curr++) = result; +	} +} + +void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, +		   unsigned long sourcelen, unsigned long dstlen) +{ +	unsigned char bits[8]; +	int c; + +	for (c=0; c<8; c++) +		bits[c] = (256 - data_in[c]); + +	rubin_do_decompress(bits, data_in+8, cpage_out, dstlen); +} diff --git a/roms/u-boot/fs/jffs2/compr_zlib.c b/roms/u-boot/fs/jffs2/compr_zlib.c new file mode 100644 index 00000000..d306b6dc --- /dev/null +++ b/roms/u-boot/fs/jffs2/compr_zlib.c @@ -0,0 +1,48 @@ +/* + * 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. + * + * $Id: compr_zlib.c,v 1.2 2002/01/24 22:58:42 rfeany Exp $ + * + */ + +#include <common.h> +#include <config.h> +#include <jffs2/jffs2.h> +#include <jffs2/mini_inflate.h> + +long zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, +		      __u32 srclen, __u32 destlen) +{ +    return (decompress_block(cpage_out, data_in + 2, (void *) ldr_memcpy)); + +} diff --git a/roms/u-boot/fs/jffs2/jffs2_1pass.c b/roms/u-boot/fs/jffs2/jffs2_1pass.c new file mode 100644 index 00000000..3fb5db38 --- /dev/null +++ b/roms/u-boot/fs/jffs2/jffs2_1pass.c @@ -0,0 +1,1865 @@ +/* +------------------------------------------------------------------------- + * Filename:      jffs2.c + * Version:       $Id: jffs2_1pass.c,v 1.7 2002/01/25 01:56:47 nyet Exp $ + * 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. + * + * $Id: jffs2_1pass.c,v 1.7 2002/01/25 01:56:47 nyet Exp $ + * + */ + +/* 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 U-Boot. + * + * 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 ;). + * + */ + +/* + * 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 CONFIG_SYS_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 + * might be 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> +#include <div64.h> +#include <linux/stat.h> +#include <linux/time.h> +#include <watchdog.h> +#include <jffs2/jffs2.h> +#include <jffs2/jffs2_1pass.h> +#include <linux/compat.h> +#include <asm/errno.h> + +#include "jffs2_private.h" + + +#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 */ + + +#ifdef  DEBUG +# define DEBUGF(fmt,args...)	printf(fmt ,##args) +#else +# define DEBUGF(fmt,args...) +#endif + +#include "summary.h" + +/* keeps pointer to currentlu processed partition */ +static struct part_info *current_part; + +#if (defined(CONFIG_JFFS2_NAND) && \ +     defined(CONFIG_CMD_NAND) ) +#include <nand.h> +/* + * Support for jffs2 on top of NAND-flash + * + * NAND memory isn't mapped in processor's address space, + * so data should be fetched from flash before + * being processed. This is exactly what functions declared + * here do. + * + */ + +#define NAND_PAGE_SIZE 512 +#define NAND_PAGE_SHIFT 9 +#define NAND_PAGE_MASK (~(NAND_PAGE_SIZE-1)) + +#ifndef NAND_CACHE_PAGES +#define NAND_CACHE_PAGES 16 +#endif +#define NAND_CACHE_SIZE (NAND_CACHE_PAGES*NAND_PAGE_SIZE) + +static u8* nand_cache = NULL; +static u32 nand_cache_off = (u32)-1; + +static int read_nand_cached(u32 off, u32 size, u_char *buf) +{ +	struct mtdids *id = current_part->dev->id; +	u32 bytes_read = 0; +	size_t retlen; +	int cpy_bytes; + +	while (bytes_read < size) { +		if ((off + bytes_read < nand_cache_off) || +		    (off + bytes_read >= nand_cache_off+NAND_CACHE_SIZE)) { +			nand_cache_off = (off + bytes_read) & NAND_PAGE_MASK; +			if (!nand_cache) { +				/* This memory never gets freed but 'cause +				   it's a bootloader, nobody cares */ +				nand_cache = malloc(NAND_CACHE_SIZE); +				if (!nand_cache) { +					printf("read_nand_cached: can't alloc cache size %d bytes\n", +					       NAND_CACHE_SIZE); +					return -1; +				} +			} + +			retlen = NAND_CACHE_SIZE; +			if (nand_read(&nand_info[id->num], nand_cache_off, +						&retlen, nand_cache) != 0 || +					retlen != NAND_CACHE_SIZE) { +				printf("read_nand_cached: error reading nand off %#x size %d bytes\n", +						nand_cache_off, NAND_CACHE_SIZE); +				return -1; +			} +		} +		cpy_bytes = nand_cache_off + NAND_CACHE_SIZE - (off + bytes_read); +		if (cpy_bytes > size - bytes_read) +			cpy_bytes = size - bytes_read; +		memcpy(buf + bytes_read, +		       nand_cache + off + bytes_read - nand_cache_off, +		       cpy_bytes); +		bytes_read += cpy_bytes; +	} +	return bytes_read; +} + +static void *get_fl_mem_nand(u32 off, u32 size, void *ext_buf) +{ +	u_char *buf = ext_buf ? (u_char*)ext_buf : (u_char*)malloc(size); + +	if (NULL == buf) { +		printf("get_fl_mem_nand: can't alloc %d bytes\n", size); +		return NULL; +	} +	if (read_nand_cached(off, size, buf) < 0) { +		if (!ext_buf) +			free(buf); +		return NULL; +	} + +	return buf; +} + +static void *get_node_mem_nand(u32 off, void *ext_buf) +{ +	struct jffs2_unknown_node node; +	void *ret = NULL; + +	if (NULL == get_fl_mem_nand(off, sizeof(node), &node)) +		return NULL; + +	if (!(ret = get_fl_mem_nand(off, node.magic == +			       JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node), +			       ext_buf))) { +		printf("off = %#x magic %#x type %#x node.totlen = %d\n", +		       off, node.magic, node.nodetype, node.totlen); +	} +	return ret; +} + +static void put_fl_mem_nand(void *buf) +{ +	free(buf); +} +#endif + +#if defined(CONFIG_CMD_ONENAND) + +#include <linux/mtd/mtd.h> +#include <linux/mtd/onenand.h> +#include <onenand_uboot.h> + +#define ONENAND_PAGE_SIZE 2048 +#define ONENAND_PAGE_SHIFT 11 +#define ONENAND_PAGE_MASK (~(ONENAND_PAGE_SIZE-1)) + +#ifndef ONENAND_CACHE_PAGES +#define ONENAND_CACHE_PAGES 4 +#endif +#define ONENAND_CACHE_SIZE (ONENAND_CACHE_PAGES*ONENAND_PAGE_SIZE) + +static u8* onenand_cache; +static u32 onenand_cache_off = (u32)-1; + +static int read_onenand_cached(u32 off, u32 size, u_char *buf) +{ +	u32 bytes_read = 0; +	size_t retlen; +	int cpy_bytes; + +	while (bytes_read < size) { +		if ((off + bytes_read < onenand_cache_off) || +		    (off + bytes_read >= onenand_cache_off + ONENAND_CACHE_SIZE)) { +			onenand_cache_off = (off + bytes_read) & ONENAND_PAGE_MASK; +			if (!onenand_cache) { +				/* This memory never gets freed but 'cause +				   it's a bootloader, nobody cares */ +				onenand_cache = malloc(ONENAND_CACHE_SIZE); +				if (!onenand_cache) { +					printf("read_onenand_cached: can't alloc cache size %d bytes\n", +					       ONENAND_CACHE_SIZE); +					return -1; +				} +			} + +			retlen = ONENAND_CACHE_SIZE; +			if (onenand_read(&onenand_mtd, onenand_cache_off, retlen, +						&retlen, onenand_cache) != 0 || +					retlen != ONENAND_CACHE_SIZE) { +				printf("read_onenand_cached: error reading nand off %#x size %d bytes\n", +					onenand_cache_off, ONENAND_CACHE_SIZE); +				return -1; +			} +		} +		cpy_bytes = onenand_cache_off + ONENAND_CACHE_SIZE - (off + bytes_read); +		if (cpy_bytes > size - bytes_read) +			cpy_bytes = size - bytes_read; +		memcpy(buf + bytes_read, +		       onenand_cache + off + bytes_read - onenand_cache_off, +		       cpy_bytes); +		bytes_read += cpy_bytes; +	} +	return bytes_read; +} + +static void *get_fl_mem_onenand(u32 off, u32 size, void *ext_buf) +{ +	u_char *buf = ext_buf ? (u_char *)ext_buf : (u_char *)malloc(size); + +	if (NULL == buf) { +		printf("get_fl_mem_onenand: can't alloc %d bytes\n", size); +		return NULL; +	} +	if (read_onenand_cached(off, size, buf) < 0) { +		if (!ext_buf) +			free(buf); +		return NULL; +	} + +	return buf; +} + +static void *get_node_mem_onenand(u32 off, void *ext_buf) +{ +	struct jffs2_unknown_node node; +	void *ret = NULL; + +	if (NULL == get_fl_mem_onenand(off, sizeof(node), &node)) +		return NULL; + +	ret = get_fl_mem_onenand(off, node.magic == +			JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node), +			ext_buf); +	if (!ret) { +		printf("off = %#x magic %#x type %#x node.totlen = %d\n", +		       off, node.magic, node.nodetype, node.totlen); +	} +	return ret; +} + + +static void put_fl_mem_onenand(void *buf) +{ +	free(buf); +} +#endif + + +#if defined(CONFIG_CMD_FLASH) +/* + * Support for jffs2 on top of NOR-flash + * + * NOR flash memory is mapped in processor's address space, + * just return address. + */ +static inline void *get_fl_mem_nor(u32 off, u32 size, void *ext_buf) +{ +	u32 addr = off; +	struct mtdids *id = current_part->dev->id; + +	extern flash_info_t flash_info[]; +	flash_info_t *flash = &flash_info[id->num]; + +	addr += flash->start[0]; +	if (ext_buf) { +		memcpy(ext_buf, (void *)addr, size); +		return ext_buf; +	} +	return (void*)addr; +} + +static inline void *get_node_mem_nor(u32 off, void *ext_buf) +{ +	struct jffs2_unknown_node *pNode; + +	/* pNode will point directly to flash - don't provide external buffer +	   and don't care about size */ +	pNode = get_fl_mem_nor(off, 0, NULL); +	return (void *)get_fl_mem_nor(off, pNode->magic == JFFS2_MAGIC_BITMASK ? +			pNode->totlen : sizeof(*pNode), ext_buf); +} +#endif + + +/* + * Generic jffs2 raw memory and node read routines. + * + */ +static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf) +{ +	struct mtdids *id = current_part->dev->id; + +	switch(id->type) { +#if defined(CONFIG_CMD_FLASH) +	case MTD_DEV_TYPE_NOR: +		return get_fl_mem_nor(off, size, ext_buf); +		break; +#endif +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) +	case MTD_DEV_TYPE_NAND: +		return get_fl_mem_nand(off, size, ext_buf); +		break; +#endif +#if defined(CONFIG_CMD_ONENAND) +	case MTD_DEV_TYPE_ONENAND: +		return get_fl_mem_onenand(off, size, ext_buf); +		break; +#endif +	default: +		printf("get_fl_mem: unknown device type, " \ +			"using raw offset!\n"); +	} +	return (void*)off; +} + +static inline void *get_node_mem(u32 off, void *ext_buf) +{ +	struct mtdids *id = current_part->dev->id; + +	switch(id->type) { +#if defined(CONFIG_CMD_FLASH) +	case MTD_DEV_TYPE_NOR: +		return get_node_mem_nor(off, ext_buf); +		break; +#endif +#if defined(CONFIG_JFFS2_NAND) && \ +    defined(CONFIG_CMD_NAND) +	case MTD_DEV_TYPE_NAND: +		return get_node_mem_nand(off, ext_buf); +		break; +#endif +#if defined(CONFIG_CMD_ONENAND) +	case MTD_DEV_TYPE_ONENAND: +		return get_node_mem_onenand(off, ext_buf); +		break; +#endif +	default: +		printf("get_fl_mem: unknown device type, " \ +			"using raw offset!\n"); +	} +	return (void*)off; +} + +static inline void put_fl_mem(void *buf, void *ext_buf) +{ +	struct mtdids *id = current_part->dev->id; + +	/* If buf is the same as ext_buf, it was provided by the caller - +	   we shouldn't free it then. */ +	if (buf == ext_buf) +		return; +	switch (id->type) { +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) +	case MTD_DEV_TYPE_NAND: +		return put_fl_mem_nand(buf); +#endif +#if defined(CONFIG_CMD_ONENAND) +	case MTD_DEV_TYPE_ONENAND: +		return put_fl_mem_onenand(buf); +#endif +	} +} + +/* Compression names */ +static char *compr_names[] = { +	"NONE", +	"ZERO", +	"RTIME", +	"RUBINMIPS", +	"COPY", +	"DYNRUBIN", +	"ZLIB", +#if defined(CONFIG_JFFS2_LZO) +	"LZO", +#endif +}; + +/* 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_list *list) +{ +	u32 index = 0; +	struct mem_block *memBase; +	struct b_node *b; + +	memBase = list->listMemBase; +	if (memBase != NULL) +		index = memBase->index; +#if 0 +	putLabeledWord("add_node: index = ", index); +	putLabeledWord("add_node: memBase = ", list->listMemBase); +#endif + +	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 = &memBase->nodes[index]; +	index ++; + +	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 CONFIG_SYS_JFFS2_SORT_FRAGMENTS +	struct b_node *b, *prev; +#endif + +	if (!(new = add_node(list))) { +		putstr("add_node failed!\r\n"); +		return NULL; +	} +	new->offset = offset; + +#ifdef CONFIG_SYS_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 +	{ +		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; +} + +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +/* Sort data entries with the latest version last, so that if there + * is overlapping data the latest version will be used. + */ +static int compare_inodes(struct b_node *new, struct b_node *old) +{ +	struct jffs2_raw_inode ojNew; +	struct jffs2_raw_inode ojOld; +	struct jffs2_raw_inode *jNew = +		(struct jffs2_raw_inode *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew); +	struct jffs2_raw_inode *jOld = +		(struct jffs2_raw_inode *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld); + +	return jNew->version > jOld->version; +} + +/* Sort directory entries so all entries in the same directory + * with the same name are grouped together, with the latest version + * last. This makes it easy to eliminate all but the latest version + * by marking the previous version dead by setting the inode to 0. + */ +static int compare_dirents(struct b_node *new, struct b_node *old) +{ +	struct jffs2_raw_dirent ojNew; +	struct jffs2_raw_dirent ojOld; +	struct jffs2_raw_dirent *jNew = +		(struct jffs2_raw_dirent *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew); +	struct jffs2_raw_dirent *jOld = +		(struct jffs2_raw_dirent *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld); +	int cmp; + +	/* ascending sort by pino */ +	if (jNew->pino != jOld->pino) +		return jNew->pino > jOld->pino; + +	/* pino is the same, so use ascending sort by nsize, so +	 * we don't do strncmp unless we really must. +	 */ +	if (jNew->nsize != jOld->nsize) +		return jNew->nsize > jOld->nsize; + +	/* length is also the same, so use ascending sort by name +	 */ +	cmp = strncmp((char *)jNew->name, (char *)jOld->name, jNew->nsize); +	if (cmp != 0) +		return cmp > 0; + +	/* we have duplicate names in this directory, so use ascending +	 * sort by version +	 */ +	if (jNew->version > jOld->version) { +		/* since jNew is newer, we know jOld is not valid, so +		 * mark it with inode 0 and it will not be used +		 */ +		jOld->ino = 0; +		return 1; +	} + +	return 0; +} +#endif + +void +jffs2_free_cache(struct part_info *part) +{ +	struct b_lists *pL; + +	if (part->jffs2_priv != NULL) { +		pL = (struct b_lists *)part->jffs2_priv; +		free_nodes(&pL->frag); +		free_nodes(&pL->dir); +		free(pL->readbuf); +		free(pL); +	} +} + +static u32 +jffs_init_1pass_list(struct part_info *part) +{ +	struct b_lists *pL; + +	jffs2_free_cache(part); + +	if (NULL != (part->jffs2_priv = malloc(sizeof(struct b_lists)))) { +		pL = (struct b_lists *)part->jffs2_priv; + +		memset(pL, 0, sizeof(*pL)); +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +		pL->dir.listCompare = compare_dirents; +		pL->frag.listCompare = compare_inodes; +#endif +	} +	return 0; +} + +/* find the inode from the slashless name given a parent */ +static long +jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) +{ +	struct b_node *b; +	struct jffs2_raw_inode *jNode; +	u32 totalSize = 0; +	u32 latestVersion = 0; +	uchar *lDest; +	uchar *src; +	int i; +	u32 counter = 0; +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +	/* Find file size before loading any data, so fragments that +	 * start past the end of file can be ignored. A fragment +	 * that is partially in the file is loaded, so extra data may +	 * be loaded up to the next 4K boundary above the file size. +	 * This shouldn't cause trouble when loading kernel images, so +	 * we will live with it. +	 */ +	for (b = pL->frag.listHead; b != NULL; b = b->next) { +		jNode = (struct jffs2_raw_inode *) get_fl_mem(b->offset, +			sizeof(struct jffs2_raw_inode), pL->readbuf); +		if ((inode == jNode->ino)) { +			/* get actual file length from the newest node */ +			if (jNode->version >= latestVersion) { +				totalSize = jNode->isize; +				latestVersion = jNode->version; +			} +		} +		put_fl_mem(jNode, pL->readbuf); +	} +#endif + +	for (b = pL->frag.listHead; b != NULL; b = b->next) { +		jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset, +								pL->readbuf); +		if ((inode == jNode->ino)) { +#if 0 +			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); +#endif + +#ifndef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +			/* get actual file length from the newest node */ +			if (jNode->version >= latestVersion) { +				totalSize = jNode->isize; +				latestVersion = jNode->version; +			} +#endif + +			if(dest) { +				src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode); +				/* ignore data behind latest known EOF */ +				if (jNode->offset > totalSize) { +					put_fl_mem(jNode, pL->readbuf); +					continue; +				} +				if (b->datacrc == CRC_UNKNOWN) +					b->datacrc = data_crc(jNode) ? +						CRC_OK : CRC_BAD; +				if (b->datacrc == CRC_BAD) { +					put_fl_mem(jNode, pL->readbuf); +					continue; +				} + +				lDest = (uchar *) (dest + jNode->offset); +#if 0 +				putLabeledWord("read_inode: src = ", src); +				putLabeledWord("read_inode: dest = ", lDest); +#endif +				switch (jNode->compr) { +				case JFFS2_COMPR_NONE: +					ldr_memcpy(lDest, src, jNode->dsize); +					break; +				case JFFS2_COMPR_ZERO: +					for (i = 0; i < jNode->dsize; i++) +						*(lDest++) = 0; +					break; +				case JFFS2_COMPR_RTIME: +					rtime_decompress(src, lDest, jNode->csize, jNode->dsize); +					break; +				case JFFS2_COMPR_DYNRUBIN: +					/* this is slow but it works */ +					dynrubin_decompress(src, lDest, jNode->csize, jNode->dsize); +					break; +				case JFFS2_COMPR_ZLIB: +					zlib_decompress(src, lDest, jNode->csize, jNode->dsize); +					break; +#if defined(CONFIG_JFFS2_LZO) +				case JFFS2_COMPR_LZO: +					lzo_decompress(src, lDest, jNode->csize, jNode->dsize); +					break; +#endif +				default: +					/* unknown */ +					putLabeledWord("UNKNOWN COMPRESSION METHOD = ", jNode->compr); +					put_fl_mem(jNode, pL->readbuf); +					return -1; +					break; +				} +			} + +#if 0 +			putLabeledWord("read_inode: totalSize = ", totalSize); +#endif +		} +		counter++; +		put_fl_mem(jNode, pL->readbuf); +	} + +#if 0 +	putLabeledWord("read_inode: returning = ", totalSize); +#endif +	return totalSize; +} + +/* find the inode from the slashless name given a parent */ +static u32 +jffs2_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->dir.listHead; b; b = b->next, counter++) { +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf); +		if ((pino == jDir->pino) && (len == jDir->nsize) && +		    (jDir->ino) &&	/* 0 for unlink */ +		    (!strncmp((char *)jDir->name, name, len))) {	/* a match */ +			if (jDir->version < version) { +				put_fl_mem(jDir, pL->readbuf); +				continue; +			} + +			if (jDir->version == version && inode != 0) { +				/* I'm pretty sure this isn't legal */ +				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 +		put_fl_mem(jDir, pL->readbuf); +	} +	return inode; +} + +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((time_t *)&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, (char *)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; +	st.st_size = i->isize; + +	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 pino */ +static u32 +jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) +{ +	struct b_node *b; +	struct jffs2_raw_dirent *jDir; + +	for (b = pL->dir.listHead; b; b = b->next) { +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf); +		if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */ +			u32 i_version = 0; +			struct jffs2_raw_inode ojNode; +			struct jffs2_raw_inode *jNode, *i = NULL; +			struct b_node *b2 = pL->frag.listHead; + +			while (b2) { +				jNode = (struct jffs2_raw_inode *) +					get_fl_mem(b2->offset, sizeof(ojNode), &ojNode); +				if (jNode->ino == jDir->ino && jNode->version >= i_version) { +					i_version = jNode->version; +					if (i) +						put_fl_mem(i, NULL); + +					if (jDir->type == DT_LNK) +						i = get_node_mem(b2->offset, +								 NULL); +					else +						i = get_fl_mem(b2->offset, +							       sizeof(*i), +							       NULL); +				} +				b2 = b2->next; +			} + +			dump_inode(pL, jDir, i); +			put_fl_mem(i, NULL); +		} +		put_fl_mem(jDir, pL->readbuf); +	} +	return pino; +} + +static u32 +jffs2_1pass_search_inode(struct b_lists * pL, const char *fname, u32 pino) +{ +	int i; +	char tmp[256]; +	char working_tmp[256]; +	char *c; + +	/* discard any leading slash */ +	i = 0; +	while (fname[i] == '/') +		i++; +	strcpy(tmp, &fname[i]); + +	while ((c = (char *) strchr(tmp, '/')))	/* we are still dired searching */ +	{ +		strncpy(working_tmp, tmp, c - tmp); +		working_tmp[c - tmp] = '\0'; +#if 0 +		putstr("search_inode: tmp = "); +		putstr(tmp); +		putstr("\r\n"); +		putstr("search_inode: wtmp = "); +		putstr(working_tmp); +		putstr("\r\n"); +		putstr("search_inode: c = "); +		putstr(c); +		putstr("\r\n"); +#endif +		for (i = 0; i < strlen(c) - 1; i++) +			tmp[i] = c[i + 1]; +		tmp[i] = '\0'; +#if 0 +		putstr("search_inode: post tmp = "); +		putstr(tmp); +		putstr("\r\n"); +#endif + +		if (!(pino = jffs2_1pass_find_inode(pL, working_tmp, pino))) { +			putstr("find_inode failed for name="); +			putstr(working_tmp); +			putstr("\r\n"); +			return 0; +		} +	} +	/* this is for the bare filename, directories have already been mapped */ +	if (!(pino = jffs2_1pass_find_inode(pL, tmp, pino))) { +		putstr("find_inode failed for name="); +		putstr(tmp); +		putstr("\r\n"); +		return 0; +	} +	return pino; + +} + +static u32 +jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino) +{ +	struct b_node *b; +	struct b_node *b2; +	struct jffs2_raw_dirent *jDir; +	struct jffs2_raw_inode *jNode; +	u8 jDirFoundType = 0; +	u32 jDirFoundIno = 0; +	u32 jDirFoundPino = 0; +	char tmp[256]; +	u32 version = 0; +	u32 pino; +	unsigned char *src; + +	/* we need to search all and return the inode with the highest version */ +	for(b = pL->dir.listHead; b; b = b->next) { +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf); +		if (ino == jDir->ino) { +			if (jDir->version < version) { +				put_fl_mem(jDir, pL->readbuf); +				continue; +			} + +			if (jDir->version == version && jDirFoundType) { +				/* I'm pretty sure this isn't legal */ +				putstr(" ** ERROR ** "); +				putnstr(jDir->name, jDir->nsize); +				putLabeledWord(" has dup version (resolve) = ", +					version); +			} + +			jDirFoundType = jDir->type; +			jDirFoundIno = jDir->ino; +			jDirFoundPino = jDir->pino; +			version = jDir->version; +		} +		put_fl_mem(jDir, pL->readbuf); +	} +	/* now we found the right entry again. (shoulda returned inode*) */ +	if (jDirFoundType != DT_LNK) +		return jDirFoundIno; + +	/* it's a soft link so we follow it again. */ +	b2 = pL->frag.listHead; +	while (b2) { +		jNode = (struct jffs2_raw_inode *) get_node_mem(b2->offset, +								pL->readbuf); +		if (jNode->ino == jDirFoundIno) { +			src = (unsigned char *)jNode + sizeof(struct jffs2_raw_inode); + +#if 0 +			putLabeledWord("\t\t dsize = ", jNode->dsize); +			putstr("\t\t target = "); +			putnstr(src, jNode->dsize); +			putstr("\r\n"); +#endif +			strncpy(tmp, (char *)src, jNode->dsize); +			tmp[jNode->dsize] = '\0'; +			put_fl_mem(jNode, pL->readbuf); +			break; +		} +		b2 = b2->next; +		put_fl_mem(jNode, pL->readbuf); +	} +	/* ok so the name of the new file to find is in tmp */ +	/* if it starts with a slash it is root based else shared dirs */ +	if (tmp[0] == '/') +		pino = 1; +	else +		pino = jDirFoundPino; + +	return jffs2_1pass_search_inode(pL, tmp, pino); +} + +static u32 +jffs2_1pass_search_list_inodes(struct b_lists * pL, const char *fname, u32 pino) +{ +	int i; +	char tmp[256]; +	char working_tmp[256]; +	char *c; + +	/* discard any leading slash */ +	i = 0; +	while (fname[i] == '/') +		i++; +	strcpy(tmp, &fname[i]); +	working_tmp[0] = '\0'; +	while ((c = (char *) strchr(tmp, '/')))	/* we are still dired searching */ +	{ +		strncpy(working_tmp, tmp, c - tmp); +		working_tmp[c - tmp] = '\0'; +		for (i = 0; i < strlen(c) - 1; i++) +			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])) { +			putstr("find_inode failed for name="); +			putstr(working_tmp); +			putstr("\r\n"); +			return 0; +		} +	} + +	if (tmp[0] && !(pino = jffs2_1pass_find_inode(pL, tmp, pino))) { +		putstr("find_inode failed for name="); +		putstr(tmp); +		putstr("\r\n"); +		return 0; +	} +	/* this is for the bare filename, directories have already been mapped */ +	if (!(pino = jffs2_1pass_list_inodes(pL, pino))) { +		putstr("find_inode failed for name="); +		putstr(tmp); +		putstr("\r\n"); +		return 0; +	} +	return pino; + +} + +unsigned char +jffs2_1pass_rescan_needed(struct part_info *part) +{ +	struct b_node *b; +	struct jffs2_unknown_node onode; +	struct jffs2_unknown_node *node; +	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->frag.listCount == 0) { +		DEBUGF ("rescan: fraglist zero\n"); +		return 1; +	} + +	/* but suppose someone reflashed a partition at the same offset... */ +	b = pL->dir.listHead; +	while (b) { +		node = (struct jffs2_unknown_node *) get_fl_mem(b->offset, +			sizeof(onode), &onode); +		if (node->nodetype != JFFS2_NODETYPE_DIRENT) { +			DEBUGF ("rescan: fs changed beneath me? (%lx)\n", +					(unsigned long) b->offset); +			return 1; +		} +		b = b->next; +	} +	return 0; +} + +#ifdef CONFIG_JFFS2_SUMMARY +static u32 sum_get_unaligned32(u32 *ptr) +{ +	u32 val; +	u8 *p = (u8 *)ptr; + +	val = *p | (*(p + 1) << 8) | (*(p + 2) << 16) | (*(p + 3) << 24); + +	return __le32_to_cpu(val); +} + +static u16 sum_get_unaligned16(u16 *ptr) +{ +	u16 val; +	u8 *p = (u8 *)ptr; + +	val = *p | (*(p + 1) << 8); + +	return __le16_to_cpu(val); +} + +#define dbg_summary(...) do {} while (0); +/* + * Process the stored summary information - helper function for + * jffs2_sum_scan_sumnode() + */ + +static int jffs2_sum_process_sum_data(struct part_info *part, uint32_t offset, +				struct jffs2_raw_summary *summary, +				struct b_lists *pL) +{ +	void *sp; +	int i, pass; +	void *ret; + +	for (pass = 0; pass < 2; pass++) { +		sp = summary->sum; + +		for (i = 0; i < summary->sum_num; i++) { +			struct jffs2_sum_unknown_flash *spu = sp; +			dbg_summary("processing summary index %d\n", i); + +			switch (sum_get_unaligned16(&spu->nodetype)) { +				case JFFS2_NODETYPE_INODE: { +				struct jffs2_sum_inode_flash *spi; +					if (pass) { +						spi = sp; + +						ret = insert_node(&pL->frag, +							(u32)part->offset + +							offset + +							sum_get_unaligned32( +								&spi->offset)); +						if (ret == NULL) +							return -1; +					} + +					sp += JFFS2_SUMMARY_INODE_SIZE; + +					break; +				} +				case JFFS2_NODETYPE_DIRENT: { +					struct jffs2_sum_dirent_flash *spd; +					spd = sp; +					if (pass) { +						ret = insert_node(&pL->dir, +							(u32) part->offset + +							offset + +							sum_get_unaligned32( +								&spd->offset)); +						if (ret == NULL) +							return -1; +					} + +					sp += JFFS2_SUMMARY_DIRENT_SIZE( +							spd->nsize); + +					break; +				} +				default : { +					uint16_t nodetype = sum_get_unaligned16( +								&spu->nodetype); +					printf("Unsupported node type %x found" +							" in summary!\n", +							nodetype); +					if ((nodetype & JFFS2_COMPAT_MASK) == +							JFFS2_FEATURE_INCOMPAT) +						return -EIO; +					return -EBADMSG; +				} +			} +		} +	} +	return 0; +} + +/* Process the summary node - called from jffs2_scan_eraseblock() */ +int jffs2_sum_scan_sumnode(struct part_info *part, uint32_t offset, +			   struct jffs2_raw_summary *summary, uint32_t sumsize, +			   struct b_lists *pL) +{ +	struct jffs2_unknown_node crcnode; +	int ret, ofs; +	uint32_t crc; + +	ofs = part->sector_size - sumsize; + +	dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", +		    offset, offset + ofs, sumsize); + +	/* OK, now check for node validity and CRC */ +	crcnode.magic = JFFS2_MAGIC_BITMASK; +	crcnode.nodetype = JFFS2_NODETYPE_SUMMARY; +	crcnode.totlen = summary->totlen; +	crc = crc32_no_comp(0, (uchar *)&crcnode, sizeof(crcnode)-4); + +	if (summary->hdr_crc != crc) { +		dbg_summary("Summary node header is corrupt (bad CRC or " +				"no summary at all)\n"); +		goto crc_err; +	} + +	if (summary->totlen != sumsize) { +		dbg_summary("Summary node is corrupt (wrong erasesize?)\n"); +		goto crc_err; +	} + +	crc = crc32_no_comp(0, (uchar *)summary, +			sizeof(struct jffs2_raw_summary)-8); + +	if (summary->node_crc != crc) { +		dbg_summary("Summary node is corrupt (bad CRC)\n"); +		goto crc_err; +	} + +	crc = crc32_no_comp(0, (uchar *)summary->sum, +			sumsize - sizeof(struct jffs2_raw_summary)); + +	if (summary->sum_crc != crc) { +		dbg_summary("Summary node data is corrupt (bad CRC)\n"); +		goto crc_err; +	} + +	if (summary->cln_mkr) +		dbg_summary("Summary : CLEANMARKER node \n"); + +	ret = jffs2_sum_process_sum_data(part, offset, summary, pL); +	if (ret == -EBADMSG) +		return 0; +	if (ret) +		return ret;		/* real error */ + +	return 1; + +crc_err: +	putstr("Summary node crc error, skipping summary information.\n"); + +	return 0; +} +#endif /* CONFIG_JFFS2_SUMMARY */ + +#ifdef DEBUG_FRAGMENTS +static void +dump_fragments(struct b_lists *pL) +{ +	struct b_node *b; +	struct jffs2_raw_inode ojNode; +	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 *) get_fl_mem(b->offset, +			sizeof(ojNode), &ojNode); +		putLabeledWord("\r\n\tbuild_list: FLASH_OFFSET = ", b->offset); +		putLabeledWord("\tbuild_list: totlen = ", jNode->totlen); +		putLabeledWord("\tbuild_list: inode = ", jNode->ino); +		putLabeledWord("\tbuild_list: version = ", jNode->version); +		putLabeledWord("\tbuild_list: isize = ", jNode->isize); +		putLabeledWord("\tbuild_list: atime = ", jNode->atime); +		putLabeledWord("\tbuild_list: offset = ", jNode->offset); +		putLabeledWord("\tbuild_list: csize = ", jNode->csize); +		putLabeledWord("\tbuild_list: dsize = ", jNode->dsize); +		putLabeledWord("\tbuild_list: compr = ", jNode->compr); +		putLabeledWord("\tbuild_list: usercompr = ", jNode->usercompr); +		putLabeledWord("\tbuild_list: flags = ", jNode->flags); +		putLabeledWord("\tbuild_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 *) get_node_mem(b->offset, +								pL->readbuf); +		putstr("\r\n"); +		putnstr(jDir->name, jDir->nsize); +		putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic); +		putLabeledWord("\tbuild_list: nodetype = ", jDir->nodetype); +		putLabeledWord("\tbuild_list: hdr_crc = ", jDir->hdr_crc); +		putLabeledWord("\tbuild_list: pino = ", jDir->pino); +		putLabeledWord("\tbuild_list: version = ", jDir->version); +		putLabeledWord("\tbuild_list: ino = ", jDir->ino); +		putLabeledWord("\tbuild_list: mctime = ", jDir->mctime); +		putLabeledWord("\tbuild_list: nsize = ", jDir->nsize); +		putLabeledWord("\tbuild_list: type = ", jDir->type); +		putLabeledWord("\tbuild_list: node_crc = ", jDir->node_crc); +		putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc); +		putLabeledWord("\tbuild_list: offset = ", b->offset);	/* FIXME: ? [RS] */ +		b = b->next; +		put_fl_mem(jDir, pL->readbuf); +	} +} +#endif + +#define DEFAULT_EMPTY_SCAN_SIZE	4096 + +static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) +{ +	if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) +		return sector_size; +	else +		return DEFAULT_EMPTY_SCAN_SIZE; +} + +static u32 +jffs2_1pass_build_lists(struct part_info * part) +{ +	struct b_lists *pL; +	struct jffs2_unknown_node *node; +	u32 nr_sectors; +	u32 i; +	u32 counter4 = 0; +	u32 counterF = 0; +	u32 counterN = 0; +	u32 max_totlen = 0; +	u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE; +	char *buf; + +	nr_sectors = lldiv(part->size, part->sector_size); +	/* turn off the lcd.  Refreshing the lcd adds 50% overhead to the */ +	/* jffs2 list building enterprise nope.  in newer versions the overhead is */ +	/* only about 5 %.  not enough to inconvenience people for. */ +	/* lcd_off(); */ + +	/* if we are building a list we need to refresh the cache. */ +	jffs_init_1pass_list(part); +	pL = (struct b_lists *)part->jffs2_priv; +	buf = malloc(buf_size); +	puts ("Scanning JFFS2 FS:   "); + +	/* start at the beginning of the partition */ +	for (i = 0; i < nr_sectors; i++) { +		uint32_t sector_ofs = i * part->sector_size; +		uint32_t buf_ofs = sector_ofs; +		uint32_t buf_len; +		uint32_t ofs, prevofs; +#ifdef CONFIG_JFFS2_SUMMARY +		struct jffs2_sum_marker *sm; +		void *sumptr = NULL; +		uint32_t sumlen; +		int ret; +#endif + +		WATCHDOG_RESET(); + +#ifdef CONFIG_JFFS2_SUMMARY +		buf_len = sizeof(*sm); + +		/* Read as much as we want into the _end_ of the preallocated +		 * buffer +		 */ +		get_fl_mem(part->offset + sector_ofs + part->sector_size - +				buf_len, buf_len, buf + buf_size - buf_len); + +		sm = (void *)buf + buf_size - sizeof(*sm); +		if (sm->magic == JFFS2_SUM_MAGIC) { +			sumlen = part->sector_size - sm->offset; +			sumptr = buf + buf_size - sumlen; + +			/* Now, make sure the summary itself is available */ +			if (sumlen > buf_size) { +				/* Need to kmalloc for this. */ +				sumptr = malloc(sumlen); +				if (!sumptr) { +					putstr("Can't get memory for summary " +							"node!\n"); +					free(buf); +					jffs2_free_cache(part); +					return 0; +				} +				memcpy(sumptr + sumlen - buf_len, buf + +						buf_size - buf_len, buf_len); +			} +			if (buf_len < sumlen) { +				/* Need to read more so that the entire summary +				 * node is present +				 */ +				get_fl_mem(part->offset + sector_ofs + +						part->sector_size - sumlen, +						sumlen - buf_len, sumptr); +			} +		} + +		if (sumptr) { +			ret = jffs2_sum_scan_sumnode(part, sector_ofs, sumptr, +					sumlen, pL); + +			if (buf_size && sumlen > buf_size) +				free(sumptr); +			if (ret < 0) { +				free(buf); +				jffs2_free_cache(part); +				return 0; +			} +			if (ret) +				continue; + +		} +#endif /* CONFIG_JFFS2_SUMMARY */ + +		buf_len = EMPTY_SCAN_SIZE(part->sector_size); + +		get_fl_mem((u32)part->offset + buf_ofs, buf_len, buf); + +		/* We temporarily use 'ofs' as a pointer into the buffer/jeb */ +		ofs = 0; + +		/* Scan only 4KiB of 0xFF before declaring it's empty */ +		while (ofs < EMPTY_SCAN_SIZE(part->sector_size) && +				*(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) +			ofs += 4; + +		if (ofs == EMPTY_SCAN_SIZE(part->sector_size)) +			continue; + +		ofs += sector_ofs; +		prevofs = ofs - 1; + +	scan_more: +		while (ofs < sector_ofs + part->sector_size) { +			if (ofs == prevofs) { +				printf("offset %08x already seen, skip\n", ofs); +				ofs += 4; +				counter4++; +				continue; +			} +			prevofs = ofs; +			if (sector_ofs + part->sector_size < +					ofs + sizeof(*node)) +				break; +			if (buf_ofs + buf_len < ofs + sizeof(*node)) { +				buf_len = min_t(uint32_t, buf_size, sector_ofs +						+ part->sector_size - ofs); +				get_fl_mem((u32)part->offset + ofs, buf_len, +					   buf); +				buf_ofs = ofs; +			} + +			node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs]; + +			if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { +				uint32_t inbuf_ofs; +				uint32_t scan_end; + +				ofs += 4; +				scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE( +							part->sector_size)/8, +							buf_len); +			more_empty: +				inbuf_ofs = ofs - buf_ofs; +				while (inbuf_ofs < scan_end) { +					if (*(uint32_t *)(&buf[inbuf_ofs]) != +							0xffffffff) +						goto scan_more; + +					inbuf_ofs += 4; +					ofs += 4; +				} +				/* Ran off end. */ + +				/* See how much more there is to read in this +				 * eraseblock... +				 */ +				buf_len = min_t(uint32_t, buf_size, +						sector_ofs + +						part->sector_size - ofs); +				if (!buf_len) { +					/* No more to read. Break out of main +					 * loop without marking this range of +					 * empty space as dirty (because it's +					 * not) +					 */ +					break; +				} +				scan_end = buf_len; +				get_fl_mem((u32)part->offset + ofs, buf_len, +					   buf); +				buf_ofs = ofs; +				goto more_empty; +			} +			if (node->magic != JFFS2_MAGIC_BITMASK || +					!hdr_crc(node)) { +				ofs += 4; +				counter4++; +				continue; +			} +			if (ofs + node->totlen > +					sector_ofs + part->sector_size) { +				ofs += 4; +				counter4++; +				continue; +			} +			/* if its a fragment add it */ +			switch (node->nodetype) { +			case JFFS2_NODETYPE_INODE: +				if (buf_ofs + buf_len < ofs + sizeof(struct +							jffs2_raw_inode)) { +					get_fl_mem((u32)part->offset + ofs, +						   buf_len, buf); +					buf_ofs = ofs; +					node = (void *)buf; +				} +				if (!inode_crc((struct jffs2_raw_inode *) node)) +				       break; + +				if (insert_node(&pL->frag, (u32) part->offset + +						ofs) == NULL) { +					free(buf); +					jffs2_free_cache(part); +					return 0; +				} +				if (max_totlen < node->totlen) +					max_totlen = node->totlen; +				break; +			case JFFS2_NODETYPE_DIRENT: +				if (buf_ofs + buf_len < ofs + sizeof(struct +							jffs2_raw_dirent) + +							((struct +							 jffs2_raw_dirent *) +							node)->nsize) { +					get_fl_mem((u32)part->offset + ofs, +						   buf_len, buf); +					buf_ofs = ofs; +					node = (void *)buf; +				} + +				if (!dirent_crc((struct jffs2_raw_dirent *) +							node) || +						!dirent_name_crc( +							(struct +							 jffs2_raw_dirent *) +							node)) +					break; +				if (! (counterN%100)) +					puts ("\b\b.  "); +				if (insert_node(&pL->dir, (u32) part->offset + +						ofs) == NULL) { +					free(buf); +					jffs2_free_cache(part); +					return 0; +				} +				if (max_totlen < node->totlen) +					max_totlen = node->totlen; +				counterN++; +				break; +			case JFFS2_NODETYPE_CLEANMARKER: +				if (node->totlen != sizeof(struct jffs2_unknown_node)) +					printf("OOPS Cleanmarker has bad size " +						"%d != %zu\n", +						node->totlen, +						sizeof(struct jffs2_unknown_node)); +				break; +			case JFFS2_NODETYPE_PADDING: +				if (node->totlen < sizeof(struct jffs2_unknown_node)) +					printf("OOPS Padding has bad size " +						"%d < %zu\n", +						node->totlen, +						sizeof(struct jffs2_unknown_node)); +				break; +			case JFFS2_NODETYPE_SUMMARY: +				break; +			default: +				printf("Unknown node type: %x len %d offset 0x%x\n", +					node->nodetype, +					node->totlen, ofs); +			} +			ofs += ((node->totlen + 3) & ~3); +			counterF++; +		} +	} + +	free(buf); +	putstr("\b\b done.\r\n");		/* close off the dots */ + +	/* We don't care if malloc failed - then each read operation will +	 * allocate its own buffer as necessary (NAND) or will read directly +	 * from flash (NOR). +	 */ +	pL->readbuf = malloc(max_totlen); + +	/* turn the lcd back on. */ +	/* splash(); */ + +#if 0 +	putLabeledWord("dir entries = ", pL->dir.listCount); +	putLabeledWord("frag entries = ", pL->frag.listCount); +	putLabeledWord("+4 increments = ", counter4); +	putLabeledWord("+file_offset increments = ", counterF); + +#endif + +#ifdef DEBUG_DIRENTS +	dump_dirents(pL); +#endif + +#ifdef DEBUG_FRAGMENTS +	dump_fragments(pL); +#endif + +	/* give visual feedback that we are done scanning the flash */ +	led_blink(0x0, 0x0, 0x1, 0x1);	/* off, forever, on 100ms, off 100ms */ +	return 1; +} + + +static u32 +jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL) +{ +	struct b_node *b; +	struct jffs2_raw_inode ojNode; +	struct jffs2_raw_inode *jNode; +	int i; + +	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 *) get_fl_mem(b->offset, +			sizeof(ojNode), &ojNode); +		if (jNode->compr < JFFS2_NUM_COMPR) { +			piL->compr_info[jNode->compr].num_frags++; +			piL->compr_info[jNode->compr].compr_sum += jNode->csize; +			piL->compr_info[jNode->compr].decompr_sum += jNode->dsize; +		} +		b = b->next; +	} +	return 0; +} + + +static struct b_lists * +jffs2_get_list(struct part_info * part, const char *who) +{ +	/* copy requested part_info struct pointer to global location */ +	current_part = part; + +	if (jffs2_1pass_rescan_needed(part)) { +		if (!jffs2_1pass_build_lists(part)) { +			printf("%s: Failed to scan JFFSv2 file structure\n", who); +			return NULL; +		} +	} +	return (struct b_lists *)part->jffs2_priv; +} + + +/* Print directory / file contents */ +u32 +jffs2_1pass_ls(struct part_info * part, const char *fname) +{ +	struct b_lists *pl; +	long ret = 1; +	u32 inode; + +	if (! (pl = jffs2_get_list(part, "ls"))) +		return 0; + +	if (! (inode = jffs2_1pass_search_list_inodes(pl, fname, 1))) { +		putstr("ls: Failed to scan jffs2 file structure\r\n"); +		return 0; +	} + + +#if 0 +	putLabeledWord("found file at inode = ", inode); +	putLabeledWord("read_inode returns = ", ret); +#endif + +	return ret; +} + + +/* Load a file from flash into memory. fname can be a full path */ +u32 +jffs2_1pass_load(char *dest, struct part_info * part, const char *fname) +{ + +	struct b_lists *pl; +	long ret = 1; +	u32 inode; + +	if (! (pl  = jffs2_get_list(part, "load"))) +		return 0; + +	if (! (inode = jffs2_1pass_search_inode(pl, fname, 1))) { +		putstr("load: Failed to find inode\r\n"); +		return 0; +	} + +	/* Resolve symlinks */ +	if (! (inode = jffs2_1pass_resolve_inode(pl, inode))) { +		putstr("load: Failed to resolve inode structure\r\n"); +		return 0; +	} + +	if ((ret = jffs2_1pass_read_inode(pl, inode, dest)) < 0) { +		putstr("load: Failed to read inode\r\n"); +		return 0; +	} + +	DEBUGF ("load: loaded '%s' to 0x%lx (%ld bytes)\n", fname, +				(unsigned long) dest, ret); +	return ret; +} + +/* Return information about the fs on this partition */ +u32 +jffs2_1pass_info(struct part_info * part) +{ +	struct b_jffs2_info info; +	struct b_lists *pl; +	int i; + +	if (! (pl  = jffs2_get_list(part, "info"))) +		return 0; + +	jffs2_1pass_fill_info(pl, &info); +	for (i = 0; i < JFFS2_NUM_COMPR; i++) { +		printf ("Compression: %s\n" +			"\tfrag count: %d\n" +			"\tcompressed sum: %d\n" +			"\tuncompressed sum: %d\n", +			compr_names[i], +			info.compr_info[i].num_frags, +			info.compr_info[i].compr_sum, +			info.compr_info[i].decompr_sum); +	} +	return 1; +} diff --git a/roms/u-boot/fs/jffs2/jffs2_nand_1pass.c b/roms/u-boot/fs/jffs2/jffs2_nand_1pass.c new file mode 100644 index 00000000..740f787d --- /dev/null +++ b/roms/u-boot/fs/jffs2/jffs2_nand_1pass.c @@ -0,0 +1,1030 @@ +#include <common.h> + +#include <malloc.h> +#include <linux/stat.h> +#include <linux/time.h> + +#include <jffs2/jffs2.h> +#include <jffs2/jffs2_1pass.h> +#include <nand.h> + +#include "jffs2_nand_private.h" + +#define	NODE_CHUNK	1024	/* size of memory allocation chunk in b_nodes */ + +/* Debugging switches */ +#undef	DEBUG_DIRENTS		/* print directory entry list after scan */ +#undef	DEBUG_FRAGMENTS		/* print fragment list after scan */ +#undef	DEBUG			/* enable debugging messages */ + +#ifdef  DEBUG +# define DEBUGF(fmt,args...)	printf(fmt ,##args) +#else +# define DEBUGF(fmt,args...) +#endif + +static nand_info_t *nand; + +/* Compression names */ +static char *compr_names[] = { +	"NONE", +	"ZERO", +	"RTIME", +	"RUBINMIPS", +	"COPY", +	"DYNRUBIN", +	"ZLIB", +#if defined(CONFIG_JFFS2_LZO) +	"LZO", +#endif +}; + +/* Spinning wheel */ +static char spinner[] = { '|', '/', '-', '\\' }; + +/* Memory management */ +struct mem_block { +	unsigned index; +	struct mem_block *next; +	char nodes[0]; +}; + +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_list *list, int size) +{ +	u32 index = 0; +	struct mem_block *memBase; +	struct b_node *b; + +	memBase = list->listMemBase; +	if (memBase != NULL) +		index = memBase->index; + +	if (memBase == NULL || index >= NODE_CHUNK) { +		/* we need more space before we continue */ +		memBase = mmalloc(sizeof(struct mem_block) + NODE_CHUNK * size); +		if (memBase == NULL) { +			putstr("add_node: malloc failed\n"); +			return NULL; +		} +		memBase->next = list->listMemBase; +		index = 0; +	} +	/* now we have room to add it. */ +	b = (struct b_node *)&memBase->nodes[size * index]; +	index ++; + +	memBase->index = index; +	list->listMemBase = memBase; +	list->listCount++; +	return b; +} + +static struct b_node * +insert_node(struct b_list *list, struct b_node *new) +{ +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +	struct b_node *b, *prev; + +	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 +	{ +		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; +} + +static struct b_node * +insert_inode(struct b_list *list, struct jffs2_raw_inode *node, u32 offset) +{ +	struct b_inode *new; + +	if (!(new = (struct b_inode *)add_node(list, sizeof(struct b_inode)))) { +		putstr("add_node failed!\r\n"); +		return NULL; +	} +	new->offset = offset; +	new->version = node->version; +	new->ino = node->ino; +	new->isize = node->isize; +	new->csize = node->csize; + +	return insert_node(list, (struct b_node *)new); +} + +static struct b_node * +insert_dirent(struct b_list *list, struct jffs2_raw_dirent *node, u32 offset) +{ +	struct b_dirent *new; + +	if (!(new = (struct b_dirent *)add_node(list, sizeof(struct b_dirent)))) { +		putstr("add_node failed!\r\n"); +		return NULL; +	} +	new->offset = offset; +	new->version = node->version; +	new->pino = node->pino; +	new->ino = node->ino; +	new->nhash = full_name_hash(node->name, node->nsize); +	new->nsize = node->nsize; +	new->type = node->type; + +	return insert_node(list, (struct b_node *)new); +} + +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +/* Sort data entries with the latest version last, so that if there + * is overlapping data the latest version will be used. + */ +static int compare_inodes(struct b_node *new, struct b_node *old) +{ +	struct jffs2_raw_inode ojNew; +	struct jffs2_raw_inode ojOld; +	struct jffs2_raw_inode *jNew = +		(struct jffs2_raw_inode *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew); +	struct jffs2_raw_inode *jOld = +		(struct jffs2_raw_inode *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld); + +	return jNew->version > jOld->version; +} + +/* Sort directory entries so all entries in the same directory + * with the same name are grouped together, with the latest version + * last. This makes it easy to eliminate all but the latest version + * by marking the previous version dead by setting the inode to 0. + */ +static int compare_dirents(struct b_node *new, struct b_node *old) +{ +	struct jffs2_raw_dirent ojNew; +	struct jffs2_raw_dirent ojOld; +	struct jffs2_raw_dirent *jNew = +		(struct jffs2_raw_dirent *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew); +	struct jffs2_raw_dirent *jOld = +		(struct jffs2_raw_dirent *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld); +	int cmp; + +	/* ascending sort by pino */ +	if (jNew->pino != jOld->pino) +		return jNew->pino > jOld->pino; + +	/* pino is the same, so use ascending sort by nsize, so +	 * we don't do strncmp unless we really must. +	 */ +	if (jNew->nsize != jOld->nsize) +		return jNew->nsize > jOld->nsize; + +	/* length is also the same, so use ascending sort by name +	 */ +	cmp = strncmp(jNew->name, jOld->name, jNew->nsize); +	if (cmp != 0) +		return cmp > 0; + +	/* we have duplicate names in this directory, so use ascending +	 * sort by version +	 */ +	if (jNew->version > jOld->version) { +		/* since jNew is newer, we know jOld is not valid, so +		 * mark it with inode 0 and it will not be used +		 */ +		jOld->ino = 0; +		return 1; +	} + +	return 0; +} +#endif + +static u32 +jffs_init_1pass_list(struct part_info *part) +{ +	struct b_lists *pL; + +	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 CONFIG_SYS_JFFS2_SORT_FRAGMENTS +		pL->dir.listCompare = compare_dirents; +		pL->frag.listCompare = compare_inodes; +#endif +	} +	return 0; +} + +/* find the inode from the slashless name given a parent */ +static long +jffs2_1pass_read_inode(struct b_lists *pL, u32 ino, char *dest, +		       struct stat *stat) +{ +	struct b_inode *jNode; +	u32 totalSize = 0; +	u32 latestVersion = 0; +	long ret; + +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +	/* Find file size before loading any data, so fragments that +	 * start past the end of file can be ignored. A fragment +	 * that is partially in the file is loaded, so extra data may +	 * be loaded up to the next 4K boundary above the file size. +	 * This shouldn't cause trouble when loading kernel images, so +	 * we will live with it. +	 */ +	for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) { +		if ((ino == jNode->ino)) { +			/* get actual file length from the newest node */ +			if (jNode->version >= latestVersion) { +				totalSize = jNode->isize; +				latestVersion = jNode->version; +			} +		} +	} +#endif + +	for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) { +		if ((ino != jNode->ino)) +			continue; +#ifndef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +		/* get actual file length from the newest node */ +		if (jNode->version >= latestVersion) { +			totalSize = jNode->isize; +			latestVersion = jNode->version; +		} +#endif +		if (dest || stat) { +			char *src, *dst; +			char data[4096 + sizeof(struct jffs2_raw_inode)]; +			struct jffs2_raw_inode *inode; +			size_t len; + +			inode = (struct jffs2_raw_inode *)&data; +			len = sizeof(struct jffs2_raw_inode); +			if (dest) +				len += jNode->csize; +			nand_read(nand, jNode->offset, &len, inode); +			/* ignore data behind latest known EOF */ +			if (inode->offset > totalSize) +				continue; + +			if (stat) { +				stat->st_mtime = inode->mtime; +				stat->st_mode = inode->mode; +				stat->st_ino = inode->ino; +				stat->st_size = totalSize; +			} + +			if (!dest) +				continue; + +			src = ((char *) inode) + sizeof(struct jffs2_raw_inode); +			dst = (char *) (dest + inode->offset); + +			switch (inode->compr) { +			case JFFS2_COMPR_NONE: +				ret = 0; +				memcpy(dst, src, inode->dsize); +				break; +			case JFFS2_COMPR_ZERO: +				ret = 0; +				memset(dst, 0, inode->dsize); +				break; +			case JFFS2_COMPR_RTIME: +				ret = 0; +				rtime_decompress(src, dst, inode->csize, inode->dsize); +				break; +			case JFFS2_COMPR_DYNRUBIN: +				/* this is slow but it works */ +				ret = 0; +				dynrubin_decompress(src, dst, inode->csize, inode->dsize); +				break; +			case JFFS2_COMPR_ZLIB: +				ret = zlib_decompress(src, dst, inode->csize, inode->dsize); +				break; +#if defined(CONFIG_JFFS2_LZO) +			case JFFS2_COMPR_LZO: +				ret = lzo_decompress(src, dst, inode->csize, inode->dsize); +				break; +#endif +			default: +				/* unknown */ +				putLabeledWord("UNKNOWN COMPRESSION METHOD = ", inode->compr); +				return -1; +			} +		} +	} + +	return totalSize; +} + +/* find the inode from the slashless name given a parent */ +static u32 +jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino) +{ +	struct b_dirent *jDir; +	int len = strlen(name);	/* name is assumed slash free */ +	unsigned int nhash = full_name_hash(name, len); +	u32 version = 0; +	u32 inode = 0; + +	/* we need to search all and return the inode with the highest version */ +	for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) { +		if ((pino == jDir->pino) && (jDir->ino) &&	/* 0 for unlink */ +		    (len == jDir->nsize) && (nhash == jDir->nhash)) { +			/* TODO: compare name */ +			if (jDir->version < version) +				continue; + +			if (jDir->version == version && inode != 0) { +				/* I'm pretty sure this isn't legal */ +				putstr(" ** ERROR ** "); +/*				putnstr(jDir->name, jDir->nsize); */ +/*				putLabeledWord(" has dup version =", version); */ +			} +			inode = jDir->ino; +			version = jDir->version; +		} +	} +	return inode; +} + +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 int +dump_inode(struct b_lists *pL, struct b_dirent *d, struct b_inode *i) +{ +	char fname[JFFS2_MAX_NAME_LEN + 1]; +	struct stat st; +	size_t len; + +	if(!d || !i) return -1; +	len = d->nsize; +	nand_read(nand, d->offset + sizeof(struct jffs2_raw_dirent), +		  &len, &fname); +	fname[d->nsize] = '\0'; + +	memset(&st, 0, sizeof(st)); + +	jffs2_1pass_read_inode(pL, i->ino, NULL, &st); + +	dump_stat(&st, fname); +/* FIXME +	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 pino */ +static u32 +jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) +{ +	struct b_dirent *jDir; +	u32 i_version = 0; + +	for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) { +		if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */ +			struct b_inode *jNode = (struct b_inode *)pL->frag.listHead; +			struct b_inode *i = NULL; + +			while (jNode) { +				if (jNode->ino == jDir->ino && jNode->version >= i_version) { +					i_version = jNode->version; +					i = jNode; +				} +				jNode = jNode->next; +			} +			dump_inode(pL, jDir, i); +		} +	} +	return pino; +} + +static u32 +jffs2_1pass_search_inode(struct b_lists * pL, const char *fname, u32 pino) +{ +	int i; +	char tmp[256]; +	char working_tmp[256]; +	char *c; + +	/* discard any leading slash */ +	i = 0; +	while (fname[i] == '/') +		i++; +	strcpy(tmp, &fname[i]); + +	while ((c = (char *) strchr(tmp, '/')))	/* we are still dired searching */ +	{ +		strncpy(working_tmp, tmp, c - tmp); +		working_tmp[c - tmp] = '\0'; +#if 0 +		putstr("search_inode: tmp = "); +		putstr(tmp); +		putstr("\r\n"); +		putstr("search_inode: wtmp = "); +		putstr(working_tmp); +		putstr("\r\n"); +		putstr("search_inode: c = "); +		putstr(c); +		putstr("\r\n"); +#endif +		for (i = 0; i < strlen(c) - 1; i++) +			tmp[i] = c[i + 1]; +		tmp[i] = '\0'; +#if 0 +		putstr("search_inode: post tmp = "); +		putstr(tmp); +		putstr("\r\n"); +#endif + +		if (!(pino = jffs2_1pass_find_inode(pL, working_tmp, pino))) { +			putstr("find_inode failed for name="); +			putstr(working_tmp); +			putstr("\r\n"); +			return 0; +		} +	} +	/* this is for the bare filename, directories have already been mapped */ +	if (!(pino = jffs2_1pass_find_inode(pL, tmp, pino))) { +		putstr("find_inode failed for name="); +		putstr(tmp); +		putstr("\r\n"); +		return 0; +	} +	return pino; + +} + +static u32 +jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino) +{ +	struct b_dirent *jDir; +	struct b_inode *jNode; +	u8 jDirFoundType = 0; +	u32 jDirFoundIno = 0; +	u32 jDirFoundPino = 0; +	char tmp[JFFS2_MAX_NAME_LEN + 1]; +	u32 version = 0; +	u32 pino; + +	/* we need to search all and return the inode with the highest version */ +	for (jDir = (struct b_dirent *)pL->dir.listHead; jDir; jDir = jDir->next) { +		if (ino == jDir->ino) { +			if (jDir->version < version) +				continue; + +			if (jDir->version == version && jDirFoundType) { +				/* I'm pretty sure this isn't legal */ +				putstr(" ** ERROR ** "); +/*				putnstr(jDir->name, jDir->nsize); */ +/*				putLabeledWord(" has dup version (resolve) = ", */ +/*					version); */ +			} + +			jDirFoundType = jDir->type; +			jDirFoundIno = jDir->ino; +			jDirFoundPino = jDir->pino; +			version = jDir->version; +		} +	} +	/* now we found the right entry again. (shoulda returned inode*) */ +	if (jDirFoundType != DT_LNK) +		return jDirFoundIno; + +	/* it's a soft link so we follow it again. */ +	for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) { +		if (jNode->ino == jDirFoundIno) { +			size_t len = jNode->csize; +			nand_read(nand, jNode->offset + sizeof(struct jffs2_raw_inode), &len, &tmp); +			tmp[jNode->csize] = '\0'; +			break; +		} +	} +	/* ok so the name of the new file to find is in tmp */ +	/* if it starts with a slash it is root based else shared dirs */ +	if (tmp[0] == '/') +		pino = 1; +	else +		pino = jDirFoundPino; + +	return jffs2_1pass_search_inode(pL, tmp, pino); +} + +static u32 +jffs2_1pass_search_list_inodes(struct b_lists * pL, const char *fname, u32 pino) +{ +	int i; +	char tmp[256]; +	char working_tmp[256]; +	char *c; + +	/* discard any leading slash */ +	i = 0; +	while (fname[i] == '/') +		i++; +	strcpy(tmp, &fname[i]); +	working_tmp[0] = '\0'; +	while ((c = (char *) strchr(tmp, '/')))	/* we are still dired searching */ +	{ +		strncpy(working_tmp, tmp, c - tmp); +		working_tmp[c - tmp] = '\0'; +		for (i = 0; i < strlen(c) - 1; i++) +			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])) { +			putstr("find_inode failed for name="); +			putstr(working_tmp); +			putstr("\r\n"); +			return 0; +		} +	} + +	if (tmp[0] && !(pino = jffs2_1pass_find_inode(pL, tmp, pino))) { +		putstr("find_inode failed for name="); +		putstr(tmp); +		putstr("\r\n"); +		return 0; +	} +	/* this is for the bare filename, directories have already been mapped */ +	if (!(pino = jffs2_1pass_list_inodes(pL, pino))) { +		putstr("find_inode failed for name="); +		putstr(tmp); +		putstr("\r\n"); +		return 0; +	} +	return pino; + +} + +unsigned char +jffs2_1pass_rescan_needed(struct part_info *part) +{ +	struct b_node *b; +	struct jffs2_unknown_node onode; +	struct jffs2_unknown_node *node; +	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->frag.listCount == 0) { +		DEBUGF ("rescan: fraglist zero\n"); +		return 1; +	} + +	/* or if we are scanning a new partition */ +	if (pL->partOffset != part->offset) { +		DEBUGF ("rescan: different partition\n"); +		return 1; +	} + +	/* FIXME */ +#if 0 +	/* but suppose someone reflashed a partition at the same offset... */ +	b = pL->dir.listHead; +	while (b) { +		node = (struct jffs2_unknown_node *) get_fl_mem(b->offset, +			sizeof(onode), &onode); +		if (node->nodetype != JFFS2_NODETYPE_DIRENT) { +			DEBUGF ("rescan: fs changed beneath me? (%lx)\n", +					(unsigned long) b->offset); +			return 1; +		} +		b = b->next; +	} +#endif +	return 0; +} + +#ifdef DEBUG_FRAGMENTS +static void +dump_fragments(struct b_lists *pL) +{ +	struct b_node *b; +	struct jffs2_raw_inode ojNode; +	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 *) get_fl_mem(b->offset, +			sizeof(ojNode), &ojNode); +		putLabeledWord("\r\n\tbuild_list: FLASH_OFFSET = ", b->offset); +		putLabeledWord("\tbuild_list: totlen = ", jNode->totlen); +		putLabeledWord("\tbuild_list: inode = ", jNode->ino); +		putLabeledWord("\tbuild_list: version = ", jNode->version); +		putLabeledWord("\tbuild_list: isize = ", jNode->isize); +		putLabeledWord("\tbuild_list: atime = ", jNode->atime); +		putLabeledWord("\tbuild_list: offset = ", jNode->offset); +		putLabeledWord("\tbuild_list: csize = ", jNode->csize); +		putLabeledWord("\tbuild_list: dsize = ", jNode->dsize); +		putLabeledWord("\tbuild_list: compr = ", jNode->compr); +		putLabeledWord("\tbuild_list: usercompr = ", jNode->usercompr); +		putLabeledWord("\tbuild_list: flags = ", jNode->flags); +		putLabeledWord("\tbuild_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 *) get_node_mem(b->offset); +		putstr("\r\n"); +		putnstr(jDir->name, jDir->nsize); +		putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic); +		putLabeledWord("\tbuild_list: nodetype = ", jDir->nodetype); +		putLabeledWord("\tbuild_list: hdr_crc = ", jDir->hdr_crc); +		putLabeledWord("\tbuild_list: pino = ", jDir->pino); +		putLabeledWord("\tbuild_list: version = ", jDir->version); +		putLabeledWord("\tbuild_list: ino = ", jDir->ino); +		putLabeledWord("\tbuild_list: mctime = ", jDir->mctime); +		putLabeledWord("\tbuild_list: nsize = ", jDir->nsize); +		putLabeledWord("\tbuild_list: type = ", jDir->type); +		putLabeledWord("\tbuild_list: node_crc = ", jDir->node_crc); +		putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc); +		putLabeledWord("\tbuild_list: offset = ", b->offset);	/* FIXME: ? [RS] */ +		b = b->next; +		put_fl_mem(jDir); +	} +} +#endif + +static int +jffs2_fill_scan_buf(nand_info_t *nand, unsigned char *buf, +		    unsigned ofs, unsigned len) +{ +	int ret; +	unsigned olen; + +	olen = len; +	ret = nand_read(nand, ofs, &olen, buf); +	if (ret) { +		printf("nand_read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret); +		return ret; +	} +	if (olen < len) { +		printf("Read at 0x%x gave only 0x%x bytes\n", ofs, olen); +		return -1; +	} +	return 0; +} + +#define	EMPTY_SCAN_SIZE	1024 +static u32 +jffs2_1pass_build_lists(struct part_info * part) +{ +	struct b_lists *pL; +	struct jffs2_unknown_node *node; +	unsigned nr_blocks, sectorsize, ofs, offset; +	char *buf; +	int i; +	u32 counter = 0; +	u32 counter4 = 0; +	u32 counterF = 0; +	u32 counterN = 0; + +	struct mtdids *id = part->dev->id; +	nand = nand_info + id->num; + +	/* if we are building a list we need to refresh the cache. */ +	jffs_init_1pass_list(part); +	pL = (struct b_lists *)part->jffs2_priv; +	pL->partOffset = part->offset; +	puts ("Scanning JFFS2 FS:   "); + +	sectorsize = nand->erasesize; +	nr_blocks = part->size / sectorsize; +	buf = malloc(sectorsize); +	if (!buf) +		return 0; + +	for (i = 0; i < nr_blocks; i++) { +		printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]); + +		offset = part->offset + i * sectorsize; + +		if (nand_block_isbad(nand, offset)) +			continue; + +		if (jffs2_fill_scan_buf(nand, buf, offset, EMPTY_SCAN_SIZE)) +			return 0; + +		ofs = 0; +		/* Scan only 4KiB of 0xFF before declaring it's empty */ +		while (ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) +			ofs += 4; +		if (ofs == EMPTY_SCAN_SIZE) +			continue; + +		if (jffs2_fill_scan_buf(nand, buf + EMPTY_SCAN_SIZE, offset + EMPTY_SCAN_SIZE, sectorsize - EMPTY_SCAN_SIZE)) +			return 0; +		offset += ofs; + +		while (ofs < sectorsize - sizeof(struct jffs2_unknown_node)) { +			node = (struct jffs2_unknown_node *)&buf[ofs]; +			if (node->magic != JFFS2_MAGIC_BITMASK || !hdr_crc(node)) { +				offset += 4; +				ofs += 4; +				counter4++; +				continue; +			} +			/* if its a fragment add it */ +			if (node->nodetype == JFFS2_NODETYPE_INODE && +				    inode_crc((struct jffs2_raw_inode *) node)) { +				if (insert_inode(&pL->frag, (struct jffs2_raw_inode *) node, +						 offset) == NULL) { +					return 0; +				} +			} 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)) +					puts ("\b\b.  "); +				if (insert_dirent(&pL->dir, (struct jffs2_raw_dirent *) node, +						  offset) == NULL) { +					return 0; +				} +				counterN++; +			} else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) { +				if (node->totlen != sizeof(struct jffs2_unknown_node)) +					printf("OOPS Cleanmarker has bad size " +						"%d != %zu\n", +						node->totlen, +						sizeof(struct jffs2_unknown_node)); +			} else if (node->nodetype == JFFS2_NODETYPE_PADDING) { +				if (node->totlen < sizeof(struct jffs2_unknown_node)) +					printf("OOPS Padding has bad size " +						"%d < %zu\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); +			} +			offset += ((node->totlen + 3) & ~3); +			ofs += ((node->totlen + 3) & ~3); +			counterF++; +		} +	} + +	putstr("\b\b done.\r\n");		/* close off the dots */ + +#if 0 +	putLabeledWord("dir entries = ", pL->dir.listCount); +	putLabeledWord("frag entries = ", pL->frag.listCount); +	putLabeledWord("+4 increments = ", counter4); +	putLabeledWord("+file_offset increments = ", counterF); +#endif + +#ifdef DEBUG_DIRENTS +	dump_dirents(pL); +#endif + +#ifdef DEBUG_FRAGMENTS +	dump_fragments(pL); +#endif + +	/* give visual feedback that we are done scanning the flash */ +	led_blink(0x0, 0x0, 0x1, 0x1);	/* off, forever, on 100ms, off 100ms */ +	free(buf); + +	return 1; +} + + +static u32 +jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL) +{ +	struct b_node *b; +	struct jffs2_raw_inode ojNode; +	struct jffs2_raw_inode *jNode; +	int i; + +	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; +	} +/*	FIXME +	b = pL->frag.listHead; +	while (b) { +		jNode = (struct jffs2_raw_inode *) get_fl_mem(b->offset, +			sizeof(ojNode), &ojNode); +		if (jNode->compr < JFFS2_NUM_COMPR) { +			piL->compr_info[jNode->compr].num_frags++; +			piL->compr_info[jNode->compr].compr_sum += jNode->csize; +			piL->compr_info[jNode->compr].decompr_sum += jNode->dsize; +		} +		b = b->next; +	} +*/ +	return 0; +} + + +static struct b_lists * +jffs2_get_list(struct part_info * part, const char *who) +{ +	if (jffs2_1pass_rescan_needed(part)) { +		if (!jffs2_1pass_build_lists(part)) { +			printf("%s: Failed to scan JFFSv2 file structure\n", who); +			return NULL; +		} +	} +	return (struct b_lists *)part->jffs2_priv; +} + + +/* Print directory / file contents */ +u32 +jffs2_1pass_ls(struct part_info * part, const char *fname) +{ +	struct b_lists *pl; +	long ret = 0; +	u32 inode; + +	if (! (pl = jffs2_get_list(part, "ls"))) +		return 0; + +	if (! (inode = jffs2_1pass_search_list_inodes(pl, fname, 1))) { +		putstr("ls: Failed to scan jffs2 file structure\r\n"); +		return 0; +	} + +#if 0 +	putLabeledWord("found file at inode = ", inode); +	putLabeledWord("read_inode returns = ", ret); +#endif + +	return ret; +} + + +/* Load a file from flash into memory. fname can be a full path */ +u32 +jffs2_1pass_load(char *dest, struct part_info * part, const char *fname) +{ + +	struct b_lists *pl; +	long ret = 0; +	u32 inode; + +	if (! (pl = jffs2_get_list(part, "load"))) +		return 0; + +	if (! (inode = jffs2_1pass_search_inode(pl, fname, 1))) { +		putstr("load: Failed to find inode\r\n"); +		return 0; +	} + +	/* Resolve symlinks */ +	if (! (inode = jffs2_1pass_resolve_inode(pl, inode))) { +		putstr("load: Failed to resolve inode structure\r\n"); +		return 0; +	} + +	if ((ret = jffs2_1pass_read_inode(pl, inode, dest, NULL)) < 0) { +		putstr("load: Failed to read inode\r\n"); +		return 0; +	} + +	DEBUGF ("load: loaded '%s' to 0x%lx (%ld bytes)\n", fname, +				(unsigned long) dest, ret); +	return ret; +} + +/* Return information about the fs on this partition */ +u32 +jffs2_1pass_info(struct part_info * part) +{ +	struct b_jffs2_info info; +	struct b_lists *pl; +	int i; + +	if (! (pl = jffs2_get_list(part, "info"))) +		return 0; + +	jffs2_1pass_fill_info(pl, &info); +	for (i = 0; i < JFFS2_NUM_COMPR; i++) { +		printf ("Compression: %s\n" +			"\tfrag count: %d\n" +			"\tcompressed sum: %d\n" +			"\tuncompressed sum: %d\n", +			compr_names[i], +			info.compr_info[i].num_frags, +			info.compr_info[i].compr_sum, +			info.compr_info[i].decompr_sum); +	} +	return 1; +} diff --git a/roms/u-boot/fs/jffs2/jffs2_nand_private.h b/roms/u-boot/fs/jffs2/jffs2_nand_private.h new file mode 100644 index 00000000..18cca8d0 --- /dev/null +++ b/roms/u-boot/fs/jffs2/jffs2_nand_private.h @@ -0,0 +1,133 @@ +#ifndef jffs2_private_h +#define jffs2_private_h + +#include <jffs2/jffs2.h> + +struct b_node { +	struct b_node *next; +}; + +struct b_inode { +	struct b_inode *next; +	u32 offset;	/* physical offset to beginning of real inode */ +	u32 version; +	u32 ino; +	u32 isize; +	u32 csize; +}; + +struct b_dirent { +	struct b_dirent *next; +	u32 offset;	/* physical offset to beginning of real dirent */ +	u32 version; +	u32 pino; +	u32 ino; +	unsigned int nhash; +	unsigned char nsize; +	unsigned char type; +}; + +struct b_list { +	struct b_node *listTail; +	struct b_node *listHead; +	unsigned int listCount; +	struct mem_block *listMemBase; +}; + +struct b_lists { +	char *partOffset; +	struct b_list dir; +	struct b_list frag; +}; + +struct b_compr_info { +	u32 num_frags; +	u32 compr_sum; +	u32 decompr_sum; +}; + +struct b_jffs2_info { +	struct b_compr_info compr_info[JFFS2_NUM_COMPR]; +}; + +static inline int +hdr_crc(struct jffs2_unknown_node *node) +{ +#if 1 +	u32 crc = crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4); +#else +	/* what's the semantics of this? why is this here? */ +	u32 crc = crc32_no_comp(~0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4); + +	crc ^= ~0; +#endif +	if (node->hdr_crc != crc) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +dirent_crc(struct jffs2_raw_dirent *node) +{ +	if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_dirent) - 8)) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +dirent_name_crc(struct jffs2_raw_dirent *node) +{ +	if (node->name_crc != crc32_no_comp(0, (unsigned char *)&(node->name), node->nsize)) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +inode_crc(struct jffs2_raw_inode *node) +{ +	if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_inode) - 8)) { +		return 0; +	} else { +		return 1; +	} +} + +/* Borrowed from include/linux/dcache.h */ + +/* Name hashing routines. Initial hash value */ +/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */ +#define init_name_hash()		0 + +/* partial hash update function. Assume roughly 4 bits per character */ +static inline unsigned long +partial_name_hash(unsigned long c, unsigned long prevhash) +{ +	return (prevhash + (c << 4) + (c >> 4)) * 11; +} + +/* + * Finally: cut down the number of bits to a int value (and try to avoid + * losing bits) + */ +static inline unsigned long end_name_hash(unsigned long hash) +{ +	return (unsigned int) hash; +} + +/* Compute the hash for a name string. */ +static inline unsigned int +full_name_hash(const unsigned char *name, unsigned int len) +{ +	unsigned long hash = init_name_hash(); +	while (len--) +		hash = partial_name_hash(*name++, hash); +	return end_name_hash(hash); +} + +#endif /* jffs2_private.h */ diff --git a/roms/u-boot/fs/jffs2/jffs2_private.h b/roms/u-boot/fs/jffs2/jffs2_private.h new file mode 100644 index 00000000..658b3252 --- /dev/null +++ b/roms/u-boot/fs/jffs2/jffs2_private.h @@ -0,0 +1,101 @@ +#ifndef jffs2_private_h +#define jffs2_private_h + +#include <jffs2/jffs2.h> + + +struct b_node { +	u32 offset; +	struct b_node *next; +	enum { CRC_UNKNOWN = 0, CRC_OK, CRC_BAD } datacrc; +}; + +struct b_list { +	struct b_node *listTail; +	struct b_node *listHead; +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS +	struct b_node *listLast; +	int (*listCompare)(struct b_node *new, struct b_node *node); +	u32 listLoops; +#endif +	u32 listCount; +	struct mem_block *listMemBase; +}; + +struct b_lists { +	struct b_list dir; +	struct b_list frag; +	void *readbuf; +}; + +struct b_compr_info { +	u32 num_frags; +	u32 compr_sum; +	u32 decompr_sum; +}; + +struct b_jffs2_info { +	struct b_compr_info compr_info[JFFS2_NUM_COMPR]; +}; + +static inline int +hdr_crc(struct jffs2_unknown_node *node) +{ +#if 1 +	u32 crc = crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4); +#else +	/* what's the semantics of this? why is this here? */ +	u32 crc = crc32_no_comp(~0, (unsigned char *)node, sizeof(struct jffs2_unknown_node) - 4); + +	crc ^= ~0; +#endif +	if (node->hdr_crc != crc) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +dirent_crc(struct jffs2_raw_dirent *node) +{ +	if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_dirent) - 8)) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +dirent_name_crc(struct jffs2_raw_dirent *node) +{ +	if (node->name_crc != crc32_no_comp(0, (unsigned char *)&(node->name), node->nsize)) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +inode_crc(struct jffs2_raw_inode *node) +{ +	if (node->node_crc != crc32_no_comp(0, (unsigned char *)node, sizeof(struct jffs2_raw_inode) - 8)) { +		return 0; +	} else { +		return 1; +	} +} + +static inline int +data_crc(struct jffs2_raw_inode *node) +{ +	if (node->data_crc != crc32_no_comp(0, (unsigned char *) +					    ((int) &node->node_crc + sizeof (node->node_crc)), +					     node->csize)) { +		return 0; +	} else { +		return 1; +	} +} + +#endif /* jffs2_private.h */ diff --git a/roms/u-boot/fs/jffs2/mini_inflate.c b/roms/u-boot/fs/jffs2/mini_inflate.c new file mode 100644 index 00000000..2f13412f --- /dev/null +++ b/roms/u-boot/fs/jffs2/mini_inflate.c @@ -0,0 +1,377 @@ +/*------------------------------------------------------------------------- + * Filename:      mini_inflate.c + * Version:       $Id: mini_inflate.c,v 1.3 2002/01/24 22:58:42 rfeany Exp $ + * Copyright:     Copyright (C) 2001, Russ Dill + * Author:        Russ Dill <Russ.Dill@asu.edu> + * Description:   Mini inflate implementation (RFC 1951) + *-----------------------------------------------------------------------*/ +/* + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <config.h> +#include <jffs2/mini_inflate.h> + +/* The order that the code lengths in section 3.2.7 are in */ +static unsigned char huffman_order[] = {16, 17, 18,  0,  8,  7,  9,  6, 10,  5, +					11,  4, 12,  3, 13,  2, 14,  1, 15}; + +inline void cramfs_memset(int *s, const int c, size n) +{ +	n--; +	for (;n > 0; n--) s[n] = c; +	s[0] = c; +} + +/* associate a stream with a block of data and reset the stream */ +static void init_stream(struct bitstream *stream, unsigned char *data, +			void *(*inflate_memcpy)(void *, const void *, size)) +{ +	stream->error = NO_ERROR; +	stream->memcpy = inflate_memcpy; +	stream->decoded = 0; +	stream->data = data; +	stream->bit = 0;	/* The first bit of the stream is the lsb of the +				 * first byte */ + +	/* really sorry about all this initialization, think of a better way, +	 * let me know and it will get cleaned up */ +	stream->codes.bits = 8; +	stream->codes.num_symbols = 19; +	stream->codes.lengths = stream->code_lengths; +	stream->codes.symbols = stream->code_symbols; +	stream->codes.count = stream->code_count; +	stream->codes.first = stream->code_first; +	stream->codes.pos = stream->code_pos; + +	stream->lengths.bits = 16; +	stream->lengths.num_symbols = 288; +	stream->lengths.lengths = stream->length_lengths; +	stream->lengths.symbols = stream->length_symbols; +	stream->lengths.count = stream->length_count; +	stream->lengths.first = stream->length_first; +	stream->lengths.pos = stream->length_pos; + +	stream->distance.bits = 16; +	stream->distance.num_symbols = 32; +	stream->distance.lengths = stream->distance_lengths; +	stream->distance.symbols = stream->distance_symbols; +	stream->distance.count = stream->distance_count; +	stream->distance.first = stream->distance_first; +	stream->distance.pos = stream->distance_pos; + +} + +/* pull 'bits' bits out of the stream. The last bit pulled it returned as the + * msb. (section 3.1.1) + */ +inline unsigned long pull_bits(struct bitstream *stream, +			       const unsigned int bits) +{ +	unsigned long ret; +	int i; + +	ret = 0; +	for (i = 0; i < bits; i++) { +		ret += ((*(stream->data) >> stream->bit) & 1) << i; + +		/* if, before incrementing, we are on bit 7, +		 * go to the lsb of the next byte */ +		if (stream->bit++ == 7) { +			stream->bit = 0; +			stream->data++; +		} +	} +	return ret; +} + +inline int pull_bit(struct bitstream *stream) +{ +	int ret = ((*(stream->data) >> stream->bit) & 1); +	if (stream->bit++ == 7) { +		stream->bit = 0; +		stream->data++; +	} +	return ret; +} + +/* discard bits up to the next whole byte */ +static void discard_bits(struct bitstream *stream) +{ +	if (stream->bit != 0) { +		stream->bit = 0; +		stream->data++; +	} +} + +/* No decompression, the data is all literals (section 3.2.4) */ +static void decompress_none(struct bitstream *stream, unsigned char *dest) +{ +	unsigned int length; + +	discard_bits(stream); +	length = *(stream->data++); +	length += *(stream->data++) << 8; +	pull_bits(stream, 16);	/* throw away the inverse of the size */ + +	stream->decoded += length; +	stream->memcpy(dest, stream->data, length); +	stream->data += length; +} + +/* Read in a symbol from the stream (section 3.2.2) */ +static int read_symbol(struct bitstream *stream, struct huffman_set *set) +{ +	int bits = 0; +	int code = 0; +	while (!(set->count[bits] && code < set->first[bits] + +					     set->count[bits])) { +		code = (code << 1) + pull_bit(stream); +		if (++bits > set->bits) { +			/* error decoding (corrupted data?) */ +			stream->error = CODE_NOT_FOUND; +			return -1; +		} +	} +	return set->symbols[set->pos[bits] + code - set->first[bits]]; +} + +/* decompress a stream of data encoded with the passed length and distance + * huffman codes */ +static void decompress_huffman(struct bitstream *stream, unsigned char *dest) +{ +	struct huffman_set *lengths = &(stream->lengths); +	struct huffman_set *distance = &(stream->distance); + +	int symbol, length, dist, i; + +	do { +		if ((symbol = read_symbol(stream, lengths)) < 0) return; +		if (symbol < 256) { +			*(dest++) = symbol; /* symbol is a literal */ +			stream->decoded++; +		} else if (symbol > 256) { +			/* Determine the length of the repitition +			 * (section 3.2.5) */ +			if (symbol < 265) length = symbol - 254; +			else if (symbol == 285) length = 258; +			else { +				length = pull_bits(stream, (symbol - 261) >> 2); +				length += (4 << ((symbol - 261) >> 2)) + 3; +				length += ((symbol - 1) % 4) << +					  ((symbol - 261) >> 2); +			} + +			/* Determine how far back to go */ +			if ((symbol = read_symbol(stream, distance)) < 0) +				return; +			if (symbol < 4) dist = symbol + 1; +			else { +				dist = pull_bits(stream, (symbol - 2) >> 1); +				dist += (2 << ((symbol - 2) >> 1)) + 1; +				dist += (symbol % 2) << ((symbol - 2) >> 1); +			} +			stream->decoded += length; +			for (i = 0; i < length; i++) { +				*dest = dest[-dist]; +				dest++; +			} +		} +	} while (symbol != 256); /* 256 is the end of the data block */ +} + +/* Fill the lookup tables (section 3.2.2) */ +static void fill_code_tables(struct huffman_set *set) +{ +	int code = 0, i, length; + +	/* fill in the first code of each bit length, and the pos pointer */ +	set->pos[0] = 0; +	for (i = 1; i < set->bits; i++) { +		code = (code + set->count[i - 1]) << 1; +		set->first[i] = code; +		set->pos[i] = set->pos[i - 1] + set->count[i - 1]; +	} + +	/* Fill in the table of symbols in order of their huffman code */ +	for (i = 0; i < set->num_symbols; i++) { +		if ((length = set->lengths[i])) +			set->symbols[set->pos[length]++] = i; +	} + +	/* reset the pos pointer */ +	for (i = 1; i < set->bits; i++) set->pos[i] -= set->count[i]; +} + +static void init_code_tables(struct huffman_set *set) +{ +	cramfs_memset(set->lengths, 0, set->num_symbols); +	cramfs_memset(set->count, 0, set->bits); +	cramfs_memset(set->first, 0, set->bits); +} + +/* read in the huffman codes for dynamic decoding (section 3.2.7) */ +static void decompress_dynamic(struct bitstream *stream, unsigned char *dest) +{ +	/* I tried my best to minimize the memory footprint here, while still +	 * keeping up performance. I really dislike the _lengths[] tables, but +	 * I see no way of eliminating them without a sizable performance +	 * impact. The first struct table keeps track of stats on each bit +	 * length. The _length table keeps a record of the bit length of each +	 * symbol. The _symbols table is for looking up symbols by the huffman +	 * code (the pos element points to the first place in the symbol table +	 * where that bit length occurs). I also hate the initization of these +	 * structs, if someone knows how to compact these, lemme know. */ + +	struct huffman_set *codes = &(stream->codes); +	struct huffman_set *lengths = &(stream->lengths); +	struct huffman_set *distance = &(stream->distance); + +	int hlit = pull_bits(stream, 5) + 257; +	int hdist = pull_bits(stream, 5) + 1; +	int hclen = pull_bits(stream, 4) + 4; +	int length, curr_code, symbol, i, last_code; + +	last_code = 0; + +	init_code_tables(codes); +	init_code_tables(lengths); +	init_code_tables(distance); + +	/* fill in the count of each bit length' as well as the lengths +	 * table */ +	for (i = 0; i < hclen; i++) { +		length = pull_bits(stream, 3); +		codes->lengths[huffman_order[i]] = length; +		if (length) codes->count[length]++; + +	} +	fill_code_tables(codes); + +	/* Do the same for the length codes, being carefull of wrap through +	 * to the distance table */ +	curr_code = 0; +	while (curr_code < hlit) { +		if ((symbol = read_symbol(stream, codes)) < 0) return; +		if (symbol == 0) { +			curr_code++; +			last_code = 0; +		} else if (symbol < 16) { /* Literal length */ +			lengths->lengths[curr_code] =  last_code = symbol; +			lengths->count[symbol]++; +			curr_code++; +		} else if (symbol == 16) { /* repeat the last symbol 3 - 6 +					    * times */ +			length = 3 + pull_bits(stream, 2); +			for (;length; length--, curr_code++) +				if (curr_code < hlit) { +					lengths->lengths[curr_code] = +						last_code; +					lengths->count[last_code]++; +				} else { /* wrap to the distance table */ +					distance->lengths[curr_code - hlit] = +						last_code; +					distance->count[last_code]++; +				} +		} else if (symbol == 17) { /* repeat a bit length 0 */ +			curr_code += 3 + pull_bits(stream, 3); +			last_code = 0; +		} else { /* same, but more times */ +			curr_code += 11 + pull_bits(stream, 7); +			last_code = 0; +		} +	} +	fill_code_tables(lengths); + +	/* Fill the distance table, don't need to worry about wrapthrough +	 * here */ +	curr_code -= hlit; +	while (curr_code < hdist) { +		if ((symbol = read_symbol(stream, codes)) < 0) return; +		if (symbol == 0) { +			curr_code++; +			last_code = 0; +		} else if (symbol < 16) { +			distance->lengths[curr_code] = last_code = symbol; +			distance->count[symbol]++; +			curr_code++; +		} else if (symbol == 16) { +			length = 3 + pull_bits(stream, 2); +			for (;length; length--, curr_code++) { +				distance->lengths[curr_code] = +					last_code; +				distance->count[last_code]++; +			} +		} else if (symbol == 17) { +			curr_code += 3 + pull_bits(stream, 3); +			last_code = 0; +		} else { +			curr_code += 11 + pull_bits(stream, 7); +			last_code = 0; +		} +	} +	fill_code_tables(distance); + +	decompress_huffman(stream, dest); +} + +/* fill in the length and distance huffman codes for fixed encoding + * (section 3.2.6) */ +static void decompress_fixed(struct bitstream *stream, unsigned char *dest) +{ +	/* let gcc fill in the initial values */ +	struct huffman_set *lengths = &(stream->lengths); +	struct huffman_set *distance = &(stream->distance); + +	cramfs_memset(lengths->count, 0, 16); +	cramfs_memset(lengths->first, 0, 16); +	cramfs_memset(lengths->lengths, 8, 144); +	cramfs_memset(lengths->lengths + 144, 9, 112); +	cramfs_memset(lengths->lengths + 256, 7, 24); +	cramfs_memset(lengths->lengths + 280, 8, 8); +	lengths->count[7] = 24; +	lengths->count[8] = 152; +	lengths->count[9] = 112; + +	cramfs_memset(distance->count, 0, 16); +	cramfs_memset(distance->first, 0, 16); +	cramfs_memset(distance->lengths, 5, 32); +	distance->count[5] = 32; + + +	fill_code_tables(lengths); +	fill_code_tables(distance); + + +	decompress_huffman(stream, dest); +} + +/* returns the number of bytes decoded, < 0 if there was an error. Note that + * this function assumes that the block starts on a byte boundry + * (non-compliant, but I don't see where this would happen). section 3.2.3 */ +long decompress_block(unsigned char *dest, unsigned char *source, +		      void *(*inflate_memcpy)(void *, const void *, size)) +{ +	int bfinal, btype; +	struct bitstream stream; + +	init_stream(&stream, source, inflate_memcpy); +	do { +		bfinal = pull_bit(&stream); +		btype = pull_bits(&stream, 2); +		if (btype == NO_COMP) decompress_none(&stream, dest + stream.decoded); +		else if (btype == DYNAMIC_COMP) +			decompress_dynamic(&stream, dest + stream.decoded); +		else if (btype == FIXED_COMP) decompress_fixed(&stream, dest + stream.decoded); +		else stream.error = COMP_UNKNOWN; +	} while (!bfinal && !stream.error); + +#if 0 +	putstr("decompress_block start\r\n"); +	putLabeledWord("stream.error = ",stream.error); +	putLabeledWord("stream.decoded = ",stream.decoded); +	putLabeledWord("dest = ",dest); +	putstr("decompress_block end\r\n"); +#endif +	return stream.error ? -stream.error : stream.decoded; +} diff --git a/roms/u-boot/fs/jffs2/summary.h b/roms/u-boot/fs/jffs2/summary.h new file mode 100644 index 00000000..834933cd --- /dev/null +++ b/roms/u-boot/fs/jffs2/summary.h @@ -0,0 +1,163 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>, + *		     Zoltan Sogor <weth@inf.u-szeged.hu>, + *		     Patrik Kluba <pajko@halom.u-szeged.hu>, + *		     University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ + +#ifndef JFFS2_SUMMARY_H +#define JFFS2_SUMMARY_H + +#define BLK_STATE_ALLFF		0 +#define BLK_STATE_CLEAN		1 +#define BLK_STATE_PARTDIRTY	2 +#define BLK_STATE_CLEANMARKER	3 +#define BLK_STATE_ALLDIRTY	4 +#define BLK_STATE_BADBLOCK	5 + +#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff +#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) +#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) +#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash)) +#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash)) + +/* Summary structures used on flash */ + +struct jffs2_sum_unknown_flash +{ +	__u16 nodetype;	/* node type */ +}; + +struct jffs2_sum_inode_flash +{ +	__u16 nodetype;	/* node type */ +	__u32 inode;		/* inode number */ +	__u32 version;	/* inode version */ +	__u32 offset;	/* offset on jeb */ +	__u32 totlen; 	/* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_flash +{ +	__u16 nodetype;	/* == JFFS_NODETYPE_DIRENT */ +	__u32 totlen;	/* record length */ +	__u32 offset;	/* offset on jeb */ +	__u32 pino;		/* parent inode */ +	__u32 version;	/* dirent version */ +	__u32 ino; 		/* == zero for unlink */ +	uint8_t nsize;		/* dirent name size */ +	uint8_t type;		/* dirent type */ +	uint8_t name[0];	/* dirent name */ +} __attribute__((packed)); + +struct jffs2_sum_xattr_flash +{ +	__u16 nodetype;	/* == JFFS2_NODETYPE_XATR */ +	__u32 xid;		/* xattr identifier */ +	__u32 version;	/* version number */ +	__u32 offset;	/* offset on jeb */ +	__u32 totlen;	/* node length */ +} __attribute__((packed)); + +struct jffs2_sum_xref_flash +{ +	__u16 nodetype;	/* == JFFS2_NODETYPE_XREF */ +	__u32 offset;	/* offset on jeb */ +} __attribute__((packed)); + +union jffs2_sum_flash +{ +	struct jffs2_sum_unknown_flash u; +	struct jffs2_sum_inode_flash i; +	struct jffs2_sum_dirent_flash d; +	struct jffs2_sum_xattr_flash x; +	struct jffs2_sum_xref_flash r; +}; + +/* Summary structures used in the memory */ + +struct jffs2_sum_unknown_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype;	/* node type */ +}; + +struct jffs2_sum_inode_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype;	/* node type */ +	__u32 inode;		/* inode number */ +	__u32 version;	/* inode version */ +	__u32 offset;	/* offset on jeb */ +	__u32 totlen; 	/* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype;	/* == JFFS_NODETYPE_DIRENT */ +	__u32 totlen;	/* record length */ +	__u32 offset;	/* ofset on jeb */ +	__u32 pino;		/* parent inode */ +	__u32 version;	/* dirent version */ +	__u32 ino; 		/* == zero for unlink */ +	uint8_t nsize;		/* dirent name size */ +	uint8_t type;		/* dirent type */ +	uint8_t name[0];	/* dirent name */ +} __attribute__((packed)); + +struct jffs2_sum_xattr_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype; +	__u32 xid; +	__u32 version; +	__u32 offset; +	__u32 totlen; +} __attribute__((packed)); + +struct jffs2_sum_xref_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype; +	__u32 offset; +} __attribute__((packed)); + +union jffs2_sum_mem +{ +	struct jffs2_sum_unknown_mem u; +	struct jffs2_sum_inode_mem i; +	struct jffs2_sum_dirent_mem d; +	struct jffs2_sum_xattr_mem x; +	struct jffs2_sum_xref_mem r; +}; + +/* Summary related information stored in superblock */ + +struct jffs2_summary +{ +	uint32_t sum_size;      /* collected summary information for nextblock */ +	uint32_t sum_num; +	uint32_t sum_padded; +	union jffs2_sum_mem *sum_list_head; +	union jffs2_sum_mem *sum_list_tail; + +	__u32 *sum_buf;	/* buffer for writing out summary */ +}; + +/* Summary marker is stored at the end of every sumarized erase block */ + +struct jffs2_sum_marker +{ +	__u32 offset;	/* offset of the summary node in the jeb */ +	__u32 magic; 	/* == JFFS2_SUM_MAGIC */ +}; + +#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) + +#endif /* JFFS2_SUMMARY_H */  | 
