*** empty log message ***
[yaffs/.git] / yaffs_guts.c
index abb01e2c1694ede4e0be49e82b7c9e564c560029..32b755972370aae9773519c0704e1d69df651dad 100644 (file)
  */\r
  //yaffs_guts.c\r
 \r
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.12 2002-11-08 07:19:41 charles Exp $";\r
+\r
 #include "yportenv.h"\r
 \r
 #include "yaffsinterface.h"\r
 #include "yaffs_guts.h"\r
 \r
 \r
+#define YAFFS_GARBAGE_COLLECT_LOW_WATER 2\r
+\r
+\r
 \r
 // External functions for ECC on data\r
 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);\r
@@ -58,25 +63,22 @@ static int yaffs_CountBits(__u8 x)
 \r
 \r
 \r
-// Device info\r
-//static yaffs_Device *yaffs_device;\r
-//yaffs_Object *yaffs_rootDir;\r
-//yaffs_Object *yaffs_lostNFound;\r
-\r
-\r
-\r
 // Local prototypes\r
 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);\r
 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);\r
-static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);\r
+static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);\r
 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);\r
 \r
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);\r
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);\r
-static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name);\r
+static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force);\r
 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);\r
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);\r
 static int yaffs_CheckStructures(void);\r
+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);\r
+static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);\r
+\r
+static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);\r
 \r
 // Robustification\r
 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);\r
@@ -87,6 +89,7 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaf
 \r
 static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);\r
 \r
+static int yaffs_UnlinkWorker(yaffs_Object *obj);\r
 \r
 \r
 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1);\r
@@ -107,7 +110,22 @@ static int yaffs_CheckFileSanity(yaffs_Object *in);
 #define yaffs_CheckFileSanity(in)\r
 #endif\r
 \r
-static int __inline__ yaffs_HashFunction(int n)\r
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);\r
+static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);\r
+\r
+\r
+static  __inline__ yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)\r
+{\r
+       if(blk < dev->startBlock || blk > dev->endBlock)\r
+       {\r
+               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs: block %d is not valid" TENDSTR),blk));\r
+               YBUG();\r
+       }\r
+       return &dev->blockInfo[blk - dev->startBlock];\r
+}\r
+\r
+\r
+static  __inline__ int yaffs_HashFunction(int n)\r
 {\r
        return (n % YAFFS_NOBJECT_BUCKETS);\r
 }\r
@@ -126,12 +144,22 @@ yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
 \r
 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)\r
 {\r
+       if(chunkInNAND < dev->startBlock * YAFFS_CHUNKS_PER_BLOCK)\r
+       {\r
+               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d is not valid" TENDSTR),chunkInNAND));\r
+               return YAFFS_FAIL;\r
+       }\r
+\r
        dev->nPageWrites++;\r
        return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);\r
 }\r
 \r
 \r
-int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare,int doErrorCorrection)\r
+int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,\r
+                                                       int chunkInNAND, \r
+                                                       __u8 *data, \r
+                                                       yaffs_Spare *spare, \r
+                                                       int doErrorCorrection)\r
 {\r
        int retVal;\r
        __u8 calcEcc[3];\r
@@ -140,6 +168,9 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8
        \r
        dev->nPageReads++;\r
        \r
+       \r
+\r
+       \r
        if(!spare && data)\r
        {\r
                // If we don't have a real spare, then we use a local one.\r
@@ -159,20 +190,24 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8
                 \r
                 if(eccResult1>0)\r
                 {\r
-                       T((TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));\r
+                       T(YAFFS_TRACE_ERROR, (TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));\r
+                       dev->eccFixed++;\r
                 }\r
                 else if(eccResult1<0)\r
                 {\r
-                       T((TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));\r
+                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));\r
+                       dev->eccUnfixed++;\r
                 }\r
                 \r
                 if(eccResult2>0)\r
                 {\r
-                       T((TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));\r
+                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));\r
+                       dev->eccFixed++;\r
                 }\r
                 else if(eccResult2<0)\r
                 {\r
-                       T((TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));\r
+                       T(YAFFS_TRACE_ERROR,(TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));\r
+                       dev->eccUnfixed++;\r
                 }\r
                 \r
                 if(eccResult1 || eccResult2)\r
@@ -181,13 +216,13 @@ int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8
                        yaffs_HandleReadDataError(dev,chunkInNAND);\r
                 }\r
        }\r
+\r
        return retVal;\r
 }\r
 \r
 \r
 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)\r
 {\r
-#if 1\r
 \r
        static int init = 0;\r
        static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];\r
@@ -208,7 +243,6 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND
        if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return  YAFFS_FAIL;\r
        if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL;\r
 \r
-#endif\r
        \r
        return YAFFS_OK;\r
        \r
@@ -244,9 +278,14 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
                {\r
 \r
                        // First check this chunk is erased...\r
+#ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK\r
                        writeOk = yaffs_CheckChunkErased(dev,chunk);\r
-               \r
-                       if(writeOk)\r
+#endif         \r
+                       if(!writeOk)\r
+                       {\r
+                               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));\r
+                       }\r
+                       else\r
                        {\r
                                writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);\r
                        }\r
@@ -260,14 +299,15 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
                                // NB We check a raw read without ECC correction applied\r
                                yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0);\r
                                \r
+#ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY\r
                                if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare))\r
-                                                       {\r
+                               {\r
                                        // Didn't verify\r
-                                       T((TSTR("**>> yaffs write failed on chunk %d" TENDSTR), chunk));\r
-                                       // yaffs_DeleteChunk(dev,chunk);\r
+                                       T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk));\r
 \r
                                        writeOk = 0;\r
-                               }                                       \r
+                               }       \r
+#endif                         \r
                                \r
                        }\r
                        if(writeOk)\r
@@ -287,7 +327,7 @@ static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8
        \r
        if(attempts > 1)\r
        {\r
-               T((TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));\r
+               T(YAFFS_TRACE_ERROR,(TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));\r
                dev->nRetriedWrites+= (attempts - 1);   \r
        }\r
        \r
@@ -312,7 +352,7 @@ static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
        yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK, NULL , &spare);\r
        yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK + 1, NULL , &spare);\r
        \r
-       dev->blockInfo[blockInNAND].blockState = YAFFS_BLOCK_STATE_DEAD;\r
+       yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;\r
        dev->nRetiredBlocks++;\r
 }\r
 \r
@@ -327,12 +367,21 @@ static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
        //      Set current write block to the new block\r
        \r
        dev->doingBufferedBlockRewrite = 0;\r
+       \r
+       return 1;\r
 }\r
 \r
 \r
 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)\r
 {\r
-       \r
+       int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;\r
+\r
+       // Mark the block for retirement\r
+       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;\r
+       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));\r
+\r
+\r
+       //TODO  \r
        // Just do a garbage collection on the affected block then retire the block\r
        // NB recursion\r
 }\r
@@ -352,6 +401,12 @@ static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaf
 \r
 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)\r
 {\r
+       int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;\r
+\r
+       // Mark the block for retirement\r
+       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;\r
+       // Delete the chunk\r
+       yaffs_DeleteChunk(dev,chunkInNAND);\r
 }\r
 \r
 \r
@@ -360,6 +415,7 @@ static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1)\r
 {\r
 \r
+\r
        if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 ||\r
                s0->tagByte0 != s1->tagByte0 ||\r
                s0->tagByte1 != s1->tagByte1 ||\r
@@ -403,16 +459,36 @@ static __u16 yaffs_CalcNameSum(const char *name)
        __u16 i = 1;\r
        \r
        __u8 *bname = (__u8 *)name;\r
-       \r
-       while (*bname)\r
+       if(bname)\r
        {\r
-               sum += (*bname) * i;\r
-               i++;\r
-               bname++;\r
+               while ((*bname) && (i <=YAFFS_MAX_NAME_LENGTH))\r
+               {\r
+#ifdef CONFIG_YAFFS_WINCE\r
+                       sum += toupper(*bname) * i;\r
+#else\r
+                       sum += (*bname) * i;\r
+#endif\r
+                       i++;\r
+                       bname++;\r
+               }\r
        }\r
        return sum;\r
 }\r
 \r
+void yaffs_SetObjectName(yaffs_Object *obj, const char *name)\r
+{\r
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM\r
+                                       if(name && strlen(name) <= YAFFS_SHORT_NAME_LENGTH)\r
+                                       {\r
+                                               strcpy(obj->shortName,name);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               obj->shortName[0]='\0';\r
+                                       }\r
+#endif\r
+                                       obj->sum = yaffs_CalcNameSum(name);\r
+}\r
 \r
 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)\r
 {\r
@@ -433,7 +509,7 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
        \r
        for(i = 0; i < 8; i++)\r
        {\r
-               for(j = 1; j &0x7f; j<<=1)\r
+               for(j = 1; j &0xff; j<<=1)\r
                {\r
                        bit++;\r
                        if(b[i] & j)\r
@@ -448,7 +524,7 @@ void yaffs_CalcTagsECC(yaffs_Tags *tags)
        \r
 }\r
 \r
-void yaffs_CheckECCOnTags(yaffs_Tags *tags)\r
+int  yaffs_CheckECCOnTags(yaffs_Tags *tags)\r
 {\r
        unsigned ecc = tags->ecc;\r
        \r
@@ -456,9 +532,9 @@ void yaffs_CheckECCOnTags(yaffs_Tags *tags)
        \r
        ecc ^= tags->ecc;\r
        \r
-       if(ecc)\r
+       if(ecc && ecc <= 64)\r
        {\r
-               // Needs fixing\r
+               // TODO: Handle the failure better. Retire?\r
                unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;\r
 \r
                ecc--;\r
@@ -467,7 +543,17 @@ void yaffs_CheckECCOnTags(yaffs_Tags *tags)
                \r
                // Now recvalc the ecc\r
                yaffs_CalcTagsECC(tags);\r
+               \r
+               return 1; // recovered error\r
+       }\r
+       else if(ecc)\r
+       {\r
+               // Wierd ecc failure value\r
+               // TODO Need to do somethiong here\r
+               return -1; //unrecovered error\r
        }\r
+       \r
+       return 0;\r
 }\r
 \r
 \r
@@ -503,7 +589,7 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
    \r
     if (!newTnodes)\r
     {\r
-               YALERT("Could not malloc tnodes");\r
+               T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not allocate Tnodes"TENDSTR)));\r
                return YAFFS_FAIL;\r
     }\r
     \r
@@ -519,11 +605,13 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
        dev->nTnodesCreated += nTnodes;\r
 \r
        // Now add this bunch of tnodes to a list for freeing up.\r
-\r
+       // NB If we can't add this to the management list it isn't fatal\r
+       // but it just means we can't free this bunch of tnodes later.\r
        tnl = YMALLOC(sizeof(yaffs_TnodeList));\r
        if(!tnl)\r
        {\r
-               YALERT("Could not add tnodes to management list");\r
+               T(YAFFS_TRACE_ERROR,(TSTR("yaffs: Could not add tnodes to management list" TENDSTR)));\r
+               \r
        }\r
        else\r
        {\r
@@ -533,7 +621,7 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
        }\r
 \r
 \r
-       YINFO("Tnodes created");\r
+       T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Tnodes added" TENDSTR)));\r
 \r
 \r
        return YAFFS_OK;\r
@@ -597,6 +685,7 @@ static void yaffs_InitialiseTnodes(yaffs_Device*dev)
 \r
 }\r
 \r
+#if 0\r
 void yaffs_TnodeTest(yaffs_Device *dev)\r
 {\r
 \r
@@ -624,6 +713,8 @@ void yaffs_TnodeTest(yaffs_Device *dev)
                \r
        }\r
 }\r
