*** empty log message ***
[yaffs/.git] / yaffs_guts.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.
3  * yaffs_guts.c  The main guts of YAFFS
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15  //yaffs_guts.c
16
17 const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.11 2002-10-02 02:11:25 charles Exp $";
18
19 #include "yportenv.h"
20
21 #include "yaffsinterface.h"
22 #include "yaffs_guts.h"
23
24
25 #define YAFFS_GARBAGE_COLLECT_LOW_WATER 2
26
27
28 // External functions for ECC on data
29 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
30 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
31
32
33 // countBits is a quick way of counting the number of bits in a byte.
34 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
35
36 static const char yaffs_countBitsTable[256] =
37 {
38 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
39 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
40 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
41 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
42 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
43 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
44 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
45 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
46 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
47 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
48 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
49 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
50 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
51 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
52 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
53 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
54 };
55
56 static int yaffs_CountBits(__u8 x)
57 {
58         int retVal;
59         retVal = yaffs_countBitsTable[x];
60         return retVal;
61 }
62
63
64
65 // Local prototypes
66 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
67 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
68 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
69 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
70
71 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
72 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
73 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force);
74 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);
75 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
76 static int yaffs_CheckStructures(void);
77 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
78 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
79
80 static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev,int blockNo);
81
82 // Robustification
83 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND);
84 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND);
85 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND);
86 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare);
87 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare);
88
89 static int  yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND);
90
91 static int yaffs_UnlinkWorker(yaffs_Object *obj);
92
93
94 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1);
95
96
97
98 loff_t yaffs_GetFileSize(yaffs_Object *obj);
99
100 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted);
101 static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted);
102
103
104 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
105
106 #ifdef YAFFS_PARANOID
107 static int yaffs_CheckFileSanity(yaffs_Object *in);
108 #else
109 #define yaffs_CheckFileSanity(in)
110 #endif
111
112 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
113 static void yaffs_InvalidateChunkCache(yaffs_Device *dev, int objectId, int chunkId);
114
115
116 static  __inline__ yaffs_BlockInfo* yaffs_GetBlockInfo(yaffs_Device *dev, int blk)
117 {
118         if(blk < dev->startBlock || blk > dev->endBlock)
119         {
120                 YBUG();
121         }
122         return &dev->blockInfo[blk - dev->startBlock];
123 }
124
125
126 static  __inline__ int yaffs_HashFunction(int n)
127 {
128         return (n % YAFFS_NOBJECT_BUCKETS);
129 }
130
131
132 yaffs_Object *yaffs_Root(yaffs_Device *dev)
133 {
134         return dev->rootDir;
135 }
136
137 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
138 {
139         return dev->lostNFoundDir;
140 }
141
142
143 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
144 {
145         dev->nPageWrites++;
146         return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
147 }
148
149
150 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare,int doErrorCorrection)
151 {
152         int retVal;
153         __u8 calcEcc[3];
154         yaffs_Spare localSpare;
155         int eccResult1,eccResult2;
156         
157         dev->nPageReads++;
158         
159         if(!spare && data)
160         {
161                 // If we don't have a real spare, then we use a local one.
162                 // Need this for the calculation of the ecc
163                 spare = &localSpare;
164         }
165         
166         retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
167         if(data && doErrorCorrection)
168         {
169                 // Do ECC correction
170                 //Todo handle any errors
171                  nand_calculate_ecc(data,calcEcc);
172                  eccResult1 = nand_correct_data (data,spare->ecc1, calcEcc);
173                  nand_calculate_ecc(&data[256],calcEcc);
174                  eccResult2 = nand_correct_data (&data[256],spare->ecc2, calcEcc);
175                  
176                  if(eccResult1>0)
177                  {
178                         T((TSTR("**>>ecc error fix performed on chunk %d:0" TENDSTR),chunkInNAND));
179                         dev->eccFixed++;
180                  }
181                  else if(eccResult1<0)
182                  {
183                         T((TSTR("**>>ecc error unfixed on chunk %d:0" TENDSTR),chunkInNAND));
184                         dev->eccUnfixed++;
185                  }
186                  
187                  if(eccResult2>0)
188                  {
189                         T((TSTR("**>>ecc error fix performed on chunk %d:1" TENDSTR),chunkInNAND));
190                         dev->eccFixed++;
191                  }
192                  else if(eccResult2<0)
193                  {
194                         T((TSTR("**>>ecc error unfixed on chunk %d:1" TENDSTR),chunkInNAND));
195                         dev->eccUnfixed++;
196                  }
197                  
198                  if(eccResult1 || eccResult2)
199                  {
200                         // Hoosterman, we had a data problem on this page
201                         yaffs_HandleReadDataError(dev,chunkInNAND);
202                  }
203         }
204         return retVal;
205 }
206
207
208 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
209 {
210
211         static int init = 0;
212         static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
213         static __u8 data[YAFFS_BYTES_PER_CHUNK];
214         static __u8 spare[16];
215         
216         
217         dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
218         
219         
220         
221         if(!init)
222         {
223                 memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK);
224                 init = 1;
225         }
226         
227         if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) return  YAFFS_FAIL;
228         if(memcmp(cmpbuf,spare,16)) return YAFFS_FAIL;
229
230         
231         return YAFFS_OK;
232         
233 }
234
235
236
237 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
238 {
239         dev->nBlockErasures++;
240         return dev->eraseBlockInNAND(dev,blockInNAND);
241 }
242
243 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
244 {
245         return dev->initialiseNAND(dev);
246 }
247
248 static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve)
249 {
250         int chunk;
251         
252         int writeOk = 1;
253         int attempts = 0;
254         
255         unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
256         yaffs_Spare rbSpare;
257         
258         do{
259                 chunk = yaffs_AllocateChunk(dev,useReserve);
260         
261                 if(chunk >= 0)
262                 {
263
264                         // First check this chunk is erased...
265 #ifndef CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
266                         writeOk = yaffs_CheckChunkErased(dev,chunk);
267 #endif          
268                         if(!writeOk)
269                         {
270                                 T((TSTR("**>> yaffs chunk %d was not erased" TENDSTR),chunk));
271                         }
272                         else
273                         {
274                                 writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);
275                         }
276                         attempts++;
277                         if(writeOk)
278                         {
279                                 // Readback & verify
280                                 // If verify fails, then delete this chunk and try again
281                                 // To verify we compare everything except the block and 
282                                 // page status bytes.
283                                 // NB We check a raw read without ECC correction applied
284                                 yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare,0);
285                                 
286 #ifndef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
287                                 if(!yaffs_VerifyCompare(data,rbData,spare,&rbSpare))
288                                                         {
289                                         // Didn't verify
290                                         T((TSTR("**>> yaffs write verify failed on chunk %d" TENDSTR), chunk));
291
292                                         writeOk = 0;
293                                 }       
294 #endif                          
295                                 
296                         }
297                         if(writeOk)
298                         {
299                                 // Copy the data into the write buffer.
300                                 // NB We do this at the end to prevent duplicates in the case of a write error.
301                                 //Todo
302                                 yaffs_HandleWriteChunkOk(dev,chunk,data,spare);
303                         }
304                         else
305                         {
306                                 yaffs_HandleWriteChunkError(dev,chunk);
307                         }
308                 }
309                 
310         } while(chunk >= 0 && ! writeOk);
311         
312         if(attempts > 1)
313         {
314                 T((TSTR("**>> yaffs write required %d attempts" TENDSTR),attempts));
315                 dev->nRetriedWrites+= (attempts - 1);   
316         }
317         
318         return chunk;
319 }
320
321 ///
322 // Functions for robustisizing
323 //
324 //
325
326 static void yaffs_RetireBlock(yaffs_Device *dev,int blockInNAND)
327 {
328         // Ding the blockStatus in the first two pages of the block.
329         
330         yaffs_Spare spare;
331
332         memset(&spare, 0xff,sizeof(yaffs_Spare));
333
334         spare.blockStatus = 0;
335         
336         yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK, NULL , &spare);
337         yaffs_WriteChunkToNAND(dev, blockInNAND * YAFFS_CHUNKS_PER_BLOCK + 1, NULL , &spare);
338         
339         yaffs_GetBlockInfo(dev,blockInNAND)->blockState = YAFFS_BLOCK_STATE_DEAD;
340         dev->nRetiredBlocks++;
341 }
342
343
344
345 static int yaffs_RewriteBufferedBlock(yaffs_Device *dev)
346 {
347         dev->doingBufferedBlockRewrite = 1;
348         //
349         //      Remove erased chunks
350         //  Rewrite existing chunks to a new block
351         //      Set current write block to the new block
352         
353         dev->doingBufferedBlockRewrite = 0;
354         
355         return 1;
356 }
357
358
359 static void yaffs_HandleReadDataError(yaffs_Device *dev,int chunkInNAND)
360 {
361         int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;
362
363         // Mark the block for retirement
364         yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
365         T((TSTR("**>>Block %d marked for retirement" TENDSTR),blockInNAND));
366
367
368         //TODO  
369         // Just do a garbage collection on the affected block then retire the block
370         // NB recursion
371 }
372
373
374 static void yaffs_CheckWrittenBlock(yaffs_Device *dev,int chunkInNAND)
375 {
376 }
377
378 static void yaffs_HandleWriteChunkOk(yaffs_Device *dev,int chunkInNAND,const __u8 *data, const yaffs_Spare *spare)
379 {
380 }
381
382 static void yaffs_HandleUpdateChunk(yaffs_Device *dev,int chunkInNAND, const yaffs_Spare *spare)
383 {
384 }
385
386 static void yaffs_HandleWriteChunkError(yaffs_Device *dev,int chunkInNAND)
387 {
388         int blockInNAND = chunkInNAND/YAFFS_CHUNKS_PER_BLOCK;
389
390         // Mark the block for retirement
391         yaffs_GetBlockInfo(dev,blockInNAND)->needsRetiring = 1;
392         // Delete the chunk
393         yaffs_DeleteChunk(dev,chunkInNAND);
394 }
395
396
397
398
399 static int yaffs_VerifyCompare(const __u8 *d0, const __u8 * d1, const yaffs_Spare *s0, const yaffs_Spare *s1)
400 {
401
402
403         if( memcmp(d0,d1,YAFFS_BYTES_PER_CHUNK) != 0 ||
404                 s0->tagByte0 != s1->tagByte0 ||
405                 s0->tagByte1 != s1->tagByte1 ||
406                 s0->tagByte2 != s1->tagByte2 ||
407                 s0->tagByte3 != s1->tagByte3 ||
408                 s0->tagByte4 != s1->tagByte4 ||
409                 s0->tagByte5 != s1->tagByte5 ||
410                 s0->tagByte6 != s1->tagByte6 ||
411                 s0->tagByte7 != s1->tagByte7 ||
412                 s0->ecc1[0]  != s1->ecc1[0]  ||
413                 s0->ecc1[1]  != s1->ecc1[1]  ||
414                 s0->ecc1[2]  != s1->ecc1[2]  ||
415                 s0->ecc2[0]  != s1->ecc2[0]  ||
416                 s0->ecc2[1]  != s1->ecc2[1]  ||
417                 s0->ecc2[2]  != s1->ecc2[2] )
418                 {
419                         return 0;
420                 }
421         
422         return 1;
423 }
424
425
426 ///////////////////////// Object management //////////////////
427 // List of spare objects
428 // The list is hooked together using the first pointer
429 // in the object
430
431 // static yaffs_Object *yaffs_freeObjects = NULL;
432
433 // static int yaffs_nFreeObjects;
434
435 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
436
437 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
438
439
440 static __u16 yaffs_CalcNameSum(const char *name)
441 {
442         __u16 sum = 0;
443         __u16 i = 1;
444         
445         __u8 *bname = (__u8 *)name;
446         if(bname)
447         {
448                 while (*bname)
449                 {
450                         sum += (*bname) * i;
451                         i++;
452                         bname++;
453                 }
454         }
455         return sum;
456 }
457
458
459 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
460 {
461         nand_calculate_ecc (data , spare->ecc1);
462         nand_calculate_ecc (&data[256] , spare->ecc2);
463 }
464
465 void yaffs_CalcTagsECC(yaffs_Tags *tags)
466 {
467         // Calculate an ecc
468         
469         unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
470         unsigned  i,j;
471         unsigned  ecc = 0;
472         unsigned bit = 0;
473
474         tags->ecc = 0;
475         
476         for(i = 0; i < 8; i++)
477         {
478                 for(j = 1; j &0xff; j<<=1)
479                 {
480                         bit++;
481                         if(b[i] & j)
482                         {
483                                 ecc ^= bit;
484                         }
485                 }
486         }
487         
488         tags->ecc = ecc;
489         
490         
491 }
492
493 int  yaffs_CheckECCOnTags(yaffs_Tags *tags)
494 {
495         unsigned ecc = tags->ecc;
496         
497         yaffs_CalcTagsECC(tags);
498         
499         ecc ^= tags->ecc;
500         
501         if(ecc && ecc <= 64)
502         {
503                 // TODO: Handle the failure better. Retire?
504                 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
505
506                 ecc--;
507                                 
508                 b[ecc / 8] ^= (1 << (ecc & 7));
509                 
510                 // Now recvalc the ecc
511                 yaffs_CalcTagsECC(tags);
512                 
513                 return 1; // recovered error
514         }
515         else if(ecc)
516         {
517                 // Wierd ecc failure value
518                 // TODO Need to do somethiong here
519                 return -1; //unrecovered error
520         }
521         
522         return 0;
523 }
524
525
526 ///////////////////////// TNODES ///////////////////////
527
528 // List of spare tnodes
529 // The list is hooked together using the first pointer
530 // in the tnode.
531
532 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
533
534 // static int yaffs_nFreeTnodes;
535
536 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
537
538
539
540 // yaffs_CreateTnodes creates a bunch more tnodes and
541 // adds them to the tnode free list.
542 // Don't use this function directly
543
544 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
545 {
546     int i;
547     yaffs_Tnode *newTnodes;
548     yaffs_TnodeList *tnl;
549     
550     if(nTnodes < 1) return YAFFS_OK;
551    
552         // make these things
553         
554     newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
555    
556     if (!newTnodes)
557     {
558                 YALERT("Could not malloc tnodes");
559                 return YAFFS_FAIL;
560     }
561     
562     // Hook them into the free list
563     for(i = 0; i < nTnodes - 1; i++)
564     {
565         newTnodes[i].internal[0] = &newTnodes[i+1];
566     }
567         
568         newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
569         dev->freeTnodes = newTnodes;
570         dev->nFreeTnodes+= nTnodes;
571         dev->nTnodesCreated += nTnodes;
572
573         // Now add this bunch of tnodes to a list for freeing up.
574
575         tnl = YMALLOC(sizeof(yaffs_TnodeList));
576         if(!tnl)
577         {
578                 YALERT("Could not add tnodes to management list");
579         }
580         else
581         {
582                 tnl->tnodes = newTnodes;
583                 tnl->next = dev->allocatedTnodeList;
584                 dev->allocatedTnodeList = tnl;
585         }
586
587
588         YINFO("Tnodes created");
589
590
591         return YAFFS_OK;
592 }
593
594
595 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
596 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
597 {
598         yaffs_Tnode *tn = NULL;
599         
600         // If there are none left make more
601         if(!dev->freeTnodes)
602         {
603                 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
604         }
605         
606         if(dev->freeTnodes)
607         {
608                 tn = dev->freeTnodes;
609                 dev->freeTnodes = dev->freeTnodes->internal[0];
610                 dev->nFreeTnodes--;
611                 // zero out
612                 memset(tn,0,sizeof(yaffs_Tnode));
613         }
614         
615
616         return tn;
617 }
618
619
620 // FreeTnode frees up a tnode and puts it back on the free list
621 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
622 {
623         tn->internal[0] = dev->freeTnodes;
624         dev->freeTnodes = tn;
625         dev->nFreeTnodes++;
626 }
627
628
629 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
630 {
631         // Free the list of allocated tnodes
632         
633         while(dev->allocatedTnodeList)
634         {
635                 YFREE(dev->allocatedTnodeList->tnodes);
636                 dev->allocatedTnodeList =  dev->allocatedTnodeList->next;
637         }
638         
639         dev->freeTnodes = NULL;
640         dev->nFreeTnodes = 0;
641 }
642
643 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
644 {
645         dev->allocatedTnodeList = NULL;
646         dev->freeTnodes = NULL;
647         dev->nFreeTnodes = 0;
648         dev->nTnodesCreated = 0;
649
650 }
651
652 void yaffs_TnodeTest(yaffs_Device *dev)
653 {
654
655         int i;
656         int j;
657         yaffs_Tnode *tn[1000];
658         
659         YINFO("Testing TNodes");
660         
661         for(j = 0; j < 50; j++)
662         {
663                 for(i = 0; i < 1000; i++)
664                 {
665                         tn[i] = yaffs_GetTnode(dev);
666                         if(!tn[i])
667                         {
668                                 YALERT("Getting tnode failed");
669                         }
670                 }
671                 for(i = 0; i < 1000; i+=3)
672                 {
673                         yaffs_FreeTnode(dev,tn[i]);
674                         tn[i] = NULL;
675                 }
676                 
677         }
678 }
679
680 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
681
682 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
683 // The look up tree is represented by the top tnode and the number of topLevel
684 // in the tree. 0 means only the level 0 tnode is in the tree.
685
686
687 // FindLevel0Tnode finds the level 0 tnode, if one exists.
688 // Used when reading.....
689 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
690 {
691         
692         yaffs_Tnode *tn = fStruct->top;
693         __u32 i;
694         int requiredTallness;   
695         int level = fStruct->topLevel;
696         
697         // Check sane level and chunk Id
698         if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
699         {
700                 char str[50];
701                 sprintf(str,"Bad level %d",level);
702                 YALERT(str);
703                 return NULL;
704         }
705         
706         if(chunkId > YAFFS_MAX_CHUNK_ID)
707         {
708                 char str[50];
709                 sprintf(str,"Bad chunkId %d",chunkId);
710                 YALERT(str);
711                 return NULL;
712         }
713
714         // First check we're tall enough (ie enough topLevel)
715         
716         i = chunkId >> (/*dev->chunkGroupBits  + */YAFFS_TNODES_LEVEL0_BITS);
717         requiredTallness = 0;
718         while(i)
719         {
720                 i >>= YAFFS_TNODES_INTERNAL_BITS;
721                 requiredTallness++;
722         }
723         
724         
725         if(requiredTallness > fStruct->topLevel)
726         {
727                 // Not tall enough, so we can't find it, return NULL.
728                 return NULL;
729         }
730                 
731         
732         // Traverse down to level 0
733         while (level > 0 && tn)
734         {
735             tn = tn->internal[(chunkId >>(/* dev->chunkGroupBits + */ YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
736                                YAFFS_TNODES_INTERNAL_MASK]; 
737                 level--;
738         
739         }
740         
741         return tn;              
742 }
743
744 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
745 // This happens in two steps:
746 //  1. If the tree isn't tall enough, then make it taller.
747 //  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
748 //
749 // Used when modifying the tree.
750 //
751 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
752 {
753         
754         yaffs_Tnode *tn; 
755         
756         int requiredTallness;
757         
758         __u32 i;
759         __u32 l;
760         
761         
762         //T((TSTR("AddOrFind topLevel=%d, chunk=%d"),fStruct->topLevel,chunkId));
763         
764         // Check sane level and page Id
765         if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
766         {
767                 char str[50];
768                 sprintf(str,"Bad level %d",fStruct->topLevel);
769                 YALERT(str);
770                 return NULL;
771         }
772         
773         if(chunkId > YAFFS_MAX_CHUNK_ID)
774         {
775                 char str[50];
776                 sprintf(str,"Bad chunkId %d",chunkId);
777                 YALERT(str);
778                 return NULL;
779         }
780         
781         // First check we're tall enough (ie enough topLevel)
782         
783         i = chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS);
784         requiredTallness = 0;
785         while(i)
786         {
787                 i >>= YAFFS_TNODES_INTERNAL_BITS;
788                 requiredTallness++;
789         }
790         
791         //T((TSTR(" required=%d"),requiredTallness));
792         
793         
794         if(requiredTallness > fStruct->topLevel)
795         {
796                 // Not tall enough,gotta make the tree taller
797                 for(i = fStruct->topLevel; i < requiredTallness; i++)
798                 {
799                         //T((TSTR(" add new top")));
800                         
801                         tn = yaffs_GetTnode(dev);
802                         
803                         if(tn)
804                         {
805                                 tn->internal[0] = fStruct->top;
806                                 fStruct->top = tn;
807                         }
808                         else
809                         {
810                                 YALERT("No more tnodes");
811                         }
812                 }
813                 
814                 fStruct->topLevel = requiredTallness;
815         }
816         
817         
818         // Traverse down to level 0, adding anything we need
819         
820         l = fStruct->topLevel;
821         tn = fStruct->top;
822         while (l > 0 && tn)
823         {
824                 i = (chunkId >> (/*dev->chunkGroupBits + */YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
825                                YAFFS_TNODES_INTERNAL_MASK;
826                                
827                 //T((TSTR(" [%d:%d]"),l,i));
828                 
829             if(!tn->internal[i])
830             {
831                 //T((TSTR(" added")));
832                 
833                 tn->internal[i] = yaffs_GetTnode(dev);
834             }
835             
836             tn =        tn->internal[i];
837                 l--;
838         
839         }
840         
841         //TSTR(TENDSTR)));
842         
843         return tn;              
844 }
845
846 // DeleteWorker scans backwards through the tnode tree and deletes all the
847 // chunks and tnodes in the file
848 // Returns 1 if the tree was deleted. Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
849
850 static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit)
851 {
852         int i;
853         int chunkInInode;
854         int theChunk;
855         yaffs_Tags tags;
856         int found;
857         int chunkDeleted;
858         int allDone = 1;
859         
860         
861         if(tn)
862         {
863                 if(level > 0)
864                 {
865                 
866                         for(i = YAFFS_NTNODES_INTERNAL -1; allDone && i >= 0; i--)
867                         {
868                             if(tn->internal[i])
869                         {
870                                         if(limit && (*limit) < 0)
871                                         {
872                                                 allDone = 0;
873                                         }
874                                         else
875                                         {
876                                                 allDone = yaffs_DeleteWorker(in,tn->internal[i],level - 1,
877                                                                                 (chunkOffset << YAFFS_TNODES_INTERNAL_BITS ) + i ,limit);
878                                         }
879                                         if(allDone)
880                                         {
881                                                 yaffs_FreeTnode(in->myDev,tn->internal[i]);
882                                         tn->internal[i] = NULL;
883                                         }
884                             }
885                     
886                         }
887                         return (allDone) ? 1 : 0;
888                 }
889                 else if(level == 0)
890                 {
891                         for(i = YAFFS_NTNODES_LEVEL0 -1; i >= 0; i--) //NB Don't apply the limit here, always delete a whole level0
892                         {
893                             if(tn->level0[i])
894                         {
895                                         int j;
896                                         
897                                         chunkInInode = (chunkOffset << YAFFS_TNODES_LEVEL0_BITS ) + i;
898                                         
899                                         theChunk =  tn->level0[i] << in->myDev->chunkGroupBits;
900
901                                         // Now we need to search for it
902                                         for(j = 0,found = 0; theChunk && j < in->myDev->chunkGroupSize && !found; j++)
903                                         {
904                                                 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,&tags,&chunkDeleted);
905                                                 if(yaffs_TagsMatch(&tags,in->objectId,chunkInInode,chunkDeleted))
906                                                 {
907                                                         // found it;
908                                                         found = 1;
909                                         
910                                                 }
911                                                 else
912                                                 {
913                                                         theChunk++;
914                                                 }
915                                         }
916                                         
917                                         if(found)
918                                         {
919                                                 yaffs_DeleteChunk(in->myDev,theChunk);
920                                                 in->nDataChunks--;
921                                                 if(limit)
922                                                 { 
923                                                         *limit = *limit-1;
924                                                 }
925                                         
926                                         }
927                                         
928                                 tn->level0[i] = 0;
929                             }
930                     
931                         }
932                         return 1;
933
934                         
935                 }
936                 
937         }
938         
939         return 1;
940         
941 }
942
943
944
945
946 // Pruning removes any part of the file structure tree that is beyond the
947 // bounds of the file (ie that does not point to chunks).
948 //
949 // A file should only get pruned when its size is reduced.
950 //
951 // Before pruning, the chunks must be pulled from the tree and the
952 // level 0 tnode entries must be zeroed out.
953 // Could also use this for file deletion, but that's probably better handled
954 // by a special case.
955
956 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
957
958 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
959 {
960         int i;
961         int hasData;
962         
963         if(tn)
964         {
965                 hasData = 0;
966                 
967                 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
968                 {
969                     if(tn->internal[i] && level > 0)
970                     {
971                         tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
972                     }
973                     
974                     if(tn->internal[i])
975                     {
976                         hasData++;
977                         }
978                 }
979                 
980                 if(hasData == 0 && del0)
981                 {
982                         // Free and return NULL
983                         
984                         yaffs_FreeTnode(dev,tn);
985                         tn = NULL;
986                 }
987                 
988         }
989
990         return tn;
991         
992 }
993
994 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
995 {
996         int i;
997         int hasData;
998         int done = 0;
999         yaffs_Tnode *tn;
1000         
1001         if(fStruct->topLevel > 0)
1002         {
1003                 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
1004                 
1005                 // Now we have a tree with all the non-zero branches NULL but the height
1006                 // is the same as it was.
1007                 // Let's see if we can trim internal tnodes to shorten the tree.
1008                 // We can do this if only the 0th element in the tnode is in use 
1009                 // (ie all the non-zero are NULL)
1010                 
1011                 while(fStruct->topLevel && !done)
1012                 {
1013                         tn = fStruct->top;
1014                         
1015                         hasData = 0;
1016                         for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
1017                         {
1018                                 if(tn->internal[i])
1019                         {
1020                                 hasData++;
1021                                 }
1022                         }
1023                         
1024                         if(!hasData)
1025                         {
1026                                 fStruct->top = tn->internal[0];
1027                                 fStruct->topLevel--;
1028                                 yaffs_FreeTnode(dev,tn);
1029                         }
1030                         else
1031                         {
1032                                 done = 1;
1033                         }
1034                 }
1035         }
1036         
1037         return YAFFS_OK;
1038 }
1039
1040
1041
1042
1043 /////////////////////// End of File Structure functions. /////////////////
1044
1045 // yaffs_CreateFreeObjects creates a bunch more objects and
1046 // adds them to the object free list.
1047 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
1048 {
1049     int i;
1050     yaffs_Object *newObjects;
1051     yaffs_ObjectList *list;
1052     
1053     if(nObjects < 1) return YAFFS_OK;
1054    
1055         // make these things
1056         
1057     newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
1058    
1059     if (!newObjects)
1060     {
1061                 YALERT("Could not allocate more objects");
1062                 return YAFFS_FAIL;
1063     }
1064     
1065     // Hook them into the free list
1066     for(i = 0; i < nObjects - 1; i++)
1067     {
1068         (yaffs_Object *)newObjects[i].siblings.next = &newObjects[i+1];
1069     }
1070         
1071         newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
1072         dev->freeObjects = newObjects;
1073         dev->nFreeObjects+= nObjects;
1074         dev->nObjectsCreated+= nObjects;
1075         
1076         // Now add this bunch of Objects to a list for freeing up.
1077         
1078         list = YMALLOC(sizeof(yaffs_ObjectList));
1079         if(!list)
1080         {
1081                 YALERT("Could not add Objects to management list");
1082         }
1083         else
1084         {
1085                 list->objects = newObjects;
1086                 list->next = dev->allocatedObjectList;
1087                 dev->allocatedObjectList = list;
1088         }
1089         
1090         
1091         YINFO("Objects created");
1092         
1093         
1094         return YAFFS_OK;
1095 }
1096
1097
1098 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
1099 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
1100 {
1101         yaffs_Object *tn = NULL;
1102         
1103         // If there are none left make more
1104         if(!dev->freeObjects)
1105         {
1106                 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
1107         }
1108         
1109         if(dev->freeObjects)
1110         {
1111                 tn = dev->freeObjects;
1112                 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
1113                 dev->nFreeObjects--;
1114                 
1115                 // Now sweeten it up...
1116         
1117                 memset(tn,0,sizeof(yaffs_Object));
1118                 tn->myDev = dev;
1119                 tn->chunkId = -1;
1120                 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
1121                 INIT_LIST_HEAD(&(tn->hardLinks));
1122                 INIT_LIST_HEAD(&(tn->hashLink));
1123                 INIT_LIST_HEAD(&tn->siblings);
1124                 
1125                 // Add it to the lost and found directory.
1126                 // NB Can't put root or lostNFound in lostNFound so
1127                 // check if lostNFound exists first
1128                 if(dev->lostNFoundDir)
1129                 {
1130                         yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);      
1131                 }
1132         }
1133         
1134
1135         return tn;
1136 }
1137
1138 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
1139 {
1140
1141         yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);              
1142         if(obj)
1143         {
1144                 obj->fake = 1;                  // it is fake so it has no NAND presence...
1145                 obj->renameAllowed= 0;  // ... and we're not allowed to rename it...
1146                 obj->unlinkAllowed= 0;  // ... or unlink it
1147                 obj->deleted = 0;
1148                 obj->unlinked = 0;
1149                 obj->st_mode = mode;
1150                 obj->myDev = dev;
1151                 obj->chunkId = 0; // Not a valid chunk.
1152         }
1153         
1154         return obj;
1155         
1156 }
1157
1158
1159 static void yaffs_UnhashObject(yaffs_Object *tn)
1160 {
1161         int bucket;
1162         yaffs_Device *dev = tn->myDev;
1163         
1164         
1165         // If it is still linked into the bucket list, free from the list
1166         if(!list_empty(&tn->hashLink))
1167         {
1168                 list_del_init(&tn->hashLink);
1169                 bucket =  yaffs_HashFunction(tn->objectId);
1170                 dev->objectBucket[bucket].count--;
1171         }
1172         
1173 }
1174
1175
1176 // FreeObject frees up a Object and puts it back on the free list
1177 static void yaffs_FreeObject(yaffs_Object *tn)
1178 {
1179
1180         yaffs_Device *dev = tn->myDev;
1181         
1182         yaffs_UnhashObject(tn);
1183         
1184         // Link into the free list.
1185         (yaffs_Object *)(tn->siblings.next) = dev->freeObjects;
1186         dev->freeObjects = tn;
1187         dev->nFreeObjects++;
1188 }
1189
1190
1191
1192
1193 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
1194 {
1195         // Free the list of allocated Objects
1196         
1197         while( dev->allocatedObjectList)
1198         {
1199                 YFREE(dev->allocatedObjectList->objects);
1200                 dev->allocatedObjectList =  dev->allocatedObjectList->next;
1201         }
1202         
1203         dev->freeObjects = NULL;
1204         dev->nFreeObjects = 0;
1205 }
1206
1207 static void yaffs_InitialiseObjects(yaffs_Device *dev)
1208 {
1209         int i;
1210         
1211         dev->allocatedObjectList = NULL;
1212         dev->freeObjects = NULL;
1213         dev->nFreeObjects = 0;
1214         
1215         for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
1216         {
1217                 INIT_LIST_HEAD(&dev->objectBucket[i].list);
1218                 dev->objectBucket[i].count = 0; 
1219         }
1220
1221 }
1222
1223
1224
1225
1226
1227
1228 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
1229 {
1230         static int x = 0;
1231         int i;
1232         int l = 999;
1233         int lowest = 999999;
1234
1235                 
1236         // First let's see if we can find one that's empty.
1237         
1238         for(i = 0; i < 10 && lowest > 0; i++)
1239          {
1240                 x++;
1241                 x %=  YAFFS_NOBJECT_BUCKETS;
1242                 if(dev->objectBucket[x].count < lowest)
1243                 {
1244                         lowest = dev->objectBucket[x].count;
1245                         l = x;
1246                 }
1247                 
1248         }
1249         
1250         // If we didn't find an empty list, then try
1251         // looking a bit further for a short one
1252         
1253         for(i = 0; i < 10 && lowest > 3; i++)
1254          {
1255                 x++;
1256                 x %=  YAFFS_NOBJECT_BUCKETS;
1257                 if(dev->objectBucket[x].count < lowest)
1258                 {
1259                         lowest = dev->objectBucket[x].count;
1260                         l = x;
1261                 }
1262                 
1263         }
1264         
1265         return l;
1266 }
1267
1268 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
1269 {
1270         int bucket = yaffs_FindNiceObjectBucket(dev);
1271         
1272         // Now find an object value that has not already been taken
1273         // by scanning the list.
1274         
1275         int found = 0;
1276         struct list_head *i;
1277         
1278         int n = bucket;
1279
1280         //yaffs_CheckObjectHashSanity();        
1281         
1282         while(!found)
1283         {
1284                 found = 1;
1285                 n +=  YAFFS_NOBJECT_BUCKETS;
1286                 if(1 ||dev->objectBucket[bucket].count > 0)
1287                 {
1288                         list_for_each(i,&dev->objectBucket[bucket].list)
1289                         {
1290                                 // If there is already one in the list
1291                                 if(list_entry(i, yaffs_Object,hashLink)->objectId == n)
1292                                 {
1293                                         found = 0;
1294                                 }
1295                         }
1296                 }
1297         }
1298         
1299         //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
1300         
1301         return n;       
1302 }
1303
1304 void yaffs_HashObject(yaffs_Object *in)
1305 {
1306         int bucket = yaffs_HashFunction(in->objectId);
1307         yaffs_Device *dev = in->myDev;
1308         
1309         if(!list_empty(&in->hashLink))
1310         {
1311                 YINFO("!!!");
1312         }
1313         
1314         
1315         list_add(&in->hashLink,&dev->objectBucket[bucket].list);
1316         dev->objectBucket[bucket].count++;
1317
1318 }
1319
1320 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,int number)
1321 {
1322         int bucket = yaffs_HashFunction(number);
1323         struct list_head *i;
1324         yaffs_Object *in;
1325         
1326         list_for_each(i,&dev->objectBucket[bucket].list)
1327         {
1328                 // Look if it is in the list
1329                 in = list_entry(i, yaffs_Object,hashLink);
1330                 if(in->objectId == number)
1331                 {
1332                         return in;
1333                 }
1334         }
1335         
1336         return NULL;
1337 }
1338
1339
1340
1341 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1342 {
1343                 
1344         yaffs_Object *theObject;
1345
1346         if(number < 0)
1347         {
1348                 number = yaffs_CreateNewObjectNumber(dev);
1349         }
1350         
1351         theObject = yaffs_AllocateEmptyObject(dev);
1352         
1353         if(theObject)
1354         {
1355                 theObject->fake = 0;
1356                 theObject->renameAllowed = 1;
1357                 theObject->unlinkAllowed = 1;
1358                 theObject->objectId = number;
1359                 yaffs_HashObject(theObject);
1360                 theObject->variantType = type;
1361                 theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME;
1362
1363                 switch(type)
1364                 {
1365                         case YAFFS_OBJECT_TYPE_FILE: 
1366                                 theObject->variant.fileVariant.fileSize = 0;
1367                                 theObject->variant.fileVariant.scannedFileSize = 0;
1368                                 theObject->variant.fileVariant.topLevel = 0;
1369                                 theObject->variant.fileVariant.top  = yaffs_GetTnode(dev);
1370                                 break;
1371                         case YAFFS_OBJECT_TYPE_DIRECTORY:
1372                                 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1373                                 break;
1374                         case YAFFS_OBJECT_TYPE_SYMLINK:
1375                                 // No action required
1376                                 break;
1377                         case YAFFS_OBJECT_TYPE_HARDLINK:
1378                                 // No action required
1379                                 break;
1380                         case YAFFS_OBJECT_TYPE_SPECIAL:
1381                                 // No action required
1382                                 break;
1383                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1384                                 // todo this should not happen
1385                                 break;
1386                 }
1387         }
1388         
1389         return theObject;
1390 }
1391
1392 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1393 {
1394         yaffs_Object *theObject = NULL;
1395         
1396         if(number > 0)
1397         {
1398                 theObject = yaffs_FindObjectByNumber(dev,number);
1399         }
1400         
1401         if(!theObject)
1402         {
1403                 theObject = yaffs_CreateNewObject(dev,number,type);
1404         }
1405         
1406         return theObject;
1407
1408 }
1409
1410 char *yaffs_CloneString(const char *str)
1411 {
1412         char *newStr = NULL;
1413         
1414         if(str && *str)
1415         {
1416                 newStr = YMALLOC(strlen(str) + 1);
1417                 strcpy(newStr,str);
1418         }
1419
1420         return newStr;
1421         
1422 }
1423
1424 //
1425 // Mknod (create) a new object.
1426 // equivalentObject only has meaning for a hard link;
1427 // aliasString only has meaning for a sumlink.
1428 // rdev only has meaning for devices (a subset of special objects)
1429 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1430                                                                  yaffs_Object *parent,
1431                                                                  const char *name, 
1432                                                                  __u32 mode,
1433                                                                  __u32 uid,
1434                                                                  __u32 gid,
1435                                                                  yaffs_Object *equivalentObject,
1436                                                                  const char *aliasString,
1437                                                                  __u32 rdev)
1438 {
1439         yaffs_Object *in;
1440
1441         yaffs_Device *dev = parent->myDev;
1442         
1443         // Check if the entry exists. If it does then fail the call since we don't want a dup.
1444         if(yaffs_FindObjectByName(parent,name))
1445         {
1446                 return NULL;
1447         }
1448         
1449         in = yaffs_CreateNewObject(dev,-1,type);
1450         
1451         if(in)
1452         {
1453                 in->chunkId = -1;
1454                 in->valid = 1;
1455                 in->variantType = type;
1456
1457                 in->st_mode  = mode;
1458                 in->st_rdev  = rdev;
1459                 in->st_uid   = uid;
1460                 in->st_gid   = gid;
1461                 in->st_atime =  in->st_mtime =  in->st_ctime = CURRENT_TIME;
1462                 
1463                 in->nDataChunks = 0;
1464
1465                 in->sum = yaffs_CalcNameSum(name);
1466                 in->dirty = 1;
1467                 
1468                 yaffs_AddObjectToDirectory(parent,in);
1469                 
1470                 in->myDev = parent->myDev;
1471                 
1472                                 
1473                 switch(type)
1474                 {
1475                         case YAFFS_OBJECT_TYPE_SYMLINK:
1476                                 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1477                                 break;
1478                         case YAFFS_OBJECT_TYPE_HARDLINK:
1479                                 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1480                                 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1481                                 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1482                                 break;
1483                         case YAFFS_OBJECT_TYPE_FILE: // do nothing
1484                         case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1485                         case YAFFS_OBJECT_TYPE_SPECIAL: // do nothing
1486                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1487                                 break;
1488                 }
1489
1490                 if(yaffs_GetNumberOfFreeChunks(dev) <= 0 ||
1491                    yaffs_UpdateObjectHeader(in,name,0) < 0)
1492                 {
1493                         // Could not create the object header, fail the creation
1494                         yaffs_UnlinkWorker(in);
1495                         in = NULL;
1496                 }
1497
1498         }
1499         
1500         return in;
1501 }
1502
1503 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1504 {
1505         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL,0);
1506 }
1507
1508 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1509 {
1510         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,0);
1511 }
1512
1513 yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid, __u32 rdev)
1514 {
1515         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL,rdev);
1516 }
1517
1518 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid,const char *alias)
1519 {
1520         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias,0);
1521 }
1522
1523 // NB yaffs_Link returns the object id of the equivalent object.
1524 yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *equivalentObject)
1525 {
1526         // Get the real object in case we were fed a hard link as an equivalent object
1527         equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1528         
1529         if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL,0))
1530         {
1531                 return equivalentObject;
1532         }
1533         else
1534         {
1535                 return NULL;
1536         }
1537         
1538 }
1539
1540
1541 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName,int force)
1542 {
1543         int unlinkOp;
1544
1545         if(newDir == NULL)
1546         {
1547                 newDir = obj->parent; // use the old directory
1548         }
1549
1550         unlinkOp = (newDir == obj->myDev->unlinkedDir && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
1551         
1552         // If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
1553         // duplicate names are allowed.
1554         // Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
1555         if( (unlinkOp|| 
1556                  force || 
1557                  !yaffs_FindObjectByName(newDir,newName))  &&
1558              newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1559         {
1560                 obj->sum = yaffs_CalcNameSum(newName);
1561                 obj->dirty = 1;
1562                 
1563                 yaffs_AddObjectToDirectory(newDir,obj);
1564                 
1565                 if(unlinkOp) obj->unlinked = 1;
1566                 
1567                 
1568                 if(yaffs_UpdateObjectHeader(obj,newName,0) >= 0)
1569                 {
1570                         return YAFFS_OK;
1571                 }
1572         }
1573         
1574         return YAFFS_FAIL;
1575 }
1576
1577 int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName)
1578 {
1579         yaffs_Object *obj;
1580         int force = 0;
1581         
1582 #if WIN32
1583         // Special case for WinCE.
1584         // While look-up is case insensitive, the name isn't.
1585         // THerefore we might want to change x.txt to X.txt
1586         if(oldDir == newDir && stricmp(oldName,newName) == 0)
1587         {
1588                 force = 1;
1589         }       
1590 #endif
1591         
1592         obj = yaffs_FindObjectByName(oldDir,oldName);
1593         if(obj && obj->renameAllowed)
1594         {
1595                 return yaffs_ChangeObjectName(obj,newDir,newName,force);
1596         }
1597         return YAFFS_FAIL;
1598 }
1599
1600
1601
1602 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
1603 {
1604         // Scan the buckets and check that the lists 
1605         // have as many members as the count says there are
1606         int bucket;
1607         int countEm;
1608         struct list_head *j;
1609         int ok = YAFFS_OK;
1610         
1611         for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
1612         {
1613                 countEm = 0;
1614                 
1615                 list_for_each(j,&dev->objectBucket[bucket].list)
1616                 {
1617                         countEm++;
1618                 }
1619                 
1620                 if(countEm != dev->objectBucket[bucket].count)
1621                 {
1622                         YALERT("Inode hash inconsistency");
1623                         ok = YAFFS_FAIL;
1624                 }
1625         }
1626
1627         return ok;
1628 }
1629
1630 void yaffs_ObjectTest(yaffs_Device *dev)
1631 {
1632         yaffs_Object *in[1000];
1633         int inNo[1000];
1634         yaffs_Object *inold[1000];
1635         int i;
1636         int j;
1637         
1638         memset(in,0,1000*sizeof(yaffs_Object *));
1639         memset(inold,0,1000*sizeof(yaffs_Object *));
1640         
1641         yaffs_CheckObjectHashSanity(dev);
1642         
1643         for(j = 0; j < 10; j++)
1644         {
1645                 //T(("%d\n",j));
1646                 
1647                 for(i = 0; i < 1000; i++)
1648                 {
1649                         in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
1650                         if(!in[i])
1651                         {
1652                                 YINFO("No more inodes");
1653                         }
1654                         else
1655                         {
1656                                 inNo[i] = in[i]->objectId;
1657                         }
1658                 }
1659                 
1660                 for(i = 0; i < 1000; i++)
1661                 {
1662                         if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
1663                         {
1664                                 //T(("Differnce in look up test\n"));
1665                         }
1666                         else
1667                         {
1668                                 // T(("Look up ok\n"));
1669                         }
1670                 }
1671                 
1672                 yaffs_CheckObjectHashSanity(dev);
1673         
1674                 for(i = 0; i < 1000; i+=3)
1675                 {
1676                         yaffs_FreeObject(in[i]);        
1677                         in[i] = NULL;
1678                 }
1679                 
1680         
1681                 yaffs_CheckObjectHashSanity(dev);
1682         }
1683                 
1684 }
1685
1686
1687
1688 /////////////////////////// Block Management and Page Allocation ///////////////////
1689
1690
1691 static int yaffs_InitialiseBlocks(yaffs_Device *dev,int nBlocks)
1692 {
1693         dev->allocationBlock = -1; // force it to get a new one
1694         //Todo we're assuming the malloc will pass.
1695         dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
1696         if(dev->blockInfo)
1697         {
1698                 memset(dev->blockInfo,0,nBlocks * sizeof(yaffs_BlockInfo));
1699                 return YAFFS_OK;
1700         }
1701         return YAFFS_FAIL;
1702         
1703 }
1704
1705 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
1706 {
1707         YFREE(dev->blockInfo);
1708 }
1709
1710 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
1711 // for garbage collection.
1712
1713 static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
1714 {
1715
1716         int b = dev->currentDirtyChecker;
1717         
1718         int i;
1719         int dirtiest = -1;
1720         int pagesInUse = 100; // silly big number
1721         yaffs_BlockInfo *bi;
1722         
1723         for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)
1724         {
1725                 b++;
1726                 if (b > dev->endBlock)
1727                 {
1728                         b =  dev->startBlock;
1729                 }
1730                 
1731                 bi = yaffs_GetBlockInfo(dev,b);
1732                 
1733                 if(bi->blockState == YAFFS_BLOCK_STATE_FULL &&
1734                    bi->pagesInUse < pagesInUse)
1735                 {
1736                         dirtiest = b;
1737                         pagesInUse = bi->pagesInUse;
1738                 }
1739         }
1740         
1741         dev->currentDirtyChecker = b;
1742         
1743         return dirtiest;
1744 }
1745
1746
1747 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
1748 {
1749         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,blockNo);
1750         
1751         int erasedOk = 0;
1752         
1753         // If the block is still healthy erase it and mark as clean.
1754         // If the block has had a data failure, then retire it.
1755         bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
1756
1757         if(!bi->needsRetiring)
1758         {
1759                 erasedOk = yaffs_EraseBlockInNAND(dev,blockNo);
1760                 if(!erasedOk)
1761                 {
1762                         T((TSTR("**>> Erasure failed %d" TENDSTR),blockNo));
1763                 }
1764         }
1765         
1766         if( erasedOk )
1767         {
1768                 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
1769                 dev->nErasedBlocks++;
1770                 bi->pagesInUse = 0;
1771                 bi->pageBits = 0;
1772         
1773                 T((TSTR("Erased block %d" TENDSTR),blockNo));
1774         }
1775         else
1776         {
1777                 yaffs_RetireBlock(dev,blockNo);
1778                 T((TSTR("**>> Block %d retired" TENDSTR),blockNo));
1779         }
1780 }
1781
1782
1783 static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
1784 {
1785         int i;
1786         yaffs_BlockInfo *bi;
1787         
1788         if(dev->nErasedBlocks < 1)
1789         {
1790                 // Hoosterman we've got a problem.
1791                 // Can't get space to gc
1792                 return -1;
1793         }
1794         
1795         // Find an empty block.
1796         
1797         for(i = dev->startBlock; i <= dev->endBlock; i++)
1798         {
1799                 bi = yaffs_GetBlockInfo(dev,i);
1800                 if(bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
1801                 {
1802                         bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
1803                         dev->nErasedBlocks--;                   
1804                         return i;
1805                 }
1806         }
1807         
1808         return -1;      
1809 }
1810
1811
1812
1813 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
1814 {
1815         int retVal;
1816         yaffs_BlockInfo *bi;
1817         
1818         if(dev->allocationBlock < 0)
1819         {
1820                 // Get next block to allocate off
1821                 dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
1822                 dev->allocationPage = 0;
1823         }
1824         
1825         if(!useReserve &&  dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1826         {
1827                 // Not enough space to allocate unless we're allowed to use the reserve.
1828                 return -1;
1829         }
1830         
1831         // Next page please....
1832         if(dev->allocationBlock >= 0)
1833         {
1834                 bi = yaffs_GetBlockInfo(dev,dev->allocationBlock);
1835                 
1836                 retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) + 
1837                                   dev->allocationPage;
1838                 bi->pagesInUse++;
1839                 bi->pageBits |= (1 << (dev->allocationPage));
1840
1841                 dev->allocationPage++;
1842                 
1843                 dev->nFreeChunks--;
1844                 
1845                 // If the block is full set the state to full
1846                 if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK)
1847                 {
1848                         bi->blockState = YAFFS_BLOCK_STATE_FULL;
1849                         dev->allocationBlock = -1;
1850                 }
1851
1852
1853                 return retVal;
1854                 
1855         }
1856         T((TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
1857
1858         return -1;      
1859 }
1860
1861
1862 int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
1863 {
1864         int oldChunk;
1865         int newChunk;
1866         __u32 mask;
1867         
1868         
1869         yaffs_Spare spare;
1870         yaffs_Tags  tags;
1871                 __u8  buffer[YAFFS_BYTES_PER_CHUNK];
1872         
1873         yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev,block);
1874         
1875         yaffs_Object *object;
1876
1877         //T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));        
1878         
1879         for(mask = 1,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; 
1880             mask && bi->pageBits;
1881             mask <<= 1, oldChunk++ )
1882         {
1883                 if(bi->pageBits & mask)
1884                 {
1885                         
1886                         // This page is in use and needs to be copied off
1887                         
1888                         dev->nGCCopies++;
1889                         
1890                         //T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
1891                         
1892                         yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare,1);
1893                         
1894                         yaffs_GetTagsFromSpare(dev,&spare,&tags);
1895                         
1896                         tags.serialNumber++;
1897                         yaffs_LoadTagsIntoSpare(&spare,&tags);
1898
1899 #if 0
1900                         newChunk = yaffs_AllocatePage(dev,1);
1901                         if(newChunk < 0)
1902                         {
1903                                 return YAFFS_FAIL;
1904                         }
1905
1906                         yaffs_WriteChunkToNAND(dev,newChunk, buffer, &spare);
1907
1908 #else
1909                         newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);
1910 #endif
1911                         if(newChunk < 0)
1912                         {
1913                                 return YAFFS_FAIL;
1914                         }
1915
1916                         object = yaffs_FindObjectByNumber(dev,tags.objectId);
1917                         
1918                         // Ok, now fix up the Tnodes etc.
1919                         
1920                         if(tags.chunkId == 0)
1921                         {
1922                                 // It's a header
1923                                 object->chunkId = newChunk;
1924                         }
1925                         else
1926                         {
1927                                 // It's a data chunk
1928                                 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
1929
1930                         }
1931                         
1932                         yaffs_DeleteChunk(dev,oldChunk);                        
1933                         
1934                 }
1935         }
1936
1937         return YAFFS_OK;
1938 }
1939
1940
1941 static yaffs_Object *yaffs_FindDeletedUnlinkedFile(yaffs_Device *dev)
1942 {
1943         // todo find a file to delete
1944         struct list_head *i;    
1945         yaffs_Object *l;
1946
1947
1948         // To the free chunks add the chunks that are in the deleted unlinked files.
1949         list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
1950         {
1951                 l = list_entry(i, yaffs_Object,siblings);
1952                 if(l->deleted)
1953                 {
1954                         return l;                       
1955                 }
1956         }       
1957         return NULL;
1958 }
1959
1960 static void yaffs_DoUnlinkedFileDeletion(yaffs_Device *dev)
1961 {
1962         // This does background deletion on unlinked files.. only deleted ones.
1963         // If we don't have a file we're working on then find one
1964         if(!dev->unlinkedDeletion && dev->nDeletedFiles > 0)
1965         {
1966                 dev->unlinkedDeletion = yaffs_FindDeletedUnlinkedFile(dev);
1967         }
1968         
1969         // OK, we're working on a file...
1970         if(dev->unlinkedDeletion)
1971         {
1972                 yaffs_Object *obj = dev->unlinkedDeletion;
1973                 int delresult;
1974                 int limit; // Number of chunks to delete in a file.
1975                                    // NB this can be exceeded, but not by much.
1976                                    
1977                 if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))
1978                 {
1979                         limit = 50; // Doing GC soon, so dig deeper     
1980                 }
1981                 else
1982                 {
1983                         limit = 5;
1984                 }
1985                 
1986                 delresult = yaffs_DeleteWorker(obj, obj->variant.fileVariant.top, obj->variant.fileVariant.topLevel, 0,&limit);
1987                 
1988                 if(obj->nDataChunks == 0)
1989                 {
1990                         // Done all the deleting of data chunks.
1991                         // Now dump the header and clean up
1992                         yaffs_FreeTnode(dev,obj->variant.fileVariant.top);
1993                         yaffs_DoGenericObjectDeletion(obj);
1994                         dev->nDeletedFiles--;
1995                         dev->nUnlinkedFiles--;
1996                         dev->nBackgroundDeletions++;
1997                         dev->unlinkedDeletion = NULL;   
1998                 }
1999         }
2000 }
2001
2002 static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
2003 {
2004         int block;
2005         
2006         yaffs_DoUnlinkedFileDeletion(dev);
2007         
2008         if(dev->nErasedBlocks <= (YAFFS_RESERVED_BLOCKS + YAFFS_GARBAGE_COLLECT_LOW_WATER))
2009         {
2010                 dev->garbageCollectionRequired = 1;
2011         }       
2012         
2013         if(dev->garbageCollectionRequired)
2014         {
2015                 dev->garbageCollections++;
2016                 dev->garbageCollectionRequired = 0;
2017                 if(dev->blockSelectedForGC >= 0)
2018                 {
2019                         block = dev->blockSelectedForGC;
2020                 }
2021                 else
2022                 {
2023                         block = yaffs_FindDirtiestBlock(dev);
2024                 }
2025                 
2026                 if(block >= 0)
2027                 {
2028                         return yaffs_GarbageCollectBlock(dev,block);
2029                 }       
2030                 else
2031                 {
2032                         return YAFFS_FAIL;
2033                 }
2034         }
2035
2036         return YAFFS_OK;
2037 }
2038
2039
2040 //////////////////////////// TAGS ///////////////////////////////////////
2041
2042 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
2043 {
2044         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2045         
2046         yaffs_CalcTagsECC(tagsPtr);
2047         
2048         sparePtr->tagByte0 = tu->asBytes[0];
2049         sparePtr->tagByte1 = tu->asBytes[1];
2050         sparePtr->tagByte2 = tu->asBytes[2];
2051         sparePtr->tagByte3 = tu->asBytes[3];
2052         sparePtr->tagByte4 = tu->asBytes[4];
2053         sparePtr->tagByte5 = tu->asBytes[5];
2054         sparePtr->tagByte6 = tu->asBytes[6];
2055         sparePtr->tagByte7 = tu->asBytes[7];
2056 }
2057
2058 static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
2059 {
2060         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
2061         int result;
2062
2063         tu->asBytes[0]= sparePtr->tagByte0;
2064         tu->asBytes[1]= sparePtr->tagByte1;
2065         tu->asBytes[2]= sparePtr->tagByte2;
2066         tu->asBytes[3]= sparePtr->tagByte3;
2067         tu->asBytes[4]= sparePtr->tagByte4;
2068         tu->asBytes[5]= sparePtr->tagByte5;
2069         tu->asBytes[6]= sparePtr->tagByte6;
2070         tu->asBytes[7]= sparePtr->tagByte7;
2071         
2072         result =  yaffs_CheckECCOnTags(tagsPtr);
2073         if(result> 0)
2074         {
2075                 dev->tagsEccFixed++;
2076         }
2077         else if(result <0)
2078         {
2079                 dev->tagsEccUnfixed++;
2080         }
2081 }
2082
2083 static void yaffs_SpareInitialise(yaffs_Spare *spare)
2084 {
2085         memset(spare,0xFF,sizeof(yaffs_Spare));
2086 }
2087
2088 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags, int *chunkDeleted)
2089 {
2090         if(tags)
2091         {
2092                 yaffs_Spare spare;
2093                 if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare,1) == YAFFS_OK)
2094                 {
2095                         *chunkDeleted = (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
2096                         yaffs_GetTagsFromSpare(dev,&spare,tags);
2097                         return YAFFS_OK;
2098                 }
2099                 else
2100                 {
2101                         return YAFFS_FAIL;
2102                 }
2103         }
2104         
2105         return YAFFS_OK;
2106 }
2107
2108 #if 0
2109 static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags)
2110 {
2111         // NB There must be tags, data is optional
2112         // If there is data, then an ECC is calculated on it.
2113         
2114         yaffs_Spare spare;
2115         
2116         if(!tags)
2117         {
2118                 return YAFFS_FAIL;
2119         }
2120         
2121         yaffs_SpareInitialise(&spare);
2122         
2123
2124         if(buffer)
2125         {
2126                 yaffs_CalcECC(buffer,&spare);
2127         }
2128         
2129         yaffs_LoadTagsIntoSpare(&spare,tags);
2130         
2131         return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
2132         
2133 }
2134 #endif
2135
2136
2137 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve)
2138 {
2139         // NB There must be tags, data is optional
2140         // If there is data, then an ECC is calculated on it.
2141         
2142         yaffs_Spare spare;
2143         
2144         if(!tags)
2145         {
2146                 return YAFFS_FAIL;
2147         }
2148         
2149         yaffs_SpareInitialise(&spare);
2150         
2151
2152         if(buffer)
2153         {
2154                 yaffs_CalcECC(buffer,&spare);
2155         }
2156         
2157         yaffs_LoadTagsIntoSpare(&spare,tags);
2158         
2159         return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
2160         
2161 }
2162
2163 static int yaffs_TagsMatch(const yaffs_Tags *tags, int objectId, int chunkInObject, int chunkDeleted)
2164 {
2165         return  (  tags->chunkId == chunkInObject &&
2166                            tags->objectId == objectId &&
2167                            !chunkDeleted) ? 1 : 0;
2168         
2169 }
2170
2171
2172
2173 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
2174 {
2175         //Get the Tnode, then get the level 0 offset chunk offset
2176     yaffs_Tnode *tn;     
2177     int theChunk = -1;
2178     yaffs_Tags localTags;
2179     int i;
2180     int found = 0;
2181     int chunkDeleted;
2182     
2183     yaffs_Device *dev = in->myDev;
2184     
2185     
2186     if(!tags)
2187     {
2188         // Passed a NULL, so use our own tags space
2189         tags = &localTags;
2190     }
2191     
2192     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2193     
2194     if(tn)
2195     {
2196                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2197
2198                 // Now we need to do the shifting etc and search for it
2199                 for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
2200                 {
2201                         yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags,&chunkDeleted);
2202                         if(yaffs_TagsMatch(tags,in->objectId,chunkInInode,chunkDeleted))
2203                         {
2204                                 // found it;
2205                                 found = 1;
2206                         }
2207                         else
2208                         {
2209                                 theChunk++;
2210                         }
2211                 }
2212     }
2213     return found ? theChunk : -1;
2214 }
2215
2216 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
2217 {
2218         //Get the Tnode, then get the level 0 offset chunk offset
2219     yaffs_Tnode *tn;     
2220     int theChunk = -1;
2221     yaffs_Tags localTags;
2222     int i;
2223     int found = 0;
2224     yaffs_Device *dev = in->myDev;
2225     int chunkDeleted;
2226     
2227     if(!tags)
2228     {
2229         // Passed a NULL, so use our own tags space
2230         tags = &localTags;
2231     }
2232     
2233     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2234     
2235     if(tn)
2236     {
2237     
2238                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
2239     
2240                 // Now we need to do the shifting etc and search for it
2241                 for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
2242                 {
2243                         yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags,&chunkDeleted);
2244                         if(yaffs_TagsMatch(tags,in->objectId,chunkInInode,chunkDeleted))
2245                         {
2246                                 // found it;
2247                                 found = 1;
2248                         }
2249                         else
2250                         {
2251                                 theChunk++;
2252                         }
2253                 }
2254     
2255                 // Delete the entry in the filestructure
2256                 if(found)
2257                 {
2258                         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
2259                 }
2260     }
2261     else
2262     {
2263         //T(("No level 0 found for %d\n", chunkInInode));
2264     }
2265     
2266     if(!found)
2267     {
2268         //T(("Could not find %d to delete\n",chunkInInode));
2269     }
2270     return found ? theChunk : -1;
2271 }
2272
2273
2274 #if YAFFS_PARANOID
2275
2276 static int yaffs_CheckFileSanity(yaffs_Object *in)
2277 {
2278         int chunk;
2279         int nChunks;
2280         int fSize;
2281         int failed = 0;
2282         int objId;
2283         yaffs_Tnode *tn;
2284     yaffs_Tags localTags;
2285     yaffs_Tags *tags = &localTags;
2286     int theChunk;
2287     int chunkDeleted;
2288     
2289         
2290         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2291         {
2292                 //T(("Object not a file\n"));
2293                 return YAFFS_FAIL;
2294         }
2295         
2296         objId = in->objectId;
2297         fSize  = in->variant.fileVariant.fileSize;
2298         nChunks = (fSize + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK;
2299         
2300         for(chunk = 1; chunk <= nChunks; chunk++)
2301         {
2302                 tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
2303     
2304                 if(tn)
2305                 {
2306     
2307                         theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
2308     
2309
2310                                 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags,&chunkDeleted);
2311                                 if(yaffs_TagsMatch(tags,in->objectId,chunk,chunkDeleted))
2312                                 {
2313                                         // found it;
2314                                 
2315                                 }
2316                                 else
2317                                 {
2318                                         //T(("File problem file [%d,%d] NAND %d  tags[%d,%d]\n",
2319                                         //              objId,chunk,theChunk,tags->chunkId,tags->objectId);
2320                                                         
2321                                         failed = 1;
2322                                                                 
2323                                 }
2324     
2325                 }
2326                 else
2327                 {
2328                         //T(("No level 0 found for %d\n", chunk));
2329                 }
2330         }
2331         
2332         return failed ? YAFFS_FAIL : YAFFS_OK;
2333 }
2334
2335 #endif
2336
2337 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
2338 {
2339         yaffs_Tnode *tn;
2340         yaffs_Device *dev = in->myDev;
2341         int existingChunk;
2342         yaffs_Tags existingTags;
2343         yaffs_Tags newTags;
2344         unsigned existingSerial, newSerial;
2345         
2346         int newChunkDeleted;
2347         
2348         
2349         tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
2350         if(!tn)
2351         {
2352                 return YAFFS_FAIL;
2353         }
2354
2355         existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
2356         
2357         if(inScan)
2358         {
2359                 // If we're scanning then we need to test for duplicates
2360                 // NB This does not need to be efficient since it should only ever 
2361                 // happen when the power fails during a write, then only one
2362                 // chunk should ever be affected.
2363         
2364                 
2365                 if(existingChunk != 0)
2366                 {
2367                         // NB Right now existing chunk will not be real chunkId if the device >= 32MB
2368                         //    thus we have to do a FindChunkInFile to get the real chunk id.
2369                         //
2370                         // We have a duplicate now we need to decide which one to use
2371                         // To do this we get both sets of tags and compare serial numbers.
2372                         yaffs_ReadChunkTagsFromNAND(dev,chunkInNAND, &newTags,&newChunkDeleted);
2373                         
2374                         
2375                         // Do a proper find
2376                         existingChunk = yaffs_FindChunkInFile(in,chunkInInode, &existingTags);
2377
2378                         if(existingChunk <=0)
2379                         {
2380                                 //Hoosterman - how did this happen?
2381                                 // todo
2382                         }
2383
2384                         
2385                         // NB The deleted flags should be false, otherwise the chunks will 
2386                         // not be loaded during a scan
2387                         
2388                         newSerial = newTags.serialNumber;
2389                         existingSerial = existingTags.serialNumber;
2390                         
2391                         if( existingChunk <= 0 ||
2392                             ((existingSerial+1) & 3) == newSerial)
2393                         {
2394                                 // Use new
2395                                 // Delete the old one and drop through to update the tnode
2396                                 yaffs_DeleteChunk(dev,existingChunk);
2397                         }
2398                         else
2399                         {
2400                                 // Use existing.
2401                                 // Delete the new one and return early so that the tnode isn't changed
2402                                 yaffs_DeleteChunk(dev,chunkInNAND);
2403                                 return YAFFS_OK;
2404                         }
2405                 }
2406
2407         }
2408                 
2409         if(existingChunk == 0)
2410         {
2411                 in->nDataChunks++;
2412         }
2413         
2414         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = (chunkInNAND >> dev->chunkGroupBits);
2415         
2416         return YAFFS_OK;
2417 }
2418
2419
2420
2421 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
2422 {
2423     int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
2424     
2425     if(chunkInNAND >= 0)
2426     {
2427                 return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL,1);
2428         }
2429         else
2430         {
2431                 return 0;
2432         }
2433
2434 }
2435
2436
2437 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
2438 {
2439         int block;
2440         int page;
2441         yaffs_Spare spare;
2442         yaffs_BlockInfo *bi;
2443         
2444         if(chunkId <= 0) return;        
2445                 
2446         block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
2447         page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
2448         yaffs_SpareInitialise(&spare);
2449         
2450         spare.pageStatus = 0; // To mark it as deleted.
2451
2452         
2453         yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);
2454         yaffs_HandleUpdateChunk(dev,chunkId,&spare);
2455         bi = yaffs_GetBlockInfo(dev,block);
2456                         
2457         
2458         // Pull out of the management area.
2459         // If the whole block became dirty, this will kick off an erasure.
2460         if(     bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
2461             bi->blockState == YAFFS_BLOCK_STATE_FULL)
2462         {
2463                 dev->nFreeChunks++;
2464
2465                 bi->pageBits &= ~(1 << page);
2466                 bi->pagesInUse--;
2467                 
2468                 if(bi->pagesInUse == 0 &&
2469                bi->blockState == YAFFS_BLOCK_STATE_FULL)
2470             {
2471                 yaffs_BlockBecameDirty(dev,block);
2472             }
2473
2474         }
2475         else
2476         {
2477                 // T(("Bad news deleting chunk %d\n",chunkId));
2478         }
2479         
2480 }
2481
2482
2483
2484
2485 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
2486 {
2487         // Find old chunk Need to do this to get serial number
2488         // Write new one and patch into tree.
2489         // Invalidate old tags.
2490
2491     int prevChunkId;
2492     yaffs_Tags prevTags;
2493     
2494     int newChunkId;
2495     yaffs_Tags newTags;
2496
2497     yaffs_Device *dev = in->myDev;    
2498
2499         yaffs_CheckGarbageCollection(dev);
2500
2501         // Get the previous chunk at this location in the file if it exists
2502     prevChunkId  = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
2503     
2504     // Set up new tags
2505         newTags.chunkId = chunkInInode;
2506         newTags.objectId = in->objectId;
2507         newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
2508         newTags.byteCount = nBytes;
2509         newTags.unusedStuff = 0xFFFFFFFF;
2510                 
2511         yaffs_CalcTagsECC(&newTags);
2512
2513     
2514  #if 0
2515     // Create new chunk in NAND
2516     newChunkId = yaffs_AllocatePage(dev,useReserve);
2517  
2518     
2519     if(newChunkId >= 0)
2520     {
2521                 
2522
2523                 yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,buffer,&newTags);
2524                 
2525                 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
2526                 
2527                 
2528                 if(prevChunkId >= 0)
2529                 {
2530                         yaffs_DeleteChunk(dev,prevChunkId);
2531         
2532                 }
2533                 
2534                 yaffs_CheckFileSanity(in);
2535                 
2536                 return newChunkId;
2537     }
2538
2539      
2540     return -1;
2541 #else
2542
2543         newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
2544         if(newChunkId >= 0)
2545         {
2546                 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
2547                 
2548                 
2549                 if(prevChunkId >= 0)
2550                 {
2551                         yaffs_DeleteChunk(dev,prevChunkId);
2552         
2553                 }
2554                 
2555                 yaffs_CheckFileSanity(in);
2556         }
2557         return newChunkId;
2558
2559 #endif
2560
2561
2562
2563 }
2564
2565
2566 // UpdateObjectHeader updates the header on NAND for an object.
2567 // If name is not NULL, then that new name is used.
2568 //
2569 int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name, int force)
2570 {
2571
2572         yaffs_Device *dev = in->myDev;
2573         
2574     int prevChunkId;
2575     
2576     int newChunkId;
2577     yaffs_Tags newTags;
2578     __u8 bufferNew[YAFFS_BYTES_PER_CHUNK];
2579     __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
2580     
2581     yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew;
2582     yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
2583
2584     yaffs_InvalidateWholeChunkCache(in);
2585     
2586     if(!in->fake || force)
2587     {
2588   
2589                 yaffs_CheckGarbageCollection(dev);              
2590     
2591                 memset(bufferNew,0xFF,YAFFS_BYTES_PER_CHUNK);
2592     
2593                 prevChunkId = in->chunkId;
2594     
2595                 if(prevChunkId >= 0)
2596                 {
2597                         yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL,1);      
2598                 }
2599
2600                 // Header data
2601                 oh->type = in->variantType;
2602         
2603                 oh->st_mode = in->st_mode;
2604                 oh->st_uid = in->st_uid;
2605                 oh->st_gid = in->st_gid;
2606                 oh->st_atime = in->st_atime;
2607                 oh->st_mtime = in->st_mtime;
2608                 oh->st_ctime = in->st_ctime;
2609                 oh->st_rdev = in->st_rdev;
2610         
2611                 if(in->parent)
2612                 {
2613                         oh->parentObjectId = in->parent->objectId;
2614                 }
2615                 else
2616                 {
2617                         oh->parentObjectId = 0;
2618                 }
2619                 
2620                 oh->sum = in->sum;
2621                 if(name && *name)
2622                 {
2623                         memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);
2624                         strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
2625                 }
2626                 else if(prevChunkId)
2627                 {       
2628                         memcpy(oh->name, ohOld->name,YAFFS_MAX_NAME_LENGTH + 1);
2629                 }
2630                 else
2631                 {
2632                         memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);   
2633                 }
2634         
2635                 switch(in->variantType)
2636                 {
2637                         case YAFFS_OBJECT_TYPE_UNKNOWN:         
2638                                 // Should not happen
2639                                 break;
2640                         case YAFFS_OBJECT_TYPE_FILE:
2641                                 oh->fileSize = in->variant.fileVariant.fileSize;
2642                                 break;
2643                         case YAFFS_OBJECT_TYPE_HARDLINK:
2644                                 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
2645                                 break;
2646                         case YAFFS_OBJECT_TYPE_SPECIAL: 
2647                                 // Do nothing
2648                                 break;
2649                         case YAFFS_OBJECT_TYPE_DIRECTORY:       
2650                                 // Do nothing
2651                                 break;
2652                         case YAFFS_OBJECT_TYPE_SYMLINK:
2653                                 strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
2654                                 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
2655                                 break;
2656                 }
2657
2658                 // Tags
2659                 in->serial++;
2660                 newTags.chunkId = 0;
2661                 newTags.objectId = in->objectId;
2662                 newTags.serialNumber = in->serial;
2663                 newTags.byteCount =   0xFFFFFFFF;
2664                 newTags.unusedStuff = 0xFFFFFFFF;
2665         
2666                 yaffs_CalcTagsECC(&newTags);
2667         
2668     
2669     
2670 #if 0
2671                 // Create new chunk in NAND
2672                 newChunkId = yaffs_AllocatePage(dev,1);
2673     
2674                 if(newChunkId >= 0)
2675                 {
2676
2677                         yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,bufferNew,&newTags);
2678                 
2679                         in->chunkId = newChunkId;               
2680                 
2681                         if(prevChunkId >= 0)
2682                         {
2683                                 yaffs_DeleteChunk(dev,prevChunkId);
2684                         }
2685                 
2686                         in->dirty = 0;
2687                         return newChunkId;
2688                 }
2689     
2690                 return -1;
2691 #else
2692                 // Create new chunk in NAND
2693                 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);
2694     
2695                 if(newChunkId >= 0)
2696                 {
2697                 
2698                         in->chunkId = newChunkId;               
2699                 
2700                         if(prevChunkId >= 0)
2701                         {
2702                                 yaffs_DeleteChunk(dev,prevChunkId);
2703                         }
2704                 
2705                         in->dirty = 0;
2706                 }
2707                 
2708                 return newChunkId;
2709
2710 #endif
2711     }
2712     return 0;
2713 }
2714
2715
2716 /////////////////////// Short Read Cache ////////////////////////////////
2717 //      In many siturations where there is no high level buffering a lot of
2718 //      reads might be short sequential reads. eg. scanning a jpeg file.
2719 //      In these cases, a shoprt read cache can provide a huge perfomance benefit 
2720 //  with dumb-as-a-rock code.
2721 //  There are a limited number (~10) of cache chunks per device
2722
2723
2724 #ifdef CONFIG_YAFFS_SHORT_OP_CACHE
2725
2726
2727 // Grab us a chunk for use.
2728 // First look for an empty one. 
2729 // Then look for the least recently used one.
2730 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
2731 {
2732         int i;
2733         int usage;
2734         int theOne;
2735         
2736         for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
2737         {
2738                 if(dev->srCache[i].objectId == 0)
2739                 {
2740                         //T(("Grabbing empty %d\n",i));
2741                         
2742                         return &dev->srCache[i];
2743                 }
2744         }
2745         
2746         
2747         usage = dev->srCache[i].lastUse;
2748         theOne = 0;
2749         
2750         for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++)
2751         {
2752                 if(dev->srCache[i].lastUse < usage)
2753                 {
2754                         usage = dev->srCache[i].lastUse;
2755                         theOne = i;
2756                 }
2757         }
2758         
2759         //T(("Grabbing non-empty %d\n",theOne));
2760         return  &dev->srCache[theOne];
2761         
2762 }
2763
2764
2765 // Find a cached chunk
2766 static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId)
2767 {
2768         int i;
2769 ;
2770         
2771         for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
2772         {
2773                 if(dev->srCache[i].objectId == objectId && 
2774                    dev->srCache[i].chunkId == chunkId)
2775                 {
2776                         dev->cacheHits++;
2777                         
2778                         return &dev->srCache[i];
2779                 }
2780         }
2781         
2782         return NULL;
2783 }
2784
2785 // Mark the chunk for the least recently used algorithym
2786 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache)
2787 {
2788         if( dev->srLastUse < 0 || 
2789                 dev->srLastUse > 1000000)
2790         {
2791                 // Reset the cache usages
2792                 int i;
2793                 for(i = 1; i < YAFFS_N_CACHE_CHUNKS; i++)
2794                 {
2795                         dev->srCache[i].lastUse = 0;
2796                 }
2797                 dev->srLastUse = 0;
2798         }
2799
2800         dev->srLastUse++;
2801         
2802         cache->lastUse = dev->srLastUse;
2803
2804 }
2805
2806 // Invalidate a single cache page
2807 static void yaffs_InvalidateChunkCache(yaffs_Device *dev, int objectId, int chunkId)
2808 {
2809         yaffs_ChunkCache *cache = yaffs_FindChunkCache(dev,objectId,chunkId);
2810
2811         if(cache)
2812         {
2813                 cache->objectId = 0;
2814         }
2815 }
2816
2817
2818 // Invalidate all the cache pages associated with this object
2819 // Do this whenever ther file is modified... dumb as a rock remember!
2820 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
2821 {
2822         int i;
2823         yaffs_Device *dev = in->myDev;
2824         int id = in->objectId;
2825         
2826         for(i = 0; i < YAFFS_N_CACHE_CHUNKS; i++)
2827         {
2828                 if(dev->srCache[i].objectId == id)
2829                 {
2830                         dev->srCache[i].objectId = 0;
2831                 }
2832         }
2833 }
2834
2835
2836 #else
2837
2838 static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
2839 {
2840         return NULL;    
2841 }
2842
2843
2844 static yaffs_ChunkCache *yaffs_FindChunkCache(yaffs_Device *dev, int objectId, int chunkId)
2845 {
2846         return NULL;
2847 }
2848
2849 static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache)
2850 {
2851 }
2852
2853 static void yaffs_InvalidateChunkCache(yaffs_Device *dev, int objectId, int chunkId)
2854 {
2855 }
2856
2857 static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
2858 {
2859 }
2860
2861
2862
2863 #endif
2864
2865
2866
2867 ///////////////////////// File read/write ///////////////////////////////
2868 // Read and write have very similar structures.
2869 // In general the read/write has three parts to it
2870 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
2871 // * Some complete chunks
2872 // * An incomplete chunk to end off with
2873 //
2874 // Curve-balls: the first chunk might also be the last chunk.
2875
2876 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
2877 {
2878         
2879 //      yaffs_Device *dev = in->myDev;
2880         
2881 #ifdef CONFIG_YAFFS_SHORT_OP_CACHE
2882         yaffs_ChunkCache *cache;
2883 #endif
2884
2885         __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2886         
2887         
2888         int chunk;
2889         int start;
2890         int nToCopy;
2891         int n = nBytes;
2892         int nDone = 0;
2893         
2894         while(n > 0)
2895         {
2896                 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1; // The first chunk is 1
2897                 start = offset % YAFFS_BYTES_PER_CHUNK;
2898
2899                 // OK now check for the curveball where the start and end are in
2900                 // the same chunk.      
2901                 if(     (start + n) < YAFFS_BYTES_PER_CHUNK)
2902                 {
2903                         nToCopy = n;
2904                 }
2905                 else
2906                 {
2907                         nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2908                 }
2909         
2910                 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2911                 {
2912                         // An incomplete start or end chunk (or maybe both start and end chunk)
2913 #ifdef CONFIG_YAFFS_SHORT_OP_CACHE
2914                         // If we can't find the data in the cache, then load it up.
2915                         cache = yaffs_FindChunkCache(in->myDev,in->objectId,chunk);
2916                         if(!cache)
2917                         {
2918                                 cache = yaffs_GrabChunkCache(in->myDev);
2919                                 cache->objectId = in->objectId;
2920                                 cache->chunkId = chunk;
2921                                 yaffs_ReadChunkDataFromObject(in,chunk,cache->data);            
2922                         }
2923                         
2924                         yaffs_UseChunkCache(in->myDev,cache);
2925
2926                         memcpy(buffer,&cache->data[start],nToCopy);
2927 #else
2928                         // Read into the local buffer then copy...
2929                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);            
2930                         memcpy(buffer,&localBuffer[start],nToCopy);
2931 #endif
2932                 }
2933                 else
2934                 {
2935 #ifdef WIN32
2936                         // Under WinCE can't do direct transfer. Need to use a local buffer.
2937                         // This is because we otherwise screw up WinCE's memory mapper
2938                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
2939                         memcpy(buffer,localBuffer,YAFFS_BYTES_PER_CHUNK);
2940 #else
2941                         // A full chunk. Read directly into the supplied buffer.
2942                         yaffs_ReadChunkDataFromObject(in,chunk,buffer);
2943 #endif
2944                 }
2945                 
2946                 n -= nToCopy;
2947                 offset += nToCopy;
2948                 buffer += nToCopy;
2949                 nDone += nToCopy;
2950                 
2951         }
2952         
2953         return nDone;
2954 }
2955
2956
2957 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
2958 {       
2959         __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2960         
2961         int chunk;
2962         int start;
2963         int nToCopy;
2964         int n = nBytes;
2965         int nDone = 0;
2966         int nToWriteBack;
2967         int endOfWrite = offset+nBytes;
2968         int chunkWritten = 0;
2969         int nBytesRead;
2970         
2971         yaffs_InvalidateWholeChunkCache(in);
2972         
2973         
2974         while(n > 0 && chunkWritten >= 0)
2975         {
2976                 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1;
2977                 start = offset % YAFFS_BYTES_PER_CHUNK;
2978                 
2979
2980                 // OK now check for the curveball where the start and end are in
2981                 // the same chunk.
2982                 
2983                 if(     (start + n) < YAFFS_BYTES_PER_CHUNK)
2984                 {
2985                         nToCopy = n;
2986                         
2987                         // Now folks, to calculate how many bytes to write back....
2988                         // If we're overwriting and not writing to then end of file then
2989                         // we need to write back as much as was there before.
2990                         
2991                         nBytesRead = in->variant.fileVariant.fileSize - ((chunk -1) * YAFFS_BYTES_PER_CHUNK);
2992                         
2993                         if(nBytesRead > YAFFS_BYTES_PER_CHUNK)
2994                         {
2995                                 nBytesRead = YAFFS_BYTES_PER_CHUNK;
2996                         }
2997                         nToWriteBack = (nBytesRead > (start + n)) ? nBytesRead : (start +n);
2998                         
2999                 }
3000                 else
3001                 {
3002                         nToCopy = YAFFS_BYTES_PER_CHUNK - start;
3003                         nToWriteBack = YAFFS_BYTES_PER_CHUNK;
3004                 }
3005         
3006                 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
3007                 {
3008                         // An incomplete start or end chunk (or maybe both start and end chunk)
3009                         // Read into the local buffer then copy, then copy over and write back.
3010                 
3011                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
3012                                 
3013                         memcpy(&localBuffer[start],buffer,nToCopy);
3014                         
3015                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
3016                         
3017                         //T(("Write with readback to chunk %d %d  start %d  copied %d wrote back %d\n",chunk,chunkWritten,start, nToCopy, nToWriteBack));
3018                         
3019                 }
3020                 else
3021                 {
3022                         
3023 #ifdef WIN32
3024                         // Under WinCE can't do direct transfer. Need to use a local buffer.
3025                         // This is because we otherwise screw up WinCE's memory mapper
3026                         memcpy(localBuffer,buffer,YAFFS_BYTES_PER_CHUNK);
3027                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,YAFFS_BYTES_PER_CHUNK,0);
3028 #else
3029                         // A full chunk. Write directly from the supplied buffer.
3030                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,YAFFS_BYTES_PER_CHUNK,0);
3031 #endif
3032                         // Since we've overwritten the cached data, we better invalidate it.
3033                         yaffs_InvalidateChunkCache(in->myDev,in->objectId,chunk);
3034                         //T(("Write to chunk %d %d\n",chunk,chunkWritten));
3035                 }
3036                 
3037                 if(chunkWritten >= 0)
3038                 {
3039                         n -= nToCopy;
3040                         offset += nToCopy;
3041                         buffer += nToCopy;
3042                         nDone += nToCopy;
3043                 }
3044                 
3045         }
3046         
3047         // Update file object
3048         
3049         if(endOfWrite > in->variant.fileVariant.fileSize)
3050         {
3051                 in->variant.fileVariant.fileSize = endOfWrite;
3052         }
3053         
3054         in->dirty = 1;
3055         /*in->st_mtime = CURRENT_TIME; only update in flush*/
3056         
3057         return nDone;
3058 }
3059
3060
3061 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
3062 {
3063         int i;
3064         int chunkId;
3065         int oldFileSize = in->variant.fileVariant.fileSize;
3066         int sizeOfPartialChunk = newSize % YAFFS_BYTES_PER_CHUNK;
3067         
3068         yaffs_Device *dev = in->myDev;
3069         
3070         __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
3071
3072         yaffs_InvalidateWholeChunkCache(in);
3073         
3074         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
3075         {
3076                 return yaffs_GetFileSize(in);
3077         }
3078         
3079         if(newSize < oldFileSize)
3080         {
3081                 
3082                 int lastDel = 1 + (oldFileSize-1)/YAFFS_BYTES_PER_CHUNK;
3083                 
3084                 int startDel = 1 + (newSize + YAFFS_BYTES_PER_CHUNK - 1)/
3085                                                         YAFFS_BYTES_PER_CHUNK;
3086
3087                 // Delete backwards so that we don't end up with holes if
3088                 // power is lost part-way through the operation.
3089                 for(i = lastDel; i >= startDel; i--)
3090                 {
3091                         // NB this could be optimised somewhat,
3092                         // eg. could retrieve the tags and write them without
3093                         // using yaffs_DeleteChunk
3094
3095                         chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
3096                         if(chunkId <= 0 || chunkId >= (dev->endBlock * 32))
3097                         {
3098                                 //T(("Found daft chunkId %d for %d\n",chunkId,i));
3099                         }
3100                         else
3101                         {
3102                                 in->nDataChunks--;
3103                                 yaffs_DeleteChunk(dev,chunkId);
3104                         }
3105                 }
3106                 
3107                 
3108                 if(sizeOfPartialChunk != 0)
3109                 {
3110                         int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK;
3111                         
3112                         // Got to read and rewrite the last chunk with its new size.
3113                         yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
3114                         
3115                         yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfPartialChunk,1);
3116                                 
3117                 }
3118                 
3119                 in->variant.fileVariant.fileSize = newSize;
3120                 
3121                 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
3122                 
3123                 return newSize;
3124                 
3125         }
3126         else
3127         {
3128                 return oldFileSize;
3129         }
3130 }
3131
3132
3133 loff_t yaffs_GetFileSize(yaffs_Object *obj)
3134 {
3135         obj = yaffs_GetEquivalentObject(obj);
3136         
3137         switch(obj->variantType)
3138         {
3139                 case YAFFS_OBJECT_TYPE_FILE: 
3140                         return obj->variant.fileVariant.fileSize;
3141                 case YAFFS_OBJECT_TYPE_SYMLINK:
3142                         return strlen(obj->variant.symLinkVariant.alias);
3143                 default:
3144                         return 0;
3145         }
3146 }
3147
3148
3149
3150 // yaffs_FlushFile() updates the file's
3151 // objectId in NAND
3152
3153 int yaffs_FlushFile(yaffs_Object *in)
3154 {
3155         int retVal;
3156         if(in->dirty)
3157         {
3158                 //T(("flushing object header\n"));
3159         
3160                 in->st_mtime = CURRENT_TIME;
3161
3162                 retVal = yaffs_UpdateObjectHeader(in,NULL,0);
3163         }
3164         else
3165         {
3166                 retVal = YAFFS_OK;
3167         }
3168         
3169         return retVal;
3170         
3171 }
3172
3173
3174 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
3175 {
3176         yaffs_InvalidateWholeChunkCache(in);
3177         yaffs_RemoveObjectFromDirectory(in);
3178         yaffs_DeleteChunk(in->myDev,in->chunkId);
3179 #if __KERNEL__
3180         if(in->myInode)
3181         {
3182                 in->myInode->u.generic_ip = NULL;
3183                 in->myInode = 0;
3184         }
3185 #endif
3186         yaffs_FreeObject(in);
3187         return YAFFS_OK;
3188
3189 }
3190
3191 // yaffs_DeleteFile deletes the whole file data
3192 // and the inode associated with the file.
3193 // It does not delete the links associated with the file.
3194 static int yaffs_UnlinkFile(yaffs_Object *in)
3195 {
3196
3197 #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND_DELETION
3198         // Delete the file data & tnodes
3199 #if 0
3200         yaffs_ResizeFile(in,0);
3201 #else
3202          yaffs_DeleteWorker(in, in->variant.fileVariant.top, in->variant.fileVariant.topLevel, 0,NULL);
3203
3204 #endif
3205
3206         yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
3207         
3208         return  yaffs_DoGenericObjectDeletion(in);
3209 #else
3210         int retVal;
3211         int immediateDeletion=0;
3212         retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
3213         if(retVal == YAFFS_OK)
3214         {
3215                 //in->unlinked = 1;
3216                 //in->myDev->nUnlinkedFiles++;
3217                 //in->renameAllowed = 0;
3218 #ifdef __KERNEL__
3219                 if(in->myInode)
3220                 {
3221                         immediateDeletion = 1;
3222
3223                 }
3224 #endif
3225 #if WIN32
3226                 if(in->inUse <= 0)
3227                 {
3228                         immediateDeletion = 1;
3229
3230                 }
3231 #endif
3232                 
3233                 if(immediateDeletion)
3234                 {
3235                         T((TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
3236                         in->deleted=1;
3237                         in->myDev->nDeletedFiles++;
3238                 }
3239         
3240         }
3241         return retVal;
3242
3243         
3244 #endif
3245 }
3246
3247 int yaffs_DeleteFile(yaffs_Object *in)
3248 {
3249         int retVal = YAFFS_OK;
3250         if(!in->unlinked)
3251         {
3252                 retVal = yaffs_UnlinkFile(in);
3253         }
3254         if(retVal == YAFFS_OK && 
3255            in->unlinked &&
3256            !in->deleted)
3257         {
3258                 in->deleted = 1;
3259                 in->myDev->nDeletedFiles++;
3260         }
3261         return in->deleted ? YAFFS_OK : YAFFS_FAIL;     
3262 }
3263
3264 static int yaffs_DeleteDirectory(yaffs_Object *in)
3265 {
3266         //First check that the directory is empty.
3267         if(list_empty(&in->variant.directoryVariant.children))
3268         {
3269                 return  yaffs_DoGenericObjectDeletion(in);
3270         }
3271         
3272         return YAFFS_FAIL;
3273         
3274 }
3275
3276 static int yaffs_DeleteSymLink(yaffs_Object *in)
3277 {
3278         YFREE(in->variant.symLinkVariant.alias);
3279
3280         return  yaffs_DoGenericObjectDeletion(in);
3281 }
3282
3283 static int yaffs_DeleteHardLink(yaffs_Object *in)
3284 {
3285         // remove this hardlink from the list assocaited with the equivalent
3286         // object
3287         list_del(&in->hardLinks);
3288         return  yaffs_DoGenericObjectDeletion(in);      
3289 }
3290
3291
3292 static int yaffs_UnlinkWorker(yaffs_Object *obj)
3293 {
3294
3295         
3296         if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
3297         {
3298                 return  yaffs_DeleteHardLink(obj);
3299         }
3300         else if(!list_empty(&obj->hardLinks))
3301         {       
3302 #if 0
3303                 // Curve ball: We're unlinking an object that has a hardlink.
3304                 // Therefore we can't really delete the object.
3305                 // Instead, we do the following:
3306                 // - Select a hardlink.
3307                 // - Re-type a hardlink as the equivalent object and populate the fields, including the
3308                 //  objectId. Updating the object id is important so that all the hardlinks do not need
3309                 // to be rewritten.
3310                 // - Update the equivalet object pointers.
3311                 // - Delete all object.
3312
3313                 yaffs_Object *hl;
3314                 struct list_head *i;
3315
3316
3317                 yaffs_RemoveObjectFromDirectory(obj);
3318
3319
3320
3321                 hl =  list_entry(obj->hardLinks.next, yaffs_Object,hardLinks);
3322                 
3323                 hl->dirty = 1;
3324                 hl->st_mode = obj->st_mode;
3325                 hl->st_uid = obj->st_uid;
3326                 hl->st_gid = obj->st_gid;
3327                 hl->st_atime = obj->st_atime;
3328                 hl->st_mtime = obj->st_mtime;
3329                 hl->st_ctime = obj->st_ctime;
3330                 hl->st_rdev = obj->st_rdev;
3331                 
3332                 hl->variantType = obj->variantType;
3333                 
3334                 switch(hl->variantType)
3335                 {
3336                         case YAFFS_OBJECT_TYPE_FILE:
3337                         case YAFFS_OBJECT_TYPE_SYMLINK:
3338                         case YAFFS_OBJECT_TYPE_SPECIAL:
3339                                 // These types are OK to just copy across.
3340                                 hl->variant = obj->variant;
3341                                 break;
3342                         case YAFFS_OBJECT_TYPE_DIRECTORY:
3343                                 // Fix the list up
3344                                 list_add(&hl->variant.directoryVariant.children,
3345                                             &obj->variant.directoryVariant.children);
3346                                 list_del(&obj->variant.directoryVariant.children);
3347                                 
3348                                 // Now change all the directory children to point to the new parent.
3349                                 list_for_each(i,&hl->variant.directoryVariant.children)
3350                                 {
3351                                         list_entry(i,yaffs_Object,siblings)->parent = hl;
3352                                 }
3353                                 break;
3354                                 
3355                         case YAFFS_OBJECT_TYPE_HARDLINK:
3356                         case YAFFS_OBJECT_TYPE_UNKNOWN:
3357                                 // Should not be either of these types.
3358                 }
3359                 
3360                 // Now fix up the hardlink chain
3361                 list_del(&obj->hardLinks);
3362
3363                 list_for_each(i,&hl->hardLinks)
3364                 {
3365                         list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObject = hl;
3366                         list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObjectId = hl->objectId;
3367                 }
3368                 
3369                 // Now fix up the hash links.
3370                 yaffs_UnhashObject(hl);
3371                 hl->objectId = obj->objectId;
3372                 yaffs_HashObject(hl);
3373                 
3374                 // Update the hardlink which has become an object
3375                 yaffs_UpdateObjectHeader(hl,NULL,0);
3376
3377                 // Finally throw away the deleted object
3378                 yaffs_DeleteChunk(obj->myDev,obj->chunkId);
3379                 yaffs_FreeObject(obj);
3380                 
3381                 return YAFFS_OK;                
3382 #else
3383                 // Curve ball: We're unlinking an object that has a hardlink.
3384                 //
3385                 //      This problem arises because we are not strictly following
3386                 //  The Linux link/inode model.
3387                 //
3388                 // We can't really delete the object.
3389                 // Instead, we do the following:
3390                 // - Select a hardlink.
3391                 // - Unhook it from the hard links
3392                 // - Unhook it from its parent directory (so that the rename can work)
3393                 // - Rename the object to the hardlink's name.
3394                 // - Delete the hardlink
3395                 
3396                 
3397                 yaffs_Object *hl;
3398                 int retVal;
3399                 char name[YAFFS_MAX_NAME_LENGTH+1];
3400                 
3401                 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
3402                 
3403                 list_del_init(&hl->hardLinks);
3404                 list_del_init(&hl->siblings);
3405                 
3406                 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
3407                 
3408                 retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
3409                 
3410                 if(retVal == YAFFS_OK)
3411                 {
3412                         retVal = yaffs_DoGenericObjectDeletion(hl);
3413                 }
3414                 return retVal;
3415
3416 #endif
3417
3418                                 
3419         }
3420         else
3421         {
3422                 switch(obj->variantType)
3423                 {
3424                         case YAFFS_OBJECT_TYPE_FILE:
3425                                 return yaffs_UnlinkFile(obj);
3426                                 break;
3427                         case YAFFS_OBJECT_TYPE_DIRECTORY:
3428                                 return yaffs_DeleteDirectory(obj);
3429                                 break;
3430                         case YAFFS_OBJECT_TYPE_SYMLINK:
3431                                 return yaffs_DeleteSymLink(obj);
3432                                 break;
3433                         case YAFFS_OBJECT_TYPE_HARDLINK:
3434                         case YAFFS_OBJECT_TYPE_UNKNOWN:
3435                         default:
3436                                 return YAFFS_FAIL;
3437                 }
3438         }
3439 }
3440
3441 int yaffs_Unlink(yaffs_Object *dir, const char *name)
3442 {
3443         yaffs_Object *obj;
3444         
3445          obj = yaffs_FindObjectByName(dir,name);
3446          
3447          if(obj && obj->unlinkAllowed)
3448          {
3449                 return yaffs_UnlinkWorker(obj);
3450          }
3451          
3452          return YAFFS_FAIL;
3453         
3454 }
3455
3456 //////////////// Initialisation Scanning /////////////////
3457
3458
3459
3460 // For now we use the SmartMedia check.
3461 // We look at the blockStatus byte in the first two chunks
3462 // These must be 0xFF to pass as OK.
3463 // todo: this function needs to be modifyable foir different NAND types
3464 // and different chunk sizes.  Suggest make this into a per-device configurable
3465 // function.
3466 static int yaffs_IsBlockBad(yaffs_Device *dev, int blk)
3467 {
3468         yaffs_Spare spare;
3469         
3470         yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK,NULL,&spare,1);
3471 #if 1
3472         if(yaffs_CountBits(spare.blockStatus) < 7)
3473         {
3474                 return 1;
3475         }
3476 #else
3477         if(spare.blockStatus != 0xFF)
3478         {
3479                 return 1;
3480         }
3481 #endif
3482         yaffs_ReadChunkFromNAND(dev,blk * YAFFS_CHUNKS_PER_BLOCK + 1,NULL,&spare,1);
3483
3484 #if 1
3485         if(yaffs_CountBits(spare.blockStatus) < 7)
3486         {
3487                 return 1;
3488         }
3489 #else
3490         if(spare.blockStatus != 0xFF)
3491         {
3492                 return 1;
3493         }
3494 #endif
3495         
3496         return 0;
3497         
3498 }
3499
3500 static int yaffs_Scan(yaffs_Device *dev)
3501 {
3502         yaffs_Spare spare;
3503         yaffs_Tags tags;
3504         int blk;
3505         int chunk;
3506         int c;
3507         int deleted;
3508         yaffs_BlockState state;
3509         yaffs_Object *hardList = NULL;
3510         yaffs_Object *hl;
3511         yaffs_BlockInfo *bi;
3512
3513         
3514         yaffs_ObjectHeader *oh;
3515         yaffs_Object *in;
3516         yaffs_Object *parent;
3517         
3518         __u8 chunkData[YAFFS_BYTES_PER_CHUNK];
3519         
3520         
3521         // Scan all the blocks...
3522         
3523         for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
3524         {
3525                 deleted = 0;
3526                 bi = yaffs_GetBlockInfo(dev,blk);
3527                 bi->pageBits = 0;
3528                 bi->pagesInUse = 0;
3529                 state = YAFFS_BLOCK_STATE_SCANNING;
3530                 
3531                 
3532                 if(yaffs_IsBlockBad(dev,blk))
3533                 {
3534                         state = YAFFS_BLOCK_STATE_DEAD;
3535                         T((TSTR("block %d is bad" TENDSTR),blk));
3536                 }
3537                 
3538                 // Read each chunk in the block.
3539                 
3540                 for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK && 
3541                                    state == YAFFS_BLOCK_STATE_SCANNING; c++)
3542                 {
3543                         // Read the spare area and decide what to do
3544                         chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;
3545                         
3546                         yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare,1);
3547
3548                         
3549                         // This block looks ok, now what's in this chunk?
3550                         yaffs_GetTagsFromSpare(dev,&spare,&tags);
3551                         
3552                         if(yaffs_CountBits(spare.pageStatus) < 6)
3553                         {
3554                                 // A deleted chunk
3555                                 deleted++;
3556                                 dev->nFreeChunks ++;
3557                                 //T((" %d %d deleted\n",blk,c));
3558                         }
3559                         else if(tags.objectId == YAFFS_UNUSED_OBJECT_ID)
3560                         {
3561                                 // An unassigned chunk in the block
3562                                 // This means that either the block is empty or 
3563                                 // this is the one being allocated from
3564                                 
3565                                 if(c == 0)
3566                                 {
3567                                         // the block is unused
3568                                         state = YAFFS_BLOCK_STATE_EMPTY;
3569                                         dev->nErasedBlocks++;
3570                                 }
3571                                 else
3572                                 {
3573                                         // this is the block being allocated from
3574                                         T((TSTR(" Allocating from %d %d" TENDSTR),blk,c));
3575                                         state = YAFFS_BLOCK_STATE_ALLOCATING;
3576                                         dev->allocationBlock = blk;
3577                                         dev->allocationPage = c;
3578                                 }
3579
3580                                 dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c);
3581                         }
3582                         else if(tags.chunkId > 0)
3583                         {
3584                                 int endpos;
3585                                 // A data chunk.
3586                                 bi->pageBits |= (1 << c);
3587                                 bi->pagesInUse++;
3588                                                                 
3589                                 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
3590                                 // PutChunkIntoFIle checks for a clash (two data chunks with
3591                                 // the same chunkId).
3592                                 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
3593                                 endpos = (tags.chunkId - 1)* YAFFS_BYTES_PER_CHUNK + tags.byteCount;
3594                                 if(in->variant.fileVariant.scannedFileSize <endpos)
3595                                 {
3596                                         in->variant.fileVariant.scannedFileSize = endpos;
3597 #ifndef CONFIG_YAFFS_USE_HEADER_FILE_SIZE
3598                                                 in->variant.fileVariant.fileSize =      
3599                                                         in->variant.fileVariant.scannedFileSize;
3600 #endif
3601
3602                                 }
3603                                 //T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));  
3604                         }
3605                         else
3606                         {
3607                                 // chunkId == 0, so it is an ObjectHeader.
3608                                 // Thus, we read in the object header and make the object
3609                                 bi->pageBits |= (1 << c);
3610                                 bi->pagesInUse++;
3611                                                         
3612                                 yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL,1);
3613                                 
3614                                 oh = (yaffs_ObjectHeader *)chunkData;
3615                                 
3616                                 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
3617                                 
3618                                 if(in->valid)
3619                                 {
3620                                         // We have already filled this one. We have a duplicate and need to resolve it.
3621                                         
3622                                         unsigned existingSerial = in->serial;
3623                                         unsigned newSerial = tags.serialNumber;
3624                                         
3625                                         if(((existingSerial+1) & 3) == newSerial)
3626                                         {
3627                                                 // Use new one - destroy the exisiting one
3628                                                 yaffs_DeleteChunk(dev,in->chunkId);
3629                                                 in->valid = 0;
3630                                         }
3631                                         else
3632                                         {
3633                                                 // Use existing - destroy this one.
3634                                                 yaffs_DeleteChunk(dev,chunk);
3635                                         }
3636                                 }
3637                                 
3638                                 if(!in->valid &&
3639                                    (tags.objectId == YAFFS_OBJECTID_ROOT ||
3640                                     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))
3641                                 {
3642                                         // We only load some info, don't fiddle with directory structure
3643                                         in->valid = 1;
3644                                         in->variantType = oh->type;
3645         
3646                                         in->st_mode  = oh->st_mode;
3647                                         in->st_uid   = oh->st_uid;
3648                                         in->st_gid   = oh->st_gid;
3649                                         in->st_atime = oh->st_atime;
3650                                         in->st_mtime = oh->st_mtime;
3651                                         in->st_ctime = oh->st_ctime;
3652                                         in->st_rdev = oh->st_rdev;
3653                                         in->chunkId  = chunk;
3654
3655                                 }
3656                                 else if(!in->valid)
3657                                 {
3658                                         // we need to load this info
3659                                 
3660                                         in->valid = 1;
3661                                         in->variantType = oh->type;
3662         
3663                                         in->st_mode  = oh->st_mode;
3664                                         in->st_uid   = oh->st_uid;
3665                                         in->st_gid   = oh->st_gid;
3666                                         in->st_atime = oh->st_atime;
3667                                         in->st_mtime = oh->st_mtime;
3668                                         in->st_ctime = oh->st_ctime;
3669                                         in->st_rdev = oh->st_rdev;
3670                                         in->chunkId  = chunk;
3671
3672                                         in->sum = oh->sum;
3673                                         in->dirty = 0;
3674                                                         
3675                                         // directory stuff...
3676                                         // hook up to parent
3677         
3678                                         parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
3679                                         if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
3680                                         {
3681                                                 // Set up as a directory
3682                                                 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
3683                                                 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
3684                                         }
3685                                         else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
3686                                         {
3687                                                 // Hoosterman, another problem....
3688                                                 // We're trying to use a non-directory as a directory
3689                                                 // Todo ... handle
3690                                         }
3691                                 
3692                                         yaffs_AddObjectToDirectory(parent,in);
3693                                         if(parent == dev->unlinkedDir)
3694                                         {
3695                                                 in->deleted = 1; // If it is unlinked at start up then it wants deleting
3696                                                 dev->nDeletedFiles++;
3697                                         }
3698                                 
3699                                         // Note re hardlinks.
3700                                         // Since we might scan a hardlink before its equivalent object is scanned
3701                                         // we put them all in a list.
3702                                         // After scanning is complete, we should have all the objects, so we run through this
3703                                         // list and fix up all the chains.              
3704         
3705                                         switch(in->variantType)
3706                                         {
3707                                                 case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
3708                                                         break;
3709                                                 case YAFFS_OBJECT_TYPE_FILE:
3710 #ifdef CONFIG_YAFFS_USE_HEADER_FILE_SIZE
3711                                                         in->variant.fileVariant.fileSize = oh->fileSize;
3712 #endif
3713                                                         break;
3714                                                 case YAFFS_OBJECT_TYPE_HARDLINK:
3715                                                         in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
3716                                                         (yaffs_Object *)(in->hardLinks.next) = hardList;
3717                                                         hardList = in;
3718                                                         break;
3719                                                 case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
3720                                                         break;
3721                                                 case YAFFS_OBJECT_TYPE_SPECIAL: // Do nothing
3722                                                         break;
3723                                                 case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
3724                                                         in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
3725                                                         break;
3726                                         }
3727                                         //T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));        
3728                                 }
3729                         }
3730                 }
3731                 
3732                 if(state == YAFFS_BLOCK_STATE_SCANNING)
3733                 {
3734                         // If we got this far while scanning, then the block is fully allocated.
3735                         state = YAFFS_BLOCK_STATE_FULL; 
3736                 }
3737                 
3738                 bi->blockState = state;
3739                 
3740                 // Now let's see if it was dirty
3741                 if(     bi->pagesInUse == 0 &&
3742                 bi->blockState == YAFFS_BLOCK_STATE_FULL)
3743             {
3744                 yaffs_BlockBecameDirty(dev,blk);
3745             }
3746
3747         }
3748         
3749         // Fix up the hard link chains.
3750         // We should now have scanned all the objects, now it's time to add these 
3751         // hardlinks.
3752         while(hardList)
3753         {
3754                 hl = hardList;
3755                 hardList = (yaffs_Object *)(hardList->hardLinks.next);
3756                 
3757                 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
3758                 
3759                 if(in)
3760                 {
3761                         // Add the hardlink pointers
3762                         hl->variant.hardLinkVariant.equivalentObject=in;
3763                         list_add(&hl->hardLinks,&in->hardLinks);
3764                 }
3765                 else
3766                 {
3767                         //Todo Need to report/handle this better.
3768                         // Got a problem... hardlink to a non-existant object
3769                         hl->variant.hardLinkVariant.equivalentObject=NULL;
3770                         INIT_LIST_HEAD(&hl->hardLinks);
3771                         
3772                 }
3773                 
3774         }
3775         
3776         
3777         
3778         return YAFFS_OK;
3779 }
3780
3781
3782 ////////////////////////// Directory Functions /////////////////////////
3783
3784
3785 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
3786 {
3787
3788         if(obj->siblings.prev == NULL)
3789         {
3790                 // Not initialised
3791                 INIT_LIST_HEAD(&obj->siblings);
3792                 
3793         }
3794         else if(!list_empty(&obj->siblings))
3795         {
3796                 // If it is holed up somewhere else, un hook it
3797                 list_del_init(&obj->siblings);
3798         }
3799         // Now add it
3800         list_add(&obj->siblings,&directory->variant.directoryVariant.children);
3801         obj->parent = directory;
3802         
3803         if(directory == obj->myDev->unlinkedDir)
3804         {
3805                 obj->unlinked = 1;
3806                 obj->myDev->nUnlinkedFiles++;
3807                 obj->renameAllowed = 0;
3808         }
3809 }
3810
3811 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
3812 {
3813         list_del_init(&obj->siblings);
3814         obj->parent = NULL;
3815 }
3816
3817 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const char *name)
3818 {
3819         int sum;
3820         
3821         struct list_head *i;
3822         char buffer[YAFFS_MAX_NAME_LENGTH+1];
3823         
3824         yaffs_Object *l;
3825         
3826         sum = yaffs_CalcNameSum(name);
3827         
3828         list_for_each(i,&directory->variant.directoryVariant.children)
3829         {
3830                 l = list_entry(i, yaffs_Object,siblings);
3831                 
3832                 // Special case for lost-n-found
3833                 if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
3834                 {
3835                         if(yaffs_strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
3836                         {
3837                                 return l;
3838                         }
3839                 }
3840                 else if(yaffs_SumCompare(l->sum, sum))
3841                 {
3842                         // Do a real check
3843                         yaffs_GetObjectName(l,buffer,YAFFS_MAX_NAME_LENGTH);
3844                         if(yaffs_strcmp(name,buffer) == 0)
3845                         {
3846                                 return l;
3847                         }
3848                         
3849                         
3850                 }
3851         }
3852         
3853         return NULL;
3854 }
3855
3856
3857 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
3858 {
3859         struct list_head *i;    
3860         yaffs_Object *l;
3861         
3862         
3863         list_for_each(i,&theDir->variant.directoryVariant.children)
3864         {
3865                 l = list_entry(i, yaffs_Object,siblings);
3866                 if(!fn(l))
3867                 {
3868                         return YAFFS_FAIL;
3869                 }
3870         }
3871         
3872         return YAFFS_OK;
3873
3874 }
3875
3876
3877 // GetEquivalentObject dereferences any hard links to get to the
3878 // actual object.
3879
3880 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
3881 {
3882         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
3883         {
3884                 // We want the object id of the equivalent object, not this one
3885                 obj = obj->variant.hardLinkVariant.equivalentObject;
3886         }
3887         return obj;
3888
3889 }
3890
3891 int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize)
3892 {
3893         memset(name,0,buffSize);
3894         
3895         if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
3896         {
3897                 strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
3898         }
3899         else if(obj->chunkId <= 0)
3900         {
3901                 char locName[20];
3902                 // make up a name
3903                 sprintf(locName,"%s%d",YAFFS_LOSTNFOUND_PREFIX,obj->objectId);
3904                 strncpy(name,locName,buffSize - 1);
3905
3906         }
3907         else
3908         {
3909                 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
3910                 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
3911
3912                 memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
3913         
3914                 if(obj->chunkId >= 0)
3915                 {
3916                         yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL,1);
3917                 }
3918                 strncpy(name,oh->name,buffSize - 1);
3919         }
3920         
3921         return strlen(name);
3922 }
3923
3924 int yaffs_GetObjectFileLength(yaffs_Object *obj)
3925 {
3926         
3927         // Dereference any hard linking
3928         obj = yaffs_GetEquivalentObject(obj);
3929         
3930         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
3931         {
3932                 return obj->variant.fileVariant.fileSize;
3933         }
3934         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
3935         {
3936                 return strlen(obj->variant.symLinkVariant.alias);
3937         }
3938         else
3939         {
3940                 // Only a directory should drop through to here
3941                 return YAFFS_BYTES_PER_CHUNK;
3942         }       
3943 }
3944
3945 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
3946 {
3947         int count = 0; 
3948         struct list_head *i;
3949         
3950         if(!obj->unlinked)
3951         {
3952                 count++;        // the object itself
3953         }
3954         list_for_each(i,&obj->hardLinks)
3955         {
3956                 count++;        // add the hard links;
3957         }
3958         return count;
3959         
3960 }
3961
3962
3963 int yaffs_GetObjectInode(yaffs_Object *obj)
3964 {
3965         obj = yaffs_GetEquivalentObject(obj);
3966         
3967         return obj->objectId;
3968 }
3969
3970 unsigned yaffs_GetObjectType(yaffs_Object *obj)
3971 {
3972         obj = yaffs_GetEquivalentObject(obj);
3973         
3974         switch(obj->variantType)
3975         {
3976                 case YAFFS_OBJECT_TYPE_FILE:            return DT_REG; break;
3977                 case YAFFS_OBJECT_TYPE_DIRECTORY:       return DT_DIR; break;
3978                 case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
3979                 case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
3980                 case YAFFS_OBJECT_TYPE_SPECIAL:         
3981                         if(S_ISFIFO(obj->st_mode)) return DT_FIFO;
3982                         if(S_ISCHR(obj->st_mode)) return DT_CHR;
3983                         if(S_ISBLK(obj->st_mode)) return DT_BLK;
3984                         if(S_ISSOCK(obj->st_mode)) return DT_SOCK;
3985                 default: return DT_REG; break;
3986         }
3987 }
3988
3989 char *yaffs_GetSymlinkAlias(yaffs_Object *obj)
3990 {
3991         obj = yaffs_GetEquivalentObject(obj);
3992         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
3993         {
3994                 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
3995         }
3996         else
3997         {
3998                 return yaffs_CloneString("");
3999         }
4000 }
4001
4002
4003 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
4004 {
4005         unsigned int valid = attr->ia_valid;
4006         
4007         if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
4008         if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
4009         if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
4010         
4011         if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime;
4012         if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime;
4013         if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime;
4014         
4015         if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
4016         
4017         yaffs_UpdateObjectHeader(obj,NULL,1);
4018         
4019         return YAFFS_OK;
4020         
4021 }
4022 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
4023 {
4024         unsigned int valid = 0;
4025         
4026         attr->ia_mode = obj->st_mode;   valid |= ATTR_MODE;
4027         attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
4028         attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
4029         
4030         attr->ia_atime = obj->st_atime; valid |= ATTR_ATIME;
4031         attr->ia_ctime = obj->st_ctime; valid |= ATTR_CTIME;
4032         attr->ia_mtime = obj->st_mtime; valid |= ATTR_MTIME;
4033         
4034         attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
4035         
4036         attr->ia_valid = valid;
4037         
4038         return YAFFS_OK;
4039         
4040 }
4041
4042
4043
4044 int yaffs_DumpObject(yaffs_Object *obj)
4045 {
4046 //      __u8 buffer[YAFFS_BYTES_PER_CHUNK];
4047         char name[257];
4048 //      yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
4049
4050 //      memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
4051         
4052 //      if(obj->chunkId >= 0)
4053 //      {
4054 //              yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
4055 //      }
4056         
4057         yaffs_GetObjectName(obj,name,256);
4058         
4059         YPRINTF(("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",
4060                         obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, 
4061                         obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
4062
4063 #if 0
4064         YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
4065                         obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial, 
4066                         obj->sum, obj->chunkId));
4067                 switch(obj->variantType)
4068         {
4069                 case YAFFS_OBJECT_TYPE_FILE: 
4070                         YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
4071                         break;
4072                 case YAFFS_OBJECT_TYPE_DIRECTORY:
4073                         YPRINTF((" DIRECTORY\n"));
4074                         break;
4075                 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
4076                 case YAFFS_OBJECT_TYPE_SYMLINK:
4077                 case YAFFS_OBJECT_TYPE_UNKNOWN:
4078                 default:
4079         }
4080 #endif
4081         
4082         return YAFFS_OK;
4083 }
4084
4085
4086 ///////////////////////// Initialisation code ///////////////////////////
4087
4088
4089
4090 int yaffs_GutsInitialise(yaffs_Device *dev)
4091 {
4092         unsigned x;
4093         int bits;
4094         int extraBits;
4095         int nBlocks;
4096
4097
4098         
4099         if(!yaffs_CheckStructures())
4100         {
4101                 YPRINTF(("yaffs_CheckStructures failed\n"));
4102                 return YAFFS_FAIL;
4103         }
4104         
4105         if(dev->startBlock <= 0 ||
4106            (dev->endBlock - dev->startBlock) < 10)
4107         {
4108                 YPRINTF(("startBlock %d or endBlock %d invalid\n",
4109                                 dev->startBlock, dev->endBlock));
4110                 return YAFFS_FAIL;
4111         }
4112         
4113         nBlocks = dev->endBlock - dev->startBlock + 1;
4114         
4115
4116                 
4117         // OK now calculate a few things for the device
4118         // Calculate chunkGroupBits. 
4119         // We need to find the next power of 2 > than endBlock
4120         
4121         x = YAFFS_CHUNKS_PER_BLOCK * (dev->endBlock+1);
4122         
4123         for(bits = extraBits = 0; x > 1; bits++)
4124         {
4125                 if(x & 1) extraBits++;
4126                 x >>= 1;
4127         }
4128
4129         if(extraBits > 0) bits++;
4130         
4131         
4132         // Level0 Tnodes are 16 bits, so if the bitwidth of the
4133         // chunk range we're using is greater than 16 we need 
4134         // to figure out chunk shift and chunkGroupSize
4135         if(bits <= 16) 
4136         {
4137                 dev->chunkGroupBits = 0;
4138         }
4139         else
4140         {
4141                 dev->chunkGroupBits = bits - 16;
4142         }
4143         dev->chunkGroupSize = 1 << dev->chunkGroupBits;
4144         
4145         
4146         // More device initialisation
4147         dev->garbageCollectionRequired  = 0;
4148         dev->garbageCollections = 0;
4149         dev->currentDirtyChecker = 0;
4150         dev->bufferedBlock = -1;
4151         dev->doingBufferedBlockRewrite = 0;
4152         dev->blockSelectedForGC = -1;
4153         dev->nDeletedFiles = 0;
4154         dev->nBackgroundDeletions=0;
4155         dev->nUnlinkedFiles = 0;
4156         dev->eccFixed=0;
4157         dev->eccUnfixed=0;
4158         dev->tagsEccFixed=0;
4159         dev->tagsEccUnfixed=0;
4160         
4161         yaffs_InitialiseBlocks(dev,nBlocks);
4162         
4163         yaffs_InitialiseTnodes(dev);
4164
4165         yaffs_InitialiseObjects(dev);
4166         
4167 #ifdef CONFIG_YAFFS_SHORT_OP_CACHE
4168         { 
4169                 int i;
4170                 for(i=0; i < YAFFS_N_CACHE_CHUNKS; i++)
4171                 {
4172                         dev->srCache[i].objectId = 0;
4173                         dev->srCache[i].lastUse = 0;
4174                 }
4175                 dev->srLastUse = 0;
4176         }
4177 #endif
4178
4179         dev->cacheHits = 0;
4180         
4181         
4182         // Initialise the unlinked, root and lost and found directories
4183         dev->lostNFoundDir = dev->rootDir = dev->unlinkedDir = NULL;
4184         
4185         dev->unlinkedDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_UNLINKED, S_IFDIR);
4186
4187         dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
4188         dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_LOSTNFOUND_MODE | S_IFDIR);
4189         yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
4190         
4191                 
4192         // Now scan the flash.  
4193         yaffs_Scan(dev);
4194         
4195         // Zero out stats
4196         dev->nPageReads = 0;
4197     dev->nPageWrites =  0;
4198         dev->nBlockErasures = 0;
4199         dev->nGCCopies = 0;
4200         dev->nRetriedWrites = 0;
4201         dev->nRetiredBlocks = 0;
4202
4203         
4204         return YAFFS_OK;
4205                 
4206 }
4207
4208 void yaffs_Deinitialise(yaffs_Device *dev)
4209 {
4210         yaffs_DeinitialiseBlocks(dev);
4211         yaffs_DeinitialiseTnodes(dev);
4212         yaffs_DeinitialiseObjects(dev);
4213         
4214 }
4215
4216 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
4217 {
4218         int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);
4219         
4220         struct list_head *i;    
4221         yaffs_Object *l;
4222         
4223         
4224         // To the free chunks add the chunks that are in the deleted unlinked files.
4225         list_for_each(i,&dev->unlinkedDir->variant.directoryVariant.children)
4226         {
4227                 l = list_entry(i, yaffs_Object,siblings);
4228                 if(l->deleted)
4229                 {
4230                         nFree++;
4231                         nFree += l->nDataChunks;
4232                 }
4233         }
4234
4235
4236         return (nFree < 0) ? 0 : nFree; 
4237         
4238 }
4239
4240
4241 /////////////////// YAFFS test code //////////////////////////////////
4242
4243 #define yaffs_CheckStruct(structure,syze, name) \
4244            if(sizeof(structure) != syze) \
4245                { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \
4246                  return YAFFS_FAIL; \
4247                    }
4248                  
4249                  
4250 static int yaffs_CheckStructures(void)
4251 {
4252         yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
4253         yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
4254         yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
4255         yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
4256         yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
4257         
4258         
4259         return YAFFS_OK;
4260 }
4261
4262 void yaffs_GutsTest(yaffs_Device *dev)
4263 {
4264         
4265         if(yaffs_CheckStructures() != YAFFS_OK)
4266         {
4267                 YPRINTF(("One or more structures malformed-- aborting\n"));
4268                 return;
4269         }
4270         else
4271         {
4272                 YPRINTF(("Structures OK\n"));
4273         }
4274         
4275         yaffs_TnodeTest(dev);
4276         yaffs_ObjectTest(dev);  
4277 }
4278
4279