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