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