+#endif\r
+\r
 \r
 ////////////////// END OF TNODE MANIPULATION ///////////////////////////\r
 \r
@@ -645,17 +736,17 @@ static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure
        // Check sane level and chunk Id\r
        if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)\r
        {\r
-               char str[50];\r
-               sprintf(str,"Bad level %d",level);\r
-               YALERT(str);\r
+//             char str[50];\r
+//             sprintf(str,"Bad level %d",level);\r
+//             YALERT(str);\r
                return NULL;\r
        }\r
        \r
        if(chunkId > YAFFS_MAX_CHUNK_ID)\r
        {\r
-               char str[50];\r
-               sprintf(str,"Bad chunkId %d",chunkId);\r
-               YALERT(str);\r
+//             char str[50];\r
+//             sprintf(str,"Bad chunkId %d",chunkId);\r
+//             YALERT(str);\r
                return NULL;\r
        }\r
 \r
@@ -702,37 +793,38 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru
        yaffs_Tnode *tn; \r
        \r
        int requiredTallness;\r
+       int i;\r
+       int l;\r
        \r
-       __u32 i;\r
-       __u32 l;\r
-       \r
+       __u32 x;\r
+               \r
        \r
        //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));\r
        \r
        // Check sane level and page Id\r
        if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)\r
        {\r
-               char str[50];\r
-               sprintf(str,"Bad level %d",fStruct->topLevel);\r
-               YALERT(str);\r
+//             char str[50];\r
+//             sprintf(str,"Bad level %d",fStruct->topLevel);\r
+//             YALERT(str);\r
                return NULL;\r
        }\r
        \r
        if(chunkId > YAFFS_MAX_CHUNK_ID)\r
        {\r
-               char str[50];\r
-               sprintf(str,"Bad chunkId %d",chunkId);\r
-               YALERT(str);\r
+//             char str[50];\r
+//             sprintf(str,"Bad chunkId %d",chunkId);\r
+//             YALERT(str);\r
                return NULL;\r
        }\r
        \r
        // First check we're tall enough (ie enough topLevel)\r
        \r
-       i = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);\r
+       x = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);\r
        requiredTallness = 0;\r
-       while(i)\r
+       while(x)\r
        {\r
-               i >>= YAFFS_TNODES_INTERNAL_BITS;\r
+               x >>= YAFFS_TNODES_INTERNAL_BITS;\r
                requiredTallness++;\r
        }\r
        \r
@@ -755,7 +847,7 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru
                        }\r
                        else\r
                        {\r
-                               YALERT("No more tnodes");\r
+                                       T(YAFFS_TRACE_ERROR,(TSTR("yaffs: no more tnodes" TENDSTR)));\r
                        }\r
                }\r
                \r
@@ -769,19 +861,19 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru
        tn = fStruct->top;\r
        while (l > 0 && tn)\r
        {\r
-               i = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & \r
+               x = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & \r
                               YAFFS_TNODES_INTERNAL_MASK;\r
                               \r
                //T((TSTR(" [%d:%d]"),l,i));\r
                \r
-           if(!tn->internal[i])\r
+           if(!tn->internal[x])\r
            {\r
                //T((TSTR(" added")));\r
                \r
-               tn->internal[i] = yaffs_GetTnode(dev);\r
+               tn->internal[x] = yaffs_GetTnode(dev);\r
            }\r
            \r
-           tn =        tn->internal[i];\r
+           tn =        tn->internal[x];\r
                l--;\r
        \r
        }\r
@@ -791,10 +883,11 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru
        return tn;              \r
 }\r
 \r
-// DeleteWorker scans backwards through the tnode tree and delets all the\r
+// DeleteWorker scans backwards through the tnode tree and deletes all the\r
 // chunks and tnodes in the file\r
+// Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.\r
 \r
-static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset)\r
+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)\r
 {\r
        int i;\r
        int chunkInInode;\r
@@ -802,6 +895,7 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
        yaffs_Tags tags;\r
        int found;\r
        int chunkDeleted;\r
+       int allDone = 1;\r
        \r
        \r
        if(tn)\r
@@ -809,21 +903,32 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
                if(level > 0)\r
                {\r
                \r
-                       for(i = YAFFS_NTNODES_INTERNAL -1; i >= 0; i--)\r
+                       for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)\r
                        {\r
                            if(tn->internal[i])\r
                        {\r
-                                       yaffs_DeleteWorker(in,tn->internal[i],level - 1,\r
-                                                                               (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i );\r
-                                       yaffs_FreeTnode(in->myDev,tn->internal[i]);\r
-                               tn->internal[i] = NULL;\r
+                                       if(limit && (*limit) < 0)\r
+                                       {\r
+                                               allDone = 0;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,\r
+                                                                               (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);\r
+                                       }\r
+                                       if(allDone)\r
+                                       {\r
+                                               yaffs_FreeTnode(in->myDev,tn->internal[i]);\r
+                                       tn->internal[i] = NULL;\r
+                                       }\r
                            }\r
                    \r
                        }\r
+                       return (allDone) ? 1 : 0;\r
                }\r
                else if(level == 0)\r
                {\r
-                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0; i--)\r
+                       for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0; i--) //NB Don't apply the limit here, always delete a whole level0\r
                        {\r
                            if(tn->level0[i])\r
                        {\r
@@ -852,6 +957,11 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
                                        if(found)\r
                                        {\r
                                                yaffs_DeleteChunk(in->myDev,theChunk);\r
+                                               in->nDataChunks--;\r
+                                               if(limit)\r
+                                               { \r
+                                                       *limit = *limit-1;\r
+                                               }\r
                                        \r
                                        }\r
                                        \r
@@ -859,11 +969,15 @@ static void yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, i
                            }\r
                    \r
                        }\r
+                       return 1;\r
+\r
                        \r
                }\r
                \r
        }\r
        \r
+       return 1;\r
+       \r
 }\r
 \r
 \r
@@ -966,6 +1080,7 @@ static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStr
 \r
 \r
 \r
+\r
 /////////////////////// End of File Structure functions. /////////////////\r
 \r
 // yaffs_CreateFreeObjects creates a bunch more objects and\r
@@ -984,7 +1099,7 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
    \r
     if (!newObjects)\r
     {\r
-               YALERT("Could not allocate more objects");\r
+               T(YAFFS_TRACE_ALLOCATE,(TSTR("yaffs: Could not allocate more objects" TENDSTR)));\r
                return YAFFS_FAIL;\r
     }\r
     \r
@@ -1004,7 +1119,7 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
        list = YMALLOC(sizeof(yaffs_ObjectList));\r
        if(!list)\r
        {\r
-               YALERT("Could not add Objects to management list");\r
+               T(YAFFS_TRACE_ALLOCATE,(TSTR("Could not add objects to management list" TENDSTR)));\r
        }\r
        else\r
        {\r
@@ -1014,8 +1129,6 @@ static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
        }\r
        \r
        \r
-       YINFO("Objects created");\r
-       \r
        \r
        return YAFFS_OK;\r
 }\r
@@ -1041,6 +1154,7 @@ static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
                // Now sweeten it up...\r
        \r
                memset(tn,0,sizeof(yaffs_Object));\r
+               tn->myDev = dev;\r
                tn->chunkId = -1;\r
                tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;\r
                INIT_LIST_HEAD(&(tn->hardLinks));\r
@@ -1069,6 +1183,8 @@ static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u3
                obj->fake = 1;                  // it is fake so it has no NAND presence...\r
                obj->renameAllowed= 0;  // ... and we're not allowed to rename it...\r
                obj->unlinkAllowed= 0;  // ... or unlink it\r
+               obj->deleted = 0;\r
+               obj->unlinked = 0;\r
                obj->st_mode = mode;\r
                obj->myDev = dev;\r
                obj->chunkId = 0; // Not a valid chunk.\r
@@ -1198,7 +1314,7 @@ static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
        int found = 0;\r
        struct list_head *i;\r
        \r
-       int n = bucket;\r
+       __u32 n = (__u32)bucket;\r
 \r
        //yaffs_CheckObjectHashSanity();        \r
        \r
@@ -1231,16 +1347,16 @@ void yaffs_HashObject(yaffs_Object *in)
        \r
        if(!list_empty(&in->hashLink))\r
        {\r
-               YINFO("!!!");\r
+               //YINFO("!!!");\r
        }\r
-       \r
+\r
        \r
        list_add(&in->hashLink,&dev->objectBucket[bucket].list);\r
        dev->objectBucket[bucket].count++;\r
 \r
 }\r
 \r
-yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,int number)\r
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,__u32 number)\r
 {\r
        int bucket = yaffs_HashFunction(number);\r
        struct list_head *i;\r
@@ -1279,11 +1395,16 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
                theObject->renameAllowed = 1;\r
                theObject->unlinkAllowed = 1;\r
                theObject->objectId = number;\r
-               theObject->myDev = dev;\r
                yaffs_HashObject(theObject);\r
                theObject->variantType = type;\r
-               theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME;\r
+#ifdef CONFIG_YAFFS_WINCE\r
+               yfsd_WinFileTimeNow(theObject->win_atime);\r
+               theObject->win_ctime[0] = theObject->win_mtime[0] = theObject->win_atime[0];\r
+               theObject->win_ctime[1] = theObject->win_mtime[1] = theObject->win_atime[1];\r
 \r
+#else\r
+               theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME;\r
+#endif\r
                switch(type)\r
                {\r
                        case YAFFS_OBJECT_TYPE_FILE: \r
@@ -1379,14 +1500,21 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                in->variantType = type;\r
 \r
                in->st_mode  = mode;\r
+               \r
+#ifdef CONFIG_YAFFS_WINCE\r
+               yfsd_WinFileTimeNow(in->win_atime);\r
+               in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];\r
+               in->win_ctime[1] = in->win_mtime[1] = in->win_atime[0];\r
+               \r
+#else\r
+               in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME;\r
                in->st_rdev  = rdev;\r
                in->st_uid   = uid;\r
                in->st_gid   = gid;\r
-               in->st_atime =  in->st_mtime =  in->st_ctime = CURRENT_TIME;\r
-               \r
+#endif         \r
                in->nDataChunks = 0;\r
 \r
-               in->sum = yaffs_CalcNameSum(name);\r
+               yaffs_SetObjectName(in,name);\r
                in->dirty = 1;\r
                \r
                yaffs_AddObjectToDirectory(parent,in);\r
@@ -1411,7 +1539,8 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                                break;\r
                }\r
 \r
