Strip obsolete code
[yaffs2.git] / yaffs_guts.c
index 87afa2205f3e61c1e76aaf69df32fdc27f91e84f..998969996f672241e45aecd46c2097e2de5d4054 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * YAFFS: Yet another FFS. A NAND-flash specific file system. 
  *
@@ -14,7 +13,7 @@
  */
  //yaffs_guts.c
 
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.8 2005-07-05 23:54:59 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.17 2005-08-09 04:17:30 charles Exp $";
 
 #include "yportenv.h"
 
@@ -32,60 +31,10 @@ void yfsd_UnlockYAFFS(BOOL fsLockOnly);
 
 #define YAFFS_PASSIVE_GC_CHUNKS 2
 
-#if 0
-// Use Steven Hill's ECC struff instead
-// External functions for ECC on data
-void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
-int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-#define yaffs_ECCCalculate(data,ecc) nand_calculate_ecc(data,ecc)
-#define yaffs_ECCCorrect(data,read_ecc,calc_ecc) nand_correct_ecc(data,read_ecc,calc_ecc)
-#else
-#include "yaffs_ecc.h"
-#endif
-
-#if 0
-// countBits is a quick way of counting the number of bits in a byte.
-// ie. countBits[n] holds the number of 1 bits in a byte with the value n.
-
-static const char yaffs_countBitsTable[256] =
-{
-0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
-4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
-};
-
-static int yaffs_CountBits(__u8 x)
-{
-       int retVal;
-       retVal = yaffs_countBitsTable[x];
-       return retVal;
-}
-
-#endif
 
+#include "yaffs_ecc.h"
 
-#if 0
-// Stuff using yea olde tags
-static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
-static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
 
-static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);
-static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted);
-#else
-#endif
 
 // NAND access
 
@@ -96,14 +45,11 @@ static Y_INLINE int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
 static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo, yaffs_BlockState *state,unsigned *sequenceNumber);
 // Local prototypes
 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve);
-#if 0
-static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
-#endif
 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
 
 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
-static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink);
+static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink, int shadows);
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
 static int yaffs_CheckStructures(void);
 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
@@ -117,9 +63,6 @@ static void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo)
 
 // Robustification (if it ever comes about...)
 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
-#if 0
-static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
-#endif
 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags);
 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND,  const yaffs_ExtendedTags *tags);
@@ -129,9 +72,6 @@ static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAN
 static int yaffs_UnlinkWorker(yaffs_Object *obj);
 static void yaffs_DestroyObject(yaffs_Object *obj);
 
-#if 0
-static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize);
-#endif
 
 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject);
 
@@ -141,6 +81,8 @@ loff_t yaffs_GetFileSize(yaffs_Object *obj);
 
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
 
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
+
 #ifdef YAFFS_PARANOID
 static int yaffs_CheckFileSanity(yaffs_Object *in);
 #else
@@ -206,7 +148,7 @@ static Y_INLINE int yaffs_QueryInitialBlockState(yaffs_Device *dev,int blockNo,
                return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
 }
 
-int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
+static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
 {
        int result;
        
@@ -391,7 +333,6 @@ static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND
 
 
 
-#if 1
 static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_ExtendedTags *tags,int useReserve)
 {
        int chunk;
@@ -446,7 +387,7 @@ static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev, con
        
        return chunk;
 }
-#endif
+
 
 
 ///
@@ -465,41 +406,6 @@ static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
 }
 
 
-#if 0
-static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
-{
-       dev->doingBufferedBlockRewrite = 1;
-       //
-       //      Remove erased chunks
-       //  Rewrite existing chunks to a new block
-       //      Set current write block to the new block
-       
-       dev->doingBufferedBlockRewrite = 0;
-       
-       return 1;
-}
-
-
-static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
-{
-       int blockInNAND = chunkInNAND/dev->nChunksPerBlock;
-
-       // Mark the block for retirement
-       yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
-       T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
-
-
-       //TODO  
-       // Just do a garbage collection on the affected block then retire the block
-       // NB recursion
-}
-
-
-static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
-{
-}
-
-#endif
 
 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_ExtendedTags *tags)
 {
@@ -521,35 +427,6 @@ static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
 
 
 
-#if 0
-static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1,int dataSize)
-{
-
-
-       if( memcmp(d0,d1,dataSize) != 0 ||
-               s0->tagByte0 != s1->tagByte0 ||
-               s0->tagByte1 != s1->tagByte1 ||
-               s0->tagByte2 != s1->tagByte2 ||
-               s0->tagByte3 != s1->tagByte3 ||
-               s0->tagByte4 != s1->tagByte4 ||
-               s0->tagByte5 != s1->tagByte5 ||
-               s0->tagByte6 != s1->tagByte6 ||
-               s0->tagByte7 != s1->tagByte7 ||
-               s0->ecc1[0]  != s1->ecc1[0]  ||
-               s0->ecc1[1]  != s1->ecc1[1]  ||
-               s0->ecc1[2]  != s1->ecc1[2]  ||
-               s0->ecc2[0]  != s1->ecc2[0]  ||
-               s0->ecc2[1]  != s1->ecc2[1]  ||
-               s0->ecc2[2]  != s1->ecc2[2] )
-               {
-                       return 0;
-               }
-       
-       return 1;
-}
-#endif
-
-
 ///////////////////////// Object management //////////////////
 // List of spare objects
 // The list is hooked together using the first pointer
@@ -587,7 +464,7 @@ static __u16 yaffs_CalcNameSum(const YCHAR *name)
        return sum;
 }
 
-void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
+static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
 {
 #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
                                        if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
@@ -602,13 +479,6 @@ void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
                                        obj->sum = yaffs_CalcNameSum(name);
 }
 
-#if 0
-void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
-{
-       yaffs_ECCCalculate(data , spare->ecc1);
-       yaffs_ECCCalculate(&data[256] , spare->ecc2);
-}
-#endif
 
 
 ///////////////////////// TNODES ///////////////////////
@@ -652,13 +522,13 @@ static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
     {
        newTnodes[i].internal[0] = &newTnodes[i+1];
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
-       newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = 1;
+       newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
 #endif
     }
        
        newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
-       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = 1;
+       newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
 #endif
        dev->freeTnodes = newTnodes;
        dev->nFreeTnodes+= nTnodes;
