2 * YAFFS: Yet another FFS. A NAND-flash specific file system.
3 * yaffs_guts.c The main guts of YAFFS
5 * Copyright (C) 2002 Aleph One Ltd.
6 * for Toby Churchill Ltd and Brightstar Engineering
8 * Created by Charles Manning <charles@aleph1.co.uk>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
19 #include "yaffsinterface.h"
20 #include "yaffs_guts.h"
29 // External functions for ECC on data
30 void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
31 int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
34 // countBits is a quick way of counting the number of bits in a byte.
35 // ie. countBits[n] holds the number of 1 bits in a byte with the value n.
37 static const char yaffs_countBits[256] =
39 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,
40 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
41 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
42 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
43 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
44 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
45 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
46 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
47 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
48 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
49 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
50 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
51 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
52 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
53 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
54 4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
60 //static yaffs_Device *yaffs_device;
61 //yaffs_Object *yaffs_rootDir;
62 //yaffs_Object *yaffs_lostNFound;
67 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
68 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
69 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
70 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
72 static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
73 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
74 static int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name);
75 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);
76 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
77 static int yaffs_CheckStructures(void);
78 static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
80 loff_t yaffs_GetFileSize(yaffs_Object *obj);
83 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
86 static int yaffs_CheckFileSanity(yaffs_Object *in);
88 #define yaffs_CheckFileSanity(in)
91 static int __inline__ yaffs_HashFunction(int n)
93 return (n % YAFFS_NOBJECT_BUCKETS);
97 yaffs_Object *yaffs_Root(yaffs_Device *dev)
102 yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
104 return dev->lostNFoundDir;
108 static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, const __u8 *data, yaffs_Spare *spare)
110 return dev->writeChunkToNAND(dev,chunkInNAND,data,spare);
113 int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
117 yaffs_Spare localSpare;
121 // If we don't have a real spare, then we use a local one.
122 // Need this for the calculation of the ecc
126 retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
130 //Todo handle any errors
131 nand_calculate_ecc(data,calcEcc);
132 nand_correct_data (data,spare->ecc1, calcEcc);
133 nand_calculate_ecc(&data[256],calcEcc);
134 nand_correct_data (&data[256],spare->ecc2, calcEcc);
139 #ifdef YAFFS_PARANOID
141 static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
144 static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
145 static __u8 data[YAFFS_BYTES_PER_CHUNK];
146 static __u8 spare[16];
152 dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
158 memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK);
162 if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) retVal = YAFFS_FAIL;
163 if(memcmp(cmpbuf,spare,16)) retVal = YAFFS_FAIL;
172 int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
174 return dev->eraseBlockInNAND(dev,blockInNAND);
177 int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
179 return dev->initialiseNAND(dev);
182 static int yaffs_WriteNewChunkToNAND(struct yaffs_DeviceStruct *dev, const __u8 *data, yaffs_Spare *spare,int useReserve)
188 unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
192 chunk = yaffs_AllocateChunk(dev,useReserve);
196 writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);
200 // If verify fails, then delete this chunk and try again
201 // To verify we compare everything except the block and
202 // page status bytes.
203 yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);
205 if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||
206 spare->tagByte0 != rbSpare.tagByte0 ||
207 spare->tagByte1 != rbSpare.tagByte1 ||
208 spare->tagByte2 != rbSpare.tagByte2 ||
209 spare->tagByte3 != rbSpare.tagByte3 ||
210 spare->tagByte4 != rbSpare.tagByte4 ||
211 spare->tagByte5 != rbSpare.tagByte5 ||
212 spare->tagByte6 != rbSpare.tagByte6 ||
213 spare->tagByte7 != rbSpare.tagByte7 ||
214 spare->ecc1[0] != rbSpare.ecc1[0] ||
215 spare->ecc1[1] != rbSpare.ecc1[1] ||
216 spare->ecc1[2] != rbSpare.ecc1[2] ||
217 spare->ecc2[0] != rbSpare.ecc2[0] ||
218 spare->ecc2[1] != rbSpare.ecc2[1] ||
219 spare->ecc2[2] != rbSpare.ecc2[2] )
222 yaffs_DeleteChunk(dev,chunk);
228 } while(chunk >= 0 && ! writeOk);
236 ///////////////////////// Object management //////////////////
237 // List of spare objects
238 // The list is hooked together using the first pointer
241 // static yaffs_Object *yaffs_freeObjects = NULL;
243 // static int yaffs_nFreeObjects;
245 // static yaffs_ObjectList *yaffs_allocatedObjectList = NULL;
247 // static yaffs_ObjectBucket yaffs_objectBucket[YAFFS_NOBJECT_BUCKETS];
250 static __u16 yaffs_CalcNameSum(const char *name)
255 __u8 *bname = (__u8 *)name;
267 void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
269 nand_calculate_ecc (data , spare->ecc1);
270 nand_calculate_ecc (&data[256] , spare->ecc2);
273 void yaffs_CalcTagsECC(yaffs_Tags *tags)
275 // Todo don't do anything yet. Need to calculate ecc
276 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
283 for(i = 0; i < 8; i++)
285 for(j = 1; j &0x7f; j<<=1)
300 void yaffs_CheckECCOnTags(yaffs_Tags *tags)
302 unsigned ecc = tags->ecc;
304 yaffs_CalcTagsECC(tags);
311 unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
315 b[ecc / 8] ^= (1 << (ecc & 7));
317 // Now recvalc the ecc
318 yaffs_CalcTagsECC(tags);
323 ///////////////////////// TNODES ///////////////////////
325 // List of spare tnodes
326 // The list is hooked together using the first pointer
329 //static yaffs_Tnode *yaffs_freeTnodes = NULL;
331 // static int yaffs_nFreeTnodes;
333 //static yaffs_TnodeList *yaffs_allocatedTnodeList = NULL;
337 // yaffs_CreateTnodes creates a bunch more tnodes and
338 // adds them to the tnode free list.
339 // Don't use this function directly
341 static int yaffs_CreateTnodes(yaffs_Device *dev,int nTnodes)
344 yaffs_Tnode *newTnodes;
345 yaffs_TnodeList *tnl;
347 if(nTnodes < 1) return YAFFS_OK;
351 newTnodes = YMALLOC(nTnodes * sizeof(yaffs_Tnode));
355 YALERT("Could not malloc tnodes");
359 // Hook them into the free list
360 for(i = 0; i < nTnodes - 1; i++)
362 newTnodes[i].internal[0] = &newTnodes[i+1];
365 newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
366 dev->freeTnodes = newTnodes;
367 dev->nFreeTnodes+= nTnodes;
368 dev->nTnodesCreated += nTnodes;
370 // Now add this bunch of tnodes to a list for freeing up.
372 tnl = YMALLOC(sizeof(yaffs_TnodeList));
375 YALERT("Could not add tnodes to management list");
379 tnl->tnodes = newTnodes;
380 tnl->next = dev->allocatedTnodeList;
381 dev->allocatedTnodeList = tnl;
385 YINFO("Tnodes created");
392 // GetTnode gets us a clean tnode. Tries to make allocate more if we run out
393 static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
395 yaffs_Tnode *tn = NULL;
397 // If there are none left make more
400 yaffs_CreateTnodes(dev,YAFFS_ALLOCATION_NTNODES);
405 tn = dev->freeTnodes;
406 dev->freeTnodes = dev->freeTnodes->internal[0];
409 memset(tn,0,sizeof(yaffs_Tnode));
417 // FreeTnode frees up a tnode and puts it back on the free list
418 static void yaffs_FreeTnode(yaffs_Device*dev, yaffs_Tnode *tn)
420 tn->internal[0] = dev->freeTnodes;
421 dev->freeTnodes = tn;
426 static void yaffs_DeinitialiseTnodes(yaffs_Device*dev)
428 // Free the list of allocated tnodes
430 while(dev->allocatedTnodeList)
432 YFREE(dev->allocatedTnodeList->tnodes);
433 dev->allocatedTnodeList = dev->allocatedTnodeList->next;
436 dev->freeTnodes = NULL;
437 dev->nFreeTnodes = 0;
440 static void yaffs_InitialiseTnodes(yaffs_Device*dev)
442 dev->allocatedTnodeList = NULL;
443 dev->freeTnodes = NULL;
444 dev->nFreeTnodes = 0;
445 dev->nTnodesCreated = 0;
449 void yaffs_TnodeTest(yaffs_Device *dev)
454 yaffs_Tnode *tn[1000];
456 YINFO("Testing TNodes");
458 for(j = 0; j < 50; j++)
460 for(i = 0; i < 1000; i++)
462 tn[i] = yaffs_GetTnode(dev);
465 YALERT("Getting tnode failed");
468 for(i = 0; i < 1000; i+=3)
470 yaffs_FreeTnode(dev,tn[i]);
477 ////////////////// END OF TNODE MANIPULATION ///////////////////////////
479 /////////////// Functions to manipulate the look-up tree (made up of tnodes)
480 // The look up tree is represented by the top tnode and the number of topLevel
481 // in the tree. 0 means only the level 0 tnode is in the tree.
484 // FindLevel0Tnode finds the level 0 tnode, if one exists.
485 // Used when reading.....
486 static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,yaffs_FileStructure *fStruct, __u32 chunkId)
489 yaffs_Tnode *tn = fStruct->top;
491 int requiredTallness;
492 int level = fStruct->topLevel;
494 // Check sane level and chunk Id
495 if(level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
498 sprintf(str,"Bad level %d",level);
502 if(chunkId > YAFFS_MAX_CHUNK_ID)
505 sprintf(str,"Bad chunkId %d",chunkId);
510 // First check we're tall enough (ie enough topLevel)
512 i = chunkId >> (dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS);
513 requiredTallness = 0;
516 i >>= YAFFS_TNODES_INTERNAL_BITS;
521 if(requiredTallness > fStruct->topLevel)
523 // Not tall enough, so we can't find it, return NULL.
528 // Traverse down to level 0
529 while (level > 0 && tn)
531 tn = tn->internal[(chunkId >>(dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS + (level-1) * YAFFS_TNODES_INTERNAL_BITS)) &
532 YAFFS_TNODES_INTERNAL_MASK];
540 // AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
541 // This happens in two steps:
542 // 1. If the tree isn't tall enough, then make it taller.
543 // 2. Scan down the tree towards the level 0 tnode adding tnodes if required.
545 // Used when modifying the tree.
547 static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId)
552 int requiredTallness;
558 T(("AddOrFind topLevel=%d, chunk=%d",fStruct->topLevel,chunkId));
560 // Check sane level and page Id
561 if(fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
564 sprintf(str,"Bad level %d",fStruct->topLevel);
569 if(chunkId > YAFFS_MAX_CHUNK_ID)
572 sprintf(str,"Bad chunkId %d",chunkId);
577 // First check we're tall enough (ie enough topLevel)
579 i = chunkId >> (dev->chunkGroupBits + YAFFS_TNODES_LEVEL0_BITS);
580 requiredTallness = 0;
583 i >>= YAFFS_TNODES_INTERNAL_BITS;
587 T((" required=%d",requiredTallness));
590 if(requiredTallness > fStruct->topLevel)
592 // Not tall enough,gotta make the tree taller
593 for(i = fStruct->topLevel; i < requiredTallness; i++)
597 tn = yaffs_GetTnode(dev);
601 tn->internal[0] = fStruct->top;
606 YALERT("No more tnodes");
610 fStruct->topLevel = requiredTallness;
614 // Traverse down to level 0, adding anything we need
616 l = fStruct->topLevel;
620 i = (chunkId >> (dev->chunkGroupBits +YAFFS_TNODES_LEVEL0_BITS + (l-1) * YAFFS_TNODES_INTERNAL_BITS)) &
621 YAFFS_TNODES_INTERNAL_MASK;
629 tn->internal[i] = yaffs_GetTnode(dev);
632 tn = tn->internal[i];
643 // Pruning removes any part of the file structure tree that is beyond the
644 // bounds of the file.
645 // A file should only get pruned when its size is reduced.
647 // Before pruning, the chunks must be pulled from the tree and the
648 // level 0 tnode entries must be zeroed out.
649 // Could also use this for file deletion, but that's probably better handled
650 // by a special case.
652 // yaffs_PruneWorker should only be called by yaffs_PruneFileStructure()
654 static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn, __u32 level, int del0)
663 for(i = 0; i < YAFFS_NTNODES_INTERNAL; i++)
665 if(tn->internal[i] && level > 0)
667 tn->internal[i] = yaffs_PruneWorker(dev,tn->internal[i],level - 1, ( i == 0) ? del0 : 1);
676 if(hasData == 0 && del0)
678 // Free and return NULL
680 yaffs_FreeTnode(dev,tn);
690 static int yaffs_PruneFileStructure(yaffs_Device *dev, yaffs_FileStructure *fStruct)
697 if(fStruct->topLevel > 0)
699 fStruct->top = yaffs_PruneWorker(dev,fStruct->top, fStruct->topLevel,0);
701 // Now we have a tree with all the non-zero branches NULL but the height
702 // is the same as it was.
703 // Let's see if we can trim internal tnodes to shorten the tree.
704 // We can do this if only the 0th element in the tnode is in use
705 // (ie all the non-zero are NULL)
707 while(fStruct->topLevel && !done)
712 for(i = 1; i <YAFFS_NTNODES_INTERNAL; i++)
722 fStruct->top = tn->internal[0];
724 yaffs_FreeTnode(dev,tn);
739 /////////////////////// End of File Structure functions. /////////////////
741 // yaffs_CreateFreeObjects creates a bunch more objects and
742 // adds them to the object free list.
743 static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
746 yaffs_Object *newObjects;
747 yaffs_ObjectList *list;
749 if(nObjects < 1) return YAFFS_OK;
753 newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
757 YALERT("Could not allocate more objects");
761 // Hook them into the free list
762 for(i = 0; i < nObjects - 1; i++)
764 (yaffs_Object *)newObjects[i].siblings.next = &newObjects[i+1];
767 newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
768 dev->freeObjects = newObjects;
769 dev->nFreeObjects+= nObjects;
770 dev->nObjectsCreated+= nObjects;
772 // Now add this bunch of Objects to a list for freeing up.
774 list = YMALLOC(sizeof(yaffs_ObjectList));
777 YALERT("Could not add Objects to management list");
781 list->objects = newObjects;
782 list->next = dev->allocatedObjectList;
783 dev->allocatedObjectList = list;
787 YINFO("Objects created");
794 // AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out
795 static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
797 yaffs_Object *tn = NULL;
799 // If there are none left make more
800 if(!dev->freeObjects)
802 yaffs_CreateFreeObjects(dev,YAFFS_ALLOCATION_NOBJECTS);
807 tn = dev->freeObjects;
808 dev->freeObjects = (yaffs_Object *)(dev->freeObjects->siblings.next);
811 // Now sweeten it up...
813 memset(tn,0,sizeof(yaffs_Object));
815 tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
816 INIT_LIST_HEAD(&(tn->hardLinks));
817 INIT_LIST_HEAD(&(tn->hashLink));
818 INIT_LIST_HEAD(&tn->siblings);
820 // Add it to the lost and found directory.
821 // NB Can't put root or lostNFound in lostNFound so
822 // check if lostNFound exists first
823 if(dev->lostNFoundDir)
825 yaffs_AddObjectToDirectory(dev->lostNFoundDir,tn);
833 static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev,int number,__u32 mode)
836 yaffs_Object *obj = yaffs_CreateNewObject(dev,number,YAFFS_OBJECT_TYPE_DIRECTORY);
839 obj->fake = 1; // it is fake so it has no NAND presence...
840 obj->renameAllowed= 0; // ... and we're not allowed to rename it...
841 obj->unlinkAllowed= 0; // ... or unlink it
844 obj->chunkId = 0; // Not a valid chunk.
852 static void yaffs_UnhashObject(yaffs_Object *tn)
855 yaffs_Device *dev = tn->myDev;
858 // If it is still linked into the bucket list, free from the list
859 if(!list_empty(&tn->hashLink))
861 list_del_init(&tn->hashLink);
862 bucket = yaffs_HashFunction(tn->objectId);
863 dev->objectBucket[bucket].count--;
869 // FreeObject frees up a Object and puts it back on the free list
870 static void yaffs_FreeObject(yaffs_Object *tn)
873 yaffs_Device *dev = tn->myDev;
875 yaffs_UnhashObject(tn);
877 // Link into the free list.
878 (yaffs_Object *)(tn->siblings.next) = dev->freeObjects;
879 dev->freeObjects = tn;
886 static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
888 // Free the list of allocated Objects
890 while( dev->allocatedObjectList)
892 YFREE(dev->allocatedObjectList->objects);
893 dev->allocatedObjectList = dev->allocatedObjectList->next;
896 dev->freeObjects = NULL;
897 dev->nFreeObjects = 0;
900 static void yaffs_InitialiseObjects(yaffs_Device *dev)
904 dev->allocatedObjectList = NULL;
905 dev->freeObjects = NULL;
906 dev->nFreeObjects = 0;
908 for(i = 0; i < YAFFS_NOBJECT_BUCKETS; i++)
910 INIT_LIST_HEAD(&dev->objectBucket[i].list);
911 dev->objectBucket[i].count = 0;
921 int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
929 // First let's see if we can find one that's empty.
931 for(i = 0; i < 10 && lowest > 0; i++)
934 x %= YAFFS_NOBJECT_BUCKETS;
935 if(dev->objectBucket[x].count < lowest)
937 lowest = dev->objectBucket[x].count;
943 // If we didn't find an empty list, then try
944 // looking a bit further for a short one
946 for(i = 0; i < 10 && lowest > 3; i++)
949 x %= YAFFS_NOBJECT_BUCKETS;
950 if(dev->objectBucket[x].count < lowest)
952 lowest = dev->objectBucket[x].count;
961 static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
963 int bucket = yaffs_FindNiceObjectBucket(dev);
965 // Now find an object value that has not already been taken
966 // by scanning the list.
973 //yaffs_CheckObjectHashSanity();
978 n += YAFFS_NOBJECT_BUCKETS;
979 if(1 ||dev->objectBucket[bucket].count > 0)
981 list_for_each(i,&dev->objectBucket[bucket].list)
983 // If there is already one in the list
984 if(list_entry(i, yaffs_Object,hashLink)->objectId == n)
992 //T(("bucket %d count %d inode %d\n",bucket,yaffs_objectBucket[bucket].count,n);
997 void yaffs_HashObject(yaffs_Object *in)
999 int bucket = yaffs_HashFunction(in->objectId);
1000 yaffs_Device *dev = in->myDev;
1002 if(!list_empty(&in->hashLink))
1008 list_add(&in->hashLink,&dev->objectBucket[bucket].list);
1009 dev->objectBucket[bucket].count++;
1013 yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev,int number)
1015 int bucket = yaffs_HashFunction(number);
1016 struct list_head *i;
1019 list_for_each(i,&dev->objectBucket[bucket].list)
1021 // Lookm if it is in the list
1022 in = list_entry(i, yaffs_Object,hashLink);
1023 if(in->objectId == number)
1034 yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type)
1037 yaffs_Object *theObject;
1041 number = yaffs_CreateNewObjectNumber(dev);
1044 theObject = yaffs_AllocateEmptyObject(dev);
1048 theObject->fake = 0;
1049 theObject->renameAllowed = 1;
1050 theObject->unlinkAllowed = 1;
1051 theObject->objectId = number;
1052 theObject->myDev = dev;
1053 yaffs_HashObject(theObject);
1054 theObject->variantType = type;
1055 theObject->st_atime = theObject->st_mtime = theObject->st_ctime = CURRENT_TIME;
1059 case YAFFS_OBJECT_TYPE_FILE:
1060 theObject->variant.fileVariant.fileSize = 0;
1061 theObject->variant.fileVariant.topLevel = 0;
1062 theObject->variant.fileVariant.top = yaffs_GetTnode(dev);
1064 case YAFFS_OBJECT_TYPE_DIRECTORY:
1065 INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
1067 case YAFFS_OBJECT_TYPE_SYMLINK:
1068 // No action required
1070 case YAFFS_OBJECT_TYPE_HARDLINK:
1071 // No action required
1073 case YAFFS_OBJECT_TYPE_UNKNOWN:
1074 // todo this should not happen
1081 yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
1083 yaffs_Object *theObject = NULL;
1087 theObject = yaffs_FindObjectByNumber(dev,number);
1092 theObject = yaffs_CreateNewObject(dev,number,type);
1099 char *yaffs_CloneString(const char *str)
1101 char *newStr = NULL;
1105 newStr = YMALLOC(strlen(str) + 1);
1114 // Mknod (create) a new object.
1115 // equivalentObject only has meaning for a hard link;
1116 // aliasString only has meaning for a sumlink.
1117 yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
1118 yaffs_Object *parent,
1123 yaffs_Object *equivalentObject,
1124 const char *aliasString)
1128 yaffs_Device *dev = parent->myDev;
1130 in = yaffs_CreateNewObject(dev,-1,type);
1136 in->variantType = type;
1141 in->st_atime = in->st_mtime = in->st_ctime = CURRENT_TIME;
1143 in->sum = yaffs_CalcNameSum(name);
1146 yaffs_AddObjectToDirectory(parent,in);
1148 in->myDev = parent->myDev;
1153 case YAFFS_OBJECT_TYPE_SYMLINK:
1154 in->variant.symLinkVariant.alias = yaffs_CloneString(aliasString);
1156 case YAFFS_OBJECT_TYPE_HARDLINK:
1157 in->variant.hardLinkVariant.equivalentObject = equivalentObject;
1158 in->variant.hardLinkVariant.equivalentObjectId = equivalentObject->objectId;
1159 list_add(&in->hardLinks,&equivalentObject->hardLinks);
1161 case YAFFS_OBJECT_TYPE_FILE: // do nothing
1162 case YAFFS_OBJECT_TYPE_DIRECTORY: // do nothing
1163 case YAFFS_OBJECT_TYPE_UNKNOWN:
1166 yaffs_UpdateObjectHeader(in,name);
1173 yaffs_Object *yaffs_MknodFile(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1175 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE,parent,name,mode,uid,gid,NULL,NULL);
1178 yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid)
1180 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY,parent,name,mode,uid,gid,NULL,NULL);
1183 yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent,const char *name, __u32 mode, __u32 uid, __u32 gid,const char *alias)
1185 return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK,parent,name,mode,uid,gid,NULL,alias);
1188 // NB yaffs_Link returns the object id of the equivalent object.
1189 yaffs_Object *yaffs_Link(yaffs_Object *parent, const char *name, yaffs_Object *equivalentObject)
1191 // Get the real object in case we were fed a hard link as an equivalent object
1192 equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
1194 if(yaffs_MknodObject(YAFFS_OBJECT_TYPE_HARDLINK,parent,name,0,0,0,equivalentObject,NULL))
1196 return equivalentObject;
1206 static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const char *newName)
1208 //yaffs_Device *dev = obj->myDev;
1212 newDir = obj->parent; // use the old directory
1215 // Only proceed if the new name does not exist and
1216 // if we're putting it into a directory.
1217 if(!yaffs_FindObjectByName(newDir,newName) &&
1218 newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
1220 obj->sum = yaffs_CalcNameSum(newName);
1222 yaffs_AddObjectToDirectory(newDir,obj);
1224 return yaffs_UpdateObjectHeader(obj,newName);
1230 int yaffs_RenameObject(yaffs_Object *oldDir, const char *oldName, yaffs_Object *newDir, const char *newName)
1234 obj = yaffs_FindObjectByName(oldDir,oldName);
1235 if(obj && obj->renameAllowed)
1237 return yaffs_ChangeObjectName(obj,newDir,newName);
1244 static int yaffs_CheckObjectHashSanity(yaffs_Device *dev)
1246 // Scan the buckets and check that the lists
1247 // have as many members as the count says there are
1250 struct list_head *j;
1253 for(bucket = 0; bucket < YAFFS_NOBJECT_BUCKETS; bucket++)
1257 list_for_each(j,&dev->objectBucket[bucket].list)
1262 if(countEm != dev->objectBucket[bucket].count)
1264 YALERT("Inode hash inconsistency");
1272 void yaffs_ObjectTest(yaffs_Device *dev)
1274 yaffs_Object *in[1000];
1276 yaffs_Object *inold[1000];
1280 memset(in,0,1000*sizeof(yaffs_Object *));
1281 memset(inold,0,1000*sizeof(yaffs_Object *));
1283 yaffs_CheckObjectHashSanity(dev);
1285 for(j = 0; j < 10; j++)
1289 for(i = 0; i < 1000; i++)
1291 in[i] = yaffs_CreateNewObject(dev,-1,YAFFS_OBJECT_TYPE_FILE);
1294 YINFO("No more inodes");
1298 inNo[i] = in[i]->objectId;
1302 for(i = 0; i < 1000; i++)
1304 if(yaffs_FindObjectByNumber(dev,inNo[i]) != in[i])
1306 T(("Differnce in look up test\n"));
1310 // T(("Look up ok\n"));
1314 yaffs_CheckObjectHashSanity(dev);
1316 for(i = 0; i < 1000; i+=3)
1318 yaffs_FreeObject(in[i]);
1323 yaffs_CheckObjectHashSanity(dev);
1330 /////////////////////////// Block Management and Page Allocation ///////////////////
1333 static void yaffs_InitialiseBlocks(yaffs_Device *dev)
1335 dev->blockInfo = YMALLOC(dev->nBlocks * sizeof(yaffs_BlockInfo));
1336 memset(dev->blockInfo,0,dev->nBlocks * sizeof(yaffs_BlockInfo));
1337 dev->allocationBlock = -1; // force it to get a new one
1340 static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
1342 YFREE(dev->blockInfo);
1345 // FindDiretiestBlock is used to select the dirtiest block (or close enough)
1346 // for garbage collection.
1348 static int yaffs_FindDirtiestBlock(yaffs_Device *dev)
1351 int b = dev->currentDirtyChecker;
1355 int pagesInUse = 100; // silly big number
1357 for(i = dev->startBlock; i <= dev->endBlock && pagesInUse > 2 ; i++)
1360 if (b > dev->endBlock)
1362 b = dev->startBlock;
1365 if(dev->blockInfo[b].blockState == YAFFS_BLOCK_STATE_FULL &&
1366 (dev->blockInfo)[b].pagesInUse < pagesInUse)
1369 pagesInUse = (dev->blockInfo)[b].pagesInUse;
1373 dev->currentDirtyChecker = b;
1379 static int yaffs_FindBlockForAllocation(yaffs_Device *dev,int useReserve)
1383 if(useReserve && dev->nErasedBlocks < 1)
1385 // Hoosterman we've got a problem.
1386 // Can't get space to gc
1389 else if(!useReserve && dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1391 // We are not in GC, so we hold some in reserve so we can get
1395 // Find an empty block.
1397 for(i = dev->startBlock; i <= dev->endBlock; i++)
1400 if(dev->blockInfo[i].blockState == YAFFS_BLOCK_STATE_EMPTY)
1402 dev->blockInfo[i].blockState = YAFFS_BLOCK_STATE_ALLOCATING;
1403 dev->nErasedBlocks--;
1404 if(dev->nErasedBlocks <= YAFFS_RESERVED_BLOCKS)
1406 dev->garbageCollectionRequired = 1;
1417 static void yaffs_BlockBecameDirty(yaffs_Device *dev,int blockNo)
1419 yaffs_BlockInfo *bi = &dev->blockInfo[blockNo];
1421 // Mark as dirty, erase it and mark as clean.
1422 bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
1423 yaffs_EraseBlockInNAND(dev,blockNo);
1424 bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
1425 dev->nErasedBlocks++;
1429 T(("Erased block %d\n",blockNo));
1433 static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve)
1437 if(dev->allocationBlock < 0)
1439 // Get next block to allocate off
1440 dev->allocationBlock = yaffs_FindBlockForAllocation(dev,useReserve);
1441 dev->allocationPage = 0;
1444 // Next page please....
1445 if(dev->allocationBlock >= 0)
1447 retVal = (dev->allocationBlock * YAFFS_CHUNKS_PER_BLOCK) +
1448 dev->allocationPage;
1449 dev->blockInfo[dev->allocationBlock].pagesInUse++;
1450 dev->blockInfo[dev->allocationBlock].pageBits |=
1451 (1 << (dev->allocationPage));
1453 dev->allocationPage++;
1457 // If the block is full set the state to full
1458 if(dev->allocationPage >= YAFFS_CHUNKS_PER_BLOCK)
1460 dev->blockInfo[dev->allocationBlock].blockState = YAFFS_BLOCK_STATE_FULL;
1461 dev->allocationBlock = -1;
1464 #ifdef YAFFS_PARANOID
1465 if(yaffs_CheckChunkErased(dev,retVal) == YAFFS_FAIL)
1467 T(("..................Trying to allocate non-erased page %d\n",retVal));
1473 T(("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!\n"));
1479 int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
1488 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
1490 yaffs_BlockInfo *bi = &dev->blockInfo[block];
1492 yaffs_Object *object;
1494 T(("Collecting block %d n %d bits %x\n",block, bi->pagesInUse, bi->pageBits));
1496 for(mask = 1,oldChunk = block * YAFFS_CHUNKS_PER_BLOCK;
1497 mask && bi->pageBits;
1498 mask <<= 1, oldChunk++ )
1500 if(bi->pageBits & mask)
1503 // This page is in use and needs to be copied off
1505 T(("copying page %x from %d to %d\n",mask,oldChunk,newChunk));
1507 yaffs_ReadChunkFromNAND(dev,oldChunk,buffer, &spare);
1509 yaffs_GetTagsFromSpare(&spare,&tags);
1510 tags.serialNumber++;
1511 yaffs_LoadTagsIntoSpare(&spare,&tags);
1514 newChunk = yaffs_AllocatePage(dev,1);
1520 yaffs_WriteChunkToNAND(dev,newChunk, buffer, &spare);
1523 newChunk = yaffs_WriteNewChunkToNAND(dev, buffer, &spare,1);
1530 object = yaffs_FindObjectByNumber(dev,tags.objectId);
1532 // Ok, now fix up the Tnodes etc.
1534 if(tags.chunkId == 0)
1537 object->chunkId = newChunk;
1541 // It's a data chunk
1542 yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
1546 yaffs_DeleteChunk(dev,oldChunk);
1554 int yaffs_CheckGarbageCollection(yaffs_Device *dev)
1558 if(dev->garbageCollectionRequired)
1560 dev->garbageCollectionRequired = 0;
1561 block = yaffs_FindDirtiestBlock(dev);
1564 return yaffs_GarbageCollectBlock(dev,block);
1576 //////////////////////////// TAGS ///////////////////////////////////////
1578 static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr)
1580 yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
1582 yaffs_CalcTagsECC(tagsPtr);
1584 sparePtr->tagByte0 = tu->asBytes[0];
1585 sparePtr->tagByte1 = tu->asBytes[1];
1586 sparePtr->tagByte2 = tu->asBytes[2];
1587 sparePtr->tagByte3 = tu->asBytes[3];
1588 sparePtr->tagByte4 = tu->asBytes[4];
1589 sparePtr->tagByte5 = tu->asBytes[5];
1590 sparePtr->tagByte6 = tu->asBytes[6];
1591 sparePtr->tagByte7 = tu->asBytes[7];
1594 static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr)
1596 yaffs_TagsUnion *tu = (yaffs_TagsUnion *)tagsPtr;
1598 tu->asBytes[0]= sparePtr->tagByte0;
1599 tu->asBytes[1]= sparePtr->tagByte1;
1600 tu->asBytes[2]= sparePtr->tagByte2;
1601 tu->asBytes[3]= sparePtr->tagByte3;
1602 tu->asBytes[4]= sparePtr->tagByte4;
1603 tu->asBytes[5]= sparePtr->tagByte5;
1604 tu->asBytes[6]= sparePtr->tagByte6;
1605 tu->asBytes[7]= sparePtr->tagByte7;
1607 yaffs_CheckECCOnTags(tagsPtr);
1610 static void yaffs_SpareInitialise(yaffs_Spare *spare)
1612 memset(spare,0xFF,sizeof(yaffs_Spare));
1615 static int yaffs_ReadChunkTagsFromNAND(yaffs_Device *dev,int chunkInNAND, yaffs_Tags *tags)
1620 if(yaffs_ReadChunkFromNAND(dev,chunkInNAND,NULL,&spare) == YAFFS_OK)
1622 yaffs_GetTagsFromSpare(&spare,tags);
1634 static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags)
1636 // NB There must be tags, data is optional
1637 // If there is data, then an ECC is calculated on it.
1646 yaffs_SpareInitialise(&spare);
1651 yaffs_CalcECC(buffer,&spare);
1654 yaffs_LoadTagsIntoSpare(&spare,tags);
1656 return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
1660 static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve)
1662 // NB There must be tags, data is optional
1663 // If there is data, then an ECC is calculated on it.
1672 yaffs_SpareInitialise(&spare);
1677 yaffs_CalcECC(buffer,&spare);
1680 yaffs_LoadTagsIntoSpare(&spare,tags);
1682 return yaffs_WriteNewChunkToNAND(dev,buffer,&spare,useReserve);
1689 int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
1691 //Get the Tnode, then get the level 0 offset chunk offset
1694 yaffs_Tags localTags;
1697 yaffs_Device *dev = in->myDev;
1702 // Passed a NULL, so use our own tags space
1706 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1710 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1712 // Now we need to do the shifting etc and search for it
1713 for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
1715 yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
1716 if(tags->chunkId == chunkInInode &&
1717 tags->objectId == in->objectId)
1728 return found ? theChunk : -1;
1731 int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_Tags *tags)
1733 //Get the Tnode, then get the level 0 offset chunk offset
1736 yaffs_Tags localTags;
1739 yaffs_Device *dev = in->myDev;
1743 // Passed a NULL, so use our own tags space
1747 tn = yaffs_FindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1752 theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
1754 // Now we need to do the shifting etc and search for it
1755 for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
1757 yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
1758 if(tags->chunkId == chunkInInode &&
1759 tags->objectId == in->objectId)
1770 // Delete the entry in the filestructure
1773 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = 0;
1778 T(("No level 0 found for %d\n", chunkInInode));
1783 T(("Could not find %d to delete\n",chunkInInode));
1785 return found ? theChunk : -1;
1791 static int yaffs_CheckFileSanity(yaffs_Object *in)
1799 yaffs_Tags localTags;
1800 yaffs_Tags *tags = &localTags;
1804 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
1806 T(("Object not a file\n"));
1810 objId = in->objectId;
1811 fSize = in->variant.fileVariant.fileSize;
1812 nChunks = (fSize + YAFFS_BYTES_PER_CHUNK -1)/YAFFS_BYTES_PER_CHUNK;
1814 for(chunk = 1; chunk <= nChunks; chunk++)
1816 tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
1821 theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
1824 yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags);
1825 if(tags->chunkId == chunk &&
1826 tags->objectId == in->objectId)
1833 //T(("File problem file [%d,%d] NAND %d tags[%d,%d]\n",
1834 // objId,chunk,theChunk,tags->chunkId,tags->objectId);
1843 T(("No level 0 found for %d\n", chunk));
1847 return failed ? YAFFS_FAIL : YAFFS_OK;
1852 static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
1855 yaffs_Device *dev = in->myDev;
1857 yaffs_Tags existingTags;
1859 unsigned existingSerial, newSerial;
1862 tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
1866 // If we're scanning then we need to test for duplicates
1867 // NB This does not need to be efficient since it should only ever
1868 // happen when the power fails during a write, then only one
1869 // chunk should ever be affected.
1871 existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
1873 if(existingChunk != 0)
1875 // We have a duplicate now we need to decide which one to use
1876 // To do this we get both sets of tags and compare serial numbers.
1877 yaffs_ReadChunkTagsFromNAND(dev,chunkInInode, &newTags);
1878 yaffs_ReadChunkTagsFromNAND(dev,existingChunk, &existingTags);
1879 newSerial = newTags.serialNumber;
1880 existingSerial = existingTags.serialNumber;
1881 if(((existingSerial+1) & 3) == newSerial)
1884 // Delete the old one and drop through to update the tnode
1885 yaffs_DeleteChunk(dev,existingChunk);
1890 // Delete the new one and return early so that the tnode isn't changed
1891 yaffs_DeleteChunk(dev,chunkInInode);
1897 tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
1904 int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
1906 int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
1908 if(chunkInNAND >= 0)
1910 return yaffs_ReadChunkFromNAND(in->myDev,chunkInNAND,buffer,NULL);
1920 static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId)
1922 int block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
1923 int page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
1926 // Mark the deleted NAND page as deleted
1932 yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
1935 // Pull out of the management area.
1936 if( dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
1937 dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
1941 dev->blockInfo[block].pageBits &= ~(1 << page);
1942 dev->blockInfo[block].pagesInUse--;
1944 if( dev->blockInfo[block].pagesInUse == 0 &&
1945 dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
1947 yaffs_BlockBecameDirty(dev,block);
1953 T(("Bad news deleting chunk %d\n",chunkId));
1961 int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
1963 // Find old chunk Need to do this to get serial number
1964 // Write new one and patch into tree.
1965 // Invalidate old tags.
1968 yaffs_Tags prevTags;
1973 yaffs_Device *dev = in->myDev;
1975 yaffs_CheckGarbageCollection(dev);
1977 // Get the previous chunk at this location in the file if it exists
1978 prevChunkId = yaffs_FindChunkInFile(in,chunkInInode,&prevTags);
1981 newTags.chunkId = chunkInInode;
1982 newTags.objectId = in->objectId;
1983 newTags.serialNumber = (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
1984 newTags.byteCount = nBytes;
1985 newTags.unusedStuff = 0xFFFFFFFF;
1987 yaffs_CalcTagsECC(&newTags);
1991 // Create new chunk in NAND
1992 newChunkId = yaffs_AllocatePage(dev,useReserve);
1999 yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,buffer,&newTags);
2001 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
2004 if(prevChunkId >= 0)
2006 yaffs_DeleteChunk(dev,prevChunkId);
2010 yaffs_CheckFileSanity(in);
2019 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
2022 yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
2025 if(prevChunkId >= 0)
2027 yaffs_DeleteChunk(dev,prevChunkId);
2031 yaffs_CheckFileSanity(in);
2042 // UpdateObjectHeader updates the header on NAND for an object.
2043 // If name is not NULL, then that new name is used.
2045 int yaffs_UpdateObjectHeader(yaffs_Object *in,const char *name)
2048 yaffs_Device *dev = in->myDev;
2054 __u8 bufferNew[YAFFS_BYTES_PER_CHUNK];
2055 __u8 bufferOld[YAFFS_BYTES_PER_CHUNK];
2057 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)bufferNew;
2058 yaffs_ObjectHeader *ohOld = (yaffs_ObjectHeader *)bufferOld;
2063 yaffs_CheckGarbageCollection(dev);
2065 memset(bufferNew,0xFF,YAFFS_BYTES_PER_CHUNK);
2067 prevChunkId = in->chunkId;
2069 if(prevChunkId >= 0)
2071 yaffs_ReadChunkFromNAND(dev,prevChunkId,bufferOld,NULL);
2075 oh->type = in->variantType;
2077 oh->st_mode = in->st_mode;
2078 oh->st_uid = in->st_uid;
2079 oh->st_gid = in->st_gid;
2080 oh->st_atime = in->st_atime;
2081 oh->st_mtime = in->st_mtime;
2082 oh->st_ctime = in->st_ctime;
2084 oh->parentObjectId = in->parent->objectId;
2088 memset(oh->name,0,YAFFS_MAX_NAME_LENGTH + 1);
2089 strncpy(oh->name,name,YAFFS_MAX_NAME_LENGTH);
2093 memcpy(oh->name, ohOld->name,YAFFS_MAX_NAME_LENGTH + 1);
2096 switch(in->variantType)
2098 case YAFFS_OBJECT_TYPE_UNKNOWN:
2099 // Should not happen
2101 case YAFFS_OBJECT_TYPE_FILE:
2102 oh->fileSize = in->variant.fileVariant.fileSize;
2104 case YAFFS_OBJECT_TYPE_HARDLINK:
2105 oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
2107 case YAFFS_OBJECT_TYPE_DIRECTORY:
2110 case YAFFS_OBJECT_TYPE_SYMLINK:
2111 strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
2112 oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
2118 newTags.chunkId = 0;
2119 newTags.objectId = in->objectId;
2120 newTags.serialNumber = in->serial;
2121 newTags.byteCount = 0xFFFFFFFF;
2122 newTags.unusedStuff = 0xFFFFFFFF;
2124 yaffs_CalcTagsECC(&newTags);
2129 // Create new chunk in NAND
2130 newChunkId = yaffs_AllocatePage(dev,1);
2135 yaffs_WriteChunkWithTagsToNAND(dev,newChunkId,bufferNew,&newTags);
2137 in->chunkId = newChunkId;
2139 if(prevChunkId >= 0)
2141 yaffs_DeleteChunk(dev,prevChunkId);
2150 // Create new chunk in NAND
2151 newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,bufferNew,&newTags,1);
2156 in->chunkId = newChunkId;
2158 if(prevChunkId >= 0)
2160 yaffs_DeleteChunk(dev,prevChunkId);
2175 ///////////////////////// File read/write ///////////////////////////////
2176 // Read and write have very similar structures.
2177 // In general the read/write has three parts to it
2178 // * An incomplete chunk to start with (if the read/write is not chunk-aligned)
2179 // * Some complete chunks
2180 // * An incomplete chunk to end off with
2182 // Curve-balls: the first chunk might also be the last chunk.
2184 int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 * buffer, __u32 offset, int nBytes)
2187 // yaffs_Device *dev = in->myDev;
2189 __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2199 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1; // The first chunk is 1
2200 start = offset % YAFFS_BYTES_PER_CHUNK;
2202 // OK now check for the curveball where the start and end are in
2204 if( (start + n) < YAFFS_BYTES_PER_CHUNK)
2210 nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2213 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2215 // An incomplete start or end chunk (or maybe both start and end chunk)
2216 // Read into the local buffer then copy...
2218 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
2219 memcpy(buffer,&localBuffer[start],nToCopy);
2223 // A full chunk. Read directly into the supplied buffer.
2224 yaffs_ReadChunkDataFromObject(in,chunk,buffer);
2238 int yaffs_WriteDataToFile(yaffs_Object *in,const __u8 * buffer, __u32 offset, int nBytes)
2240 __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2248 int endOfWrite = offset+nBytes;
2249 int chunkWritten = 0;
2251 while(n > 0 && chunkWritten >= 0)
2253 chunk = offset / YAFFS_BYTES_PER_CHUNK + 1;
2254 start = offset % YAFFS_BYTES_PER_CHUNK;
2257 // OK now check for the curveball where the start and end are in
2259 if( (start + n) < YAFFS_BYTES_PER_CHUNK)
2262 nToWriteBack = (start + n);
2266 nToCopy = YAFFS_BYTES_PER_CHUNK - start;
2267 nToWriteBack = YAFFS_BYTES_PER_CHUNK;
2270 if(nToCopy != YAFFS_BYTES_PER_CHUNK)
2272 // An incomplete start or end chunk (or maybe both start and end chunk)
2273 // Read into the local buffer then copy, then copy over and write back.
2275 yaffs_ReadChunkDataFromObject(in,chunk,localBuffer);
2277 memcpy(&localBuffer[start],buffer,nToCopy);
2279 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,localBuffer,nToWriteBack,0);
2281 T(("Write with readback to chunk %d %d\n",chunk,chunkWritten));
2286 // A full chunk. Write directly from the supplied buffer.
2287 chunkWritten = yaffs_WriteChunkDataToObject(in,chunk,buffer,YAFFS_BYTES_PER_CHUNK,0);
2288 T(("Write to chunk %d %d\n",chunk,chunkWritten));
2291 if(chunkWritten >= 0)
2301 // Update file object
2303 if(endOfWrite > in->variant.fileVariant.fileSize)
2305 in->variant.fileVariant.fileSize = endOfWrite;
2309 in->st_mtime = CURRENT_TIME;
2315 int yaffs_ResizeFile(yaffs_Object *in, int newSize)
2319 int oldFileSize = in->variant.fileVariant.fileSize;
2320 int sizeOfLastChunk = newSize % YAFFS_BYTES_PER_CHUNK;
2322 yaffs_Device *dev = in->myDev;
2324 __u8 localBuffer[YAFFS_BYTES_PER_CHUNK];
2326 if(in->variantType != YAFFS_OBJECT_TYPE_FILE)
2328 return yaffs_GetFileSize(in);
2331 if(newSize < oldFileSize)
2334 int lastDel = 1 + oldFileSize/YAFFS_BYTES_PER_CHUNK;
2336 int startDel = 1 + (newSize + YAFFS_BYTES_PER_CHUNK - 1)/
2337 YAFFS_BYTES_PER_CHUNK;
2339 for(i = startDel; i <= lastDel; i++)
2341 // NB this could be optimised somewhat,
2342 // eg. could retrieve the tags and write them without
2343 // using yaffs_DeleteChunk
2344 chunkId = yaffs_FindAndDeleteChunkInFile(in,i,NULL);
2345 if(chunkId < 0 || chunkId >= (dev->endBlock * 32))
2347 T(("Found daft chunkId %d for %d\n",chunkId,i));
2351 yaffs_DeleteChunk(dev,chunkId);
2356 if(sizeOfLastChunk != 0)
2358 int lastChunk = 1+ newSize/YAFFS_BYTES_PER_CHUNK;
2360 // Got to read and rewrite the last chunk with its new size.
2361 yaffs_ReadChunkDataFromObject(in,lastChunk,localBuffer);
2363 yaffs_WriteChunkDataToObject(in,lastChunk,localBuffer,sizeOfLastChunk,1);
2367 in->variant.fileVariant.fileSize = newSize;
2369 yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
2381 loff_t yaffs_GetFileSize(yaffs_Object *obj)
2383 obj = yaffs_GetEquivalentObject(obj);
2385 switch(obj->variantType)
2387 case YAFFS_OBJECT_TYPE_FILE:
2388 return obj->variant.fileVariant.fileSize;
2389 case YAFFS_OBJECT_TYPE_SYMLINK:
2390 return strlen(obj->variant.symLinkVariant.alias);
2398 // yaffs_FlushFile() updates the file's
2401 int yaffs_FlushFile(yaffs_Object *in)
2406 T(("flushing object header\n"));
2407 retVal = yaffs_UpdateObjectHeader(in,NULL);
2419 static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
2421 yaffs_RemoveObjectFromDirectory(in);
2422 yaffs_DeleteChunk(in->myDev,in->chunkId);
2423 yaffs_FreeObject(in);
2428 // yaffs_DeleteFile deletes the whole file data
2429 // and the inode associated with the file.
2430 // It does not delete the links associated with the file.
2431 static int yaffs_DeleteFile(yaffs_Object *in)
2433 // Delete the file data & tnodes
2434 yaffs_ResizeFile(in,0);
2435 yaffs_FreeTnode(in->myDev,in->variant.fileVariant.top);
2437 return yaffs_DoGenericObjectDeletion(in);
2440 static int yaffs_DeleteDirectory(yaffs_Object *in)
2442 //First check that the directory is empty.
2443 if(list_empty(&in->variant.directoryVariant.children))
2445 return yaffs_DoGenericObjectDeletion(in);
2452 static int yaffs_DeleteSymLink(yaffs_Object *in)
2454 YFREE(in->variant.symLinkVariant.alias);
2456 return yaffs_DoGenericObjectDeletion(in);
2459 static int yaffs_DeleteHardLink(yaffs_Object *in)
2461 // remove this hardlink from the list assocaited with the equivalent
2463 list_del(&in->hardLinks);
2464 return yaffs_DoGenericObjectDeletion(in);
2468 static int yaffs_UnlinkWorker(yaffs_Object *obj)
2472 if(obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
2474 return yaffs_DeleteHardLink(obj);
2476 else if(!list_empty(&obj->hardLinks))
2479 // Curve ball: We're unlinking an object that has a hardlink.
2480 // Therefore we can't really delete the object.
2481 // Instead, we do the following:
2482 // - Select a hardlink.
2483 // - Re-type a hardlink as the equivalent object and populate the fields, including the
2484 // objectId. Updating the object id is important so that all the hardlinks do not need
2486 // - Update the equivalet object pointers.
2487 // - Delete all object.
2490 struct list_head *i;
2493 yaffs_RemoveObjectFromDirectory(obj);
2497 hl = list_entry(obj->hardLinks.next, yaffs_Object,hardLinks);
2500 hl->st_mode = obj->st_mode;
2501 hl->st_uid = obj->st_uid;
2502 hl->st_gid = obj->st_gid;
2503 hl->st_atime = obj->st_atime;
2504 hl->st_mtime = obj->st_mtime;
2505 hl->st_ctime = obj->st_ctime;
2507 hl->variantType = obj->variantType;
2509 switch(hl->variantType)
2511 case YAFFS_OBJECT_TYPE_FILE:
2512 case YAFFS_OBJECT_TYPE_SYMLINK:
2513 // These types are OK to just copy across.
2514 hl->variant = obj->variant;
2516 case YAFFS_OBJECT_TYPE_DIRECTORY:
2518 list_add(&hl->variant.directoryVariant.children,
2519 &obj->variant.directoryVariant.children);
2520 list_del(&obj->variant.directoryVariant.children);
2522 // Now change all the directory children to point to the new parent.
2523 list_for_each(i,&hl->variant.directoryVariant.children)
2525 list_entry(i,yaffs_Object,siblings)->parent = hl;
2529 case YAFFS_OBJECT_TYPE_HARDLINK:
2530 case YAFFS_OBJECT_TYPE_UNKNOWN:
2531 // Should not be either of these types.
2534 // Now fix up the hardlink chain
2535 list_del(&obj->hardLinks);
2537 list_for_each(i,&hl->hardLinks)
2539 list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObject = hl;
2540 list_entry(i,yaffs_Object,hardLinks)->variant.hardLinkVariant.equivalentObjectId = hl->objectId;
2543 // Now fix up the hash links.
2544 yaffs_UnhashObject(hl);
2545 hl->objectId = obj->objectId;
2546 yaffs_HashObject(hl);
2548 // Update the hardlink which has become an object
2549 yaffs_UpdateObjectHeader(hl,NULL);
2551 // Finally throw away the deleted object
2552 yaffs_DeleteChunk(obj->myDev,obj->chunkId);
2553 yaffs_FreeObject(obj);
2557 // Curve ball: We're unlinking an object that has a hardlink.
2559 // This problem arises because we are not strictly following
2560 // The Linux link/inode model.
2562 // We can't really delete the object.
2563 // Instead, we do the following:
2564 // - Select a hardlink.
2565 // - Unhook it from the hard links
2566 // - Unhook it from its parent directory (so that the rename can work)
2567 // - Rename the object to the hardlink's name.
2568 // - Delete the hardlink
2573 char name[YAFFS_MAX_NAME_LENGTH+1];
2575 hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
2576 list_del_init(&hl->hardLinks);
2577 list_del_init(&hl->siblings);
2579 yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
2581 retVal = yaffs_ChangeObjectName(obj, hl->parent, name);
2582 if(retVal == YAFFS_OK)
2584 retVal = yaffs_DoGenericObjectDeletion(hl);
2594 switch(obj->variantType)
2596 case YAFFS_OBJECT_TYPE_FILE:
2597 return yaffs_DeleteFile(obj);
2599 case YAFFS_OBJECT_TYPE_DIRECTORY:
2600 return yaffs_DeleteDirectory(obj);
2602 case YAFFS_OBJECT_TYPE_SYMLINK:
2603 return yaffs_DeleteSymLink(obj);
2605 case YAFFS_OBJECT_TYPE_HARDLINK:
2606 case YAFFS_OBJECT_TYPE_UNKNOWN:
2613 int yaffs_Unlink(yaffs_Object *dir, const char *name)
2617 obj = yaffs_FindObjectByName(dir,name);
2619 if(obj && obj->unlinkAllowed)
2621 return yaffs_UnlinkWorker(obj);
2628 //////////////// Initialisation Scanning /////////////////
2631 static int yaffs_Scan(yaffs_Device *dev)
2640 yaffs_BlockState state;
2641 yaffs_Object *hardList = NULL;
2646 yaffs_ObjectHeader *oh;
2648 yaffs_Object *parent;
2650 __u8 chunkData[YAFFS_BYTES_PER_CHUNK];
2652 for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
2657 state = YAFFS_BLOCK_STATE_UNKNOWN;
2659 for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK &&
2660 state == YAFFS_BLOCK_STATE_UNKNOWN; c++)
2662 // Read the spare area and decide what to do
2663 chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;
2664 yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare);
2667 // Is this a valid block?
2668 if(yaffs_countBits[spare.blockStatus] >= 7)
2670 // This block looks ok, now what's in this chunk?
2671 yaffs_GetTagsFromSpare(&spare,&tags);
2673 if(tags.objectId == YAFFS_UNUSED_OBJECT_ID)
2675 // An unassigned chunk in the block
2676 // This means that either the block is empty or
2677 // this is the one being allocated from
2681 // the block is unused
2682 state = YAFFS_BLOCK_STATE_EMPTY;
2683 dev->nErasedBlocks++;
2687 // this is the block being allocated from
2688 T((" allocating %d %d\n",blk,c));
2689 state = YAFFS_BLOCK_STATE_ALLOCATING;
2690 dev->allocationBlock = blk;
2691 dev->allocationPage = c;
2694 dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c);
2696 else if(tags.objectId == 0)
2700 dev->nFreeChunks ++;
2701 T((" %d %d deleted\n",blk,c));
2703 else if(tags.chunkId > 0)
2707 pageBits |= ( 1 <<c);
2708 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
2709 // PutChuunkIntoFIle checks for a clash (two data chunks with
2710 // the same chunkId).
2711 yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
2712 T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
2716 // chunkId == 0, so it is an ObjectHeader.
2718 pageBits |= ( 1 <<c);
2719 yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL);
2720 oh = (yaffs_ObjectHeader *)chunkData;
2722 in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
2725 // todo we have already filled this one. We have
2726 // a duplicate. Need to fix
2729 // we don't have a duplicate...
2732 in->variantType = oh->type;
2734 in->st_mode = oh->st_mode;
2735 in->st_uid = oh->st_uid;
2736 in->st_gid = oh->st_gid;
2737 in->st_atime = oh->st_atime;
2738 in->st_mtime = oh->st_mtime;
2739 in->st_ctime = oh->st_ctime;
2740 in->chunkId = chunk;
2745 // directory stuff...
2746 // hook up to parent
2748 parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
2749 if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
2751 // Set up as a directory
2752 parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
2753 INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
2755 else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
2757 // Hoosterman, another problem....
2758 // We're trying to use a non-directory as a directory
2762 yaffs_AddObjectToDirectory(parent,in);
2764 // Note re hardlinks.
2765 // Since we might scan a hardlink before its equivalent object is scanned
2766 // we put them all in a list.
2767 // After scanning is complete, we should have all the objects, so we run through this
2768 // list and fix up all the chains.
2770 switch(in->variantType)
2772 case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
2774 case YAFFS_OBJECT_TYPE_FILE:
2775 in->variant.fileVariant.fileSize = oh->fileSize;
2777 case YAFFS_OBJECT_TYPE_HARDLINK:
2778 in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
2779 (yaffs_Object *)(in->hardLinks.next) = hardList;
2782 case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
2784 case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
2785 in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
2788 T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
2794 state = YAFFS_BLOCK_STATE_DEAD;
2798 if(state == YAFFS_BLOCK_STATE_UNKNOWN)
2800 // If we got this far, then the block is fully allocated.
2801 // ie. Full or Dirty
2802 state = (inuse) ? YAFFS_BLOCK_STATE_FULL : YAFFS_BLOCK_STATE_DIRTY;
2806 dev->blockInfo[blk].pageBits = pageBits;
2807 dev->blockInfo[blk].pagesInUse = inuse;
2808 dev->blockInfo[blk].blockState = state;
2812 // Todo fix up the hard link chains
2816 hardList = (yaffs_Object *)(hardList->hardLinks.next);
2818 in = yaffs_FindObjectByNumber(dev,hl->variant.hardLinkVariant.equivalentObjectId);
2822 hl->variant.hardLinkVariant.equivalentObject=in;
2823 list_add(&hl->hardLinks,&in->hardLinks);
2827 //Todo Need to report this better.
2828 hl->variant.hardLinkVariant.equivalentObject=NULL;
2829 INIT_LIST_HEAD(&hl->hardLinks);
2841 ////////////////////////// Directory Functions /////////////////////////
2844 static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj)
2847 if(obj->siblings.prev == NULL)
2850 INIT_LIST_HEAD(&obj->siblings);
2853 else if(!list_empty(&obj->siblings))
2855 // If it is holed up somewhere else, un hook it
2856 list_del_init(&obj->siblings);
2859 list_add(&obj->siblings,&directory->variant.directoryVariant.children);
2860 obj->parent = directory;
2863 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
2865 list_del_init(&obj->siblings);
2869 yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,const char *name)
2873 struct list_head *i;
2874 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2875 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2879 sum = yaffs_CalcNameSum(name);
2881 list_for_each(i,&directory->variant.directoryVariant.children)
2883 l = list_entry(i, yaffs_Object,siblings);
2885 // Special case for lost-n-found
2886 if(l->objectId == YAFFS_OBJECTID_LOSTNFOUND)
2888 if(strcmp(name,YAFFS_LOSTNFOUND_NAME) == 0)
2893 else if(l->sum == sum)
2896 yaffs_ReadChunkFromNAND(l->myDev,l->chunkId,buffer,NULL);
2897 if(strcmp(name,oh->name) == 0)
2910 int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,int (*fn)(yaffs_Object *))
2912 struct list_head *i;
2916 list_for_each(i,&theDir->variant.directoryVariant.children)
2918 l = list_entry(i, yaffs_Object,siblings);
2930 // GetEquivalentObject dereferences any hard links to get to the
2933 static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
2935 if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
2937 // We want the object id of the equivalent object, not this one
2938 obj = obj->variant.hardLinkVariant.equivalentObject;
2944 int yaffs_GetObjectName(yaffs_Object *obj,char *name,int buffSize)
2946 memset(name,0,buffSize);
2948 if(obj->objectId == YAFFS_OBJECTID_LOSTNFOUND)
2950 strncpy(name,YAFFS_LOSTNFOUND_NAME,buffSize - 1);
2954 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
2955 yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
2957 memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
2959 if(obj->chunkId >= 0)
2961 yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
2963 strncpy(name,oh->name,buffSize - 1);
2966 return strlen(name);
2969 int yaffs_GetObjectFileLength(yaffs_Object *obj)
2972 // Dereference any hard linking
2973 obj = yaffs_GetEquivalentObject(obj);
2975 if(obj->variantType == YAFFS_OBJECT_TYPE_FILE)
2977 return obj->variant.fileVariant.fileSize;
2979 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
2981 return strlen(obj->variant.symLinkVariant.alias);
2985 // Only a directory should drop through to here
2986 return YAFFS_BYTES_PER_CHUNK;
2990 int yaffs_GetObjectLinkCount(yaffs_Object *obj)
2992 int count = 1; // the object itself
2993 struct list_head *i;
2995 list_for_each(i,&obj->hardLinks)
3004 int yaffs_GetObjectInode(yaffs_Object *obj)
3006 obj = yaffs_GetEquivalentObject(obj);
3008 return obj->objectId;
3011 unsigned yaffs_GetObjectType(yaffs_Object *obj)
3013 obj = yaffs_GetEquivalentObject(obj);
3015 switch(obj->variantType)
3017 case YAFFS_OBJECT_TYPE_FILE: return DT_REG; break;
3018 case YAFFS_OBJECT_TYPE_DIRECTORY: return DT_DIR; break;
3019 case YAFFS_OBJECT_TYPE_SYMLINK: return DT_LNK; break;
3020 case YAFFS_OBJECT_TYPE_HARDLINK: return DT_REG; break;
3021 default: return DT_REG; break;
3025 char *yaffs_GetSymlinkAlias(yaffs_Object *obj)
3027 obj = yaffs_GetEquivalentObject(obj);
3028 if(obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
3030 return yaffs_CloneString(obj->variant.symLinkVariant.alias);
3034 return yaffs_CloneString("");
3039 int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
3041 unsigned int valid = attr->ia_valid;
3043 if(valid & ATTR_MODE) obj->st_mode = attr->ia_mode;
3044 if(valid & ATTR_UID) obj->st_uid = attr->ia_uid;
3045 if(valid & ATTR_GID) obj->st_gid = attr->ia_gid;
3047 if(valid & ATTR_ATIME) obj->st_atime = attr->ia_atime;
3048 if(valid & ATTR_CTIME) obj->st_ctime = attr->ia_ctime;
3049 if(valid & ATTR_MTIME) obj->st_mtime = attr->ia_mtime;
3051 if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
3053 yaffs_UpdateObjectHeader(obj,NULL);
3058 int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
3060 unsigned int valid = 0;
3062 attr->ia_mode = obj->st_mode; valid |= ATTR_MODE;
3063 attr->ia_uid = obj->st_uid; valid |= ATTR_UID;
3064 attr->ia_gid = obj->st_gid; valid |= ATTR_GID;
3066 attr->ia_atime = obj->st_atime; valid |= ATTR_ATIME;
3067 attr->ia_ctime = obj->st_ctime; valid |= ATTR_CTIME;
3068 attr->ia_mtime = obj->st_mtime; valid |= ATTR_MTIME;
3070 attr->ia_size = yaffs_GetFileSize(obj); valid |= ATTR_SIZE;
3072 attr->ia_valid = valid;
3080 int yaffs_DumpObject(yaffs_Object *obj)
3082 __u8 buffer[YAFFS_BYTES_PER_CHUNK];
3084 // yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
3086 memset(buffer,0,YAFFS_BYTES_PER_CHUNK);
3088 if(obj->chunkId >= 0)
3090 yaffs_ReadChunkFromNAND(obj->myDev,obj->chunkId,buffer,NULL);
3093 yaffs_GetObjectName(obj,name,256);
3095 YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",
3096 yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
3097 obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
3100 YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d\n",
3101 obj->objectId, oh->name, obj->dirty, obj->valid, obj->serial,
3102 obj->sum, obj->chunkId));
3103 switch(obj->variantType)
3105 case YAFFS_OBJECT_TYPE_FILE:
3106 YPRINTF((" FILE length %d\n",obj->variant.fileVariant.fileSize));
3108 case YAFFS_OBJECT_TYPE_DIRECTORY:
3109 YPRINTF((" DIRECTORY\n"));
3111 case YAFFS_OBJECT_TYPE_HARDLINK: //todo
3112 case YAFFS_OBJECT_TYPE_SYMLINK:
3113 case YAFFS_OBJECT_TYPE_UNKNOWN:
3122 ///////////////////////// Initialisation code ///////////////////////////
3126 int yaffs_GutsInitialise(yaffs_Device *dev)
3134 if(!yaffs_CheckStructures())
3140 // OK now calculate a few things for the device
3141 // Calculate chunkGroupBits.
3142 // If there are 64k or less chunks then this is 1
3143 // Else it is log2(nChunks) - 16
3145 x = nChunks = YAFFS_CHUNKS_PER_BLOCK * dev->nBlocks;
3147 for(bits = 0, x = nChunks; (x & 1) == 0; bits++)
3155 YPRINTF(("nBlocks should be a power of 2 but is %u\n",
3162 dev->chunkGroupBits = 0;
3163 dev->chunkGroupSize = 1;
3167 dev->chunkGroupBits = bits - 16;
3168 dev->chunkGroupSize = nChunks/0x10000;
3171 // More device initialisation
3172 dev->garbageCollectionRequired = 0;
3173 dev->currentDirtyChecker = 0;
3175 yaffs_InitialiseBlocks(dev);
3177 yaffs_InitialiseTnodes(dev);
3179 yaffs_InitialiseObjects(dev);
3182 // Initialise the root and lost and found directories
3183 dev->lostNFoundDir = dev->rootDir = NULL;
3184 dev->rootDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_ROOT,YAFFS_ROOT_MODE | S_IFDIR);
3185 dev->lostNFoundDir = yaffs_CreateFakeDirectory(dev,YAFFS_OBJECTID_LOSTNFOUND,YAFFS_ROOT_MODE | S_IFDIR);
3186 yaffs_AddObjectToDirectory(dev->rootDir,dev->lostNFoundDir);
3188 // Now scan the flash.
3196 void yaffs_Deinitialise(yaffs_Device *dev)
3198 yaffs_DeinitialiseBlocks(dev);
3199 yaffs_DeinitialiseTnodes(dev);
3200 yaffs_DeinitialiseObjects(dev);
3204 int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
3206 int nFree = dev->nFreeChunks - (YAFFS_CHUNKS_PER_BLOCK * YAFFS_RESERVED_BLOCKS);
3208 return (nFree < 0) ? 0 : nFree;
3213 /////////////////// YAFFS test code //////////////////////////////////
3215 #define yaffs_CheckStruct(structure,syze, name) \
3216 if(sizeof(structure) != syze) \
3217 { YPRINTF(("%s should be %d but is %d\n",name,syze,sizeof(structure))); \
3218 return YAFFS_FAIL; \
3222 static int yaffs_CheckStructures(void)
3224 yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags")
3225 yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion")
3226 yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare")
3227 yaffs_CheckStruct(yaffs_Tnode,2* YAFFS_NTNODES_LEVEL0,"yaffs_Tnode")
3228 yaffs_CheckStruct(yaffs_ObjectHeader,512,"yaffs_ObjectHeader")
3234 void yaffs_GutsTest(yaffs_Device *dev)
3237 if(yaffs_CheckStructures() != YAFFS_OK)
3239 YPRINTF(("One or more structures malformed-- aborting\n"));
3243 YPRINTF(("Structures OK\n"));
3246 yaffs_TnodeTest(dev);
3247 yaffs_ObjectTest(dev);