-               if(yaffs_UpdateObjectHeader(in,name) < 0)\r
+               if(yaffs_GetNumberOfFreeChunks(dev) <= 0 ||\r
+                  yaffs_UpdateObjectHeader(in,name,0) < 0)\r
                {\r
                        // Could not create the object header, fail the creation\r
                        yaffs_UnlinkWorker(in);\r
@@ -1461,25 +1590,34 @@ yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *e
 }\r
 \r
 \r
-static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName)\r
+static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName,int force)\r
 {\r
-       //yaffs_Device *dev = obj->myDev;\r
+       int unlinkOp;\r
 \r
        if(newDir == NULL)\r
        {\r
                newDir = obj->parent; // use the old directory\r
        }\r
+\r
+       unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);\r
        \r
-       // Only proceed if the new name does not exist and\r
-       // if we're putting it into a directory.\r
-       if(!yaffs_FindObjectByName(newDir,newName) &&\r
-           newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)\r
+       // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since\r
+       // duplicate names are allowed.\r
+       // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.\r
+       if( (unlinkOp|| \r
+                force || \r
+                !yaffs_FindObjectByName(newDir,newName))  &&\r
+            newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)\r
        {\r
-               obj->sum = yaffs_CalcNameSum(newName);\r
+               yaffs_SetObjectName(obj,newName);\r
                obj->dirty = 1;\r
+               \r
                yaffs_AddObjectToDirectory(newDir,obj);\r
                \r
-               if(yaffs_UpdateObjectHeader(obj,newName) >= 0)\r
+               if(unlinkOp) obj->unlinked = 1;\r
+               \r
+               \r
+               if(yaffs_UpdateObjectHeader(obj,newName,0) >= 0)\r
                {\r
                        return YAFFS_OK;\r
                }\r
@@ -1488,14 +1626,27 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
        return YAFFS_FAIL;\r
 }\r
 \r
+\r
+\r
 int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName)\r
 {\r
        yaffs_Object *obj;\r
+       int force = 0;\r
+       \r
+#ifdef CONFIG_YAFFS_WINCE\r
+       // Special case for WinCE.\r
+       // While look-up is case insensitive, the name isn't.\r
+       // THerefore we might want to change x.txt to X.txt\r
+       if(oldDir == newDir && _stricmp(oldName,newName) == 0)\r
+       {\r
+               force = 1;\r
+       }       \r
+#endif\r
        \r
        obj = yaffs_FindObjectByName(oldDir,oldName);\r
        if(obj && obj->renameAllowed)\r
        {\r
-               return yaffs_ChangeObjectName(obj,newDir,newName);\r
+               return yaffs_ChangeObjectName(obj,newDir,newName,force);\r
        }\r
        return YAFFS_FAIL;\r
 }\r
@@ -1522,7 +1673,7 @@ static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
                \r
                if(countEm != dev->objectBucket[bucket].count)\r
                {\r
-                       YALERT("Inode hash inconsistency");\r
+                       T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));\r
                        ok = YAFFS_FAIL;\r
                }\r
        }\r
@@ -1530,6 +1681,7 @@ static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
        return ok;\r
 }\r
 \r
+#if 0\r
 void yaffs_ObjectTest(yaffs_Device *dev)\r
 {\r
        yaffs_Object *in[1000];\r
@@ -1586,17 +1738,23 @@ void yaffs_ObjectTest(yaffs_Device *dev)
                \r
 }\r
 \r
-\r
+#endif\r
 \r
 /////////////////////////// Block Management and Page Allocation ///////////////////\r
 \r
 \r
-static void yaffs_InitialiseBlocks(yaffs_Device *dev)\r
+static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)\r
 {\r
-       //Todo we're assuming the malloc will pass.\r
-       dev->blockInfo = YMALLOC(dev->nBlocks * sizeof(yaffs_BlockInfo));\r
-       memset(dev->blockInfo,0,dev->nBlocks * sizeof(yaffs_BlockInfo));\r
        dev->allocationBlock = -1; // force it to get a new one\r
+       //Todo we're assuming the malloc will pass.\r
+       dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));\r
+       if(dev->blockInfo)\r
+       {\r
+               memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));\r
+               return YAFFS_OK;\r
+       }\r
+       return YAFFS_FAIL;\r
+       \r
 }\r
 \r
 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)\r
@@ -1615,20 +1773,29 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
        int i;\r
        int dirtiest = -1;\r
        int pagesInUse = 100; // silly big number\r
+       yaffs_BlockInfo *bi;\r
        \r
        for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)\r
        {\r
                b++;\r
-               if (b > dev->endBlock)\r
+               if ( b < dev->startBlock || b > dev->endBlock)\r
                {\r
                        b =  dev->startBlock;\r
                }\r
+\r
+               if(b < dev->startBlock || b > dev->endBlock)\r
+               {\r
+                       T(YAFFS_TRACE_ERROR,(TSTR("**>> Block %d is not valid" TENDSTR),b));\r
+                       YBUG();\r
+               }\r
+               \r
+               bi = yaffs_GetBlockInfo(dev,b);\r
                \r
-               if(dev->blockInfo[b].blockState == YAFFS_BLOCK_STATE_FULL &&\r
-                  (dev->blockInfo)[b].pagesInUse < pagesInUse)\r
+               if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&\r
+                  bi->pagesInUse < pagesInUse)\r
                {\r
                        dirtiest = b;\r
-                       pagesInUse = (dev->blockInfo)[b].pagesInUse;\r
+                       pagesInUse = bi->pagesInUse;\r
                }\r
        }\r
        \r
@@ -1638,36 +1805,65 @@ static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
 }\r
 \r
 \r
-static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)\r
+static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)\r
+{\r
+       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);\r
+       \r
+       int erasedOk = 0;\r
+       \r
+       // If the block is still healthy erase it and mark as clean.\r
+       // If the block has had a data failure, then retire it.\r
+       bi->blockState = YAFFS_BLOCK_STATE_DIRTY;\r
+\r
+       if(!bi->needsRetiring)\r
+       {\r
+               erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);\r
+               if(!erasedOk)\r
+               {\r
+                       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Erasure failed %d" TENDSTR),blockNo));\r
+               }\r
+       }\r
+       \r
+       if( erasedOk )\r
+       {\r
+               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;\r
+               dev->nErasedBlocks++;\r
+               bi->pagesInUse = 0;\r
+               bi->pageBits = 0;\r
+       \r
+               T(YAFFS_TRACE_ERASE,(TSTR("Erased block %d" TENDSTR),blockNo));\r
+       }\r
+       else\r
+       {\r
+               yaffs_RetireBlock(dev,blockNo);\r
+               T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));\r
+       }\r
+}\r
+\r
+\r
+static int yaffs_FindBlockForAllocation(yaffs_Device *dev)\r
 {\r
        int i;\r
+       yaffs_BlockInfo *bi;\r
        \r
-       if(useReserve && dev->nErasedBlocks < 1)\r
+       if(dev->nErasedBlocks < 1)\r
        {\r
                // Hoosterman we've got a problem.\r
                // Can't get space to gc\r
+               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during gc" TENDSTR)));\r
+\r
                return -1;\r
        }\r
-       else if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)\r
-       {\r
-               // We are not in GC, so we hold some in reserve so we can get\r
-               // a gc done.\r
-       }\r
        \r
        // Find an empty block.\r
        \r
        for(i = dev->startBlock; i <= dev->endBlock; i++)\r
        {\r
-                       \r
-               if(dev->blockInfo[i].blockState == YAFFS_BLOCK_STATE_EMPTY)\r
+               bi = yaffs_GetBlockInfo(dev,i);\r
+               if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)\r
                {\r
-                       dev->blockInfo[i].blockState = YAFFS_BLOCK_STATE_ALLOCATING;\r
-                       dev->nErasedBlocks--;\r
-                       if(dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)\r
-                       {\r
-                               dev->garbageCollectionRequired = 1;\r
-                       }\r
-                       \r
+                       bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;\r
+                       dev->nErasedBlocks--;                   \r
                        return i;\r
                }\r
        }\r
@@ -1676,51 +1872,34 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)
 }\r
 \r
 \r
-static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)\r
-{\r
-       yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];\r
-       \r
-       // Mark as dirty.\r
-       // If the block is still healthy erase it and mark as clean.\r
-       // If the block has had a data failure, then retire it.\r
-       bi->blockState = YAFFS_BLOCK_STATE_DIRTY;\r
-       \r
-       if(!bi->needsRetiring && yaffs_EraseBlockInNAND(dev,blockNo))\r
-       {\r
-               bi->blockState = YAFFS_BLOCK_STATE_EMPTY;\r
-               dev->nErasedBlocks++;\r
-               bi->pagesInUse = 0;\r
-               bi->pageBits = 0;\r
-       \r
-               T((TSTR("Erased block %d" TENDSTR),blockNo));\r
-       }\r
-       else\r
-       {\r
-               yaffs_RetireBlock(dev,blockNo);\r
-               T((TSTR("**>> Block %d retired" TENDSTR),blockNo));\r
-       }\r
-}\r
-\r
 \r
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)\r
 {\r
        int retVal;\r
+       yaffs_BlockInfo *bi;\r
        \r
        if(dev->allocationBlock < 0)\r
        {\r
                // Get next block to allocate off\r
-               dev->allocationBlock = yaffs_FindBlockForAllocation(dev,useReserve);\r
+               dev->allocationBlock = yaffs_FindBlockForAllocation(dev);\r
                dev->allocationPage = 0;\r
        }\r
        \r
+       if(!useReserve &&  dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)\r
+       {\r
+               // Not enough space to allocate unless we're allowed to use the reserve.\r
+               return -1;\r
+       }\r
+       \r
        // Next page please....\r
        if(dev->allocationBlock >= 0)\r
        {\r
+               bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);\r
+               \r
                retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) + \r
                                  dev->allocationPage;\r
-               dev->blockInfo[dev->allocationBlock].pagesInUse++;\r
-               dev->blockInfo[dev->allocationBlock].pageBits |= \r
-                               (1 << (dev->allocationPage));\r
+               bi->pagesInUse++;\r
+               bi->pageBits |= (1 << (dev->allocationPage));\r
 \r
                dev->allocationPage++;\r
                \r
@@ -1729,24 +1908,28 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
                // If the block is full set the state to full\r
                if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK)\r
                {\r
-                       dev->blockInfo[dev->allocationBlock].blockState = YAFFS_BLOCK_STATE_FULL;\r
+                       bi->blockState = YAFFS_BLOCK_STATE_FULL;\r
                        dev->allocationBlock = -1;\r
                }\r
 \r