@@ -703,7 +573,7 @@ static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
        {
                tn = dev->freeTnodes;
 #ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
-       if(tn->internal[YAFFS_NTNODES_INTERNAL] != 1)
+       if(tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1)
                {
                        // Hoosterman, this thing looks like it isn't in the list
                                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 1" TENDSTR)));
@@ -731,7 +601,7 @@ static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
                        // Hoosterman, this thing looks like it is already in the list
                                T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: Tnode list bug 2" TENDSTR)));
                }
-               tn->internal[YAFFS_NTNODES_INTERNAL] = 1;
+               tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
 #endif
                tn->internal[0] = dev->freeTnodes;
                dev->freeTnodes = tn;
@@ -768,35 +638,6 @@ static void yaffs_InitialiseTnodes(yaffs_Device*dev)
 
 }
 
-#if 0
-void yaffs_TnodeTest(yaffs_Device *dev)
-{
-
-       int i;
-       int j;
-       yaffs_Tnode *tn[1000];
-       
-       YINFO("Testing TNodes");
-       
-       for(j = 0; j < 50; j++)
-       {
-               for(i = 0; i < 1000; i++)
-               {
-                       tn[i] = yaffs_GetTnode(dev);
-                       if(!tn[i])
-                       {
-                               YALERT("Getting tnode failed");
-                       }
-               }
-               for(i = 0; i < 1000; i+=3)
-               {
-                       yaffs_FreeTnode(dev,tn[i]);
-                       tn[i] = NULL;
-               }
-               
-       }
-}
-#endif
 
 
 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
@@ -967,7 +808,7 @@ static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStru
 }
 
 
-int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
+static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
 {
        int j;
        
@@ -1090,6 +931,7 @@ static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
        if(theBlock)
        {
                theBlock->softDeletions++;
+               dev->nFreeChunks++;
        }
 }
 
@@ -1386,7 +1228,7 @@ static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u3
                obj->unlinkAllowed= 0;  // ... or unlink it
                obj->deleted = 0;
                obj->unlinked = 0;
-               obj->st_mode = mode;
+               obj->yst_mode = mode;
                obj->myDev = dev;
                obj->chunkId = 0; // Not a valid chunk.
        }
@@ -1493,7 +1335,7 @@ static void yaffs_InitialiseObjects(yaffs_Device *dev)
 
 
 
-int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
+static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
 {
        static int x = 0;
        int i;
@@ -1569,7 +1411,7 @@ static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
        return n;       
 }
 
-void yaffs_HashObject(yaffs_Object *in)
+static void yaffs_HashObject(yaffs_Object *in)
 {
        int bucket = yaffs_HashFunction(in->objectId);
        yaffs_Device *dev = in->myDev;
@@ -1642,7 +1484,7 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
 
 #else
 
-               theObject->st_atime = theObject->st_mtime = theObject->st_ctime = Y_CURRENT_TIME;               
+               theObject->yst_atime = theObject->yst_mtime = theObject->yst_ctime = Y_CURRENT_TIME;            
 #endif
                switch(type)
                {
@@ -1674,7 +1516,7 @@ yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectTyp
        return theObject;
 }
 
-yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
+static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
 {
        yaffs_Object *theObject = NULL;
        
@@ -1692,7 +1534,7 @@ yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaf
 
 }
 
-YCHAR *yaffs_CloneString(const YCHAR *str)
+static YCHAR *yaffs_CloneString(const YCHAR *str)
 {
        YCHAR *newStr = NULL;
        
@@ -1711,7 +1553,7 @@ YCHAR *yaffs_CloneString(const YCHAR *str)
 // equivalentObject only has meaning for a hard link;
 // aliasString only has meaning for a sumlink.
 // rdev only has meaning for devices (a subset of special objects)
-yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
+static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                                                                 yaffs_Object *parent,
                                                                 const YCHAR *name, 
                                                                 __u32 mode,
@@ -1739,7 +1581,7 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                in->valid = 1;
                in->variantType = type;
 
-               in->st_mode  = mode;
+               in->yst_mode  = mode;
                
 #ifdef CONFIG_YAFFS_WINCE
                yfsd_WinFileTimeNow(in->win_atime);
@@ -1747,11 +1589,11 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
                
 #else
-               in->st_atime = in->st_mtime = in->st_ctime = Y_CURRENT_TIME;
+               in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
 
-               in->st_rdev  = rdev;
-               in->st_uid   = uid;
-               in->st_gid   = gid;
+               in->yst_rdev  = rdev;
+               in->yst_uid   = uid;
+               in->yst_gid   = gid;
 #endif         
                in->nDataChunks = 0;
 
@@ -1781,7 +1623,7 @@ yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
                }
 
                if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
-                  yaffs_UpdateObjectHeader(in,name,0,0) < 0)
+                  yaffs_UpdateObjectHeader(in,name,0,0,0) < 0)
                {
                        // Could not create the object header, fail the creation
                        yaffs_DestroyObject(in);
@@ -1831,10 +1673,12 @@ yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name, yaffs_Object *
 }
 
 
