#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/mtd/compat.h>
+#include <linux/compat.h>
#include <asm/errno.h>
#include "jffs2_private.h"
*/
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;
+ /*
+ * Only read in the version info from flash, not the entire inode.
+ * This can make a big difference to speed if flash is slow.
+ */
+ u32 new_version;
+ u32 old_version;
+ get_fl_mem(new->offset + offsetof(struct jffs2_raw_inode, version),
+ sizeof(new_version), &new_version);
+ get_fl_mem(old->offset + offsetof(struct jffs2_raw_inode, version),
+ sizeof(old_version), &old_version);
+
+ return new_version > old_version;
}
/* Sort directory entries so all entries in the same directory
*/
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
+ /*
+ * Using NULL as the buffer for NOR flash prevents the entire node
+ * being read. This makes most comparisons much quicker as only one
+ * or two entries from the node will be used most of the time.
*/
- 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
+ struct jffs2_raw_dirent *jNew = get_node_mem(new->offset, NULL);
+ struct jffs2_raw_dirent *jOld = get_node_mem(old->offset, NULL);
+ int cmp;
+ int ret;
+
+ if (jNew->pino != jOld->pino) {
+ /* ascending sort by pino */
+ ret = jNew->pino > jOld->pino;
+ } else if (jNew->nsize != jOld->nsize) {
+ /*
+ * pino is the same, so use ascending sort by nsize,
+ * so we don't do strncmp unless we really must.
*/
- jOld->ino = 0;
- return 1;
+ ret = jNew->nsize > jOld->nsize;
+ } else {
+ /*
+ * length is also the same, so use ascending sort by name
+ */
+ cmp = strncmp((char *)jNew->name, (char *)jOld->name,
+ jNew->nsize);
+ if (cmp != 0) {
+ ret = cmp > 0;
+ } else {
+ /*
+ * we have duplicate names in this directory,
+ * so use ascending sort by version
+ */
+ ret = jNew->version > jOld->version;
+ }
}
+ put_fl_mem(jNew, NULL);
+ put_fl_mem(jOld, NULL);
- return 0;
+ return ret;
}
#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);
}
+ /*
+ * If no destination is provided, we are done.
+ * Just return the total size.
+ */
+ if (!dest)
+ return totalSize;
#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)) {
+ /*
+ * Copy just the node and not the data at this point,
+ * since we don't yet know if we need this data.
+ */
+ jNode = (struct jffs2_raw_inode *)get_fl_mem(b->offset,
+ sizeof(struct jffs2_raw_inode),
+ pL->readbuf);
+ if (inode == jNode->ino) {
#if 0
putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen);
putLabeledWord("read_inode: inode = ", jNode->ino);
#endif
if(dest) {
- src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode);
+ /*
+ * Now that the inode has been checked,
+ * read the entire inode, including data.
+ */
+ put_fl_mem(jNode, pL->readbuf);
+ jNode = (struct jffs2_raw_inode *)
+ get_node_mem(b->offset, pL->readbuf);
+ src = ((uchar *)jNode) +
+ sizeof(struct jffs2_raw_inode);
/* ignore data behind latest known EOF */
if (jNode->offset > totalSize) {
put_fl_mem(jNode, pL->readbuf);
#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)
case JFFS2_COMPR_LZO:
- ret = lzo_decompress(src, lDest, jNode->csize, jNode->dsize);
+ lzo_decompress(src, lDest, jNode->csize, jNode->dsize);
break;
#endif
default:
#if 0
putLabeledWord("read_inode: totalSize = ", totalSize);
- putLabeledWord("read_inode: compr ret = ", ret);
#endif
}
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);
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 */
+ if (pino == jDir->pino) {
u32 i_version = 0;
- struct jffs2_raw_inode ojNode;
struct jffs2_raw_inode *jNode, *i = NULL;
- struct b_node *b2 = pL->frag.listHead;
+ struct b_node *b2;
+
+#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS
+ /* Check for more recent versions of this file */
+ int match;
+ do {
+ struct b_node *next = b->next;
+ struct jffs2_raw_dirent *jDirNext;
+ if (!next)
+ break;
+ jDirNext = (struct jffs2_raw_dirent *)
+ get_node_mem(next->offset, NULL);
+ match = jDirNext->pino == jDir->pino &&
+ jDirNext->nsize == jDir->nsize &&
+ strncmp((char *)jDirNext->name,
+ (char *)jDir->name,
+ jDir->nsize) == 0;
+ if (match) {
+ /* Use next. It is more recent */
+ b = next;
+ /* Update buffer with the new info */
+ *jDir = *jDirNext;
+ }
+ put_fl_mem(jDirNext, NULL);
+ } while (match);
+#endif
+ if (jDir->ino == 0) {
+ /* Deleted file */
+ put_fl_mem(jDir, pL->readbuf);
+ continue;
+ }
- while (b2) {
+ for (b2 = pL->frag.listHead; b2; b2 = b2->next) {
jNode = (struct jffs2_raw_inode *)
- get_fl_mem(b2->offset, sizeof(ojNode), &ojNode);
- if (jNode->ino == jDir->ino && jNode->version >= i_version) {
+ get_fl_mem(b2->offset, sizeof(*jNode),
+ NULL);
+ if (jNode->ino == jDir->ino &&
+ jNode->version >= i_version) {
i_version = jNode->version;
if (i)
put_fl_mem(i, NULL);
sizeof(*i),
NULL);
}
- b2 = b2->next;
+ put_fl_mem(jNode, NULL);
}
dump_inode(pL, jDir, i);
{
struct b_lists *pL;
struct jffs2_unknown_node *node;
- u32 nr_sectors = part->size/part->sector_size;
+ u32 nr_sectors;
u32 i;
u32 counter4 = 0;
u32 counterF = 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. */
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,