-#ifdef YAFFS_PARANOID\r
-               if(yaffs_CheckChunkErased(dev,retVal) == YAFFS_FAIL)\r
-               {\r
-                       T((TSTR("..................Trying to allocate non-erased page %d" TENDSTR),retVal));\r
-               }\r
-#endif         \r
+\r
                return retVal;\r
                \r
        }\r
-       T((TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));\r
+       T(YAFFS_TRACE_ERROR,(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));\r
 \r
        return -1;      \r
 }\r
 \r
+// To determine if we have enough space we just look at the \r
+// number of erased blocks.\r
+// The cache is allowed to use reserved blocks.\r
+\r
+int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)\r
+{\r
+       return (dev->nErasedBlocks >= YAFFS_RESERVED_BLOCKS);\r
+}\r
+\r
 \r
 int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)\r
 {\r
@@ -1759,7 +1942,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
        yaffs_Tags  tags;\r
                __u8  buffer[YAFFS_BYTES_PER_CHUNK];\r
        \r
-       yaffs_BlockInfo *bi = &dev->blockInfo[block];\r
+       yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);\r
        \r
        yaffs_Object *object;\r
 \r
@@ -1780,41 +1963,57 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                        \r
                        yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1);\r
                        \r
-                       yaffs_GetTagsFromSpare(&spare,&tags);\r
-                       tags.serialNumber++;\r
-                       yaffs_LoadTagsIntoSpare(&spare,&tags);\r
+                       yaffs_GetTagsFromSpare(dev,&spare,&tags);\r
 \r
-#if 0\r
-                       newChunk = yaffs_AllocatePage(dev,1);\r
-                       if(newChunk < 0)\r
+                       object = yaffs_FindObjectByNumber(dev,tags.objectId);\r
+                       \r
+                       if(object && object->deleted && tags.chunkId != 0)\r
                        {\r
-                               return YAFFS_FAIL;\r
+                               // Data chunk in a deleted file, throw it away\r
+                               // It's a deleted data chunk,\r
+                               // No need to copy this, just forget about it and fix up the\r
+                               // object.\r
+                               \r
+                               yaffs_PutChunkIntoFile(object, tags.chunkId, 0,0); \r
+                               object->nDataChunks--;\r
                        }\r
-\r
-                       yaffs_WriteChunkToNAND(dev,newChunk, buffer, &spare);\r
-\r
-#else\r
-                       newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);\r
-#endif\r
-                       if(newChunk < 0)\r
+                       else if( 0 /* Todo object && object->deleted && object->nDataChunks == 0 */)\r
                        {\r
-                               return YAFFS_FAIL;\r
+                               // Deleted object header with no data chunks.\r
+                               // Can be discarded\r
+                               object->chunkId = 0;\r
+                               //Todo some clean up\r
+                               \r
                        }\r
+                       else if(object)\r
+                       {\r
+                               // It's either a data chunk in a live file or\r
+                               // an ObjectHeader, so we're interested in it.\r
+                               // NB Need to keep the ObjectHeaders of deleted files\r
+                               // until the whole file has been deleted off\r
+                               tags.serialNumber++;\r
+                               yaffs_LoadTagsIntoSpare(&spare,&tags);\r
 \r
-                       object = yaffs_FindObjectByNumber(dev,tags.objectId);\r
+\r
+                               newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);\r
+                       \r
+                               if(newChunk < 0)\r
+                               {\r
+                                       return YAFFS_FAIL;\r
+                               }\r
                        \r
-                       // Ok, now fix up the Tnodes etc.\r
+                               // Ok, now fix up the Tnodes etc.\r
                        \r
-                       if(tags.chunkId == 0)\r
-                       {\r
-                               // It's a header\r
-                               object->chunkId = newChunk;\r
-                       }\r
-                       else\r
-                       {\r
-                               // It's a data chunk\r
-                               yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);\r
-\r
+                               if(tags.chunkId == 0)\r
+                               {\r
+                                       // It's a header\r
+                                       object->chunkId = newChunk;\r
+                               }\r
+                               else\r
+                               {\r
+                                       // It's a data chunk\r
+                                       yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);\r
+                               }\r
                        }\r
                        \r
                        yaffs_DeleteChunk(dev,oldChunk);                        \r
@@ -1825,12 +2024,87 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
        return YAFFS_OK;\r
 }\r
 \r
-int yaffs_CheckGarbageCollection(yaffs_Device *dev)\r
+\r
+static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)\r
+{\r
+       // todo find a file to delete\r
+       struct list_head *i;    \r
+       yaffs_Object *l;\r
+\r
+\r
+       // To the free chunks add the chunks that are in the deleted unlinked files.\r
+       list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)\r
+       {\r
+               l = list_entry(i, yaffs_Object,siblings);\r
+               if(l->deleted)\r
+               {\r
+                       return l;                       \r
+               }\r
+       }       \r
+       return NULL;\r
+}\r
+\r
+static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)\r
+{\r
+       // This does background deletion on unlinked files.. only deleted ones.\r
+       // If we don't have a file we're working on then find one\r
+       if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)\r
+       {\r
+               dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);\r
+       }\r
+       \r
+       // OK, we're working on a file...\r
+       if(dev->unlinkedDeletion)\r
+       {\r
+               yaffs_Object *obj = dev->unlinkedDeletion;\r
+               int delresult;\r
+               int limit; // Number of chunks to delete in a file.\r
+                                  // NB this can be exceeded, but not by much.\r
+                                  \r
+               limit = 5;\r
+#if 0                             \r
+               if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))\r
+               {\r
+                       limit = 50; // Doing GC soon, so dig deeper     \r
+               }\r
+               else\r
+               {\r
+                       limit = 5;\r
+               }\r
+#endif\r
+       \r
+               delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);\r
+               \r
+               if(obj->nDataChunks == 0)\r
+               {\r
+                       // Done all the deleting of data chunks.\r
+                       // Now dump the header and clean up\r
+                       yaffs_FreeTnode(dev,obj->variant.fileVariant.top);\r
+                       yaffs_DoGenericObjectDeletion(obj);\r
+                       dev->nDeletedFiles--;\r
+                       dev->nUnlinkedFiles--;\r
+                       dev->nBackgroundDeletions++;\r
+                       dev->unlinkedDeletion = NULL;   \r
+               }\r
+       }\r
+}\r
+\r
+\r
+\r
+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)\r
 {\r
        int block;\r
        \r
+       yaffs_DoUnlinkedFileDeletion(dev);\r
+       \r
+       if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))\r
+       {\r
+               dev->garbageCollectionRequired = 1;\r
+       }       \r
+       \r
        if(dev->garbageCollectionRequired)\r
        {\r
+               dev->garbageCollections++;\r
                dev->garbageCollectionRequired = 0;\r
                if(dev->blockSelectedForGC >= 0)\r
                {\r
@@ -1873,9 +2147,10 @@ static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
        sparePtr->tagByte7 = tu->asBytes[7];\r
 }\r
 \r
-static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)\r
+static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)\r
 {\r
        yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;\r
+       int result;\r
 \r
        tu->asBytes[0]= sparePtr->tagByte0;\r
        tu->asBytes[1]= sparePtr->tagByte1;\r
@@ -1886,7 +2161,15 @@ static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
        tu->asBytes[6]= sparePtr->tagByte6;\r
        tu->asBytes[7]= sparePtr->tagByte7;\r
        \r
-       yaffs_CheckECCOnTags(tagsPtr);\r
+       result =  yaffs_CheckECCOnTags(tagsPtr);\r
+       if(result> 0)\r
+       {\r
+               dev->tagsEccFixed++;\r
+       }\r
+       else if(result <0)\r
+       {\r
+               dev->tagsEccUnfixed++;\r
+       }\r
 }\r
 \r
 static void yaffs_SpareInitialise(yaffs_Spare *spare)\r
@@ -1902,7 +2185,7 @@ static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_
                if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK)\r
                {\r
                        *chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;\r
-                       yaffs_GetTagsFromSpare(&spare,tags);\r
+                       yaffs_GetTagsFromSpare(dev,&spare,tags);\r
                        return YAFFS_OK;\r
                }\r
                else\r
@@ -2080,7 +2363,7 @@ int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags
 }\r
 \r
 \r
-#if YAFFS_PARANOID\r
+#ifdef YAFFS_PARANOID\r
 \r
 static int yaffs_CheckFileSanity(yaffs_Object *in)\r
 {\r
@@ -2187,7 +2470,9 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
                        if(existingChunk <=0)\r
                        {\r
                                //Hoosterman - how did this happen?\r
-                               // todo\r
+                               \r
+                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: existing chunk < 0 in scan" TENDSTR)));\r
+\r
                        }\r
 \r
                        \r
@@ -2248,6 +2533,7 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
        int block;\r
        int page;\r
        yaffs_Spare spare;\r
+       yaffs_BlockInfo *bi;\r
        \r
        if(chunkId <= 0) return;        \r
                \r
@@ -2260,20 +2546,21 @@ static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
        \r
        yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);\r
        yaffs_HandleUpdateChunk(dev,chunkId,&spare);\r
+       bi = yaffs_GetBlockInfo(dev,block);\r
                        \r
        \r
        // Pull out of the management area.\r
        // If the whole block became dirty, this will kick off an erasure.\r
-       if(     dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING ||\r
-           dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)\r
+       if(     bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||\r
+           bi->blockState == YAFFS_BLOCK_STATE_FULL)\r
        {\r
                dev->nFreeChunks++;\r
 \r
-               dev->blockInfo[block].pageBits &= ~(1 << page);\r
-               dev->blockInfo[block].pagesInUse--;\r
+               bi->pageBits &= ~(1 << page);\r
+               bi->pagesInUse--;\r
                \r
-               if(     dev->blockInfo[block].pagesInUse == 0 &&\r
-           dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)\r
+               if(bi->pagesInUse == 0 &&\r
+              bi->blockState == YAFFS_BLOCK_STATE_FULL)\r
            {\r
                yaffs_BlockBecameDirty(dev,block);\r
            }\r
@@ -2317,36 +2604,6 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
                \r
        yaffs_CalcTagsECC(&newTags);\r
 \r
-    \r
- #if 0\r
-    // Create new chunk in NAND\r
-    newChunkId = yaffs_AllocatePage(dev,useReserve);\r
\r
-    \r
-    if(newChunkId >= 0)\r
-    {\r
-               \r
-\r
-               yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,buffer,&newTags);\r
-               \r
-               yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);\r
-               \r
-               \r
-               if(prevChunkId >= 0)\r
-               {\r
-                       yaffs_DeleteChunk(dev,prevChunkId);\r
-       \r
-               }\r
-               \r
-               yaffs_CheckFileSanity(in);\r
-               \r
-               return newChunkId;\r
-    }\r
-\r
-     \r
-    return -1;\r
-#else\r
-\r
        newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);\r
        if(newChunkId >= 0)\r
        {\r
@@ -2363,7 +2620,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
        }\r
        return newChunkId;\r
 \r
