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