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