-#endif\r
+\r
 \r
 \r
 \r
@@ -2373,7 +2630,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
 // UpdateObjectHeader updates the header on NAND for an object.\r
 // If name is not NULL, then that new name is used.\r
 //\r
-int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)\r
+int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)\r
 {\r
 \r
        yaffs_Device *dev = in->myDev;\r
@@ -2387,8 +2644,9 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
     \r
     yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew;\r
     yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;\r
+\r
     \r
-    if(!in->fake)\r
+    if(!in->fake || force)\r
     {\r
   \r
                yaffs_CheckGarbageCollection(dev);              \r
@@ -2404,26 +2662,47 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
 \r
                // Header data\r
                oh->type = in->variantType;\r
-       \r
+               \r
                oh->st_mode = in->st_mode;\r
+\r
+#ifdef CONFIG_YAFFS_WINCE\r
+               oh->win_atime[0] = in->win_atime[0];\r
+               oh->win_ctime[0] = in->win_ctime[0];\r
+               oh->win_mtime[0] = in->win_mtime[0];\r
+               oh->win_atime[1] = in->win_atime[1];\r
+               oh->win_ctime[1] = in->win_ctime[1];\r
+               oh->win_mtime[1] = in->win_mtime[1];\r
+#else\r
                oh->st_uid = in->st_uid;\r
                oh->st_gid = in->st_gid;\r
                oh->st_atime = in->st_atime;\r
                oh->st_mtime = in->st_mtime;\r
                oh->st_ctime = in->st_ctime;\r
                oh->st_rdev = in->st_rdev;\r
-       \r
-               oh->parentObjectId = in->parent->objectId;\r
-               oh->sum = in->sum;\r
+#endif \r
+               if(in->parent)\r
+               {\r
+                       oh->parentObjectId = in->parent->objectId;\r
+               }\r
+               else\r
+               {\r
+                       oh->parentObjectId = 0;\r
+               }\r
+               \r
+               //oh->sum = in->sum;\r
                if(name && *name)\r
                {\r
                        memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);\r
                        strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);\r
                }\r
-               else\r
+               else if(prevChunkId)\r
                {       \r
                        memcpy(oh->name, ohOld->name,YAFFS_MAX_NAME_LENGTH + 1);\r
                }\r
+               else\r
+               {\r
+                       memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);   \r
+               }\r
        \r
                switch(in->variantType)\r
                {\r
@@ -2458,16 +2737,12 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
        \r
                yaffs_CalcTagsECC(&newTags);\r
        \r
-    \r
-    \r
-#if 0\r
+\r
                // Create new chunk in NAND\r
-               newChunkId = yaffs_AllocatePage(dev,1);\r
+               newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);\r
     \r
                if(newChunkId >= 0)\r
                {\r
-\r
-                       yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,bufferNew,&newTags);\r
                \r
                        in->chunkId = newChunkId;               \r
                \r
@@ -2477,35 +2752,274 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
                        }\r
                \r
                        in->dirty = 0;\r
-                       return newChunkId;\r
                }\r
-    \r
-               return -1;\r
-#else\r
-               // Create new chunk in NAND\r
-               newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);\r
-    \r
-               if(newChunkId >= 0)\r
-               {\r
                \r
-                       in->chunkId = newChunkId;               \r
+               return newChunkId;\r
+\r
+    }\r
+    return 0;\r
+}\r
+\r
+\r
+/////////////////////// Short Operations Cache ////////////////////////////////\r
+//     In many siturations where there is no high level buffering (eg WinCE) a lot of\r
+//     reads might be short sequential reads, and a lot of writes may be short \r
+//  sequential writes. eg. scanning/writing a jpeg file.\r
+//     In these cases, a short read/write cache can provide a huge perfomance benefit \r
+//  with dumb-as-a-rock code.\r
+//  There are a limited number (~10) of cache chunks per device so that we don't\r
+//  need a very intelligent search.\r
+\r
+\r
+#ifdef CONFIG_YAFFS_SHORT_OP_CACHE\r
+\r
+\r
+static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)\r
+{\r
+       yaffs_Device *dev = obj->myDev;\r
+       int lowest;\r
+       int i;\r
+       yaffs_ChunkCache *cache;\r
+       int chunkWritten;\r
+       int nBytes;\r
+       \r
+       do{\r
+               cache = NULL;\r
                \r
-                       if(prevChunkId >= 0)\r
+               // Find the dirty cache for this object with the lowest chunk id.\r
+               for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+               {\r
+                       if(dev->srCache[i].object == obj &&\r
+                          dev->srCache[i].dirty)\r
                        {\r
-                               yaffs_DeleteChunk(dev,prevChunkId);\r
+                               if(!cache ||  dev->srCache[i].chunkId < lowest)\r
+                               {\r
+                                       cache = &dev->srCache[i];\r
+                                       lowest = cache->chunkId;\r
+                               }\r
                        }\r
+               }\r
                \r
-                       in->dirty = 0;\r
+               if(cache)\r
+               {\r
+                       //Write it out\r
+\r
+                       nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);\r
+                       \r
+                       if(nBytes > YAFFS_BYTES_PER_CHUNK)\r
+                       {\r
+                               nBytes= YAFFS_BYTES_PER_CHUNK;\r
+                       }\r
+                       \r
+                       chunkWritten = yaffs_WriteChunkDataToObject(cache->object,\r
+                                                                                                               cache->chunkId,\r
+                                                                                                               cache->data,\r
+                                                                                                               nBytes,1);\r
+\r
+                       cache->dirty = 0;\r
                }\r
                \r
-               return newChunkId;\r
+       } while(cache && chunkWritten > 0);\r
+       \r
+       if(cache)\r
+       {\r
+               //Hoosterman, disk full while writing cache out.\r
+               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: no space during caceh write" TENDSTR)));\r
 \r
-#endif\r
-    }\r
-    return 0;\r
+       }       \r
+               \r
+}\r
+\r
+\r
+// Grab us a chunk for use.\r
+// First look for an empty one. \r
+// Then look for the least recently used non-dirty one.\r
+// Then look for the least recently used dirty one...., flush and look again.\r
+static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)\r
+{\r
+       int i;\r
+       int usage;\r
+       int theOne;\r
+       \r
+       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+       {\r
+               if(!dev->srCache[i].object)\r
+               {\r
+                       //T(("Grabbing empty %d\n",i));\r
+                       \r
+                       return &dev->srCache[i];\r
+               }\r
+       }\r
+       \r
+       theOne = -1; \r
+       usage = 0; // just to stop the compiler grizzling\r
+       \r
+       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+       {\r
+               if(!dev->srCache[i].dirty &&\r
+                  ((dev->srCache[i].lastUse < usage  && theOne >= 0)|| \r
+                    theOne < 0))\r
+               {\r
+                       usage = dev->srCache[i].lastUse;\r
+                       theOne = i;\r
+               }\r
+       }\r
+       \r
+       //T(("Grabbing non-empty %d\n",theOne));\r
+       return  theOne >= 0 ?  &dev->srCache[theOne] : NULL;\r
+       \r
+}\r
+\r
+\r
+static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)\r
+{\r
+       yaffs_ChunkCache *cache;\r
+       yaffs_Object *theObj;\r
+       int usage;\r
+       int i;\r
+       \r
+       // Try find a non-dirty one...\r
+       \r
+       cache = yaffs_GrabChunkCacheWorker(dev);\r
+       \r
+       if(!cache)\r
+       {\r
+               // They were all dirty, find the last recently used object and flush\r
+               // its cache, then  find again.\r
+               // NB what's here is not very accurate, we actually flush the object\r
+               // the last recently used page.\r
+               \r
+               theObj = dev->srCache[0].object;\r
+               usage = dev->srCache[0].lastUse;\r
+       \r
+               for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+               {\r
+                       if( dev->srCache[i].object && \r
+                           dev->srCache[i].lastUse < usage)\r
+                       {\r
+                               usage  = dev->srCache[i].lastUse;\r
+                               theObj = dev->srCache[i].object;\r
+                       }\r
+               }\r
+               \r
+               yaffs_FlushFilesChunkCache(theObj);\r
+               \r
+               // Try again\r
+               cache = yaffs_GrabChunkCacheWorker(dev);\r
+       }\r
+       \r
+       return cache;\r
+\r
+}\r
+\r
+\r
+// Find a cached chunk\r
+static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj, int chunkId)\r
+{\r
+       yaffs_Device *dev = obj->myDev;\r
+       int i;\r
+       \r
+       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+       {\r
+               if(dev->srCache[i].object == obj && \r
+                  dev->srCache[i].chunkId == chunkId)\r
+               {\r
+                       dev->cacheHits++;\r
+                       \r
+                       return &dev->srCache[i];\r
+               }\r
+       }\r
+       \r
+       return NULL;\r
+}\r
+\r
+// Mark the chunk for the least recently used algorithym\r
+static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache, int isAWrite)\r
+{\r
+       if( dev->srLastUse < 0 || \r
+               dev->srLastUse > 100000000)\r
+       {\r
+               // Reset the cache usages\r
+               int i;\r
+               for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+               {\r
+                       dev->srCache[i].lastUse = 0;\r
+               }\r
+               dev->srLastUse = 0;\r
+       }\r
+\r
+       dev->srLastUse++;\r
+       \r
+       cache->lastUse = dev->srLastUse;\r
+\r
+       if(isAWrite)\r
+       {\r
+               cache->dirty = 1;\r
+       }\r
+}\r
+\r
+// Invalidate a single cache page.\r
+// Do this when a whole page gets written,\r
+// ie the short cache for this page is no longer valid.\r
+static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)\r
+{\r
+       yaffs_ChunkCache *cache = yaffs_FindChunkCache(object,chunkId);\r
+\r
+       if(cache)\r
+       {\r
+               cache->object = NULL;\r
+       }\r
+}\r
+\r
+\r
+// Invalidate all the cache pages associated with this object\r
+// Do this whenever ther file is deleted or resized.\r
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)\r
+{\r
+       int i;\r
+       yaffs_Device *dev = in->myDev;\r
+       \r
+       // Now invalidate it.\r
+       for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+       {\r
+               if(dev->srCache[i].object == in)\r
+               {\r
+                       dev->srCache[i].object = NULL;\r
+               }\r
+       }\r
 }\r
 \r
 \r
+#else\r
+\r
+static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)\r
+{\r
+       return NULL;    \r
+}\r
+\r
+\r
+static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId)\r
+{\r
+       return NULL;\r
+}\r
+\r
+static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache)\r
+{\r
+}\r
+\r
+static void yaffs_InvalidateChunkCache(yaffs_Object *obj, int chunkId)\r
+{\r
+}\r
+\r
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)\r
+{\r
+}\r
+\r
+\r
+\r
+#endif\r
+\r
+\r
 \r
 ///////////////////////// File read/write ///////////////////////////////\r
 // Read and write have very similar structures.\r
