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