-static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force)
+static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows)
 {
        int unlinkOp;
        int deleteOp;
+       
+       yaffs_Object * existingTarget;
 
        if(newDir == NULL)
        {
@@ -1859,13 +1703,16 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
 
        deleteOp = (newDir == obj->myDev->deletedDir);
        
+       existingTarget = yaffs_FindObjectByName(newDir,newName);
+       
        // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
        // duplicate names are allowed.
        // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
        if( (unlinkOp|| 
                 deleteOp ||
                 force || 
-                !yaffs_FindObjectByName(newDir,newName))  &&
+                (shadows > 0) ||
+                !existingTarget)  &&
             newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
        {
                yaffs_SetObjectName(obj,newName);
@@ -1876,7 +1723,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
                if(unlinkOp) obj->unlinked = 1;
                
                // If it is a deletion then we mark it as a shrink for gc purposes.
-               if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
+               if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0)
                {
                        return YAFFS_OK;
                }
@@ -1890,6 +1737,7 @@ static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const
 int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
 {
        yaffs_Object *obj;
+       yaffs_Object *existingTarget;
        int force = 0;
        
 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
@@ -1903,102 +1751,36 @@ int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object
 #endif
        
        obj = yaffs_FindObjectByName(oldDir,oldName);
-       if(obj && obj->renameAllowed)
-       {
-               return yaffs_ChangeObjectName(obj,newDir,newName,force);
-       }
-       return YAFFS_FAIL;
-}
-
-
-#if 0
-
-static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
-{
-       // Scan the buckets and check that the lists 
-       // have as many members as the count says there are
-       int bucket;
-       int countEm;
-       struct list_head *j;
-       int ok = YAFFS_OK;
        
-       for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
+       if(obj && obj->renameAllowed)
        {
-               countEm = 0;
-               
-               list_for_each(j,&dev->objectBucket[bucket].list)
-               {
-                       countEm++;
-               }
-               
-               if(countEm != dev->objectBucket[bucket].count)
-               {
-                       T(YAFFS_TRACE_ERROR,(TSTR("Inode hash inconsistency" TENDSTR)));
-                       ok = YAFFS_FAIL;
-               }
-       }
-
-       return ok;
-}
-
-
-void yaffs_ObjectTest(yaffs_Device *dev)
-{
-       yaffs_Object *in[1000];
-       int inNo[1000];
-       yaffs_Object *inold[1000];
-       int i;
-       int j;
-       
-       memset(in,0,1000*sizeof(yaffs_Object *));
-       memset(inold,0,1000*sizeof(yaffs_Object *));
        
-       yaffs_CheckObjectHashSanity(dev);
+               // Now do the handling for an existing target, if there is one
        
-       for(j = 0; j < 10; j++)
-       {
-               //T(("%d\n",j));
+               existingTarget = yaffs_FindObjectByName(newDir,newName);
+               if(existingTarget &&
+                  existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+                  !list_empty(&existingTarget->variant.directoryVariant.children))
+                {
+                       // There is a target that is a non-empty directory, so we have to fail
+                       return YAFFS_FAIL; // EEXIST or ENOTEMPTY
+                }
+                else if(existingTarget &&
+                        existingTarget != obj)
+                {
+                       // Nuke the target first, using shadowing, 
+                       // but only if it isn't the same object
+                        yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId);
+                        yaffs_Unlink(newDir,newName);
+                }
                
-               for(i = 0; i < 1000; i++)
-               {
-                       in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
-                       if(!in[i])
-                       {
-                               YINFO("No more inodes");
-                       }
-                       else
-                       {
-                               inNo[i] = in[i]->objectId;
-                       }
-               }
-               
-               for(i = 0; i < 1000; i++)
-               {
-                       if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
-                       {
-                               //T(("Differnce in look up test\n"));
-                       }
-                       else
-                       {
-                               // T(("Look up ok\n"));
-                       }
-               }
-               
-               yaffs_CheckObjectHashSanity(dev);
-       
-               for(i = 0; i < 1000; i+=3)
-               {
-                       yaffs_FreeObject(in[i]);        
-                       in[i] = NULL;
-               }
                
-       
-               yaffs_CheckObjectHashSanity(dev);
+               return yaffs_ChangeObjectName(obj,newDir,newName,force,0);
        }
-               
+       return YAFFS_FAIL;
 }
 
-#endif
+
 
 /////////////////////////// Block Management and Page Allocation ///////////////////
 
@@ -2103,6 +1885,7 @@ static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,int aggressive)
        }
 
        pagesInUse = (aggressive)? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
        if(aggressive)
        {
                iterations = dev->internalEndBlock - dev->internalStartBlock + 1;
@@ -2206,55 +1989,20 @@ static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
        }
        else
        {
+               dev->nFreeChunks -= dev->nChunksPerBlock; // We lost a block of free space
+               
                yaffs_RetireBlock(dev,blockNo);
                T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,(TSTR("**>> Block %d retired" TENDSTR),blockNo));
        }
 }
 
-#if 0
-static void yaffs_DumpBlockStats(yaffs_Device *dev)
-{
-       int i,j;
-       yaffs_BlockInfo *bi;
-       
-       for(i= dev->internalStartBlock; i <=dev->internalEndBlock; i++)
-       {
-               bi = yaffs_GetBlockInfo(dev,i);
-               T(YAFFS_TRACE_ALLOCATE,(TSTR("%3d state %d shrink %d inuse %d/%d seq %d pages"),i,
-               bi->blockState,bi->hasShrinkHeader,bi->pagesInUse,bi->softDeletions,bi->sequenceNumber));       
-               
-               for(j = 0; j < dev->nChunksPerBlock; j++)
-               {
-                       if(yaffs_CheckChunkBit(dev,i,j))
-                       {
-                               T(YAFFS_TRACE_ALLOCATE,(TSTR(" %d"),j));
-
-                       }
-               }
-               T(YAFFS_TRACE_ALLOCATE,(TSTR(" " TENDSTR)));
-
-       }
-}
-#endif
-
 
 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
 {
        int i;
        
        yaffs_BlockInfo *bi;
-       
-#if 0
-       static int j = 0;
-       j++;
-       if(j < 0 || j > 100)
-       {
-               j = 0;
-               yaffs_DumpBlockStats(dev);
-       }
-       
-#endif
-       
+               
        if(dev->nErasedBlocks < 1)
        {
                // Hoosterman we've got a problem.
@@ -2298,6 +2046,15 @@ static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
 }
 
 
+// To determine if we have enough space we just look at the 
+// number of erased blocks.
+
+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
+{
+       int reservedChunks = (dev->nReservedBlocks * dev->nChunksPerBlock);
+       return (dev->nFreeChunks > reservedChunks);
+}
+
 
 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
 {
@@ -2311,7 +2068,7 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
                dev->allocationPage = 0;
        }
        
-       if(!useReserve &&  dev->nErasedBlocks </*=*/ dev->nReservedBlocks)
+       if(!useReserve &&  !yaffs_CheckSpaceForAllocation(dev))
        {
                // Not enough space to allocate unless we're allowed to use the reserve.
                return -1;
@@ -2354,14 +2111,6 @@ static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
 }
 
 
-// To determine if we have enough space we just look at the 
-// number of erased blocks.
-// The cache is allowed to use reserved blocks.
-
-static int yaffs_CheckSpaceForChunkCache(yaffs_Device *dev)
-{
-       return (dev->nErasedBlocks >= dev->nReservedBlocks);
-}
 
 
 static int yaffs_GetErasedChunks(yaffs_Device *dev)
@@ -2379,7 +2128,7 @@ static int yaffs_GetErasedChunks(yaffs_Device *dev)
 
 }
 
