]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - fs/jffs2/jffs2_1pass.c
* Patches by Denis Peter, 9 Sep 2003:
[karo-tx-uboot.git] / fs / jffs2 / jffs2_1pass.c
index a5d9583596ca269e2d6a395b4e7e6f3d7de71d4b..3897ce613071de4f452ac56e0322f15903620adf 100644 (file)
@@ -1,4 +1,3 @@
-/* vi: set sw=4 ts=4: */
 /*
 -------------------------------------------------------------------------
  * Filename:      jffs2.c
@@ -265,20 +264,56 @@ insert_node(struct b_list *list, u32 offset)
 }
 
 #ifdef CFG_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 *jNew = (struct jffs2_raw_inode *)new->offset;
        struct jffs2_raw_inode *jOld = (struct jffs2_raw_inode *)old->offset;
 
-       return jNew->version < jOld->version;
+       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 *jNew = (struct jffs2_raw_dirent *)new->offset;
        struct jffs2_raw_dirent *jOld = (struct jffs2_raw_dirent *)old->offset;
-
-       return jNew->version > jOld->version;
+       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
 
@@ -327,12 +362,31 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
        struct b_node *b;
        struct jffs2_raw_inode *jNode;
        u32 totalSize = 0;
-       u16 latestVersion = 0;
+       u32 latestVersion = 0;
        char *lDest;
        char *src;
        long ret;
        int i;
        u32 counter = 0;
+#ifdef CFG_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 *) (b->offset);
+               if ((inode == jNode->ino)) {
+                       /* get actual file length from the newest node */
+                       if (jNode->version >= latestVersion) {
+                               totalSize = jNode->isize;
+                               latestVersion = jNode->version;
+                       }
+               }
+       }
+#endif
 
        for (b = pL->frag.listHead; b != NULL; b = b->next) {
                jNode = (struct jffs2_raw_inode *) (b->offset);
@@ -349,11 +403,14 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
                        putLabeledWord("read_inode: usercompr = ", jNode->usercompr);
                        putLabeledWord("read_inode: flags = ", jNode->flags);
 #endif
+
+#ifndef CFG_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 = ((char *) jNode) + sizeof(struct jffs2_raw_inode);
@@ -430,15 +487,11 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)
                if ((pino == jDir->pino) && (len == jDir->nsize) &&
                    (jDir->ino) &&      /* 0 for unlink */
                    (!strncmp(jDir->name, name, len))) {        /* a match */
-                       if (jDir->version < version) continue;
+                       if (jDir->version < version)
+                               continue;
 
-                       if(jDir->version == 0) {
-                               /* Is this legal? */
-                               putstr(" ** WARNING ** ");
-                               putnstr(jDir->name, jDir->nsize);
-                               putstr(" is version 0 (in find, ignoring)\r\n");
-                       } else if(jDir->version == version) {
-                               /* Im pretty sure this isn't ... */
+                       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);
@@ -643,15 +696,11 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)
        for(b = pL->dir.listHead; b; b = b->next) {
                jDir = (struct jffs2_raw_dirent *) (b->offset);
                if (ino == jDir->ino) {
-                       if(jDir->version < version) continue;
+                       if (jDir->version < version)
+                               continue;
 
-                       if(jDir->version == 0) {
-                               /* Is this legal? */
-                               putstr(" ** WARNING ** ");
-                               putnstr(jDir->name, jDir->nsize);
-                               putstr(" is version 0 (in resolve, ignoring)\r\n");
-                       } else if(jDir->version == version) {
-                               /* Im pretty sure this isn't ... */
+                       if (jDir->version == version && jDirFound) {
+                               /* I'm pretty sure this isn't legal */
                                putstr(" ** ERROR ** ");
                                putnstr(jDir->name, jDir->nsize);
                                putLabeledWord(" has dup version (resolve) = ",
@@ -802,7 +851,7 @@ dump_fragments(struct b_lists *pL)
                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]
+               putLabeledWord("\tbuild_list: offset = ", b->offset);   /* FIXME: ? [RS] */
                b = b->next;
        }
 }
@@ -832,7 +881,7 @@ dump_dirents(struct b_lists *pL)
                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]
+               putLabeledWord("\tbuild_list: offset = ", b->offset);   /* FIXME: ? [RS] */
                b = b->next;
        }
 }
@@ -891,6 +940,11 @@ jffs2_1pass_build_lists(struct part_info * part)
                                        printf("OOPS Cleanmarker has bad size "
                                                "%d != %d\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 < %d\n", node->totlen,
+                                               sizeof(struct jffs2_unknown_node));
                        } else {
                                printf("Unknown node type: %x len %d "
                                        "offset 0x%x\n", node->nodetype,
@@ -935,9 +989,6 @@ jffs2_1pass_build_lists(struct part_info * part)
 }
 
 
-
-
-
 static u32
 jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL)
 {
@@ -965,7 +1016,6 @@ jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL)
 }
 
 
-
 static struct b_lists *
 jffs2_get_list(struct part_info * part, const char *who)
 {
@@ -1005,9 +1055,6 @@ jffs2_1pass_ls(struct part_info * part, const char *fname)
 }
 
 
-
-
-
 /* 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)