*** empty log message ***
[yaffs/.git] / yaffs_guts.c
1 /*
2  * YAFFS: Yet another FFS. A NAND-flash specific file system.
3  * yaffs_guts.c  The main guts of YAFFS
4  *
5  * Copyright (C) 2002 Aleph One Ltd.
6  *   for Toby Churchill Ltd and Brightstar Engineering
7  *
8  * Created by Charles Manning <charles@aleph1.co.uk>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  */
15  //yaffs_guts.c
16
17 #include "yportenv.h"
18
19 #include "yaffsinterface.h"
20 #include "yaffs_guts.h"
21
22
23 #if 0
24 #define T(x) printf x
25 #else
26 #define T(x)
27 #endif
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_countBits[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
58
59 // Device info
60 //static yaffs_Device *yaffs_device;
61 //yaffs_Object *yaffs_rootDir;
62 //yaffs_Object *yaffs_lostNFound;
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_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);
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 yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
79
80 loff_t yaffs_GetFileSize(yaffs_Object *obj);
81
82
83 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
84
85 #if YAFFS_PARANOID
86 static int yaffs_CheckFileSanity(yaffs_Object *in)
87 #else
88 #define yaffs_CheckFileSanity(in)
89 #endif
90
91 static int __inline__ yaffs_HashFunction(int n)
92 {
93         return (n % YAFFS_NOBJECT_BUCKETS);
94 }
95
96
97 yaffs_Object *yaffs_Root(yaffs_Device *dev)
98 {
99         return dev->rootDir;
100 }
101
102 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
103 {
104         return dev->lostNFoundDir;
105 }
106
107
108 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
109 {
110         return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
111 }
112
113 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
114 {
115         int retVal;
116         __u8 calcEcc[3];
117         yaffs_Spare localSpare;
118         
119         if(!spare && data)
120         {
121                 // If we don't have a real spare, then we use a local one.
122                 // Need this for the calculation of the ecc
123                 spare = &localSpare;
124         }
125         
126         retVal  = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
127         if(data)
128         {
129                 // Do ECC correction
130                 //Todo handle any errors
131                  nand_calculate_ecc(data,calcEcc);
132                  nand_correct_data (data,spare->ecc1, calcEcc);
133                  nand_calculate_ecc(&data[256],calcEcc);
134                  nand_correct_data (&data[256],spare->ecc2, calcEcc);
135         }
136         return retVal;
137 }
138
139 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
140 {
141         return dev->eraseBlockInNAND(dev,blockInNAND);
142 }
143
144 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
145 {
146         return dev->initialiseNAND(dev);
147 }
148
149 static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve)
150 {
151         int chunk;
152         
153         int writeOk = 0;
154         
155         unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
156         yaffs_Spare rbSpare;
157         
158         do{
159                 chunk = yaffs_AllocateChunk(dev,useReserve);
160         
161                 if(chunk >= 0)
162                 {
163                         writeOk =  yaffs_WriteChunkToNAND(dev,chunk,data,spare);
164                         if(writeOk)
165                         {
166                                 // Readback & verify
167                                 // If verify fails, then delete this chunk and try again
168                                 // To verify we compare everything except the block and 
169                                 // page status bytes.
170                                 yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);
171                                 
172                                 if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||
173                                         spare->tagByte0 != rbSpare.tagByte0 ||
174                                         spare->tagByte1 != rbSpare.tagByte1 ||
175                                         spare->tagByte2 != rbSpare.tagByte2 ||
176                                         spare->tagByte3 != rbSpare.tagByte3 ||
177                                         spare->tagByte4 != rbSpare.tagByte4 ||
178                                         spare->tagByte5 != rbSpare.tagByte5 ||
179                                         spare->tagByte6 != rbSpare.tagByte6 ||
180                                         spare->tagByte7 != rbSpare.tagByte7 ||
181                                         spare->ecc1[0]  != rbSpare.ecc1[0]  ||
182                                         spare->ecc1[1]  != rbSpare.ecc1[1]  ||
183                                         spare->ecc1[2]  != rbSpare.ecc1[2]  ||
184                                         spare->ecc2[0]  != rbSpare.ecc2[0]  ||
185                                         spare->ecc2[1]  != rbSpare.ecc2[1]  ||
186                                         spare->ecc2[2]  != rbSpare.ecc2[2] )
187                                 {
188                                         // Didn't verify
189                                         yaffs_DeleteChunk(dev,chunk);
190                                         writeOk = 0;
191                                 }                                       
192                                 
193                         }
194                 }
195         } while(chunk >= 0 && ! writeOk);
196         
197         return chunk;
198 }
199
200
201
202
203 ///////////////////////// Object management //////////////////
204 // List of spare objects
205 // The list is hooked together using the first pointer
206 // in the object
207
208 // static yaffs_Object *yaffs_freeObjects = NULL;
209
210 // static int yaffs_nFreeObjects;
211
212 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
213
214 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
215
216
217 static __u16 yaffs_CalcNameSum(const char *name)
218 {
219         __u16 sum = 0;
220         __u16 i = 1;
221         
222         __u8 *bname = (__u8 *)name;
223         
224         while (*bname)
225         {
226                 sum += (*bname) * i;
227                 i++;
228                 bname++;
229         }
230         return sum;
231 }
232
233
234 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
235 {
236         nand_calculate_ecc (data , spare->ecc1);
237         nand_calculate_ecc (&data[256] , spare->ecc2);
238 }
239
240 void yaffs_CalcTagsECC(yaffs_Tags *tags)
241 {
242         // Todo don't do anything yet. Need to calculate ecc
243         unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
244         unsigned  i,j;
245         unsigned  ecc = 0;
246         unsigned bit = 0;
247
248         tags->ecc = 0;
249         
250         for(i = 0; i < 8; i++)
251         {
252                 for(j = 1; j &0x7f; j<<=1)
253                 {
254                         bit++;
255                         if(b[i] & j)
256                         {
257                                 ecc ^= bit;
258                         }
259                 }
260         }
261         
262         tags->ecc = ecc;
263         
264         
265 }
266
267 void yaffs_CheckECCOnTags(yaffs_Tags *tags)
268 {
269         unsigned ecc = tags->ecc;
270         
271         yaffs_CalcTagsECC(tags);
272         
273         ecc ^= tags->ecc;
274         
275         if(ecc)
276         {
277                 // Needs fixing
278                 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
279
280                 ecc--;
281                                 
282                 b[ecc / 8] ^= (1 << (ecc & 7));
283                 
284                 // Now recvalc the ecc
285                 yaffs_CalcTagsECC(tags);
286         }
287 }
288
289
290 ///////////////////////// TNODES ///////////////////////
291
292 // List of spare tnodes
293 // The list is hooked together using the first pointer
294 // in the tnode.
295
296 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
297
298 // static int yaffs_nFreeTnodes;
299
300 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
301
302
303
304 // yaffs_CreateTnodes creates a bunch more tnodes and
305 // adds them to the tnode free list.
306 // Don't use this function directly
307
308 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
309 {
310     int i;
311     yaffs_Tnode *newTnodes;
312     yaffs_TnodeList *tnl;
313     
314     if(nTnodes < 1) return YAFFS_OK;
315    
316         // make these things
317         
318     newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
319    
320     if (!newTnodes)
321     {
322                 YALERT("Could not malloc tnodes");
323                 return YAFFS_FAIL;
324     }
325     
326     // Hook them into the free list
327     for(i = 0; i < nTnodes - 1; i++)
328     {
329         newTnodes[i].internal[0] = &newTnodes[i+1];
330     }
331         
332         newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
333         dev->freeTnodes = newTnodes;
334         dev->nFreeTnodes+= nTnodes;
335         dev->nTnodesCreated += nTnodes;
336
337         // Now add this bunch of tnodes to a list for freeing up.
338
339         tnl = YMALLOC(sizeof(yaffs_TnodeList));
340         if(!tnl)
341         {
342                 YALERT("Could not add tnodes to management list");
343         }
344         else
345         {
346                 tnl->tnodes = newTnodes;
347                 tnl->next = dev->allocatedTnodeList;
348                 dev->allocatedTnodeList = tnl;
349         }
350
351
352         YINFO("Tnodes created");
353
354
355         return YAFFS_OK;
356 }
357
358
359 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
360 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
361 {
362         yaffs_Tnode *tn = NULL;
363         
364         // If there are none left make more
365         if(!dev->freeTnodes)
366         {
367                 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
368         }
369         
370         if(dev->freeTnodes)
371         {
372                 tn = dev->freeTnodes;
373                 dev->freeTnodes = dev->freeTnodes->internal[0];
374                 dev->nFreeTnodes--;
375                 // zero out
376                 memset(tn,0,sizeof(yaffs_Tnode));
377         }
378         
379
380         return tn;
381 }
382
383
384 // FreeTnode frees up a tnode and puts it back on the free list
385 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
386 {
387         tn->internal[0] = dev->freeTnodes;
388         dev->freeTnodes = tn;
389         dev->nFreeTnodes++;
390 }
391
392
393 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
394 {
395         // Free the list of allocated tnodes
396         
397         while(dev->allocatedTnodeList)
398         {
399                 YFREE(dev->allocatedTnodeList->tnodes);
400                 dev->allocatedTnodeList =  dev->allocatedTnodeList->next;
401         }
402         
403         dev->freeTnodes = NULL;
404         dev->nFreeTnodes = 0;
405 }
406
407 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
408 {
409         dev->allocatedTnodeList = NULL;
410         dev->freeTnodes = NULL;
411         dev->nFreeTnodes = 0;
412         dev->nTnodesCreated = 0;
413
414 }
415
416 void yaffs_TnodeTest(yaffs_Device *dev)
417 {
418
419         int i;
420         int j;
421         yaffs_Tnode *tn[1000];
422         
423         YINFO("Testing TNodes");
424         
425         for(j = 0; j < 50; j++)
426         {
427                 for(i = 0; i < 1000; i++)
428                 {
429                         tn[i] = yaffs_GetTnode(dev);
430                         if(!tn[i])
431                         {
432                                 YALERT("Getting tnode failed");
433                         }
434                 }
435                 for(i = 0; i < 1000; i+=3)
436                 {
437                         yaffs_FreeTnode(dev,tn[i]);
438                         tn[i] = NULL;
439                 }
440                 
441         }
442 }
443
444 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
445
446 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
447 // The look up tree is represented by the top tnode and the number of topLevel
448 // in the tree. 0 means only the level 0 tnode is in the tree.
449
450
451 // FindLevel0Tnode finds the level 0 tnode, if one exists.
452 // Used when reading.....
453 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
454 {
455         
456         yaffs_Tnode *tn = fStruct->top;
457         __u32 i;
458         int requiredTallness;   
459         int level = fStruct->topLevel;
460         
461         // Check sane level and chunk Id
462         if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
463         {
464                 char str[50];
465                 sprintf(str,"Bad level %d",level);
466                 YALERT(str);
467                 return NULL;
468         }
469         if(chunkId > YAFFS_MAX_CHUNK_ID)
470         {
471                 char str[50];
472                 sprintf(str,"Bad chunkId %d",chunkId);
473                 YALERT(str);
474                 return NULL;
475         }
476
477         // First check we're tall enough (ie enough topLevel)
478         
479         i = chunkId >> (dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS);
480         requiredTallness = 0;
481         while(i)
482         {
483                 i >>= YAFFS_TNODES_INTERNAL_BITS;
484                 requiredTallness++;
485         }
486         
487         
488         if(requiredTallness > fStruct->topLevel)
489         {
490                 // Not tall enough, so we can't find it, return NULL.
491                 return NULL;
492         }
493                 
494         
495         // Traverse down to level 0
496         while (level > 0 && tn)
497         {
498             tn = tn->internal[(chunkId >>(dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
499                                YAFFS_TNODES_INTERNAL_MASK]; 
500                 level--;
501         
502         }
503         
504         return tn;              
505 }
506
507 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
508 // This happens in two steps:
509 //  1. If the tree isn't tall enough, then make it taller.
510 //  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
511 //
512 // Used when modifying the tree.
513 //
514 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
515 {
516         
517         yaffs_Tnode *tn; 
518         
519         int requiredTallness;
520         
521         __u32 i;
522         __u32 l;
523         
524         
525         T(("AddOrFind topLevel=%d, chunk=%d",fStruct->topLevel,chunkId));
526         
527         // Check sane level and page Id
528         if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
529         {
530                 char str[50];
531                 sprintf(str,"Bad level %d",fStruct->topLevel);
532                 YALERT(str);
533                 return NULL;
534         }
535         
536         if(chunkId > YAFFS_MAX_CHUNK_ID)
537         {
538                 char str[50];
539                 sprintf(str,"Bad chunkId %d",chunkId);
540                 YALERT(str);
541                 return NULL;
542         }
543         
544         // First check we're tall enough (ie enough topLevel)
545         
546         i = chunkId >> (dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS);
547         requiredTallness = 0;
548         while(i)
549         {
550                 i >>= YAFFS_TNODES_INTERNAL_BITS;
551                 requiredTallness++;
552         }
553         
554         T((" required=%d",requiredTallness));
555         
556         
557         if(requiredTallness > fStruct->topLevel)
558         {
559                 // Not tall enough,gotta make the tree taller
560                 for(i = fStruct->topLevel; i < requiredTallness; i++)
561                 {
562                         T((" add new top"));
563                         
564                         tn = yaffs_GetTnode(dev);
565                         
566                         if(tn)
567                         {
568                                 tn->internal[0] = fStruct->top;
569                                 fStruct->top = tn;
570                         }
571                         else
572                         {
573                                 YALERT("No more tnodes");
574                         }
575                 }
576                 
577                 fStruct->topLevel = requiredTallness;
578         }
579         
580         
581         // Traverse down to level 0, adding anything we need
582         
583         l = fStruct->topLevel;
584         tn = fStruct->top;
585         while (l > 0 && tn)
586         {
587                 i = (chunkId >> (dev->chunkGroupBits +YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) & 
588                                YAFFS_TNODES_INTERNAL_MASK;
589                                
590                 T((" [%d:%d]",l,i));
591                 
592             if(!tn->internal[i])
593             {
594                 T((" added"));
595                 
596                 tn->internal[i] = yaffs_GetTnode(dev);
597             }
598             
599             tn =        tn->internal[i];
600                 l--;
601         
602         }
603         
604         T(("\n"));
605         
606         return tn;              
607 }
608
609
610 // Pruning removes any part of the file structure tree that is beyond the
611 // bounds of the file.
612 // A file should only get pruned when its size is reduced.
613 //
614 // Before pruning, the chunks must be pulled from the tree and the
615 // level 0 tnode entries must be zeroed out.
616 // Could also use this for file deletion, but that's probably better handled
617 // by a special case.
618
619 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
620
621 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
622 {
623         int i;
624         int hasData;
625         
626         if(tn)
627         {
628                 hasData = 0;
629                 
630                 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
631                 {
632                     if(tn->internal[i] && level > 0)
633                     {
634                         tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
635                     }
636                     
637                     if(tn->internal[i])
638                     {
639                         hasData++;
640                         }
641                 }
642                 
643                 if(hasData == 0 && del0)
644                 {
645                         // Free and return NULL
646                         
647                         yaffs_FreeTnode(dev,tn);
648                         tn = NULL;
649                 }
650                 
651         }
652
653         return tn;
654         
655 }
656
657 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
658 {
659         int i;
660         int hasData;
661         int done = 0;
662         yaffs_Tnode *tn;
663         
664         if(fStruct->topLevel > 0)
665         {
666                 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
667                 
668                 // Now we have a tree with all the non-zero branches NULL but the height
669                 // is the same as it was.
670                 // Let's see if we can trim internal tnodes to shorten the tree.
671                 // We can do this if only the 0th element in the tnode is in use 
672                 // (ie all the non-zero are NULL)
673                 
674                 while(fStruct->topLevel && !done)
675                 {
676                         tn = fStruct->top;
677                         
678                         hasData = 0;
679                         for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
680                         {
681                                 if(tn->internal[i])
682                         {
683                                 hasData++;
684                                 }
685                         }
686                         
687                         if(!hasData)
688                         {
689                                 fStruct->top = tn->internal[0];
690                                 fStruct->topLevel--;
691                                 yaffs_FreeTnode(dev,tn);
692                         }
693                         else
694                         {
695                                 done = 1;
696                         }
697                 }
698         }
699         
700         return YAFFS_OK;
701 }
702
703
704
705
706 /////////////////////// End of File Structure functions. /////////////////
707
708 // yaffs_CreateFreeObjects creates a bunch more objects and
709 // adds them to the object free list.
710 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
711 {
712     int i;
713     yaffs_Object *newObjects;
714     yaffs_ObjectList *list;
715     
716     if(nObjects < 1) return YAFFS_OK;
717    
718         // make these things
719         
720     newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
721    
722     if (!newObjects)
723     {
724                 YALERT("Could not allocate more objects");
725                 return YAFFS_FAIL;
726     }
727     
728     // Hook them into the free list
729     for(i = 0; i < nObjects - 1; i++)
730     {
731         (yaffs_Object *)newObjects[i].siblings.next = &newObjects[i+1];
732     }
733         
734         newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
735         dev->freeObjects = newObjects;
736         dev->nFreeObjects+= nObjects;
737         dev->nObjectsCreated+= nObjects;
738         
739         // Now add this bunch of Objects to a list for freeing up.
740         
741         list = YMALLOC(sizeof(yaffs_ObjectList));
742         if(!list)
743         {
744                 YALERT("Could not add Objects to management list");
745         }
746         else
747         {
748                 list->objects = newObjects;
749                 list->next = dev->allocatedObjectList;
750                 dev->allocatedObjectList = list;
751         }
752         
753         
754         YINFO("Objects created");
755         
756         
757         return YAFFS_OK;
758 }
759
760
761 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
762 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
763 {
764         yaffs_Object *tn = NULL;
765         
766         // If there are none left make more
767         if(!dev->freeObjects)
768         {
769                 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
770         }
771         
772         if(dev->freeObjects)
773         {
774                 tn = dev->freeObjects;
775                 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
776                 dev->nFreeObjects--;
777                 
778                 // Now sweeten it up...
779         
780                 memset(tn,0,sizeof(yaffs_Object));
781                 tn->chunkId = -1;
782                 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
783                 INIT_LIST_HEAD(&(tn->hardLinks));
784                 INIT_LIST_HEAD(&(tn->hashLink));
785                 INIT_LIST_HEAD(&tn->siblings);
786                 
787                 // Add it to the lost and found directory.
788                 // NB Can't put root or lostNFound in lostNFound so
789                 // check if lostNFound exists first
790                 if(dev->lostNFoundDir)
791                 {
792                         yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);      
793                 }
794         }
795         
796
797         return tn;
798 }
799
800 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
801 {
802
803         yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);              
804         if(obj)
805         {
806                 obj->fake = 1;                  // it is fake so it has no NAND presence...
807                 obj->renameAllowed= 0;  // ... and we're not allowed to rename it...
808                 obj->unlinkAllowed= 0;  // ... or unlink it
809                 obj->st_mode = mode;
810                 obj->myDev = dev;
811                 obj->chunkId = 0; // Not a valid chunk.
812         }
813         
814         return obj;
815         
816 }
817
818
819 static void yaffs_UnhashObject(yaffs_Object *tn)
820 {
821         int bucket;
822         yaffs_Device *dev = tn->myDev;
823         
824         
825         // If it is still linked into the bucket list, free from the list
826         if(!list_empty(&tn->hashLink))
827         {
828                 list_del_init(&tn->hashLink);
829                 bucket =  yaffs_HashFunction(tn->objectId);
830                 dev->objectBucket[bucket].count--;
831         }
832         
833 }
834
835
836 // FreeObject frees up a Object and puts it back on the free list
837 static void yaffs_FreeObject(yaffs_Object *tn)
838 {
839
840         yaffs_Device *dev = tn->myDev;
841         
842         yaffs_UnhashObject(tn);
843         
844         // Link into the free list.
845         (yaffs_Object *)(tn->siblings.next) = dev->freeObjects;
846         dev->freeObjects = tn;
847         dev->nFreeObjects++;
848 }
849
850
851
852
853 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
854 {
855         // Free the list of allocated Objects
856         
857         while( dev->allocatedObjectList)
858         {
859                 YFREE(dev->allocatedObjectList->objects);
860                 dev->allocatedObjectList =  dev->allocatedObjectList->next;
861         }
862         
863         dev->freeObjects = NULL;
864         dev->nFreeObjects = 0;
865 }
866
867 static void yaffs_InitialiseObjects(yaffs_Device *dev)
868 {
869         int i;
870         
871         dev->allocatedObjectList = NULL;
872         dev->freeObjects = NULL;
873         dev->nFreeObjects = 0;
874         
875         for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
876         {
877                 INIT_LIST_HEAD(&dev->objectBucket[i].list);
878                 dev->objectBucket[i].count = 0; 
879         }
880
881 }
882
883
884
885
886
887
888 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
889 {
890         static int x = 0;
891         int i;
892         int l = 999;
893         int lowest = 999999;
894
895                 
896         // First let's see if we can find one that's empty.
897         
898         for(i = 0; i < 10 && lowest > 0; i++)
899          {
900                 x++;
901                 x %=  YAFFS_NOBJECT_BUCKETS;
902                 if(dev->objectBucket[x].count < lowest)
903                 {
904                         lowest = dev->objectBucket[x].count;
905                         l = x;
906                 }
907                 
908         }
909         
910         // If we didn't find an empty list, then try
911         // looking a bit further for a short one
912         
913         for(i = 0; i < 10 && lowest > 3; i++)
914          {
915                 x++;
916                 x %=  YAFFS_NOBJECT_BUCKETS;
917                 if(dev->objectBucket[x].count < lowest)
918                 {
919                         lowest = dev->objectBucket[x].count;
920                         l = x;
921                 }
922                 
923         }
924         
925         return l;
926 }
927
928 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
929 {
930         int bucket = yaffs_FindNiceObjectBucket(dev);
931         
932         // Now find an object value that has not already been taken
933         // by scanning the list.
934         
935         int found = 0;
936         struct list_head *i;
937         
938         int n = bucket;
939
940         //yaffs_CheckObjectHashSanity();        
941         
942         while(!found)
943         {
944                 found = 1;
945                 n +=  YAFFS_NOBJECT_BUCKETS;
946                 if(1 ||dev->objectBucket[bucket].count > 0)
947                 {
948                         list_for_each(i,&dev->objectBucket[bucket].list)
949                         {
950                                 // If there is already one in the list
951                                 if(list_entry(i, yaffs_Object,hashLink)->objectId == n)
952                                 {
953                                         found = 0;
954                                 }
955                         }
956                 }
957         }
958         
959         //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
960         
961         return n;       
962 }
963
964 void yaffs_HashObject(yaffs_Object *in)
965 {
966         int bucket = yaffs_HashFunction(in->objectId);
967         yaffs_Device *dev = in->myDev;
968         
969         if(!list_empty(&in->hashLink))
970         {
971                 YINFO("!!!");
972         }
973         
974         
975         list_add(&in->hashLink,&dev->objectBucket[bucket].list);
976         dev->objectBucket[bucket].count++;
977
978 }
979
980 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,int number)
981 {
982         int bucket = yaffs_HashFunction(number);
983         struct list_head *i;
984         yaffs_Object *in;
985         
986         list_for_each(i,&dev->objectBucket[bucket].list)
987         {
988                 // Lookm if it is in the list
989                 in = list_entry(i, yaffs_Object,hashLink);
990                 if(in->objectId == number)
991                 {
992                         return in;
993                 }
994         }
995         
996         return NULL;
997 }
998
999
1000
1001 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1002 {
1003                 
1004         yaffs_Object *theObject;
1005
1006         if(number < 0)
1007         {
1008                 number = yaffs_CreateNewObjectNumber(dev);
1009         }
1010         
1011         theObject = yaffs_AllocateEmptyObject(dev);
1012         
1013         if(theObject)
1014         {
1015                 theObject->fake = 0;
1016                 theObject->renameAllowed = 1;
1017                 theObject->unlinkAllowed = 1;
1018                 theObject->objectId = number;
1019                 theObject->myDev = dev;
1020                 yaffs_HashObject(theObject);
1021                 theObject->variantType = type;
1022                 theObject->st_atime = theObject->st_mtime =     theObject->st_ctime = CURRENT_TIME;
1023
1024                 switch(type)
1025                 {
1026                         case YAFFS_OBJECT_TYPE_FILE: 
1027                                 theObject->variant.fileVariant.fileSize = 0;
1028                                 theObject->variant.fileVariant.topLevel = 0;
1029                                 theObject->variant.fileVariant.top  = yaffs_GetTnode(dev);
1030                                 break;
1031                         case YAFFS_OBJECT_TYPE_DIRECTORY:
1032                                 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1033                                 break;
1034                         case YAFFS_OBJECT_TYPE_SYMLINK:
1035                                 // No action required
1036                                 break;
1037                         case YAFFS_OBJECT_TYPE_HARDLINK:
1038                                 // No action required
1039                                 break;
1040                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1041                                 // todo this should not happen
1042                 }
1043         }
1044         
1045         return theObject;
1046 }
1047
1048 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1049 {
1050         yaffs_Object *theObject = NULL;
1051         
1052         if(number >= 0)
1053         {
1054                 theObject = yaffs_FindObjectByNumber(dev,number);
1055         }
1056         
1057         if(!theObject)
1058         {
1059                 theObject = yaffs_CreateNewObject(dev,number,type);
1060         }
1061         
1062         return theObject;
1063
1064 }
1065
1066 char *yaffs_CloneString(const char *str)
1067 {
1068         char *newStr = NULL;
1069         
1070         if(str && *str)
1071         {
1072                 newStr = YMALLOC(strlen(str) + 1);
1073                 strcpy(newStr,str);
1074         }
1075
1076         return newStr;
1077         
1078 }
1079
1080 //
1081 // Mknod (create) a new object.
1082 // equivalentObject only has meaning for a hard link;
1083 // aliasString only has meaning for a sumlink.
1084 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1085                                                                  yaffs_Object *parent,
1086                                                                  const char *name, 
1087                                                                  __u32 mode,
1088                                                                  __u32 uid,
1089                                                                  __u32 gid,
1090                                                                  yaffs_Object *equivalentObject,
1091                                                                  const char *aliasString)
1092 {
1093         yaffs_Object *in;
1094
1095         yaffs_Device *dev = parent->myDev;
1096         
1097         in = yaffs_CreateNewObject(dev,-1,type);
1098         
1099         if(in)
1100         {
1101                 in->chunkId = -1;
1102                 in->valid = 1;
1103                 in->variantType = type;
1104
1105                 in->st_mode  = mode;
1106                 in->st_uid   = uid;
1107                 in->st_gid   = gid;
1108                 in->st_atime =  in->st_mtime =  in->st_ctime = CURRENT_TIME;
1109
1110                 in->sum = yaffs_CalcNameSum(name);
1111                 in->dirty = 1;
1112                 
1113                 yaffs_AddObjectToDirectory(parent,in);
1114                 
1115                 in->myDev = parent->myDev;
1116                 
1117                                 
1118                 switch(type)
1119                 {
1120                         case YAFFS_OBJECT_TYPE_SYMLINK:
1121                                 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1122                                 break;
1123                         case YAFFS_OBJECT_TYPE_HARDLINK:
1124                                 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1125                                 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1126                                 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1127                                 break;
1128                         case YAFFS_OBJECT_TYPE_FILE: // do nothing
1129                         case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1130                         case YAFFS_OBJECT_TYPE_UNKNOWN:
1131                 }
1132
1133                 yaffs_UpdateObjectHeader(in,name);
1134
1135         }
1136         
1137         return in;
1138 }
1139
1140 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1141 {
1142         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL);
1143 }
1144
1145 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1146 {
1147         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL);
1148 }
1149
1150 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid,const char *alias)
1151 {
1152         return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias);
1153 }
1154
1155 // NB yaffs_Link returns the object id of the equivalent object.
1156 yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *equivalentObject)
1157 {
1158         // Get the real object in case we were fed a hard link as an equivalent object
1159         equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1160         
1161         if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL))
1162         {
1163                 return equivalentObject;
1164         }
1165         else
1166         {
1167                 return NULL;
1168         }
1169         
1170 }
1171
1172
1173 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName)
1174 {
1175         //yaffs_Device *dev = obj->myDev;
1176
1177         if(newDir == NULL)
1178         {
1179                 newDir = obj->parent; // use the old directory
1180         }
1181         
1182         // Only proceed if the new name does not exist and
1183         // if we're putting it into a directory.
1184         if(!yaffs_FindObjectByName(newDir,newName) &&
1185             newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1186         {
1187                 obj->sum = yaffs_CalcNameSum(newName);
1188                 obj->dirty = 1;
1189                 yaffs_AddObjectToDirectory(newDir,obj);
1190                 
1191                 return yaffs_UpdateObjectHeader(obj,newName);   
1192         }
1193         
1194         return YAFFS_FAIL;
1195 }
1196
1197 int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName)
1198 {
1199         yaffs_Object *obj;
1200         
1201         obj = yaffs_FindObjectByName(oldDir,oldName);
1202         if(obj && obj->renameAllowed)
1203         {
1204                 return yaffs_ChangeObjectName(obj,newDir,newName);
1205         }
1206         return YAFFS_FAIL;
1207 }
1208
1209
1210
1211 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
1212 {
1213         // Scan the buckets and check that the lists 
1214         // have as many members as the count says there are
1215         int bucket;
1216         int countEm;
1217         struct list_head *j;
1218         int ok = YAFFS_OK;
1219         
1220         for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
1221         {
1222                 countEm = 0;
1223                 
1224                 list_for_each(j,&dev->objectBucket[bucket].list)
1225                 {
1226                         countEm++;
1227                 }
1228                 
1229                 if(countEm != dev->objectBucket[bucket].count)
1230                 {
1231                         YALERT("Inode hash inconsistency");
1232                         ok = YAFFS_FAIL;
1233                 }
1234         }
1235
1236         return ok;
1237 }
1238
1239 void yaffs_ObjectTest(yaffs_Device *dev)
1240 {
1241         yaffs_Object *in[1000];
1242         int inNo[1000];
1243         yaffs_Object *inold[1000];
1244         int i;
1245         int j;
1246         
1247         memset(in,0,1000*sizeof(yaffs_Object *));
1248         memset(inold,0,1000*sizeof(yaffs_Object *));
1249         
1250         yaffs_CheckObjectHashSanity(dev);
1251         
1252         for(j = 0; j < 10; j++)
1253         {
1254                 T(("%d\n",j));
1255                 
1256                 for(i = 0; i < 1000; i++)
1257                 {
1258                         in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
1259                         if(!in[i])
1260                         {
1261                                 YINFO("No more inodes");
1262                         }
1263                         else
1264                         {
1265                                 inNo[i] = in[i]->objectId;
1266                         }
1267                 }
1268                 
1269                 for(i = 0; i < 1000; i++)
1270                 {
1271                         if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
1272                         {
1273                                 T(("Differnce in look up test\n"));
1274                         }
1275                         else
1276                         {
1277                                 // T(("Look up ok\n"));
1278                         }
1279                 }
1280                 
1281                 yaffs_CheckObjectHashSanity(dev);
1282         
1283                 for(i = 0; i < 1000; i+=3)
1284                 {
1285                         yaffs_FreeObject(in[i]);        
1286                         in[i] = NULL;
1287                 }
1288                 
1289         
1290                 yaffs_CheckObjectHashSanity(dev);
1291         }
1292                 
1293 }
1294
1295
1296
1297 /////////////////////////// Block Management and Page Allocation ///////////////////
1298
1299
1300 static void yaffs_InitialiseBlocks(yaffs_Device *dev)
1301 {
1302         dev->blockInfo = YMALLOC(dev->nBlocks * sizeof(yaffs_BlockInfo));
1303         memset(dev->blockInfo,0,dev->nBlocks * sizeof(yaffs_BlockInfo));
1304         dev->allocationBlock = -1; // force it to get a new one
1305 }
1306
1307 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
1308 {
1309         YFREE(dev->blockInfo);
1310 }
1311
1312 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
1313 // for garbage collection.
1314
1315 static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
1316 {
1317
1318         int b = dev->currentDirtyChecker;
1319         
1320         int i;
1321         int dirtiest = -1;
1322         int pagesInUse = 100; // silly big number
1323         
1324         for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)
1325         {
1326                 b++;
1327                 if (b > dev->endBlock)
1328                 {
1329                         b =  dev->startBlock;
1330                 }
1331                 
1332                 if(dev->blockInfo[b].blockState == YAFFS_BLOCK_STATE_FULL &&
1333                    (dev->blockInfo)[b].pagesInUse < pagesInUse)
1334                 {
1335                         dirtiest = b;
1336                         pagesInUse = (dev->blockInfo)[b].pagesInUse;
1337                 }
1338         }
1339         
1340         dev->currentDirtyChecker = b;
1341         
1342         return dirtiest;
1343 }
1344
1345
1346 static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)
1347 {
1348         int i;
1349         
1350         if(useReserve && dev->nErasedBlocks < 1)
1351         {
1352                 // Hoosterman we've got a problem.
1353                 // Can't get space to gc
1354                 return -1;
1355         }
1356         else if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1357         {
1358                 // We are not in GC, so we hold some in reserve so we can get
1359                 // a gc done.
1360         }
1361         
1362         // Find an empty block.
1363         
1364         for(i = dev->startBlock; i <= dev->endBlock; i++)
1365         {
1366                         
1367                 if(dev->blockInfo[i].blockState == YAFFS_BLOCK_STATE_EMPTY)
1368                 {
1369                         dev->blockInfo[i].blockState = YAFFS_BLOCK_STATE_ALLOCATING;
1370                         dev->nErasedBlocks--;
1371                         if(dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1372                         {
1373                                 dev->garbageCollectionRequired = 1;
1374                         }
1375                         
1376                         return i;
1377                 }
1378         }
1379         
1380         return -1;      
1381 }
1382
1383
1384 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
1385 {
1386         yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];
1387         
1388         // Mark as dirty, erase it and mark as clean.
1389         bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
1390         yaffs_EraseBlockInNAND(dev,blockNo);
1391         bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
1392         dev->nErasedBlocks++;
1393         bi->pagesInUse = 0;
1394         bi->pageBits = 0;
1395         
1396         T(("Erased block %d\n",blockNo));
1397 }
1398
1399
1400 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
1401 {
1402         int retVal;
1403         
1404         if(dev->allocationBlock < 0)
1405         {
1406                 // Get next block to allocate off
1407                 dev->allocationBlock = yaffs_FindBlockForAllocation(dev,useReserve);
1408                 dev->allocationPage = 0;
1409         }
1410         
1411         // Next page please....
1412         if(dev->allocationBlock >= 0)
1413         {
1414                 retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) + 
1415                                   dev->allocationPage;
1416                 dev->blockInfo[dev->allocationBlock].pagesInUse++;
1417                 dev->blockInfo[dev->allocationBlock].pageBits |= 
1418                                 (1 << (dev->allocationPage));
1419
1420                 dev->allocationPage++;
1421                 
1422                 dev->nFreeChunks--;
1423                 
1424                 // If the block is full set the state to full
1425                 if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK)
1426                 {
1427                         dev->blockInfo[dev->allocationBlock].blockState = YAFFS_BLOCK_STATE_FULL;
1428                         dev->allocationBlock = -1;
1429                 }
1430
1431 #ifdef YAFFS_PARANOID
1432                 if(yaffs_CheckChunkErased(retVal) == YAFFS_FAIL)
1433                 {
1434                         T(("..................Trying to allocate non-erased page %d\n",retVal));
1435                 }
1436 #endif          
1437                 return retVal;
1438                 
1439         }
1440         T(("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!\n"));
1441
1442         return -1;      
1443 }
1444
1445
1446 int  yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
1447 {
1448         int oldChunk;
1449         int newChunk;
1450         __u32 mask;
1451         
1452         
1453         yaffs_Spare spare;
1454         yaffs_Tags  tags;
1455                 __u8  buffer[YAFFS_BYTES_PER_CHUNK];
1456         
1457         yaffs_BlockInfo *bi = &dev->blockInfo[block];
1458         
1459         yaffs_Object *object;
1460
1461         T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));  
1462         
1463         for(mask = 1,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK; 
1464             mask && bi->pageBits;
1465             mask <<= 1, oldChunk++ )
1466         {
1467                 if(bi->pageBits & mask)
1468                 {
1469                         
1470                         // This page is in use and needs to be copied off
1471                         
1472                         T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
1473                         
1474                         yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare);
1475                         
1476                         yaffs_GetTagsFromSpare(&spare,&tags);
1477                         tags.serialNumber++;
1478                         yaffs_LoadTagsIntoSpare(&spare,&tags);
1479
1480 #if 0
1481                         newChunk = yaffs_AllocatePage(dev,1);
1482                         if(newChunk < 0)
1483                         {
1484                                 return YAFFS_FAIL;
1485                         }
1486
1487                         yaffs_WriteChunkToNAND(dev,newChunk, buffer, &spare);
1488
1489 #else
1490                         newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);
1491 #endif
1492                         if(newChunk < 0)
1493                         {
1494                                 return YAFFS_FAIL;
1495                         }
1496
1497                         object = yaffs_FindObjectByNumber(dev,tags.objectId);
1498                         
1499                         // Ok, now fix up the Tnodes etc.
1500                         
1501                         if(tags.chunkId == 0)
1502                         {
1503                                 // It's a header
1504                                 object->chunkId = newChunk;
1505                         }
1506                         else
1507                         {
1508                                 // It's a data chunk
1509                                 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
1510
1511                         }
1512                         
1513                         yaffs_DeleteChunk(dev,oldChunk);                        
1514                         
1515                 }
1516         }
1517
1518         return YAFFS_OK;
1519 }
1520
1521 int yaffs_CheckGarbageCollection(yaffs_Device *dev)
1522 {
1523         int block;
1524         
1525         if(dev->garbageCollectionRequired)
1526         {
1527                 dev->garbageCollectionRequired = 0;
1528                 block = yaffs_FindDirtiestBlock(dev);
1529                 if(block >= 0)
1530                 {
1531                         return yaffs_GarbageCollectBlock(dev,block);
1532                 }       
1533                 else
1534                 {
1535                         return YAFFS_FAIL;
1536                 }
1537         }
1538
1539         return YAFFS_OK;
1540 }
1541
1542
1543 //////////////////////////// TAGS ///////////////////////////////////////
1544
1545 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
1546 {
1547         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
1548         
1549         yaffs_CalcTagsECC(tagsPtr);
1550         
1551         sparePtr->tagByte0 = tu->asBytes[0];
1552         sparePtr->tagByte1 = tu->asBytes[1];
1553         sparePtr->tagByte2 = tu->asBytes[2];
1554         sparePtr->tagByte3 = tu->asBytes[3];
1555         sparePtr->tagByte4 = tu->asBytes[4];
1556         sparePtr->tagByte5 = tu->asBytes[5];
1557         sparePtr->tagByte6 = tu->asBytes[6];
1558         sparePtr->tagByte7 = tu->asBytes[7];
1559 }
1560
1561 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
1562 {
1563         yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
1564
1565         tu->asBytes[0]= sparePtr->tagByte0;
1566         tu->asBytes[1]= sparePtr->tagByte1;
1567         tu->asBytes[2]= sparePtr->tagByte2;
1568         tu->asBytes[3]= sparePtr->tagByte3;
1569         tu->asBytes[4]= sparePtr->tagByte4;
1570         tu->asBytes[5]= sparePtr->tagByte5;
1571         tu->asBytes[6]= sparePtr->tagByte6;
1572         tu->asBytes[7]= sparePtr->tagByte7;
1573         
1574         yaffs_CheckECCOnTags(tagsPtr);
1575 }
1576
1577 static void yaffs_SpareInitialise(yaffs_Spare *spare)
1578 {
1579         memset(spare,0xFF,sizeof(yaffs_Spare));
1580 }
1581
1582 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags)
1583 {
1584         if(tags)
1585         {
1586                 yaffs_Spare spare;
1587                 if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare) == YAFFS_OK)
1588                 {
1589                         yaffs_GetTagsFromSpare(&spare,tags);
1590                         return YAFFS_OK;
1591                 }
1592                 else
1593                 {
1594                         return YAFFS_FAIL;
1595                 }
1596         }
1597         
1598         return YAFFS_OK;
1599 }
1600
1601 static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags)
1602 {
1603         // NB There must be tags, data is optional
1604         // If there is data, then an ECC is calculated on it.
1605         
1606         yaffs_Spare spare;
1607         
1608         if(!tags)
1609         {
1610                 return YAFFS_FAIL;
1611         }
1612         
1613         yaffs_SpareInitialise(&spare);
1614         
1615
1616         if(buffer)
1617         {
1618                 yaffs_CalcECC(buffer,&spare);
1619         }
1620         
1621         yaffs_LoadTagsIntoSpare(&spare,tags);
1622         
1623         return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
1624         
1625 }
1626
1627 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve)
1628 {
1629         // NB There must be tags, data is optional
1630         // If there is data, then an ECC is calculated on it.
1631         
1632         yaffs_Spare spare;
1633         
1634         if(!tags)
1635         {
1636                 return YAFFS_FAIL;
1637         }
1638         
1639         yaffs_SpareInitialise(&spare);
1640         
1641
1642         if(buffer)
1643         {
1644                 yaffs_CalcECC(buffer,&spare);
1645         }
1646         
1647         yaffs_LoadTagsIntoSpare(&spare,tags);
1648         
1649         return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
1650         
1651 }
1652
1653
1654
1655
1656 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
1657 {
1658         //Get the Tnode, then get the level 0 offset chunk offset
1659     yaffs_Tnode *tn;     
1660     int theChunk = -1;
1661     yaffs_Tags localTags;
1662     int i;
1663     int found = 0;
1664     yaffs_Device *dev = in->myDev;
1665     
1666     
1667     if(!tags)
1668     {
1669         // Passed a NULL, so use our own tags space
1670         tags = &localTags;
1671     }
1672     
1673     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1674     
1675     if(tn)
1676     {
1677                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1678
1679                 // Now we need to do the shifting etc and search for it
1680                 for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++)
1681                 {
1682                         yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
1683                         if(tags->chunkId == chunkInInode &&
1684                         tags->objectId == in->objectId)
1685                         {
1686                                 // found it;
1687                                 found = 1;
1688                         }
1689                         else
1690                         {
1691                                 theChunk++;
1692                         }
1693                 }
1694     }
1695     return found ? theChunk : -1;
1696 }
1697
1698 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
1699 {
1700         //Get the Tnode, then get the level 0 offset chunk offset
1701     yaffs_Tnode *tn;     
1702     int theChunk = -1;
1703     yaffs_Tags localTags;
1704     int i;
1705     int found = 0;
1706     yaffs_Device *dev = in->myDev;
1707     
1708     if(!tags)
1709     {
1710         // Passed a NULL, so use our own tags space
1711         tags = &localTags;
1712     }
1713     
1714     tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1715     
1716     if(tn)
1717     {
1718     
1719                 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1720     
1721                 // Now we need to do the shifting etc and search for it
1722                 for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++)
1723                 {
1724                         yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
1725                         if(tags->chunkId == chunkInInode &&
1726                         tags->objectId == in->objectId)
1727                         {
1728                                 // found it;
1729                                 found = 1;
1730                         }
1731                         else
1732                         {
1733                                 theChunk++;
1734                         }
1735                 }
1736     
1737                 // Delete the entry in the filestructure
1738                 if(found)
1739                 {
1740                         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
1741                 }
1742     }
1743     else
1744     {
1745         T(("No level 0 found for %d\n", chunkInInode));
1746     }
1747     
1748     if(!found)
1749     {
1750         T(("Could not find %d to delete\n",chunkInInode));
1751     }
1752     return found ? theChunk : -1;
1753 }
1754
1755
1756 #if YAFFS_PARANOID
1757
1758 static int yaffs_CheckFileSanity(yaffs_Object *in)
1759 {
1760         int chunk;
1761         int nChunks;
1762         int fSize;
1763         int failed = 0;
1764         int objId;
1765         yaffs_Tnode *tn;
1766     yaffs_Tags localTags;
1767     yaffs_Tags *tags = &localTags;
1768     int theChunk;
1769     
1770         
1771         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
1772         {
1773                 T(("Object not a file\n"));
1774                 return YAFFS_FAIL;
1775         }
1776         
1777         objId = in->objectId;
1778         fSize  = in->variant.fileVariant.fileSize;
1779         nChunks = (fSize + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK;
1780         
1781         for(chunk = 1; chunk <= nChunks; chunk++)
1782         {
1783                 tn = yaffs_FindLevel0Tnode(&in->variant.fileVariant, chunk);
1784     
1785                 if(tn)
1786                 {
1787     
1788                         theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1789     
1790
1791                                 yaffs_ReadChunkTagsFromNAND(theChunk,tags);
1792                                 if(tags->chunkId == chunk &&
1793                                 tags->objectId == in->objectId)
1794                                 {
1795                                         // found it;
1796                                         
1797                                 }
1798                                 else
1799                                 {
1800                                         //T(("File problem file [%d,%d] NAND %d  tags[%d,%d]\n",
1801                                         //              objId,chunk,theChunk,tags->chunkId,tags->objectId);
1802                                                         
1803                                         failed = 1;
1804                                                                 
1805                                 }
1806     
1807                 }
1808                 else
1809                 {
1810                         T(("No level 0 found for %d\n", chunk));
1811                 }
1812         }
1813         
1814         return failed ? YAFFS_FAIL : YAFFS_OK;
1815 }
1816
1817 #endif
1818
1819 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
1820 {
1821         yaffs_Tnode *tn;
1822         yaffs_Device *dev = in->myDev;
1823         int existingChunk;
1824         yaffs_Tags existingTags;
1825         yaffs_Tags newTags;
1826         unsigned existingSerial, newSerial;
1827         
1828         
1829         tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1830         
1831         if(inScan)
1832         {
1833                 // If we're scanning then we need to test for duplicates
1834                 // NB This does not need to be efficient since it should only ever 
1835                 // happen when the power fails during a write, then only one
1836                 // chunk should ever be affected.
1837         
1838                 existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];            
1839                 
1840                 if(existingChunk != 0)
1841                 {
1842                         // We have a duplicate now we need to decide which one to use
1843                         // To do this we get both sets of tags and compare serial numbers.
1844                         yaffs_ReadChunkTagsFromNAND(dev,chunkInInode, &newTags);
1845                         yaffs_ReadChunkTagsFromNAND(dev,existingChunk, &existingTags);
1846                         newSerial = newTags.serialNumber;
1847                         existingSerial = existingTags.serialNumber;
1848                         if(((existingSerial+1) & 3) == newSerial)
1849                         {
1850                                 // Use new
1851                                 // Delete the old one and drop through to update the tnode
1852                                 yaffs_DeleteChunk(dev,existingChunk);
1853                         }
1854                         else
1855                         {
1856                                 // Use existing.
1857                                 // Delete the new one and return early so that the tnode isn't changed
1858                                 yaffs_DeleteChunk(dev,chunkInInode);
1859                                 return YAFFS_OK;
1860                         }
1861                 }
1862         }
1863         
1864         tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
1865         
1866         return YAFFS_OK;
1867 }
1868
1869
1870
1871 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
1872 {
1873     int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
1874     
1875     if(chunkInNAND >= 0)
1876     {
1877                 return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL);
1878         }
1879         else
1880         {
1881                 return 0;
1882         }
1883
1884 }
1885
1886
1887 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
1888 {
1889         int block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
1890         int page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
1891         yaffs_Tags tags;
1892         
1893         // Mark the deleted NAND page as deleted
1894         tags.chunkId = 0;
1895         tags.objectId = 0;
1896         tags.byteCount = 0;
1897         tags.ecc = 0;
1898         
1899         yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags); 
1900                         
1901         
1902         // Pull out of the management area.
1903         if(     dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
1904             dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
1905         {
1906                 dev->nFreeChunks++;
1907
1908                 dev->blockInfo[block].pageBits &= ~(1 << page);
1909                 dev->blockInfo[block].pagesInUse--;
1910                 
1911                 if(     dev->blockInfo[block].pagesInUse == 0 &&
1912             dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
1913             {
1914                 yaffs_BlockBecameDirty(dev,block);
1915             }
1916
1917         }
1918         else
1919         {
1920                 T(("Bad news deleting chunk %d\n",chunkId));
1921         }
1922         
1923 }
1924
1925
1926
1927
1928 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
1929 {
1930         // Find old chunk Need to do this to get serial number
1931         // Write new one and patch into tree.
1932         // Invalidate old tags.
1933
1934     int prevChunkId;
1935     yaffs_Tags prevTags;
1936     
1937     int newChunkId;
1938     yaffs_Tags newTags;
1939
1940     yaffs_Device *dev = in->myDev;    
1941
1942         yaffs_CheckGarbageCollection(dev);
1943
1944         // Get the previous chunk at this location in the file if it exists
1945     prevChunkId  = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
1946     
1947     // Set up new tags
1948         newTags.chunkId = chunkInInode;
1949         newTags.objectId = in->objectId;
1950         newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
1951         newTags.byteCount = nBytes;
1952         newTags.unusedStuff = 0xFFFFFFFF;
1953                 
1954         yaffs_CalcTagsECC(&newTags);
1955
1956     
1957  #if 0
1958     // Create new chunk in NAND
1959     newChunkId = yaffs_AllocatePage(dev,useReserve);
1960  
1961     
1962     if(newChunkId >= 0)
1963     {
1964                 
1965
1966                 yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,buffer,&newTags);
1967                 
1968                 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
1969                 
1970                 
1971                 if(prevChunkId >= 0)
1972                 {
1973                         yaffs_DeleteChunk(dev,prevChunkId);
1974         
1975                 }
1976                 
1977                 yaffs_CheckFileSanity(in);
1978                 
1979                 return newChunkId;
1980     }
1981
1982      
1983     return -1;
1984 #else
1985
1986         newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
1987         if(newChunkId >= 0)
1988         {
1989                 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
1990                 
1991                 
1992                 if(prevChunkId >= 0)
1993                 {
1994                         yaffs_DeleteChunk(dev,prevChunkId);
1995         
1996                 }
1997                 
1998                 yaffs_CheckFileSanity(in);
1999         }
2000         return newChunkId;
2001
2002 #endif
2003
2004
2005
2006 }
2007
2008
2009 // UpdateObjectHeader updates the header on NAND for an object.
2010 // If name is not NULL, then that new name is used.
2011 //
2012 int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
2013 {
2014
2015         yaffs_Device *dev = in->myDev;
2016         
2017     int prevChunkId;
2018     
2019     int newChunkId;
2020     yaffs_Tags newTags;
2021     __u8 bufferNew[YAFFS_BYTES_PER_CHUNK];
2022     __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
2023     
2024     yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew;
2025     yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
2026     
2027     if(!in->fake)
2028     {
2029   
2030                 yaffs_CheckGarbageCollection(dev);              
2031     
2032                 memset(bufferNew,0xFF,YAFFS_BYTES_PER_CHUNK);
2033     
2034                 prevChunkId = in->chunkId;
2035     
2036                 if(prevChunkId >= 0)
2037                 {
2038                         yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL);        
2039                 }
2040
2041                 // Header data
2042                 oh->type = in->variantType;
2043         
2044                 oh->st_mode = in->st_mode;
2045                 oh->st_uid = in->st_uid;
2046                 oh->st_gid = in->st_gid;
2047                 oh->st_atime = in->st_atime;
2048                 oh->st_mtime = in->st_mtime;
2049                 oh->st_ctime = in->st_ctime;
2050         
2051                 oh->parentObjectId = in->parent->objectId;
2052                 oh->sum = in->sum;
2053                 if(name && *name)
2054                 {
2055                         memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);
2056                         strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
2057                 }
2058                 else
2059                 {       
2060                         memcpy(oh->name, ohOld->name,YAFFS_MAX_NAME_LENGTH + 1);
2061                 }
2062         
2063                 switch(in->variantType)
2064                 {
2065                         case YAFFS_OBJECT_TYPE_UNKNOWN:         
2066                                 // Should not happen
2067                                 break;
2068                         case YAFFS_OBJECT_TYPE_FILE:
2069                                 oh->fileSize = in->variant.fileVariant.fileSize;
2070                                 break;
2071                         case YAFFS_OBJECT_TYPE_HARDLINK:
2072                                 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
2073                                 break;
2074                         case YAFFS_OBJECT_TYPE_DIRECTORY:       
2075                                 // Do nothing
2076                                 break;
2077                         case YAFFS_OBJECT_TYPE_SYMLINK:
2078                                 strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
2079                                 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
2080                                 break;
2081                 }
2082
2083                 // Tags
2084                 in->serial++;
2085                 newTags.chunkId = 0;
2086                 newTags.objectId = in->objectId;
2087                 newTags.serialNumber = in->serial;
2088                 newTags.byteCount =   0xFFFFFFFF;
2089                 newTags.unusedStuff = 0xFFFFFFFF;
2090         
2091                 yaffs_CalcTagsECC(&newTags);
2092         
2093     
2094     
2095 #if 0
2096                 // Create new chunk in NAND
2097                 newChunkId = yaffs_AllocatePage(dev,1);
2098     
2099                 if(newChunkId >= 0)
2100                 {
2101
2102                         yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,bufferNew,&newTags);
2103                 
2104                         in->chunkId = newChunkId;               
2105                 
2106                         if(prevChunkId >= 0)
2107                         {
2108                                 yaffs_DeleteChunk(dev,prevChunkId);
2109                         }
2110                 
2111                         in->dirty = 0;
2112                         return newChunkId;
2113                 }
2114     
2115                 return -1;
2116 #else
2117                 // Create new chunk in NAND
2118                 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);
2119     
2120                 if(newChunkId >= 0)
2121                 {
2122                 
2123                         in->chunkId = newChunkId;               
2124                 
2125                         if(prevChunkId >= 0)
2126                         {
2127                                 yaffs_DeleteChunk(dev,prevChunkId);
2128                         }
2129                 
2130                         in->dirty = 0;
2131                 }
2132                 
2133                 return newChunkId;
2134
2135 #endif
2136     }
2137     return 0;
2138 }
2139
2140
2141
2142 ///////////////////////// File read/write ///////////////////////////////
2143 // Read and write have very similar structures.
2144 // In general the read/write has three parts to it
2145 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
2146 // * Some complete chunks
2147 // * An incomplete chunk to end off with
2148 //
2149 // Curve-balls: the first chunk might also be the last chunk.
2150
2151 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
2152 {
2153         
2154 //      yaffs_Device *dev = in->myDev;
2155         
2156         __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2157         
2158         int chunk;
2159         int start;
2160         int nToCopy;
2161         int n = nBytes;
2162         int nDone = 0;
2163         
2164         while(n > 0)
2165         {
2166                 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1; // The first chunk is 1
2167                 start = offset % YAFFS_BYTES_PER_CHUNK;
2168
2169                 // OK now check for the curveball where the start and end are in
2170                 // the same chunk.      
2171                 if(     (start + n) < YAFFS_BYTES_PER_CHUNK)
2172                 {
2173                         nToCopy = n;
2174                 }
2175                 else
2176                 {
2177                         nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2178                 }
2179         
2180                 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2181                 {
2182                         // An incomplete start or end chunk (or maybe both start and end chunk)
2183                         // Read into the local buffer then copy...
2184                 
2185                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);            
2186                         memcpy(buffer,&localBuffer[start],nToCopy);
2187                 }
2188                 else
2189                 {
2190                         // A full chunk. Read directly into the supplied buffer.
2191                         yaffs_ReadChunkDataFromObject(in,chunk,buffer);
2192                 }
2193                 
2194                 n -= nToCopy;
2195                 offset += nToCopy;
2196                 buffer += nToCopy;
2197                 nDone += nToCopy;
2198                 
2199         }
2200         
2201         return nDone;
2202 }
2203
2204
2205 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
2206 {       
2207         __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2208         
2209         int chunk;
2210         int start;
2211         int nToCopy;
2212         int n = nBytes;
2213         int nDone = 0;
2214         int nToWriteBack;
2215         int endOfWrite = offset+nBytes;
2216         int chunkWritten = 0;
2217         
2218         while(n > 0 && chunkWritten >= 0)
2219         {
2220                 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1;
2221                 start = offset % YAFFS_BYTES_PER_CHUNK;
2222                 
2223
2224                 // OK now check for the curveball where the start and end are in
2225                 // the same chunk.
2226                 if(     (start + n) < YAFFS_BYTES_PER_CHUNK)
2227                 {
2228                         nToCopy = n;
2229                         nToWriteBack = (start + n);
2230                 }
2231                 else
2232                 {
2233                         nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2234                         nToWriteBack = YAFFS_BYTES_PER_CHUNK;
2235                 }
2236         
2237                 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2238                 {
2239                         // An incomplete start or end chunk (or maybe both start and end chunk)
2240                         // Read into the local buffer then copy, then copy over and write back.
2241                 
2242                         yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
2243                                 
2244                         memcpy(&localBuffer[start],buffer,nToCopy);
2245                         
2246                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
2247                         
2248                         T(("Write with readback to chunk %d %d\n",chunk,chunkWritten));
2249                         
2250                 }
2251                 else
2252                 {
2253                         // A full chunk. Write directly from the supplied buffer.
2254                         chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,YAFFS_BYTES_PER_CHUNK,0);
2255                         T(("Write to chunk %d %d\n",chunk,chunkWritten));
2256                 }
2257                 
2258                 if(chunkWritten >= 0)
2259                 {
2260                         n -= nToCopy;
2261                         offset += nToCopy;
2262                         buffer += nToCopy;
2263                         nDone += nToCopy;
2264                 }
2265                 
2266         }
2267         
2268         // Update file object
2269         
2270         if(endOfWrite > in->variant.fileVariant.fileSize)
2271         {
2272                 in->variant.fileVariant.fileSize = endOfWrite;
2273         }
2274         
2275         in->dirty = 1;
2276         in->st_mtime = CURRENT_TIME;
2277         
2278         return nDone;
2279 }
2280
2281
2282 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
2283 {
2284         int i;
2285         int chunkId;
2286         int oldFileSize = in->variant.fileVariant.fileSize;
2287         int sizeOfLastChunk = newSize % YAFFS_BYTES_PER_CHUNK;
2288         
2289         yaffs_Device *dev = in->myDev;
2290         
2291         __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2292         
2293         if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2294         {
2295                 return yaffs_GetFileSize(in);
2296         }
2297         
2298         if(newSize < oldFileSize)
2299         {
2300                 
2301                 int lastDel = 1 + oldFileSize/YAFFS_BYTES_PER_CHUNK;
2302                 
2303                 int startDel = 1 + (newSize + YAFFS_BYTES_PER_CHUNK - 1)/
2304                                                         YAFFS_BYTES_PER_CHUNK;
2305
2306                 for(i = startDel; i <= lastDel; i++)
2307                 {
2308                         // NB this could be optimised somewhat,
2309                         // eg. could retrieve the tags and write them without
2310                         // using yaffs_DeleteChunk
2311                         chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
2312                         if(chunkId < 0 || chunkId >= (dev->endBlock * 32))
2313                         {
2314                                 T(("Found daft chunkId %d for %d\n",chunkId,i));
2315                         }
2316                         else
2317                         {
2318                                 yaffs_DeleteChunk(dev,chunkId);
2319                         }
2320                 }
2321                 
2322                 
2323                 if(sizeOfLastChunk != 0)
2324                 {
2325                         int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK;
2326                         
2327                         // Got to read and rewrite the last chunk with its new size.
2328                         yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
2329                         
2330                         yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfLastChunk,1);
2331                                 
2332                 }
2333                 
2334                 in->variant.fileVariant.fileSize = newSize;
2335                 
2336                 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
2337                 
2338                 return newSize;
2339                 
2340         }
2341         else
2342         {
2343                 return oldFileSize;
2344         }
2345 }
2346
2347
2348 loff_t yaffs_GetFileSize(yaffs_Object *obj)
2349 {
2350         obj = yaffs_GetEquivalentObject(obj);
2351         
2352         switch(obj->variantType)
2353         {
2354                 case YAFFS_OBJECT_TYPE_FILE: 
2355                         return obj->variant.fileVariant.fileSize;
2356                 case YAFFS_OBJECT_TYPE_SYMLINK:
2357                         return strlen(obj->variant.symLinkVariant.alias);
2358                 default:
2359                         return 0;
2360         }
2361 }
2362
2363
2364
2365 // yaffs_FlushFile() updates the file's
2366 // objectId in NAND
2367
2368 int yaffs_FlushFile(yaffs_Object *in)
2369 {
2370         int retVal;
2371         if(in->dirty)
2372         {
2373                 retVal = yaffs_UpdateObjectHeader(in,NULL);
2374         }
2375         else
2376         {
2377                 retVal = YAFFS_OK;
2378         }
2379         
2380         return retVal;
2381         
2382 }
2383
2384
2385 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
2386 {
2387         yaffs_RemoveObjectFromDirectory(in);
2388         yaffs_DeleteChunk(in->myDev,in->chunkId);
2389         yaffs_FreeObject(in);
2390         return YAFFS_OK;
2391
2392 }
2393
2394 // yaffs_DeleteFile deletes the whole file data
2395 // and the inode associated with the file.
2396 // It does not delete the links associated with the file.
2397 static int yaffs_DeleteFile(yaffs_Object *in)
2398 {
2399         // Delete the file data & tnodes
2400         yaffs_ResizeFile(in,0);
2401         yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
2402         
2403         return  yaffs_DoGenericObjectDeletion(in);
2404 }
2405
2406 static int yaffs_DeleteDirectory(yaffs_Object *in)
2407 {
2408         //First check that the directory is empty.
2409         if(list_empty(&in->variant.directoryVariant.children))
2410         {
2411                 return  yaffs_DoGenericObjectDeletion(in);
2412         }
2413         
2414         return YAFFS_FAIL;
2415         
2416 }
2417
2418 static int yaffs_DeleteSymLink(yaffs_Object *in)
2419 {
2420         YFREE(in->variant.symLinkVariant.alias);
2421
2422         return  yaffs_DoGenericObjectDeletion(in);
2423 }
2424
2425 static int yaffs_DeleteHardLink(yaffs_Object *in)
2426 {
2427         // remove this hardlink from the list assocaited with the equivalent
2428         // object
2429         list_del(&in->hardLinks);
2430         return  yaffs_DoGenericObjectDeletion(in);      
2431 }
2432
2433
2434 static int yaffs_UnlinkWorker(yaffs_Object *obj)
2435 {
2436
2437         
2438         if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
2439         {
2440                 return  yaffs_DeleteHardLink(obj);
2441         }
2442         else if(!list_empty(&obj->hardLinks))
2443         {       
2444 #if 0
2445                 // Curve ball: We're unlinking an object that has a hardlink.
2446                 // Therefore we can't really delete the object.
2447                 // Instead, we do the following:
2448                 // - Select a hardlink.
2449                 // - Re-type a hardlink as the equivalent object and populate the fields, including the
2450                 //  objectId. Updating the object id is important so that all the hardlinks do not need
2451                 // to be rewritten.
2452                 // - Update the equivalet object pointers.
2453                 // - Delete all object.
2454
2455                 yaffs_Object *hl;
2456                 struct list_head *i;
2457
2458
2459                 yaffs_RemoveObjectFromDirectory(obj);
2460
2461
2462
2463                 hl =  list_entry(obj->hardLinks.next, yaffs_Object,hardLinks);
2464                 
2465                 hl->dirty = 1;
2466                 hl->st_mode = obj->st_mode;
2467                 hl->st_uid = obj->st_uid;
2468                 hl->st_gid = obj->st_gid;
2469                 hl->st_atime = obj->st_atime;
2470                 hl->st_mtime = obj->st_mtime;
2471                 hl->st_ctime = obj->st_ctime;
2472                 
2473                 hl->variantType = obj->variantType;
2474                 
2475                 switch(hl->variantType)
2476                 {
2477                         case YAFFS_OBJECT_TYPE_FILE:
2478                         case YAFFS_OBJECT_TYPE_SYMLINK:
2479                                 // These types are OK to just copy across.
2480                                 hl->variant = obj->variant;
2481                                 break;
2482                         case YAFFS_OBJECT_TYPE_DIRECTORY:
2483                                 // Fix the list up
2484                                 list_add(&hl->variant.directoryVariant.children,
2485                                             &obj->variant.directoryVariant.children);
2486                                 list_del(&obj->variant.directoryVariant.children);
2487                                 
2488                                 // Now change all the directory children to point to the new parent.
2489                                 list_for_each(i,&hl->variant.directoryVariant.children)
2490                                 {
2491                                         list_entry(i,yaffs_Object,siblings)->parent = hl;
2492                                 }
2493                                 break;
2494                                 
2495                         case YAFFS_OBJECT_TYPE_HARDLINK:
2496                         case YAFFS_OBJECT_TYPE_UNKNOWN:
2497                                 // Should not be either of these types.
2498                 }
2499                 
2500                 // Now fix up the hardlink chain
2501                 list_del(&obj->hardLinks);
2502
2503                 list_for_each(i,&hl->hardLinks)
2504                 {
2505                         list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObject = hl;
2506                         list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObjectId = hl->objectId;
2507                 }
2508                 
2509                 // Now fix up the hash links.
2510                 yaffs_UnhashObject(hl);
2511                 hl->objectId = obj->objectId;
2512                 yaffs_HashObject(hl);
2513                 
2514                 // Update the hardlink which has become an object
2515                 yaffs_UpdateObjectHeader(hl,NULL);
2516
2517                 // Finally throw away the deleted object
2518                 yaffs_DeleteChunk(obj->myDev,obj->chunkId);
2519                 yaffs_FreeObject(obj);
2520                 
2521                 return YAFFS_OK;                
2522 #else
2523                 // Curve ball: We're unlinking an object that has a hardlink.
2524                 //
2525                 //      This problem arises because we are not strictly following
2526                 //  The Linux link/inode model.
2527                 //
2528                 // We can't really delete the object.
2529                 // Instead, we do the following:
2530                 // - Select a hardlink.
2531                 // - Unhook it from the hard links
2532                 // - Unhook it from its parent directory (so that the rename can work)
2533                 // - Rename the object to the hardlink's name.
2534                 // - Delete the hardlink
2535                 
2536                 
2537                 yaffs_Object *hl;
2538                 int retVal;
2539                 char name[YAFFS_MAX_NAME_LENGTH+1];
2540                 
2541                 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
2542                 list_del_init(&hl->hardLinks);
2543                 list_del_init(&hl->siblings);
2544                 
2545                 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
2546                 
2547                 retVal = yaffs_ChangeObjectName(obj, hl->parent, name);
2548                 if(retVal == YAFFS_OK)
2549                 {
2550                         retVal = yaffs_DoGenericObjectDeletion(hl);
2551                 }
2552                 return retVal;
2553
2554 #endif
2555
2556                                 
2557         }
2558         else
2559         {
2560                 switch(obj->variantType)
2561                 {
2562                         case YAFFS_OBJECT_TYPE_FILE:
2563                                 return yaffs_DeleteFile(obj);
2564                                 break;
2565                         case YAFFS_OBJECT_TYPE_DIRECTORY:
2566                                 return yaffs_DeleteDirectory(obj);
2567                                 break;
2568                         case YAFFS_OBJECT_TYPE_SYMLINK:
2569                                 return yaffs_DeleteSymLink(obj);
2570                                 break;
2571                         case YAFFS_OBJECT_TYPE_HARDLINK:
2572                         case YAFFS_OBJECT_TYPE_UNKNOWN:
2573                         default:
2574                                 return YAFFS_FAIL;
2575                 }
2576         }
2577 }
2578
2579 int yaffs_Unlink(yaffs_Object *dir, const char *name)
2580 {
2581         yaffs_Object *obj;
2582         
2583          obj = yaffs_FindObjectByName(dir,name);
2584          
2585          if(obj && obj->unlinkAllowed)
2586          {
2587                 return yaffs_UnlinkWorker(obj);
2588          }
2589          
2590          return YAFFS_FAIL;
2591         
2592 }
2593
2594 //////////////// Initialisation Scanning /////////////////
2595
2596
2597 static int yaffs_Scan(yaffs_Device *dev)
2598 {
2599         yaffs_Spare spare;
2600         yaffs_Tags tags;
2601         int blk;
2602         int chunk;
2603         int c;
2604         int deleted;
2605         int inuse;
2606         yaffs_BlockState state;
2607         yaffs_Object *hardList = NULL;
2608         yaffs_Object *hl;
2609         
2610         __u32 pageBits;
2611         
2612         yaffs_ObjectHeader *oh;
2613         yaffs_Object *in;
2614         yaffs_Object *parent;
2615         
2616         __u8 chunkData[YAFFS_BYTES_PER_CHUNK];
2617         
2618         for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
2619         {
2620                 deleted = 0;
2621                 pageBits = 0;
2622                 inuse = 0;
2623                 state = YAFFS_BLOCK_STATE_UNKNOWN;
2624                 
2625                 for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK && 
2626                                    state == YAFFS_BLOCK_STATE_UNKNOWN; c++)
2627                 {
2628                         // Read the spare area and decide what to do
2629                         chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;
2630                         yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare);
2631
2632                         
2633                         // Is this a valid block?
2634                         if(yaffs_countBits[spare.blockStatus] >= 7)
2635                         {
2636                                 // This block looks ok, now what's in this chunk?
2637                                 yaffs_GetTagsFromSpare(&spare,&tags);
2638                                 
2639                                 if(tags.objectId == YAFFS_UNUSED_OBJECT_ID)
2640                                 {
2641                                         // An unassigned chunk in the block
2642                                         // This means that either the block is empty or 
2643                                         // this is the one being allocated from
2644                                         
2645                                         if(c == 0)
2646                                         {
2647                                                 // the block is unused
2648                                                 state = YAFFS_BLOCK_STATE_EMPTY;
2649                                                 dev->nErasedBlocks++;
2650                                         }
2651                                         else
2652                                         {
2653                                                 // this is the block being allocated from
2654                                                 T((" allocating %d %d\n",blk,c));
2655                                                 state = YAFFS_BLOCK_STATE_ALLOCATING;
2656                                                 dev->allocationBlock = blk;
2657                                                 dev->allocationPage = c;
2658                                         }
2659
2660                                         dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c);
2661                                 }
2662                                 else if(tags.objectId == 0)
2663                                 {
2664                                         // A deleted chunk
2665                                         deleted++;
2666                                         dev->nFreeChunks ++;
2667                                         T((" %d %d deleted\n",blk,c));
2668                                 }
2669                                 else if(tags.chunkId > 0)
2670                                 {
2671                                         // A data chunk.
2672                                         inuse++;
2673                                         pageBits |= ( 1 <<c);                           
2674                                         in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
2675                                         // PutChuunkIntoFIle checks for a clash (two data chunks with
2676                                         // the same chunkId).
2677                                         yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
2678                                         T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));    
2679                                 }
2680                                 else
2681                                 {
2682                                         // chunkId == 0, so it is an ObjectHeader.
2683                                         inuse++;                                
2684                                         pageBits |= ( 1 <<c);                           
2685                                         yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL);
2686                                         oh = (yaffs_ObjectHeader *)chunkData;
2687                                         
2688                                         in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
2689                                         if(in->valid)
2690                                         {
2691                                                 // todo we have already filled this one. We have
2692                                                 // a duplicate. Need to fix
2693                                         }
2694                                         
2695                                         // we don't have a duplicate...
2696                                         
2697                                         in->valid = 1;
2698                                         in->variantType = oh->type;
2699                 
2700                                         in->st_mode  = oh->st_mode;
2701                                         in->st_uid   = oh->st_uid;
2702                                         in->st_gid   = oh->st_gid;
2703                                         in->st_atime = oh->st_atime;
2704                                         in->st_mtime = oh->st_mtime;
2705                                         in->st_ctime = oh->st_ctime;
2706                                         in->chunkId  = chunk;
2707
2708                                         in->sum = oh->sum;
2709                                         in->dirty = 0;
2710                                                                 
2711                                         // directory stuff...
2712                                         // hook up to parent
2713                 
2714                                         parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
2715                                         if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
2716                                         {
2717                                                 // Set up as a directory
2718                                                 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
2719                                                 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
2720                                         }
2721                                         else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
2722                                         {
2723                                                 // Hoosterman, another problem....
2724                                                 // We're trying to use a non-directory as a directory
2725                                                 // Todo ... handle
2726                                         }
2727                                         
2728                                         yaffs_AddObjectToDirectory(parent,in);  
2729                                         
2730                                         // Note re hardlinks.
2731                                         // Since we might scan a hardlink before its equivalent object is scanned
2732                                         // we put them all in a list.
2733                                         // After scanning is complete, we should have all the objects, so we run through this
2734                                         // list and fix up all the chains.              
2735                 
2736                                         switch(in->variantType)
2737                                         {
2738                                                 case YAFFS_OBJECT_TYPE_UNKNOWN:         // Todo got a problem
2739                                                         break;
2740                                                 case YAFFS_OBJECT_TYPE_FILE:
2741                                                         in->variant.fileVariant.fileSize = oh->fileSize;
2742                                                         break;
2743                                                 case YAFFS_OBJECT_TYPE_HARDLINK:
2744                                                         in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
2745                                                         (yaffs_Object *)(in->hardLinks.next) = hardList;
2746                                                         hardList = in;
2747                                                         break;
2748                                                 case YAFFS_OBJECT_TYPE_DIRECTORY:       // Do nothing
2749                                                         break;
2750                                                 case YAFFS_OBJECT_TYPE_SYMLINK:         // Do nothing
2751                                                         in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
2752                                                         break;
2753                                         }
2754                                         T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));  
2755                                 }
2756                         }
2757                         else
2758                         {
2759                                 // it's a bad block
2760                                 state = YAFFS_BLOCK_STATE_DEAD;
2761                         }                       
2762                 }
2763                 
2764                 if(state == YAFFS_BLOCK_STATE_UNKNOWN)
2765                 {
2766                         // If we got this far, then the block is fully allocated.
2767                         // ie. Full or Dirty
2768                         state = (inuse) ? YAFFS_BLOCK_STATE_FULL : YAFFS_BLOCK_STATE_DIRTY;
2769         
2770                 }
2771                 
2772                 dev->blockInfo[blk].pageBits = pageBits;
2773                 dev->blockInfo[blk].pagesInUse = inuse;
2774                 dev->blockInfo[blk].blockState = state;
2775                 
2776         }
2777         
2778         // Todo fix up the hard link chains
2779         while(hardList)
2780         {
2781                 hl = hardList;
2782                 hardList = (yaffs_Object *)(hardList->hardLinks.next);
2783                 
2784                 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
2785                 
2786                 if(in)
2787                 {
2788                         hl->variant.hardLinkVariant.equivalentObject=in;
2789                         list_add(&hl->hardLinks,&in->hardLinks);
2790                 }
2791                 else
2792                 {
2793                         //Todo Need to report this better.
2794                         hl->variant.hardLinkVariant.equivalentObject=NULL;
2795                         INIT_LIST_HEAD(&hl->hardLinks);
2796                         
2797                 }
2798                 
2799         }
2800         
2801         
2802         
2803         return YAFFS_OK;
2804 }
2805
2806
2807 ////////////////////////// Directory Functions /////////////////////////
2808
2809
2810 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
2811 {
2812
2813         if(obj->siblings.prev == NULL)
2814         {
2815                 // Not initialised
2816                 INIT_LIST_HEAD(&obj->siblings);
2817                 
2818         }
2819         else if(!list_empty(&obj->siblings))
2820         {
2821                 // If it is holed up somewhere else, un hook it
2822                 list_del_init(&obj->siblings);
2823         }
2824         // Now add it
2825         list_add(&obj->siblings,&directory->variant.directoryVariant.children);
2826         obj->parent = directory;
2827 }
2828
2829 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
2830 {
2831         list_del_init(&obj->siblings);
2832         obj->parent = NULL;
2833 }
2834
2835 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const char *name)
2836 {
2837         int sum;
2838         
2839         struct list_head *i;
2840         __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2841         yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2842         
2843         yaffs_Object *l;
2844         
2845         sum = yaffs_CalcNameSum(name);
2846         
2847         list_for_each(i,&directory->variant.directoryVariant.children)
2848         {
2849                 l = list_entry(i, yaffs_Object,siblings);
2850                 
2851                 // Special case for lost-n-found
2852                 if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
2853                 {
2854                         if(strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
2855                         {
2856                                 return l;
2857                         }
2858                 }
2859                 else if(l->sum == sum)
2860                 {
2861                         // Do a real check
2862                         yaffs_ReadChunkFromNAND(l->myDev,l->chunkId,buffer,NULL);
2863                         if(strcmp(name,oh->name) == 0)
2864                         {
2865                                 return l;
2866                         }
2867                         
2868                         
2869                 }
2870         }
2871         
2872         return NULL;
2873 }
2874
2875
2876 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
2877 {
2878         struct list_head *i;    
2879         yaffs_Object *l;
2880         
2881         
2882         list_for_each(i,&theDir->variant.directoryVariant.children)
2883         {
2884                 l = list_entry(i, yaffs_Object,siblings);
2885                 if(!fn(l))
2886                 {
2887                         return YAFFS_FAIL;
2888                 }
2889         }
2890         
2891         return YAFFS_OK;
2892
2893 }
2894
2895
2896 // GetEquivalentObject dereferences any hard links to get to the
2897 // actual object.
2898
2899 static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
2900 {
2901         if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
2902         {
2903                 // We want the object id of the equivalent object, not this one
2904                 obj = obj->variant.hardLinkVariant.equivalentObject;
2905         }
2906         return obj;
2907
2908 }
2909
2910 int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize)
2911 {
2912         memset(name,0,buffSize);
2913         
2914         if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
2915         {
2916                 strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
2917         }
2918         else
2919         {
2920                 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2921                 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2922
2923                 memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
2924         
2925                 if(obj->chunkId >= 0)
2926                 {
2927                         yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
2928                 }
2929                 strncpy(name,oh->name,buffSize - 1);
2930         }
2931         
2932         return strlen(name);
2933 }
2934
2935 int yaffs_GetObjectFileLength(yaffs_Object *obj)
2936 {
2937         
2938         // Dereference any hard linking
2939         obj = yaffs_GetEquivalentObject(obj);
2940         
2941         if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
2942         {
2943                 return obj->variant.fileVariant.fileSize;
2944         }
2945         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
2946         {
2947                 return strlen(obj->variant.symLinkVariant.alias);
2948         }
2949         else
2950         {
2951                 // Only a directory should drop through to here
2952                 return YAFFS_BYTES_PER_CHUNK;
2953         }       
2954 }
2955
2956 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
2957 {
2958         int count = 1; // the object itself
2959         struct list_head *i;
2960         
2961         list_for_each(i,&obj->hardLinks)
2962         {
2963                 count++;
2964         }
2965         return count;
2966         
2967 }
2968
2969
2970 int yaffs_GetObjectInode(yaffs_Object *obj)
2971 {
2972         obj = yaffs_GetEquivalentObject(obj);
2973         
2974         return obj->objectId;
2975 }
2976
2977 unsigned yaffs_GetObjectType(yaffs_Object *obj)
2978 {
2979         obj = yaffs_GetEquivalentObject(obj);
2980         
2981         switch(obj->variantType)
2982         {
2983                 case YAFFS_OBJECT_TYPE_FILE:            return DT_REG; break;
2984                 case YAFFS_OBJECT_TYPE_DIRECTORY:       return DT_DIR; break;
2985                 case YAFFS_OBJECT_TYPE_SYMLINK:         return DT_LNK; break;
2986                 case YAFFS_OBJECT_TYPE_HARDLINK:        return DT_REG; break;
2987                 default: return DT_REG; break;
2988         }
2989 }
2990
2991 char *yaffs_GetSymlinkAlias(yaffs_Object *obj)
2992 {
2993         obj = yaffs_GetEquivalentObject(obj);
2994         if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
2995         {
2996                 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
2997         }
2998         else
2999         {
3000                 return yaffs_CloneString("");
3001         }
3002 }
3003
3004
3005 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
3006 {
3007         unsigned int valid = attr->ia_valid;
3008         
3009         if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
3010         if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
3011         if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
3012         
3013         if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime;
3014         if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime;
3015         if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime;
3016         
3017         if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
3018         
3019         yaffs_UpdateObjectHeader(obj,NULL);
3020         
3021         return YAFFS_OK;
3022         
3023 }
3024 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
3025 {
3026         unsigned int valid = 0;
3027         
3028         attr->ia_mode = obj->st_mode;   valid |= ATTR_MODE;
3029         attr->ia_uid = obj->st_uid;             valid |= ATTR_UID;
3030         attr->ia_gid = obj->st_gid;             valid |= ATTR_GID;
3031         
3032         attr->ia_atime = obj->st_atime; valid |= ATTR_ATIME;
3033         attr->ia_ctime = obj->st_ctime; valid |= ATTR_CTIME;
3034         attr->ia_mtime = obj->st_mtime; valid |= ATTR_MTIME;
3035         
3036         attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
3037         
3038         attr->ia_valid = valid;
3039         
3040         return YAFFS_OK;
3041         
3042 }
3043
3044
3045
3046 int yaffs_DumpObject(yaffs_Object *obj)
3047 {
3048         __u8 buffer[YAFFS_BYTES_PER_CHUNK];
3049         char name[256];
3050 //      yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
3051
3052         memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
3053         
3054         if(obj->chunkId >= 0)
3055         {
3056                 yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
3057         }
3058         
3059         yaffs_GetObjectName(obj,name,256);
3060         
3061         YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",
3062                         yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial, 
3063                         obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
3064
3065 #if 0
3066         YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
3067                         obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial, 
3068                         obj->sum, obj->chunkId));
3069                 switch(obj->variantType)
3070         {
3071                 case YAFFS_OBJECT_TYPE_FILE: 
3072                         YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
3073                         break;
3074                 case YAFFS_OBJECT_TYPE_DIRECTORY:
3075                         YPRINTF((" DIRECTORY\n"));
3076                         break;
3077                 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
3078                 case YAFFS_OBJECT_TYPE_SYMLINK:
3079                 case YAFFS_OBJECT_TYPE_UNKNOWN:
3080                 default:
3081         }
3082 #endif
3083         
3084         return YAFFS_OK;
3085 }
3086
3087
3088 ///////////////////////// Initialisation code ///////////////////////////
3089
3090
3091
3092 int yaffs_GutsInitialise(yaffs_Device *dev)
3093 {
3094         unsigned  nChunks,x;
3095         int bits;
3096
3097
3098         dev = dev;
3099         
3100         if(!yaffs_CheckStructures())
3101         {
3102                 return YAFFS_FAIL;
3103         }
3104
3105                 
3106         // OK now calculate a few things for the device
3107         // Calculate chunkGroupBits. 
3108         // If there are 64k or less chunks then this is 1
3109         // Else it is log2(nChunks) - 16
3110         //
3111         x = nChunks = YAFFS_CHUNKS_PER_BLOCK * dev->nBlocks;
3112         
3113         for(bits = 0, x = nChunks; (x & 1) == 0; bits++)
3114         {
3115                 x >>= 1;
3116         }
3117         
3118         if( x != 1)
3119         {
3120                 // Not a power of 2
3121                 YPRINTF(("nBlocks should be a power of 2 but is %u\n",
3122                         dev->nBlocks));
3123                 return YAFFS_FAIL;
3124         }
3125         
3126         if(bits <= 16) 
3127         {
3128                 dev->chunkGroupBits = 0;
3129                 dev->chunkGroupSize = 1;
3130         }
3131         else
3132         {
3133                 dev->chunkGroupBits = bits - 16;
3134                 dev->chunkGroupSize = nChunks/0x10000;
3135         }
3136         
3137         // More device initialisation
3138         dev->garbageCollectionRequired  = 0;
3139         dev->currentDirtyChecker = 0;
3140         
3141         yaffs_InitialiseBlocks(dev);
3142         
3143         yaffs_InitialiseTnodes(dev);
3144
3145         yaffs_InitialiseObjects(dev);
3146         
3147         
3148         // Initialise the root and lost and found directories
3149         dev->lostNFoundDir = dev->rootDir = NULL;
3150         dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
3151         dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_ROOT_MODE | S_IFDIR);
3152         yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
3153                 
3154         // Now scan the flash.  
3155         yaffs_Scan(dev);
3156
3157         
3158         return YAFFS_OK;
3159                 
3160 }
3161
3162 void yaffs_Deinitialise(yaffs_Device *dev)
3163 {
3164         yaffs_DeinitialiseBlocks(dev);
3165         yaffs_DeinitialiseTnodes(dev);
3166         yaffs_DeinitialiseObjects(dev);
3167         
3168 }
3169
3170 int  yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
3171 {
3172         int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);
3173
3174         return (nFree < 0) ? 0 : nFree; 
3175         
3176 }
3177
3178
3179 /////////////////// YAFFS test code //////////////////////////////////
3180
3181 #define yaffs_CheckStruct(structure,syze, name) \
3182            if(sizeof(structure) != syze) \
3183                { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \
3184                  return YAFFS_FAIL; \
3185                    }
3186                  
3187                  
3188 static int yaffs_CheckStructures(void)
3189 {
3190         yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
3191         yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
3192         yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
3193         yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
3194         yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
3195         
3196         
3197         return YAFFS_OK;
3198 }
3199
3200 void yaffs_GutsTest(yaffs_Device *dev)
3201 {
3202         
3203         if(yaffs_CheckStructures() != YAFFS_OK)
3204         {
3205                 YPRINTF(("One or more structures malformed-- aborting\n"));
3206         }
3207         else
3208         {
3209                 YPRINTF(("Structures OK\n"));
3210         }
3211         
3212         yaffs_TnodeTest(dev);
3213         yaffs_ObjectTest(dev);  
3214 }
3215
3216