-int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
+static int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 {
        int oldChunk;
        int newChunk;
@@ -2402,9 +2151,15 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 
        T(YAFFS_TRACE_TRACING,(TSTR("Collecting block %d, in use %d, shrink %d, " TENDSTR),block,bi->pagesInUse,bi->hasShrinkHeader));
        //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
+       
+       //yaffs_VerifyFreeChunks(dev);
 
        bi->hasShrinkHeader = 0; // clear the flag so that the block can erase
+       
+       dev->nFreeChunks -= bi->softDeletions;  // Take off the number of soft deleted entries because
+                                               // they're going to get really deleted during GC.
 
+       dev->isDoingGC = 1;
 
        if(!yaffs_StillSomeChunkBits(dev,block))
        {
@@ -2414,7 +2169,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
        else
        {
 
-                       __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
+       __u8  *buffer = yaffs_GetTempBuffer(dev,__LINE__);
 
        for(chunkInBlock = 0,oldChunk = block * dev->nChunksPerBlock; 
            chunkInBlock < dev->nChunksPerBlock && yaffs_StillSomeChunkBits(dev,block);
@@ -2445,7 +2200,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                        if(object && object->deleted && tags.chunkId != 0)
                        {
                                // Data chunk in a deleted file, throw it away
-                               // It's a deleted data chunk,
+                               // It's a soft deleted data chunk,
                                // No need to copy this, just forget about it and fix up the
                                // object.
                                
@@ -2479,6 +2234,21 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
                                tags.serialNumber++;
 
                                dev->nGCCopies++;
+                               
+                               if(tags.chunkId == 0)
+                               {
+                                       // It is an object Id,
+                                       // We need to nuke the shrinkheader flags first
+                                       // We no longer want the shrinkHeader flag since its work is done
+                                       // and if it is left in place it will mess up scanning.
+                                       // Also, clear out any shadowing stuff
+                                       
+                                       yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
+                                       oh->isShrink = 0;
+                                       oh->shadowsObject = -1;
+                                       tags.extraShadows = 0;
+                                       tags.extraIsShrinkHeader = 0;
+                               }
 
                                newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
                        
@@ -2512,6 +2282,7 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
 
        yaffs_ReleaseTempBuffer(dev,buffer,__LINE__);
 
+       //yaffs_VerifyFreeChunks(dev);
 
        // Do any required cleanups
        for(i = 0; i < cleanups; i++)
@@ -2534,73 +2305,15 @@ int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
        {
                        T(YAFFS_TRACE_GC,(TSTR("gc did not increase free chunks before %d after %d" TENDSTR),chunksBefore,chunksAfter));
        }
+       
+       
+       dev->isDoingGC = 0;
+       
+       //yaffs_VerifyFreeChunks(dev);
                        
        return YAFFS_OK;
 }
 
-#if 0
-static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
-{
-       // find a file to delete
-       struct list_head *i;    
-       yaffs_Object *l;
-
-
-       //Scan the unlinked files looking for one to delete
-       list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
-       {
-               if(i)
-               {
-                       l = list_entry(i, yaffs_Object,siblings);
-                       if(l->deleted)
-                       {
-                               return l;                       
-                       }
-               }
-       }       
-       return NULL;
-}
-
-
-static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
-{
-       // This does background deletion on unlinked files.. only deleted ones.
-       // If we don't have a file we're working on then find one
-       if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
-       {
-               dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
-       }
-       
-       // OK, we're working on a file...
-       if(dev->unlinkedDeletion)
-       {
-               yaffs_Object *obj = dev->unlinkedDeletion;
-               int delresult;
-               int limit; // Number of chunks to delete in a file.
-                                  // NB this can be exceeded, but not by much.
-                                  
-               limit = -1;
-
-               delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
-               
-               if(obj->nDataChunks == 0)
-               {
-                       // Done all the deleting of data chunks.
-                       // Now dump the header and clean up
-                       yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
-                       obj->variant.fileVariant.top = NULL;
-                       yaffs_DoGenericObjectDeletion(obj);
-                       dev->nDeletedFiles--;
-                       dev->nUnlinkedFiles--;
-                       dev->nBackgroundDeletions++;
-                       dev->unlinkedDeletion = NULL;   
-               }
-       }
-}
-
-#endif
-
-
 
 // New garbage collector
 // If we're very low on erased blocks then we do aggressive garbage collection
@@ -2611,21 +2324,27 @@ static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
 // The idea is to help clear out space in a more spread-out manner.
 // Dunno if it really does anything useful.
 //
-int yaffs_CheckGarbageCollection(yaffs_Device *dev)
+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
 {
        int block;
        int aggressive; 
        int gcOk = YAFFS_OK;
        int maxTries = 0;
        
-       //yaffs_DoUnlinkedFileDeletion(dev);
+       //yaffs_VerifyFreeChunks(dev);
+       
+       if(dev->isDoingGC)
+       {
+               // Bail out so we don't get recursive gc
+               return YAFFS_OK;
+       }
 
        // This loop should pass the first time.
        // We'll only see looping here if the erase of the collected block fails.
        
        do{
                maxTries++;
-               if(dev->nErasedBlocks <= (dev->nReservedBlocks + 2))
+               if(dev->nErasedBlocks < dev->nReservedBlocks)
                {
                        // We need a block soon...
                        aggressive = 1;
@@ -2651,11 +2370,11 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
                        gcOk =  yaffs_GarbageCollectBlock(dev,block);
                }
 
-               if(dev->nErasedBlocks <= (dev->nReservedBlocks + 1)
+               if(dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0
                {
                        T(YAFFS_TRACE_GC,(TSTR("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d" TENDSTR),dev->nErasedBlocks,maxTries,block));
                }
-       } while((dev->nErasedBlocks <= (dev->nReservedBlocks + 1)) && (block > 0) && (maxTries < 5));
+       } while((dev->nErasedBlocks < dev->nReservedBlocks) && (block > 0) && (maxTries < 2));
 
        return aggressive ? gcOk: YAFFS_OK;
 }
@@ -2665,143 +2384,6 @@ int yaffs_CheckGarbageCollection(yaffs_Device *dev)
 
 
 
-#if 0
-
-void yaffs_CalcTagsECC(yaffs_Tags *tags)
-{
-       // Calculate an ecc
-       
-       unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
-       unsigned  i,j;
-       unsigned  ecc = 0;
-       unsigned bit = 0;
-
-       tags->ecc = 0;
-       
-       for(i = 0; i < 8; i++)
-       {
-               for(j = 1; j &0xff; j<<=1)
-               {
-                       bit++;
-                       if(b[i] & j)
-                       {
-                               ecc ^= bit;
-                       }
-               }
-       }
-       
-       tags->ecc = ecc;
-       
-       
-}
-
-int  yaffs_CheckECCOnTags(yaffs_Tags *tags)
-{
-       unsigned ecc = tags->ecc;
-       
-       yaffs_CalcTagsECC(tags);
-       
-       ecc ^= tags->ecc;
-       
-       if(ecc && ecc <= 64)
-       {
-               // TODO: Handle the failure better. Retire?
-               unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
-
-               ecc--;
-                               
-               b[ecc / 8] ^= (1 << (ecc & 7));
-               
-               // Now recvalc the ecc
-               yaffs_CalcTagsECC(tags);
-               
-               return 1; // recovered error
-       }
-       else if(ecc)
-       {
-               // Wierd ecc failure value
-               // TODO Need to do somethiong here
-               return -1; //unrecovered error
-       }
-       
-       return 0;
-}
-
-static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
-{
-       yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
-       
-       yaffs_CalcTagsECC(tagsPtr);
-       
-       sparePtr->tagByte0 = tu->asBytes[0];
-       sparePtr->tagByte1 = tu->asBytes[1];
-       sparePtr->tagByte2 = tu->asBytes[2];
-       sparePtr->tagByte3 = tu->asBytes[3];
-       sparePtr->tagByte4 = tu->asBytes[4];
-       sparePtr->tagByte5 = tu->asBytes[5];
-       sparePtr->tagByte6 = tu->asBytes[6];
-       sparePtr->tagByte7 = tu->asBytes[7];
-}
-
-static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
-{
-       yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
-       int result;
-
-       tu->asBytes[0]= sparePtr->tagByte0;
-       tu->asBytes[1]= sparePtr->tagByte1;
-       tu->asBytes[2]= sparePtr->tagByte2;
-       tu->asBytes[3]= sparePtr->tagByte3;
-       tu->asBytes[4]= sparePtr->tagByte4;
-       tu->asBytes[5]= sparePtr->tagByte5;
-       tu->asBytes[6]= sparePtr->tagByte6;
-       tu->asBytes[7]= sparePtr->tagByte7;
-       
-       result =  yaffs_CheckECCOnTags(tagsPtr);
-       if(result> 0)
-       {
-               dev->tagsEccFixed++;
-       }
-       else if(result <0)
-       {
-               dev->tagsEccUnfixed++;
-       }
-}
-
-static void yaffs_SpareInitialise(yaffs_Spare *spare)
-{
-       memset(spare,0xFF,sizeof(yaffs_Spare));
-}
-
-#endif
-
-#if 0
-static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_ExtendedTags *tags, int useReserve)
-{
-       // NB There must be tags, data is optional
-       // If there is data, then an ECC is calculated on it.
-       
-       yaffs_Spare spare;
-       
-       if(!tags)
-       {
-               return YAFFS_FAIL;
-       }
-       
-       //yaffs_SpareInitialise(&spare);
-       
-       //if(!dev->useNANDECC && buffer)
-       //{
-       //      yaffs_CalcECC(buffer,&spare);
-       //}
-       
-       //yaffs_LoadTagsIntoSpare(&spare,tags);
-       
-       return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
-       
-}
-#endif
-
 static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chunkInObject)
 {
        return  (  tags->chunkId == chunkInObject &&
@@ -2813,7 +2395,7 @@ static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId, int chu
 /////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 
-int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
+static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
 {
        //Get the Tnode, then get the level 0 offset chunk offset
     yaffs_Tnode *tn;     
@@ -2841,7 +2423,7 @@ int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *
     return retVal;
 }
 
-int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
+static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
 {
        //Get the Tnode, then get the level 0 offset chunk offset
     yaffs_Tnode *tn;     
@@ -3068,7 +2650,7 @@ static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkIn
 
 
 
-int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
+static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
 {
     int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
     
@@ -3138,9 +2720,10 @@ void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
            bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
            bi->blockState == YAFFS_BLOCK_STATE_COLLECTING)
        {
-               dev->nFreeChunks++;
+               dev->nFreeChunks++;
 
                yaffs_ClearChunkBit(dev,block,page);
+               
                bi->pagesInUse--;
                
                if(bi->pagesInUse == 0 &&
@@ -3162,7 +2745,7 @@ void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId,int markNAND,int lyn)
 
 
 
-int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
+static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
 {
        // Find old chunk Need to do this to get serial number
        // Write new one and patch into tree.
@@ -3218,7 +2801,7 @@ int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *
 // UpdateObjectHeader updates the header on NAND for an object.
 // If name is not NULL, then that new name is used.
 //
-int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink)
+int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows)
 {
 
        yaffs_BlockInfo *bi;
@@ -3261,7 +2844,10 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                // Header data
                oh->type = in->variantType;
                
-               oh->st_mode = in->st_mode;
+               oh->yst_mode = in->yst_mode;
+               
+               // shadowing
+               oh->shadowsObject = shadows;
 
 #ifdef CONFIG_YAFFS_WINCE
                oh->win_atime[0] = in->win_atime[0];
@@ -3271,12 +2857,12 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                oh->win_ctime[1] = in->win_ctime[1];
                oh->win_mtime[1] = in->win_mtime[1];
 #else
-               oh->st_uid = in->st_uid;
-               oh->st_gid = in->st_gid;
-               oh->st_atime = in->st_atime;
-               oh->st_mtime = in->st_mtime;
-               oh->st_ctime = in->st_ctime;
-               oh->st_rdev = in->st_rdev;
+               oh->yst_uid = in->yst_uid;
+               oh->yst_gid = in->yst_gid;
+               oh->yst_atime = in->yst_atime;
+               oh->yst_mtime = in->yst_mtime;
+               oh->yst_ctime = in->yst_ctime;
+               oh->yst_rdev = in->yst_rdev;
 #endif 
                if(in->parent)
                {
@@ -3342,6 +2928,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
                newTags.extraFileLength = oh->fileSize;
                newTags.extraIsShrinkHeader = oh->isShrink;
                newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+               newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
                newTags.extraObjectType  = in->variantType;
                
                // Create new chunk in NAND
@@ -3395,7 +2982,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int i
 static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
 {
        yaffs_Device *dev = obj->myDev;
-       int lowest;
+       int lowest = -99; // Stop compiler whining.
        int i;
        yaffs_ChunkCache *cache;
        int chunkWritten = 0;
@@ -3424,20 +3011,11 @@ static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
                        if(cache && !cache->locked)
                        {
                                //Write it out and free it up
-
-#if 0
-                               nBytes = cache->object->variant.fileVariant.fileSize - ((cache->chunkId -1) * YAFFS_BYTES_PER_CHUNK);
                        
-                               if(nBytes > YAFFS_BYTES_PER_CHUNK)
-                               {
-                                       nBytes= YAFFS_BYTES_PER_CHUNK;
-                               }
-#endif                 
                                chunkWritten = yaffs_WriteChunkDataToObject(cache->object,
-                                                                                                                       cache->chunkId,
-                                                                                                                       cache->data,
-                                                                                                                       cache->nBytes,1);
-
+                                                                               cache->chunkId,
+                                                                               cache->data,
+                                                                               cache->nBytes,1);
                                cache->dirty = 0;
                                cache->object = NULL;
                        }
@@ -3856,7 +3434,7 @@ int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, in
                                yaffs_ChunkCache *cache;
                                // If we can't find the data in the cache, then load it up.
                                cache = yaffs_FindChunkCache(in,chunk);
-                               if(!cache && yaffs_CheckSpaceForChunkCache(in->myDev))
+                               if(!cache && yaffs_CheckSpaceForAllocation(in->myDev))
                                {
                                        cache = yaffs_GrabChunkCache(in->myDev);
                                        cache->object = in;
@@ -4030,6 +3608,11 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                return yaffs_GetFileSize(in);
        }
        
+       if(newSize == oldFileSize)
+       {
+               return oldFileSize;
+       }
+       
        if(newSize < oldFileSize)
        {
 
@@ -4053,24 +3636,20 @@ int yaffs_ResizeFile(yaffs_Object *in, int newSize)
                in->variant.fileVariant.fileSize = newSize;
                
                yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
-               
-               // Write a new object header to show we've shrunk the file
-               // Do this only if the file is not in the deleted directories.
-               if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
-                  in->parent->objectId != YAFFS_OBJECTID_DELETED
-                 )
-               {
-                       yaffs_UpdateObjectHeader(in,NULL, 0, 1);
-               }
-
-               
-               return newSize;
-               
        }
-       else
+                       
+       // Write a new object header.
+       // show we've shrunk the file, if need be
+       // Do this only if the file is not in the deleted directories.
+       if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+          in->parent->objectId != YAFFS_OBJECTID_DELETED
+         )
        {
-               return oldFileSize;
+               yaffs_UpdateObjectHeader(in,NULL, 0, (newSize < oldFileSize) ? 1 : 0 ,0);
        }
+
+               
+       return newSize;
 }
 
 
@@ -4108,12 +3687,12 @@ int yaffs_FlushFile(yaffs_Object *in, int updateTime)
                        yfsd_WinFileTimeNow(in->win_mtime);
 #else
 
-                       in->st_mtime = Y_CURRENT_TIME;
+                       in->yst_mtime = Y_CURRENT_TIME;
 
 #endif
                }
 
-               retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
+               retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
        }
        else
        {
@@ -4134,7 +3713,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
        if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
        {
                // Move to the unlinked directory so we have a record that it was deleted.
-               yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
+               yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
 
        }
 
@@ -4142,15 +3721,6 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
        yaffs_RemoveObjectFromDirectory(in);
        yaffs_DeleteChunk(in->myDev,in->chunkId,1,__LINE__);
        in->chunkId = -1;
-#if 0
-#ifdef __KERNEL__
-       if(in->myInode)
-       {
-               in->myInode->u.generic_ip = NULL;
-               in->myInode = 0;
-       }
-#endif
-#endif
 
        yaffs_FreeObject(in);
        return YAFFS_OK;
@@ -4163,17 +3733,7 @@ static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
 static int yaffs_UnlinkFile(yaffs_Object *in)
 {
 
-#ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
 
-       // Delete the file data & tnodes
-
-        yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
-        
-
-       yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
-       
-       return  yaffs_DoGenericObjectDeletion(in);
-#else
        int retVal;
        int immediateDeletion=0;
 
@@ -4197,7 +3757,7 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
 #endif
                if(immediateDeletion)
                {
-                       retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
+                       retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
                        T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
                        in->deleted=1;
                        in->myDev->nDeletedFiles++;
@@ -4209,14 +3769,11 @@ static int yaffs_UnlinkFile(yaffs_Object *in)
                }
                else
                {
-                       retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
+                       retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0);
                }
        
        }
        return retVal;
-
-       
-#endif
 }
 
 int yaffs_DeleteFile(yaffs_Object *in)
@@ -4328,7 +3885,7 @@ static int yaffs_UnlinkWorker(yaffs_Object *obj)
                
                yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
                
-               retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
+               retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0);
                
                if(retVal == YAFFS_OK)
                {
@@ -4379,48 +3936,35 @@ int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
 //////////////// Initialisation Scanning /////////////////
 
 
-#if 0
-// For now we use the SmartMedia check.
-// We look at the blockStatus byte in the first two chunks
-// These must be 0xFF to pass as OK.
-// todo: this function needs to be modifyable foir different NAND types
-// and different chunk sizes.  Suggest make this into a per-device configurable
-// function.
-static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
+static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
 {
-       yaffsExtendedTags *tags;
+       yaffs_Object *obj;
        
-       yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock,NULL,&tags,1);
-#if 1
-       if(yaffs_CountBits(spare.blockStatus) < 7)
+       if(!backwardScanning)
        {
-               return 1;
-       }
-#else
-       if(spare.blockStatus != 0xFF)
-       {
-               return 1;
-       }
-#endif
-       yaffs_ReadChunkFromNAND(dev,blk * dev->nChunksPerBlock + 1,NULL,&spare,1);
-
-#if 1
-       if(yaffs_CountBits(spare.blockStatus) < 7)
-       {
-               return 1;
+               // Handle YAFFS1 forward scanning case
+               // For YAFFS1 we always do the deletion
+               
        }
-#else
-       if(spare.blockStatus != 0xFF)
-       {
-               return 1;
+       else
+       {       // Handle YAFFS2 case (backward scanning)
+               // If the shadowed object exists then ignore.
+               if(yaffs_FindObjectByNumber(dev,objId))
+               {
+                       return;
+               }
        }
-#endif
        
-       return 0;
+       // Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+       // We put it in unlinked dir to be cleaned up after the scanning
+       obj = yaffs_FindOrCreateObjectByNumber(dev,objId,YAFFS_OBJECT_TYPE_FILE);
+       yaffs_AddObjectToDirectory(dev->unlinkedDir,obj);
+       obj->variant.fileVariant.shrinkSize = 0;
+       obj->valid = 1; // So that we don't read any other infor for this file
        
 }
 
-#endif
+
 
 
 typedef struct 
@@ -4677,6 +4221,11 @@ static int yaffs_Scan(yaffs_Device *dev)
                                
                                in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
                                
+                               if(oh->shadowsObject > 0)
+                               {
+                                       yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
+                               }
+                               
                                if(in->valid)
                                {
                                        // We have already filled this one. We have a duplicate and need to resolve it.
@@ -4706,7 +4255,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -4715,12 +4264,12 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -4732,7 +4281,7 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -4741,12 +4290,12 @@ static int yaffs_Scan(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -4881,6 +4430,8 @@ static int yaffs_Scan(yaffs_Device *dev)
                
        }
        
+       // Handle the unlinked files. Since they were left in an unlinked state we should
+       // just delete them.
        {
                struct list_head *i;    
                struct list_head *n;
@@ -4945,10 +4496,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        
        dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
        
-       if(dev->isYaffs2)
-       {
-               blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
-       }
+       blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));               
        
        
        // Scan all the blocks to determine their state
@@ -5006,7 +4554,6 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        
        // Sort the blocks
        // Dungy old bubble sort for now...
-       if(dev->isYaffs2)
        {
                yaffs_BlockIndex temp;
                int i;
@@ -5024,12 +4571,9 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
        
        
        // Now scan the blocks looking at the data.
-       if(dev->isYaffs2)
-       {
-               startIterator = 0;
-               endIterator = nBlocksToScan-1;
-               T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
-       }
+       startIterator = 0;
+       endIterator = nBlocksToScan-1;
+       T(YAFFS_TRACE_SCAN_DEBUG,(TSTR("%d blocks to be scanned" TENDSTR),nBlocksToScan));
 
        
        // For each block.... backwards
@@ -5218,7 +4762,8 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                                        isShrink = 1;
                                                }
                                                                                                
-                                               if(in->variant.fileVariant.shrinkSize > thisSize)
+                                               if(isShrink &&
+                                                  in->variant.fileVariant.shrinkSize > thisSize)
                                                {
                                                        in->variant.fileVariant.shrinkSize = thisSize;
                                                }
@@ -5242,7 +4787,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -5251,12 +4796,12 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
 
@@ -5268,7 +4813,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->valid = 1;
                                        in->variantType = oh->type;
        
-                                       in->st_mode  = oh->st_mode;
+                                       in->yst_mode  = oh->yst_mode;
 #ifdef CONFIG_YAFFS_WINCE
                                        in->win_atime[0] = oh->win_atime[0];
                                        in->win_ctime[0] = oh->win_ctime[0];
@@ -5277,14 +4822,20 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                        in->win_ctime[1] = oh->win_ctime[1];
                                        in->win_mtime[1] = oh->win_mtime[1];
 #else
-                                       in->st_uid   = oh->st_uid;
-                                       in->st_gid   = oh->st_gid;
-                                       in->st_atime = oh->st_atime;
-                                       in->st_mtime = oh->st_mtime;
-                                       in->st_ctime = oh->st_ctime;
-                                       in->st_rdev = oh->st_rdev;
+                                       in->yst_uid   = oh->yst_uid;
+                                       in->yst_gid   = oh->yst_gid;
+                                       in->yst_atime = oh->yst_atime;
+                                       in->yst_mtime = oh->yst_mtime;
+                                       in->yst_ctime = oh->yst_ctime;
+                                       in->yst_rdev = oh->yst_rdev;
 #endif
                                        in->chunkId  = chunk;
+                                       
+                                       if(oh->shadowsObject > 0)
+                                       {
+                                               yaffs_HandleShadowedObject(dev,oh->shadowsObject,1);
+                                       }
+
 
                                        yaffs_SetObjectName(in,oh->name);
                                        in->dirty = 0;
@@ -5338,17 +4889,18 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                                        
                                                        if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
                                                        {
+                                                               // This covers the case where the file size is > than where the data is
+                                                               // This will happen if the file is resized to be larger than its current
+                                                               // data extents.
                                                                in->variant.fileVariant.fileSize = oh->fileSize;
                                                                in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
-                                                       }
-                                                       
-                                                                                                       
+                                                       }                                                                       
                                                        
-                                                       if(in->variant.fileVariant.shrinkSize > oh->fileSize)
+                                                       if(oh->isShrink &&
+                                                          in->variant.fileVariant.shrinkSize > oh->fileSize)
                                                        {
                                                                in->variant.fileVariant.shrinkSize = oh->fileSize;
-                                                       }
-                                                                                                       
+                                                       }                                               
                                                                
                                                        break;
                                                case YAFFS_OBJECT_TYPE_HARDLINK:
