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