#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 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) )
-#if defined(CONFIG_NAND_LEGACY)
-#include <linux/mtd/nand_legacy.h>
-#else
#include <nand.h>
-#endif
/*
* Support for jffs2 on top of NAND-flash
*
*
*/
-#if defined(CONFIG_NAND_LEGACY)
-/* this one defined in nand_legacy.c */
-int read_jffs2_nand(size_t start, size_t len,
- size_t * retlen, u_char * buf, int nanddev);
-#endif
-
#define NAND_PAGE_SIZE 512
#define NAND_PAGE_SHIFT 9
#define NAND_PAGE_MASK (~(NAND_PAGE_SIZE-1))
}
}
-#if defined(CONFIG_NAND_LEGACY)
- if (read_jffs2_nand(nand_cache_off, NAND_CACHE_SIZE,
- &retlen, nand_cache, id->num) < 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;
- }
-#else
retlen = NAND_CACHE_SIZE;
if (nand_read(&nand_info[id->num], nand_cache_off,
&retlen, nand_cache) != 0 ||
nand_cache_off, NAND_CACHE_SIZE);
return -1;
}
-#endif
}
cpy_bytes = nand_cache_off + NAND_CACHE_SIZE - (off + bytes_read);
if (cpy_bytes > size - bytes_read)
{
struct mtdids *id = current_part->dev->id;
+ switch(id->type) {
#if defined(CONFIG_CMD_FLASH)
- if (id->type == MTD_DEV_TYPE_NOR) {
+ 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)
- if (id->type == MTD_DEV_TYPE_NAND)
+ case MTD_DEV_TYPE_NAND:
return get_fl_mem_nand(off, size, ext_buf);
+ break;
#endif
-
#if defined(CONFIG_CMD_ONENAND)
- if (id->type == MTD_DEV_TYPE_ONENAND)
+ case MTD_DEV_TYPE_ONENAND:
return get_fl_mem_onenand(off, size, ext_buf);
+ break;
#endif
-
- printf("get_fl_mem: unknown device type, using raw offset!\n");
+ default:
+ printf("get_fl_mem: unknown device type, " \
+ "using raw offset!\n");
+ }
return (void*)off;
}
{
struct mtdids *id = current_part->dev->id;
+ switch(id->type) {
#if defined(CONFIG_CMD_FLASH)
- if (id->type == MTD_DEV_TYPE_NOR)
+ case MTD_DEV_TYPE_NOR:
return get_node_mem_nor(off, ext_buf);
+ break;
#endif
-
#if defined(CONFIG_JFFS2_NAND) && \
defined(CONFIG_CMD_NAND)
- if (id->type == MTD_DEV_TYPE_NAND)
+ case MTD_DEV_TYPE_NAND:
return get_node_mem_nand(off, ext_buf);
+ break;
#endif
-
#if defined(CONFIG_CMD_ONENAND)
- if (id->type == MTD_DEV_TYPE_ONENAND)
+ case MTD_DEV_TYPE_ONENAND:
return get_node_mem_onenand(off, ext_buf);
+ break;
#endif
-
- printf("get_node_mem: unknown device type, using raw offset!\n");
+ default:
+ printf("get_fl_mem: unknown device type, " \
+ "using raw offset!\n");
+ }
return (void*)off;
}
"COPY",
"DYNRUBIN",
"ZLIB",
-#if defined(CONFIG_JFFS2_LZO_LZARI)
+#if defined(CONFIG_JFFS2_LZO)
"LZO",
- "LZARI",
#endif
};
u32 latestVersion = 0;
uchar *lDest;
uchar *src;
- long ret;
int i;
u32 counter = 0;
#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
put_fl_mem(jNode, pL->readbuf);
continue;
}
- if (!data_crc(jNode)) {
+ 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;
}
#endif
switch (jNode->compr) {
case JFFS2_COMPR_NONE:
- ret = (unsigned long) ldr_memcpy(lDest, src, jNode->dsize);
+ ldr_memcpy(lDest, src, jNode->dsize);
break;
case JFFS2_COMPR_ZERO:
- ret = 0;
for (i = 0; i < jNode->dsize; i++)
*(lDest++) = 0;
break;
case JFFS2_COMPR_RTIME:
- ret = 0;
rtime_decompress(src, lDest, jNode->csize, jNode->dsize);
break;
case JFFS2_COMPR_DYNRUBIN:
/* this is slow but it works */
- ret = 0;
dynrubin_decompress(src, lDest, jNode->csize, jNode->dsize);
break;
case JFFS2_COMPR_ZLIB:
- ret = zlib_decompress(src, lDest, jNode->csize, jNode->dsize);
+ zlib_decompress(src, lDest, jNode->csize, jNode->dsize);
break;
-#if defined(CONFIG_JFFS2_LZO_LZARI)
+#if defined(CONFIG_JFFS2_LZO)
case JFFS2_COMPR_LZO:
- ret = lzo_decompress(src, lDest, jNode->csize, jNode->dsize);
- break;
- case JFFS2_COMPR_LZARI:
- ret = lzari_decompress(src, lDest, jNode->csize, jNode->dsize);
+ lzo_decompress(src, lDest, jNode->csize, jNode->dsize);
break;
#endif
default:
/* unknown */
- putLabeledWord("UNKOWN COMPRESSION METHOD = ", jNode->compr);
+ putLabeledWord("UNKNOWN COMPRESSION METHOD = ", jNode->compr);
put_fl_mem(jNode, pL->readbuf);
return -1;
break;
#if 0
putLabeledWord("read_inode: totalSize = ", totalSize);
- putLabeledWord("read_inode: compr ret = ", ret);
#endif
}
counter++;
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)
}
#endif
-#define min_t(type, x, y) ({ \
- type __min1 = (x); \
- type __min2 = (y); \
- __min1 < __min2 ? __min1: __min2; })
-
#define DEFAULT_EMPTY_SCAN_SIZE 4096
static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size)
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 = EMPTY_SCAN_SIZE(part->sector_size);
+ 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 */
if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
uint32_t inbuf_ofs;
- uint32_t empty_start, scan_end;
+ uint32_t scan_end;
- empty_start = ofs;
ofs += 4;
scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(
part->sector_size)/8,
break;
if (insert_node(&pL->frag, (u32) part->offset +
- ofs) == NULL)
+ ofs) == NULL) {
+ free(buf);
+ jffs2_free_cache(part);
return 0;
+ }
if (max_totlen < node->totlen)
max_totlen = node->totlen;
break;
if (! (counterN%100))
puts ("\b\b. ");
if (insert_node(&pL->dir, (u32) part->offset +
- ofs) == NULL)
+ ofs) == NULL) {
+ free(buf);
+ jffs2_free_cache(part);
return 0;
+ }
if (max_totlen < node->totlen)
max_totlen = node->totlen;
counterN++;
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,