@@ -5365,14 +4917,7 @@ static int yaffs_ScanBackwards(yaffs_Device *dev)
                                                        break;
                                        }
 
-#if 0
-                                       if(parent == dev->deletedDir)
-                                       {
-                                               yaffs_DestroyObject(in);
-                                               bi->hasShrinkHeader = 1;
-                                       }
-#endif
-                                       //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
+                               //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
                                }
                        }
                }
@@ -5521,6 +5066,10 @@ yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const YCHAR *name)
        
        yaffs_Object *l;
        
+       if(!name)
+       {
+               return NULL;
+       }
 
        if(!directory)
        {
@@ -5714,10 +5263,10 @@ unsigned yaffs_GetObjectType(yaffs_Object *obj)
                case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
                case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
                case YAFFS_OBJECT_TYPE_SPECIAL:         
-                       if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
-                       if(S_ISCHR(obj->st_mode)) return DT_CHR;
-                       if(S_ISBLK(obj->st_mode)) return DT_BLK;
-                       if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
+                       if(S_ISFIFO(obj->yst_mode)) return DT_FIFO;
+                       if(S_ISCHR(obj->yst_mode)) return DT_CHR;
+                       if(S_ISBLK(obj->yst_mode)) return DT_BLK;
+                       if(S_ISSOCK(obj->yst_mode)) return DT_SOCK;
                default: return DT_REG; break;
        }
 }