@@ -2519,9 +3033,6 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)\r
 {\r
        \r
-//     yaffs_Device *dev = in->myDev;\r
-       \r
-       __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
        \r
        int chunk;\r
        int start;\r
@@ -2548,15 +3059,42 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB
                if(nToCopy != YAFFS_BYTES_PER_CHUNK)\r
                {\r
                        // An incomplete start or end chunk (or maybe both start and end chunk)\r
+#ifdef CONFIG_YAFFS_SHORT_OP_CACHE\r
+                       yaffs_ChunkCache *cache;\r
+                       // If we can't find the data in the cache, then load it up.\r
+                       cache = yaffs_FindChunkCache(in,chunk);\r
+                       if(!cache)\r
+                       {\r
+                               cache = yaffs_GrabChunkCache(in->myDev);\r
+                               cache->object = in;\r
+                               cache->chunkId = chunk;\r
+                               cache->dirty = 0;\r
+                               yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            \r
+                       }\r
+                       \r
+                       yaffs_UseChunkCache(in->myDev,cache,0);\r
+\r
+                       memcpy(buffer,&cache->data[start],nToCopy);\r
+#else\r
+                       __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
                        // Read into the local buffer then copy...\r
-               \r
                        yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);            \r
                        memcpy(buffer,&localBuffer[start],nToCopy);\r
+#endif\r
                }\r
                else\r
                {\r
+#ifdef CONFIG_YAFFS_WINCE\r
+                       __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
+                       \r
+                       // Under WinCE can't do direct transfer. Need to use a local buffer.\r
+                       // This is because we otherwise screw up WinCE's memory mapper\r
+                       yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);\r
+                       memcpy(buffer,localBuffer,YAFFS_BYTES_PER_CHUNK);\r
+#else\r
                        // A full chunk. Read directly into the supplied buffer.\r
                        yaffs_ReadChunkDataFromObject(in,chunk,buffer);\r
+#endif\r
                }\r
                \r
                n -= nToCopy;\r
@@ -2570,9 +3108,9 @@ int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nB
 }\r
 \r
 \r
+\r
 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)\r
 {      \r
-       __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
        \r
        int chunk;\r
        int start;\r
@@ -2580,8 +3118,11 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
        int n = nBytes;\r
        int nDone = 0;\r
        int nToWriteBack;\r
-       int endOfWrite = offset+nBytes;\r
+       int startOfWrite = offset;\r
        int chunkWritten = 0;\r
+       int nBytesRead;\r
+       \r
+       \r
        \r
        while(n > 0 && chunkWritten >= 0)\r
        {\r
@@ -2591,10 +3132,24 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
 \r
                // OK now check for the curveball where the start and end are in\r
                // the same chunk.\r
+               \r
                if(     (start + n) < YAFFS_BYTES_PER_CHUNK)\r
                {\r
                        nToCopy = n;\r
-                       nToWriteBack = (start + n);\r
+                       \r
+                       // Now folks, to calculate how many bytes to write back....\r
+                       // If we're overwriting and not writing to then end of file then\r
+                       // we need to write back as much as was there before.\r
+                       \r
+                       nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * YAFFS_BYTES_PER_CHUNK);\r
+                       \r
+                       if(nBytesRead > YAFFS_BYTES_PER_CHUNK)\r
+                       {\r
+                               nBytesRead = YAFFS_BYTES_PER_CHUNK;\r
+                       }\r
+                       \r
+                       nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);\r
+                       \r
                }\r
                else\r
                {\r
@@ -2605,6 +3160,32 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                if(nToCopy != YAFFS_BYTES_PER_CHUNK)\r
                {\r
                        // An incomplete start or end chunk (or maybe both start and end chunk)\r
+#ifdef CONFIG_YAFFS_SHORT_OP_CACHE\r
+                       yaffs_ChunkCache *cache;\r
+                       // If we can't find the data in the cache, then load it up.\r
+                       cache = yaffs_FindChunkCache(in,chunk);\r
+                       if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))\r
+                       {\r
+                               cache = yaffs_GrabChunkCache(in->myDev);\r
+                               cache->object = in;\r
+                               cache->chunkId = chunk;\r
+                               cache->dirty = 0;\r
+                               yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            \r
+                       }\r
+                       \r
+                       if(cache)\r
+                       {       \r
+                               yaffs_UseChunkCache(in->myDev,cache,1);\r
+                               memcpy(&cache->data[start],buffer,nToCopy);\r
+                       }\r
+                       else\r
+                       {\r
+                               chunkWritten = -1; // fail the write\r
+                       }\r
+#else\r
+                       __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
+\r
+                       // An incomplete start or end chunk (or maybe both start and end chunk)\r
                        // Read into the local buffer then copy, then copy over and write back.\r
                \r
                        yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);\r
@@ -2613,13 +3194,25 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                        \r
                        chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);\r
                        \r
-                       //T(("Write with readback to chunk %d %d\n",chunk,chunkWritten));\r
+                       //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));\r
+#endif\r
                        \r
                }\r
                else\r
                {\r
+                       \r
+#ifdef CONFIG_YAFFS_WINCE\r
+                       __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
+                       // Under WinCE can't do direct transfer. Need to use a local buffer.\r
+                       // This is because we otherwise screw up WinCE's memory mapper\r
+                       memcpy(localBuffer,buffer,YAFFS_BYTES_PER_CHUNK);\r
+                       chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,YAFFS_BYTES_PER_CHUNK,0);\r
+#else\r
                        // A full chunk. Write directly from the supplied buffer.\r
                        chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,YAFFS_BYTES_PER_CHUNK,0);\r
+#endif\r
+                       // Since we've overwritten the cached data, we better invalidate it.\r
+                       yaffs_InvalidateChunkCache(in,chunk);\r
                        //T(("Write to chunk %d %d\n",chunk,chunkWritten));\r
                }\r
                \r
@@ -2635,13 +3228,12 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
        \r
        // Update file object\r
        \r
-       if(endOfWrite > in->variant.fileVariant.fileSize)\r
+       if((startOfWrite + nDone) > in->variant.fileVariant.fileSize)\r
        {\r
-               in->variant.fileVariant.fileSize = endOfWrite;\r
+               in->variant.fileVariant.fileSize = (startOfWrite + nDone);\r
        }\r
        \r
        in->dirty = 1;\r
-       /*in->st_mtime = CURRENT_TIME; only update in flush*/\r
        \r
        return nDone;\r
 }\r
@@ -2657,6 +3249,9 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
        yaffs_Device *dev = in->myDev;\r
        \r
        __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];\r
+\r
+       yaffs_FlushFilesChunkCache(in); \r
+       yaffs_InvalidateWholeChunkCache(in);\r
        \r
        if(in->variantType != YAFFS_OBJECT_TYPE_FILE)\r
        {\r
@@ -2743,10 +3338,16 @@ int yaffs_FlushFile(yaffs_Object *in)
        if(in->dirty)\r
        {\r
                //T(("flushing object header\n"));\r
+               \r
+               yaffs_FlushFilesChunkCache(in);\r
        \r
+#ifdef CONFIG_YAFFS_WINCE\r
+               yfsd_WinFileTimeNow(in->win_mtime);\r
+#else\r
                in->st_mtime = CURRENT_TIME;\r
+#endif\r
 \r
-               retVal = yaffs_UpdateObjectHeader(in,NULL);\r
+               retVal = yaffs_UpdateObjectHeader(in,NULL,0);\r
        }\r
        else\r
        {\r
@@ -2760,8 +3361,19 @@ int yaffs_FlushFile(yaffs_Object *in)
 \r
 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)\r
 {\r
+\r
+       // First off, invalidate the file's data in the cache, without flushing.\r
+       yaffs_InvalidateWholeChunkCache(in);\r
+       \r
        yaffs_RemoveObjectFromDirectory(in);\r
        yaffs_DeleteChunk(in->myDev,in->chunkId);\r
+#ifdef __KERNEL__\r
+       if(in->myInode)\r
+       {\r
+               in->myInode->u.generic_ip = NULL;\r
+               in->myInode = 0;\r
+       }\r
+#endif\r
        yaffs_FreeObject(in);\r
        return YAFFS_OK;\r
 \r
@@ -2770,19 +3382,71 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
 // yaffs_DeleteFile deletes the whole file data\r
 // and the inode associated with the file.\r
 // It does not delete the links associated with the file.\r
-static int yaffs_DeleteFile(yaffs_Object *in)\r
+static int yaffs_UnlinkFile(yaffs_Object *in)\r
 {\r
+\r
+#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION\r
        // Delete the file data & tnodes\r
-#if 0\r
-       yaffs_ResizeFile(in,0);\r
-#else\r
-        yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0);\r
 \r
-#endif\r
+        yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);\r
+        \r
 \r
        yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);\r
        \r
        return  yaffs_DoGenericObjectDeletion(in);\r
+#else\r
+       int retVal;\r
+       int immediateDeletion=0;\r
+       retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);\r
+       if(retVal == YAFFS_OK)\r
+       {\r
+               //in->unlinked = 1;\r
+               //in->myDev->nUnlinkedFiles++;\r
+               //in->renameAllowed = 0;\r
+#ifdef __KERNEL__\r
+               if(in->myInode)\r
+               {\r
+                       immediateDeletion = 1;\r
+\r
+               }\r
+#endif\r
+#ifdef CONFIG_YAFFS_WINCE\r
+               if(in->inUse <= 0)\r
+               {\r
+                       immediateDeletion = 1;\r
+\r
+               }\r
+#endif\r
+               \r
+               if(immediateDeletion)\r
+               {\r
+                       T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));\r
+                       in->deleted=1;\r
+                       in->myDev->nDeletedFiles++;\r
+               }\r
+       \r
+       }\r
+       return retVal;\r
+\r
+       \r
+#endif\r
+}\r
+\r
+int yaffs_DeleteFile(yaffs_Object *in)\r
+{\r
+       int retVal = YAFFS_OK;\r
+       if(!in->unlinked)\r
+       {\r
+               retVal = yaffs_UnlinkFile(in);\r
+       }\r
+       if(retVal == YAFFS_OK && \r
+          in->unlinked &&\r
+          !in->deleted)\r
+       {\r
+               in->deleted = 1;\r
+               in->myDev->nDeletedFiles++;\r
+       }\r
+       return in->deleted ? YAFFS_OK : YAFFS_FAIL;     \r
 }\r
 \r
 static int yaffs_DeleteDirectory(yaffs_Object *in)\r