@@ -5741,17 +5290,17 @@ int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
 {
        unsigned int valid = attr->ia_valid;
        
-       if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
-       if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
-       if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
+       if(valid & ATTR_MODE) obj->yst_mode = attr->ia_mode;
+       if(valid & ATTR_UID) obj->yst_uid = attr->ia_uid;
+       if(valid & ATTR_GID) obj->yst_gid = attr->ia_gid;
        
-       if(valid & ATTR_ATIME) obj->st_atime = Y_TIME_CONVERT(attr->ia_atime);
-       if(valid & ATTR_CTIME) obj->st_ctime = Y_TIME_CONVERT(attr->ia_ctime);
-       if(valid & ATTR_MTIME) obj->st_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+       if(valid & ATTR_ATIME) obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+       if(valid & ATTR_CTIME) obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+       if(valid & ATTR_MTIME) obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
        
        if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
        
-       yaffs_UpdateObjectHeader(obj,NULL,1,0);
+       yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
        
        return YAFFS_OK;
        
@@ -5760,13 +5309,13 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
 {
        unsigned int valid = 0;
        
-       attr->ia_mode = obj->st_mode;   valid |= ATTR_MODE;
-       attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
-       attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
+       attr->ia_mode = obj->yst_mode;  valid |= ATTR_MODE;
+       attr->ia_uid = obj->yst_uid;            valid |= ATTR_UID;
+       attr->ia_gid = obj->yst_gid;            valid |= ATTR_GID;
        
-       Y_TIME_CONVERT(attr->ia_atime)= obj->st_atime;  valid |= ATTR_ATIME;
-       Y_TIME_CONVERT(attr->ia_ctime) = obj->st_ctime; valid |= ATTR_CTIME;
-       Y_TIME_CONVERT(attr->ia_mtime) = obj->st_mtime; valid |= ATTR_MTIME;
+       Y_TIME_CONVERT(attr->ia_atime)= obj->yst_atime; valid |= ATTR_ATIME;
+       Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;        valid |= ATTR_CTIME;
+       Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;        valid |= ATTR_MTIME;
 
        attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
        
@@ -5797,24 +5346,7 @@ int yaffs_DumpObject(yaffs_Object *obj)
                        obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, 
                        obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
 
-#if 0
-       YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
-                       obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial, 
-                       obj->sum, obj->chunkId));
-               switch(obj->variantType)
-       {
-               case YAFFS_OBJECT_TYPE_FILE: 
-                       YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
-                       break;
-               case YAFFS_OBJECT_TYPE_DIRECTORY:
-                       YPRINTF((" DIRECTORY\n"));
-                       break;
-               case YAFFS_OBJECT_TYPE_HARDLINK: //todo
-               case YAFFS_OBJECT_TYPE_SYMLINK:
-               case YAFFS_OBJECT_TYPE_UNKNOWN:
-               default:
-       }
-#endif
+
        
        return YAFFS_OK;
 }