@@ -2823,87 +3487,6 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
        }\r
        else if(!list_empty(&obj->hardLinks))\r
        {       \r
-#if 0\r
-               // Curve ball: We're unlinking an object that has a hardlink.\r
-               // Therefore we can't really delete the object.\r
-               // Instead, we do the following:\r
-               // - Select a hardlink.\r
-               // - Re-type a hardlink as the equivalent object and populate the fields, including the\r
-               //  objectId. Updating the object id is important so that all the hardlinks do not need\r
-               // to be rewritten.\r
-               // - Update the equivalet object pointers.\r
-               // - Delete all object.\r
-\r
-               yaffs_Object *hl;\r
-               struct list_head *i;\r
-\r
-\r
-               yaffs_RemoveObjectFromDirectory(obj);\r
-\r
-\r
-\r
-               hl =  list_entry(obj->hardLinks.next, yaffs_Object,hardLinks);\r
-               \r
-               hl->dirty = 1;\r
-               hl->st_mode = obj->st_mode;\r
-               hl->st_uid = obj->st_uid;\r
-               hl->st_gid = obj->st_gid;\r
-               hl->st_atime = obj->st_atime;\r
-               hl->st_mtime = obj->st_mtime;\r
-               hl->st_ctime = obj->st_ctime;\r
-               hl->st_rdev = obj->st_rdev;\r
-               \r
-               hl->variantType = obj->variantType;\r
-               \r
-               switch(hl->variantType)\r
-               {\r
-                       case YAFFS_OBJECT_TYPE_FILE:\r
-                       case YAFFS_OBJECT_TYPE_SYMLINK:\r
-                       case YAFFS_OBJECT_TYPE_SPECIAL:\r
-                               // These types are OK to just copy across.\r
-                               hl->variant = obj->variant;\r
-                               break;\r
-                       case YAFFS_OBJECT_TYPE_DIRECTORY:\r
-                               // Fix the list up\r
-                               list_add(&hl->variant.directoryVariant.children,\r
-                                           &obj->variant.directoryVariant.children);\r
-                               list_del(&obj->variant.directoryVariant.children);\r
-                               \r
-                               // Now change all the directory children to point to the new parent.\r
-                               list_for_each(i,&hl->variant.directoryVariant.children)\r
-                               {\r
-                                       list_entry(i,yaffs_Object,siblings)->parent = hl;\r
-                               }\r
-                               break;\r
-                               \r
-                       case YAFFS_OBJECT_TYPE_HARDLINK:\r
-                       case YAFFS_OBJECT_TYPE_UNKNOWN:\r
-                               // Should not be either of these types.\r
-               }\r
-               \r
-               // Now fix up the hardlink chain\r
-               list_del(&obj->hardLinks);\r
-\r
-               list_for_each(i,&hl->hardLinks)\r
-               {\r
-                       list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObject = hl;\r
-                       list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObjectId = hl->objectId;\r
-               }\r
-               \r
-               // Now fix up the hash links.\r
-               yaffs_UnhashObject(hl);\r
-               hl->objectId = obj->objectId;\r
-               yaffs_HashObject(hl);\r
-               \r
-               // Update the hardlink which has become an object\r
-               yaffs_UpdateObjectHeader(hl,NULL);\r
-\r
-               // Finally throw away the deleted object\r
-               yaffs_DeleteChunk(obj->myDev,obj->chunkId);\r
-               yaffs_FreeObject(obj);\r
-               \r
-               return YAFFS_OK;                \r
-#else\r
                // Curve ball: We're unlinking an object that has a hardlink.\r
                //\r
                //      This problem arises because we are not strictly following\r
@@ -2929,16 +3512,13 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
                \r
                yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);\r
                \r
-               retVal = yaffs_ChangeObjectName(obj, hl->parent, name);\r
+               retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);\r
                \r
                if(retVal == YAFFS_OK)\r
                {\r
                        retVal = yaffs_DoGenericObjectDeletion(hl);\r
                }\r
                return retVal;\r
-\r
-#endif\r
-\r
                                \r
        }\r
        else\r
@@ -2946,7 +3526,7 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
                switch(obj->variantType)\r
                {\r
                        case YAFFS_OBJECT_TYPE_FILE:\r
-                               return yaffs_DeleteFile(obj);\r
+                               return yaffs_UnlinkFile(obj);\r
                                break;\r
                        case YAFFS_OBJECT_TYPE_DIRECTORY:\r
                                return yaffs_DeleteDirectory(obj);\r
@@ -3032,7 +3612,7 @@ static int yaffs_Scan(yaffs_Device *dev)
        yaffs_BlockState state;\r
        yaffs_Object *hardList = NULL;\r
        yaffs_Object *hl;\r
-       \r
+       yaffs_BlockInfo *bi;\r
 \r
        \r
        yaffs_ObjectHeader *oh;\r
@@ -3047,15 +3627,16 @@ static int yaffs_Scan(yaffs_Device *dev)
        for(blk = dev->startBlock; blk <= dev->endBlock; blk++)\r
        {\r
                deleted = 0;\r
-               dev->blockInfo[blk].pageBits = 0;\r
-               dev->blockInfo[blk].pagesInUse = 0;\r
+               bi = yaffs_GetBlockInfo(dev,blk);\r
+               bi->pageBits = 0;\r
+               bi->pagesInUse = 0;\r
                state = YAFFS_BLOCK_STATE_SCANNING;\r
                \r
                \r
                if(yaffs_IsBlockBad(dev,blk))\r
                {\r
                        state = YAFFS_BLOCK_STATE_DEAD;\r
-                       T((TSTR("block %d is bad" TENDSTR),blk));\r
+                       T(YAFFS_TRACE_BAD_BLOCKS,(TSTR("block %d is bad" TENDSTR),blk));\r
                }\r
                \r
                // Read each chunk in the block.\r
@@ -3070,7 +3651,7 @@ static int yaffs_Scan(yaffs_Device *dev)
 \r
                        \r
                        // This block looks ok, now what's in this chunk?\r
-                       yaffs_GetTagsFromSpare(&spare,&tags);\r
+                       yaffs_GetTagsFromSpare(dev,&spare,&tags);\r
                        \r
                        if(yaffs_CountBits(spare.pageStatus) < 6)\r
                        {\r
@@ -3094,7 +3675,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                else\r
                                {\r
                                        // this is the block being allocated from\r
-                                       T((TSTR(" Allocating from %d %d" TENDSTR),blk,c));\r
+                                       T(YAFFS_TRACE_SCAN,(TSTR(" Allocating from %d %d" TENDSTR),blk,c));\r
                                        state = YAFFS_BLOCK_STATE_ALLOCATING;\r
                                        dev->allocationBlock = blk;\r
                                        dev->allocationPage = c;\r
@@ -3106,8 +3687,8 @@ static int yaffs_Scan(yaffs_Device *dev)
                        {\r
                                int endpos;\r
                                // A data chunk.\r
-                               dev->blockInfo[blk].pageBits |= (1 << c);\r
-                               dev->blockInfo[blk].pagesInUse++;\r
+                               bi->pageBits |= (1 << c);\r
+                               bi->pagesInUse++;\r
                                                                \r
                                in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);\r
                                // PutChunkIntoFIle checks for a clash (two data chunks with\r
@@ -3117,6 +3698,11 @@ static int yaffs_Scan(yaffs_Device *dev)
                                if(in->variant.fileVariant.scannedFileSize <endpos)\r
                                {\r
                                        in->variant.fileVariant.scannedFileSize = endpos;\r
+#ifndef CONFIG_YAFFS_USE_HEADER_FILE_SIZE\r
+                                               in->variant.fileVariant.fileSize =      \r
+                                                       in->variant.fileVariant.scannedFileSize;\r
+#endif\r
+\r
                                }\r
                                //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  \r
                        }\r
@@ -3124,8 +3710,8 @@ static int yaffs_Scan(yaffs_Device *dev)
                        {\r
                                // chunkId == 0, so it is an ObjectHeader.\r
                                // Thus, we read in the object header and make the object\r
-                               dev->blockInfo[blk].pageBits |= (1 << c);\r
-                               dev->blockInfo[blk].pagesInUse++;\r
+                               bi->pageBits |= (1 << c);\r
+                               bi->pagesInUse++;\r
                                                        \r
                                yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL,1);\r
                                \r
@@ -3153,7 +3739,34 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        }\r
                                }\r
                                \r
-                               if(!in->valid)\r
+                               if(!in->valid &&\r
+                                  (tags.objectId == YAFFS_OBJECTID_ROOT ||\r
+                                   tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))\r
+                               {\r
+                                       // We only load some info, don't fiddle with directory structure\r
+                                       in->valid = 1;\r
+                                       in->variantType = oh->type;\r
+       \r
+                                       in->st_mode  = oh->st_mode;\r
+#ifdef CONFIG_YAFFS_WINCE\r
+                                       in->win_atime[0] = oh->win_atime[0];\r
+                                       in->win_ctime[0] = oh->win_ctime[0];\r
+                                       in->win_mtime[0] = oh->win_mtime[0];\r
+                                       in->win_atime[1] = oh->win_atime[1];\r
+                                       in->win_ctime[1] = oh->win_ctime[1];\r
+                                       in->win_mtime[1] = oh->win_mtime[1];\r
+#else\r
+                                       in->st_uid   = oh->st_uid;\r
+                                       in->st_gid   = oh->st_gid;\r
+                                       in->st_atime = oh->st_atime;\r
+                                       in->st_mtime = oh->st_mtime;\r
+                                       in->st_ctime = oh->st_ctime;\r
+                                       in->st_rdev = oh->st_rdev;\r
+#endif\r
+                                       in->chunkId  = chunk;\r
+\r
+                               }\r
+                               else if(!in->valid)\r
                                {\r
                                        // we need to load this info\r
                                \r
@@ -3161,15 +3774,24 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->variantType = oh->type;\r
        \r
                                        in->st_mode  = oh->st_mode;\r
+#ifdef CONFIG_YAFFS_WINCE\r
+                                       in->win_atime[0] = oh->win_atime[0];\r
+                                       in->win_ctime[0] = oh->win_ctime[0];\r
+                                       in->win_mtime[0] = oh->win_mtime[0];\r
+                                       in->win_atime[1] = oh->win_atime[1];\r
+                                       in->win_ctime[1] = oh->win_ctime[1];\r
+                                       in->win_mtime[1] = oh->win_mtime[1];\r
+#else\r
                                        in->st_uid   = oh->st_uid;\r
                                        in->st_gid   = oh->st_gid;\r
                                        in->st_atime = oh->st_atime;\r
                                        in->st_mtime = oh->st_mtime;\r
                                        in->st_ctime = oh->st_ctime;\r
                                        in->st_rdev = oh->st_rdev;\r
+#endif\r
                                        in->chunkId  = chunk;\r
 \r
-                                       in->sum = oh->sum;\r
+                                       yaffs_SetObjectName(in,oh->name);\r
                                        in->dirty = 0;\r
                                                        \r
                                        // directory stuff...\r
@@ -3187,9 +3809,16 @@ static int yaffs_Scan(yaffs_Device *dev)
                                                // Hoosterman, another problem....\r
                                                // We're trying to use a non-directory as a directory\r
                                                // Todo ... handle\r
+                                               T(YAFFS_TRACE_ERROR, (TSTR("yaffs tradgedy: attempting to use non-directory as a directory in scan" TENDSTR)));\r
+\r
                                        }\r
                                \r
-                                       yaffs_AddObjectToDirectory(parent,in);  \r
+                                       yaffs_AddObjectToDirectory(parent,in);\r
+                                       if(parent == dev->unlinkedDir)\r
+                                       {\r
+                                               in->deleted = 1; // If it is unlinked at start up then it wants deleting\r
+                                               dev->nDeletedFiles++;\r
+                                       }\r
                                \r
                                        // Note re hardlinks.\r
                                        // Since we might scan a hardlink before its equivalent object is scanned\r
@@ -3202,7 +3831,9 @@ static int yaffs_Scan(yaffs_Device *dev)
                                                case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem\r
                                                        break;\r
                                                case YAFFS_OBJECT_TYPE_FILE:\r
+#ifdef CONFIG_YAFFS_USE_HEADER_FILE_SIZE\r
                                                        in->variant.fileVariant.fileSize = oh->fileSize;\r
+#endif\r
                                                        break;\r
                                                case YAFFS_OBJECT_TYPE_HARDLINK:\r
                                                        in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;\r
@@ -3228,11 +3859,11 @@ static int yaffs_Scan(yaffs_Device *dev)
                        state = YAFFS_BLOCK_STATE_FULL; \r
                }\r
                \r
-               dev->blockInfo[blk].blockState = state;\r
+               bi->blockState = state;\r
                \r
                // Now let's see if it was dirty\r
-               if(     dev->blockInfo[blk].pagesInUse == 0 &&\r
-               dev->blockInfo[blk].blockState == YAFFS_BLOCK_STATE_FULL)\r
+               if(     bi->pagesInUse == 0 &&\r
+               bi->blockState == YAFFS_BLOCK_STATE_FULL)\r
            {\r
                yaffs_BlockBecameDirty(dev,blk);\r
            }\r
@@ -3292,6 +3923,13 @@ static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *ob
        // Now add it\r
        list_add(&obj->siblings,&directory->variant.directoryVariant.children);\r
        obj->parent = directory;\r
+       \r
+       if(directory == obj->myDev->unlinkedDir)\r
+       {\r
+               obj->unlinked = 1;\r
+               obj->myDev->nUnlinkedFiles++;\r
+               obj->renameAllowed = 0;\r
+       }\r
 }\r
 \r
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)\r
@@ -3390,6 +4028,12 @@ int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize)
                strncpy(name,locName,buffSize - 1);\r
 \r
        }\r
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM\r
+       else if(obj->shortName[0])\r
+       {\r
+               strcpy(name,obj->shortName);\r
+       }\r
+#endif\r
        else\r
        {\r
                __u8 buffer[YAFFS_BYTES_PER_CHUNK];\r
@@ -3430,12 +4074,16 @@ int yaffs_GetObjectFileLength(yaffs_Object *obj)
 \r
 int yaffs_GetObjectLinkCount(yaffs_Object *obj)\r
 {\r
-       int count = 1; // the object itself\r
+       int count = 0; \r
        struct list_head *i;\r
        \r
+       if(!obj->unlinked)\r
+       {\r
+               count++;        // the object itself\r
+       }\r
        list_for_each(i,&obj->hardLinks)\r
        {\r
-               count++;\r
+               count++;        // add the hard links;\r
        }\r
        return count;\r
        \r
@@ -3481,6 +4129,7 @@ char *yaffs_GetSymlinkAlias(yaffs_Object *obj)
        }\r
 }\r
 \r
+#ifndef CONFIG_YAFFS_WINCE\r
 \r
 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)\r
 {\r
@@ -3496,7 +4145,7 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
        \r
        if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);\r
        \r
-       yaffs_UpdateObjectHeader(obj,NULL);\r
+       yaffs_UpdateObjectHeader(obj,NULL,1);\r
        \r
        return YAFFS_OK;\r
        \r
@@ -3521,7 +4170,7 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
        \r
 }\r
 \r
-\r
+#endif\r
 \r
 int yaffs_DumpObject(yaffs_Object *obj)\r
 {\r
@@ -3538,7 +4187,7 @@ int yaffs_DumpObject(yaffs_Object *obj)
        \r
        yaffs_GetObjectName(obj,name,256);\r
        \r
-       YPRINTF(("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",\r
+       T(YAFFS_TRACE_ALWAYS,(TSTR("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n" TENDSTR),\r
                        obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, \r
                        obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));\r
 \r
@@ -3571,67 +4220,106 @@ int yaffs_DumpObject(yaffs_Object *obj)
 \r
 int yaffs_GutsInitialise(yaffs_Device *dev)\r
 {\r
-       unsigned  nChunks,x;\r
+       unsigned x;\r
        int bits;\r
+       int extraBits;\r
+       int nBlocks;\r
 \r
 \r
        \r
        if(!yaffs_CheckStructures())\r
        {\r
+               T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs_CheckStructures failed\n" TENDSTR)));\r
                return YAFFS_FAIL;\r
        }\r
+       \r
+       if(dev->startBlock <= 0 ||\r
+          (dev->endBlock - dev->startBlock) < 10)\r
+       {\r
+               T(YAFFS_TRACE_ALWAYS,(TSTR("startBlock %d or endBlock %d invalid\n" TENDSTR),\r
+                               dev->startBlock, dev->endBlock));\r
+               return YAFFS_FAIL;\r
+       }\r
+       \r
+       nBlocks = dev->endBlock - dev->startBlock + 1;\r
+       \r
 \r
                \r
        // OK now calculate a few things for the device\r
        // Calculate chunkGroupBits. \r
-       // If there are 64k or less chunks then this is 1\r
-       // Else it is log2(nChunks) - 16\r
-       //\r
-       x = nChunks = YAFFS_CHUNKS_PER_BLOCK * dev->nBlocks;\r
+       // We need to find the next power of 2 > than endBlock\r
+       \r
+       x = YAFFS_CHUNKS_PER_BLOCK * (dev->endBlock+1);\r
        \r
-       for(bits = 0, x = nChunks; (x & 1) == 0; bits++)\r
+       for(bits = extraBits = 0; x > 1; bits++)\r
        {\r
+               if(x & 1) extraBits++;\r
                x >>= 1;\r
        }\r
+\r
+       if(extraBits > 0) bits++;\r
        \r
-       if( x != 1)\r
-       {\r
-               // Not a power of 2\r
-               YPRINTF(("nBlocks should be a power of 2 but is %u\n",\r
-                       dev->nBlocks));\r
-               return YAFFS_FAIL;\r
-       }\r
        \r
+       // Level0 Tnodes are 16 bits, so if the bitwidth of the\r
+       // chunk range we're using is greater than 16 we need \r
+       // to figure out chunk shift and chunkGroupSize\r
        if(bits <= 16) \r
        {\r
                dev->chunkGroupBits = 0;\r
-               dev->chunkGroupSize = 1;\r
        }\r
        else\r
        {\r
                dev->chunkGroupBits = bits - 16;\r
-               dev->chunkGroupSize = nChunks>> 16;\r
        }\r
+       dev->chunkGroupSize = 1 << dev->chunkGroupBits;\r
+       \r
        \r
        // More device initialisation\r
        dev->garbageCollectionRequired  = 0;\r
+       dev->garbageCollections = 0;\r
        dev->currentDirtyChecker = 0;\r
        dev->bufferedBlock = -1;\r
        dev->doingBufferedBlockRewrite = 0;\r
        dev->blockSelectedForGC = -1;\r
+       dev->nDeletedFiles = 0;\r
+       dev->nBackgroundDeletions=0;\r
+       dev->nUnlinkedFiles = 0;\r
+       dev->eccFixed=0;\r
+       dev->eccUnfixed=0;\r
+       dev->tagsEccFixed=0;\r
+       dev->tagsEccUnfixed=0;\r
        \r
-       yaffs_InitialiseBlocks(dev);\r
+       yaffs_InitialiseBlocks(dev,nBlocks);\r
        \r
        yaffs_InitialiseTnodes(dev);\r
 \r
        yaffs_InitialiseObjects(dev);\r
        \r
+#ifdef CONFIG_YAFFS_SHORT_OP_CACHE\r
+       { \r
+               int i;\r
+               for(i=0; i < YAFFS_N_CACHE_CHUNKS; i++)\r
+               {\r
+                       dev->srCache[i].object = NULL;\r
+                       dev->srCache[i].lastUse = 0;\r
+                       dev->srCache[i].dirty = 0;\r
+               }\r
+               dev->srLastUse = 0;\r
+       }\r
+#endif\r
+\r
+       dev->cacheHits = 0;\r
        \r
-       // Initialise the root and lost and found directories\r
-       dev->lostNFoundDir = dev->rootDir = NULL;\r
+       \r
+       // Initialise the unlinked, root and lost and found directories\r
+       dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = NULL;\r
+       \r
+       dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);\r
+\r
        dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);\r
-       dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_ROOT_MODE | S_IFDIR);\r
+       dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);\r
        yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);\r
+       \r
                \r
        // Now scan the flash.  \r
        yaffs_Scan(dev);\r
@@ -3660,6 +4348,22 @@ void yaffs_Deinitialise(yaffs_Device *dev)
 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)\r
 {\r
        int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);\r
+       \r
+       struct list_head *i;    \r
+       yaffs_Object *l;\r
+       \r
+       \r
+       // To the free chunks add the chunks that are in the deleted unlinked files.\r
+       list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)\r
+       {\r
+               l = list_entry(i, yaffs_Object,siblings);\r
+               if(l->deleted)\r
+               {\r
+                       nFree++;\r
+                       nFree += l->nDataChunks;\r
+               }\r
+       }\r
+\r
 \r
        return (nFree < 0) ? 0 : nFree; \r
        \r
@@ -3670,7 +4374,8 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
 \r
 #define yaffs_CheckStruct(structure,syze, name) \\r
            if(sizeof(structure) != syze) \\r
-              { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \\r
+              { \\r
+                T(YAFFS_TRACE_ALWAYS,(TSTR("%s should be %d but is %d\n" TENDSTR),name,syze,sizeof(structure))); \\r
                 return YAFFS_FAIL; \\r
                   }\r
                 \r
@@ -3687,21 +4392,20 @@ static int yaffs_CheckStructures(void)
        return YAFFS_OK;\r
 }\r
 \r
+#if 0\r
 void yaffs_GutsTest(yaffs_Device *dev)\r
 {\r
        \r
        if(yaffs_CheckStructures() != YAFFS_OK)\r
        {\r
-               YPRINTF(("One or more structures malformed-- aborting\n"));\r
+               T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));\r
                return;\r
        }\r
-       else\r
-       {\r
-               YPRINTF(("Structures OK\n"));\r
-       }\r
        \r
        yaffs_TnodeTest(dev);\r
        yaffs_ObjectTest(dev);  \r
 }\r
+#endif\r
+\r
 \r
 \r