@@ -5823,7 +5355,7 @@ int yaffs_DumpObject(yaffs_Object *obj)
 ///////////////////////// Initialisation code ///////////////////////////
 
 
-int yaffs_CheckDevFunctions(const yaffs_Device *dev)
+static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
 {
 
        // Common functions, gotta have
@@ -5874,6 +5406,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->internalEndBlock =  dev->endBlock;
        dev->blockOffset = 0;
        dev->chunkOffset = 0;
+       dev->nFreeChunks = 0;
        
        if(dev->startBlock == 0)
        {
@@ -5997,6 +5530,7 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        dev->tagsEccUnfixed=0;
        dev->nErasureFailures = 0;
        dev->nErasedBlocks = 0;
+       dev->isDoingGC = 0;
        
        //dev->localBuffer = YMALLOC(dev->nBytesPerChunk);
        // Initialise temporary buffers
@@ -6067,12 +5601,14 @@ int yaffs_GutsInitialise(yaffs_Device *dev)
        
        // Zero out stats
        dev->nPageReads = 0;
-    dev->nPageWrites =  0;
+       dev->nPageWrites =  0;
        dev->nBlockErasures = 0;
        dev->nGCCopies = 0;
        dev->nRetriedWrites = 0;
 
        dev->nRetiredBlocks = 0;
+       
+       yaffs_VerifyFreeChunks(dev);
 
        T(YAFFS_TRACE_ALWAYS,(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
        return YAFFS_OK;
@@ -6111,49 +5647,14 @@ void yaffs_Deinitialise(yaffs_Device *dev)
        
 }
 
-#if 0
 
-int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
-{
-       int nFree = dev->nFreeChunks - (dev->nChunksPerBlock * YAFFS_RESERVED_BLOCKS);
-       
-       struct list_head *i;    
-       yaffs_Object *l;
-       
-       
-       // To the free chunks add the chunks that are in the deleted unlinked files.
-       list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
-       {
-               l = list_entry(i, yaffs_Object,siblings);
-               if(l->deleted)
-               {
-                       nFree++;
-                       nFree += l->nDataChunks;
-               }
-       }
-       
-       
-       // printf("___________ nFreeChunks is %d nFree is %d\n",dev->nFreeChunks,nFree);        
-
-       if(nFree < 0) nFree = 0;
-
-       return nFree;   
-       
-}
-
-#endif
-
-int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+static int  yaffs_CountFreeChunks(yaffs_Device *dev)
 {
        int nFree;
-       int pending;
        int b;
-       int nDirtyCacheChunks=0;
-       
-       yaffs_BlockInfo *blk;
-       
-       struct list_head *i;    
-       yaffs_Object *l;
+
+       yaffs_BlockInfo *blk;   
+
        
        for(nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock; b++)
        {
@@ -6163,44 +5664,36 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
                {
                        case YAFFS_BLOCK_STATE_EMPTY:
                        case YAFFS_BLOCK_STATE_ALLOCATING: 
-                       case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse); break;
+                       case YAFFS_BLOCK_STATE_COLLECTING:
+                       case YAFFS_BLOCK_STATE_FULL: nFree += (dev->nChunksPerBlock - blk->pagesInUse + blk->softDeletions); break;
                        default: break;
                }
+
        }
        
+       return nFree;
+}      
        
-       pending = 0;
-       
-       // To the free chunks add the chunks that are in the deleted unlinked files.
-       list_for_each(i,&dev->deletedDir->variant.directoryVariant.children)
-       {
-               if(i)
-               {
-                       l = list_entry(i, yaffs_Object,siblings);
-                       if(l->deleted)
-                       {
-                               pending++;
-                               pending += l->nDataChunks;
-                       }
-               }
-       }
-       
-       
-       
-       //printf("___________ really free is %d, pending %d, nFree is %d\n",nFree,pending, nFree+pending);
-       
-       if(nFree != dev->nFreeChunks) 
-       {
-       //      printf("___________Different! really free is %d, nFreeChunks %d\n",nFree dev->nFreeChunks);
-       }
 
-       nFree += pending;
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+{
+       // This is what we report to the outside world
+
+       int nFree;
+       int nDirtyCacheChunks;
+               
+#if 1  
+       nFree = dev->nFreeChunks;
+#else
+       nFree = yaffs_CountFreeChunks(dev);
+#endif
        
        // Now count the number of dirty chunks in the cache and subtract those
        
        {
                int i;
-               for(i = 0; i < dev->nShortOpCaches; i++)
+               for( nDirtyCacheChunks = 0,i = 0; i < dev->nShortOpCaches; i++)
                {
                        if(dev->srCache[i].dirty) nDirtyCacheChunks++;
                }
@@ -6216,7 +5709,20 @@ int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
        
 }
 
+static int  yaffs_freeVerificationFailures;
 
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
+{
+       int counted = yaffs_CountFreeChunks(dev);
+       
+       int difference = dev->nFreeChunks - counted;
+       
+       if(difference)
+       {
+               T(YAFFS_TRACE_ALWAYS,(TSTR("Freechunks verification failure %d %d %d" TENDSTR),dev->nFreeChunks,counted,difference)); 
+               yaffs_freeVerificationFailures++;       
+       }
+}
 
 /////////////////// YAFFS test code //////////////////////////////////
 
@@ -6242,19 +5748,6 @@ static int yaffs_CheckStructures(void)
        return YAFFS_OK;
 }
 
-#if 0
-void yaffs_GutsTest(yaffs_Device *dev)
-{
-       
-       if(yaffs_CheckStructures() != YAFFS_OK)
-       {
-               T(YAFFS_TRACE_ALWAYS,(TSTR("One or more structures malformed-- aborting\n" TENDSTR)));
-               return;
-       }
-       
-       yaffs_TnodeTest(dev);
-       yaffs_ObjectTest(dev);  
-}
-#endif
+