#define T(x)
#endif
+// External functions for ECC on data
+void nand_calculate_ecc (const u_char *dat, u_char *ecc_code);
+int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc);
+
// countBits is a quick way of counting the number of bits in a byte.
// ie. countBits[n] holds the number of 1 bits in a byte with the value n.
static int yaffs_CheckObjectHashSanity(yaffs_Device *dev);
static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr, yaffs_Tags *tagsPtr);
static void yaffs_GetTagsFromSpare(yaffs_Spare *sparePtr,yaffs_Tags *tagsPtr);
-static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND);
+static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan);
static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
static void yaffs_DeleteChunk(yaffs_Device *dev,int chunkId);
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
static int yaffs_CheckStructures(void);
-static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
loff_t yaffs_GetFileSize(yaffs_Object *obj);
static int yaffs_AllocateChunk(yaffs_Device *dev,int useReserve);
-#if YAFFS_PARANOID
-static int yaffs_CheckFileSanity(yaffs_Object *in)
+#ifdef YAFFS_PARANOID
+static int yaffs_CheckFileSanity(yaffs_Object *in);
#else
#define yaffs_CheckFileSanity(in)
#endif
int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,int chunkInNAND, __u8 *data, yaffs_Spare *spare)
{
- return dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+ int retVal;
+ __u8 calcEcc[3];
+ yaffs_Spare localSpare;
+
+ if(!spare && data)
+ {
+ // If we don't have a real spare, then we use a local one.
+ // Need this for the calculation of the ecc
+ spare = &localSpare;
+ }
+
+ retVal = dev->readChunkFromNAND(dev,chunkInNAND,data,spare);
+ if(data)
+ {
+ // Do ECC correction
+ //Todo handle any errors
+ nand_calculate_ecc(data,calcEcc);
+ nand_correct_data (data,spare->ecc1, calcEcc);
+ nand_calculate_ecc(&data[256],calcEcc);
+ nand_correct_data (&data[256],spare->ecc2, calcEcc);
+ }
+ return retVal;
+}
+
+#ifdef YAFFS_PARANOID
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,int chunkInNAND)
+{
+ static int init = 0;
+ static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
+ static __u8 data[YAFFS_BYTES_PER_CHUNK];
+ static __u8 spare[16];
+
+ int retVal;
+
+ retVal = YAFFS_OK;
+
+ dev->readChunkFromNAND(dev,chunkInNAND,data,(yaffs_Spare *)spare);
+
+
+
+ if(!init)
+ {
+ memset(cmpbuf,0xff,YAFFS_BYTES_PER_CHUNK);
+ init = 1;
+ }
+
+ if(memcmp(cmpbuf,data,YAFFS_BYTES_PER_CHUNK)) retVal = YAFFS_FAIL;
+ if(memcmp(cmpbuf,spare,16)) retVal = YAFFS_FAIL;
+
+ return retVal;
+
}
+#endif
+
+
int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
{
return dev->eraseBlockInNAND(dev,blockInNAND);
int writeOk = 0;
+ unsigned char rbData[YAFFS_BYTES_PER_CHUNK];
+ yaffs_Spare rbSpare;
+
do{
chunk = yaffs_AllocateChunk(dev,useReserve);
writeOk = yaffs_WriteChunkToNAND(dev,chunk,data,spare);
if(writeOk)
{
- //Todo read-back and verify
+ // Readback & verify
// If verify fails, then delete this chunk and try again
+ // To verify we compare everything except the block and
+ // page status bytes.
+ yaffs_ReadChunkFromNAND(dev,chunk,rbData,&rbSpare);
+
+ if(memcmp(data,rbData,YAFFS_BYTES_PER_CHUNK) != 0 ||
+ spare->tagByte0 != rbSpare.tagByte0 ||
+ spare->tagByte1 != rbSpare.tagByte1 ||
+ spare->tagByte2 != rbSpare.tagByte2 ||
+ spare->tagByte3 != rbSpare.tagByte3 ||
+ spare->tagByte4 != rbSpare.tagByte4 ||
+ spare->tagByte5 != rbSpare.tagByte5 ||
+ spare->tagByte6 != rbSpare.tagByte6 ||
+ spare->tagByte7 != rbSpare.tagByte7 ||
+ spare->ecc1[0] != rbSpare.ecc1[0] ||
+ spare->ecc1[1] != rbSpare.ecc1[1] ||
+ spare->ecc1[2] != rbSpare.ecc1[2] ||
+ spare->ecc2[0] != rbSpare.ecc2[0] ||
+ spare->ecc2[1] != rbSpare.ecc2[1] ||
+ spare->ecc2[2] != rbSpare.ecc2[2] )
+ {
+ // Didn't verify
+ yaffs_DeleteChunk(dev,chunk);
+ writeOk = 0;
+ }
+
}
}
} while(chunk >= 0 && ! writeOk);
}
-void yaffs_CalcECC(const __u8 *buffer, yaffs_Spare *spare)
+void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
{
-
- // Todo do nothing now. Need to put in ecc
- spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xFF;
- spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xFF;
+ nand_calculate_ecc (data , spare->ecc1);
+ nand_calculate_ecc (&data[256] , spare->ecc2);
}
void yaffs_CalcTagsECC(yaffs_Tags *tags)
{
// Todo don't do anything yet. Need to calculate ecc
- tags->ecc = 0xFFFFFFFF;
+ unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
+ unsigned i,j;
+ unsigned ecc = 0;
+ unsigned bit = 0;
+
+ tags->ecc = 0;
+
+ for(i = 0; i < 8; i++)
+ {
+ for(j = 1; j &0x7f; j<<=1)
+ {
+ bit++;
+ if(b[i] & j)
+ {
+ ecc ^= bit;
+ }
+ }
+ }
+
+ tags->ecc = ecc;
+
+
}
+void yaffs_CheckECCOnTags(yaffs_Tags *tags)
+{
+ unsigned ecc = tags->ecc;
+
+ yaffs_CalcTagsECC(tags);
+
+ ecc ^= tags->ecc;
+
+ if(ecc)
+ {
+ // Needs fixing
+ unsigned char *b = ((yaffs_TagsUnion *)tags)->asBytes;
+
+ ecc--;
+
+ b[ecc / 8] ^= (1 << (ecc & 7));
+
+ // Now recvalc the ecc
+ yaffs_CalcTagsECC(tags);
+ }
+}
///////////////////////// TNODES ///////////////////////
INIT_LIST_HEAD(&theObject->variant.directoryVariant.children);
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
+ // No action required
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
+ // No action required
break;
case YAFFS_OBJECT_TYPE_UNKNOWN:
// todo this should not happen
yaffs_Device *dev = parent->myDev;
+ // Check if the entry exists. If it does then fail the call since we don't want a dup.
+ if(yaffs_FindObjectByName(parent,name))
+ {
+ return NULL;
+ }
+
in = yaffs_CreateNewObject(dev,-1,type);
if(in)
obj->dirty = 1;
yaffs_AddObjectToDirectory(newDir,obj);
- return yaffs_UpdateObjectHeader(obj,newName);
+ if(yaffs_UpdateObjectHeader(obj,newName) >= 0)
+ {
+ return YAFFS_OK;
+ }
}
return YAFFS_FAIL;
}
#ifdef YAFFS_PARANOID
- if(yaffs_CheckChunkErased(retVal) == YAFFS_FAIL)
+ if(yaffs_CheckChunkErased(dev,retVal) == YAFFS_FAIL)
{
T(("..................Trying to allocate non-erased page %d\n",retVal));
}
else
{
// It's a data chunk
- yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk);
+ yaffs_PutChunkIntoFile(object, tags.chunkId, newChunk,0);
}
tu->asBytes[6]= sparePtr->tagByte6;
tu->asBytes[7]= sparePtr->tagByte7;
- // Todo Check ECC on tags
+ yaffs_CheckECCOnTags(tagsPtr);
}
static void yaffs_SpareInitialise(yaffs_Spare *spare)
return YAFFS_OK;
}
+#if 0
static int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,int chunkInNAND, const __u8 *buffer, yaffs_Tags *tags)
{
// NB There must be tags, data is optional
return yaffs_WriteChunkToNAND(dev,chunkInNAND,buffer,&spare);
}
+#endif
+
static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev, const __u8 *buffer, yaffs_Tags *tags, int useReserve)
{
theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
// Now we need to do the shifting etc and search for it
- for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++)
+ for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
{
yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
if(tags->chunkId == chunkInInode &&
theChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
// Now we need to do the shifting etc and search for it
- for(i = 0,found = 0; i < dev->chunkGroupSize && !found; i++)
+ for(i = 0,found = 0; theChunk && i < dev->chunkGroupSize && !found; i++)
{
yaffs_ReadChunkTagsFromNAND(dev,theChunk,tags);
if(tags->chunkId == chunkInInode &&
for(chunk = 1; chunk <= nChunks; chunk++)
{
- tn = yaffs_FindLevel0Tnode(&in->variant.fileVariant, chunk);
+ tn = yaffs_FindLevel0Tnode(in->myDev,&in->variant.fileVariant, chunk);
if(tn)
{
- theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << dev->chunkGroupBits;
+ theChunk = tn->level0[chunk & YAFFS_TNODES_LEVEL0_MASK] << in->myDev->chunkGroupBits;
- yaffs_ReadChunkTagsFromNAND(theChunk,tags);
+ yaffs_ReadChunkTagsFromNAND(in->myDev,theChunk,tags);
if(tags->chunkId == chunk &&
tags->objectId == in->objectId)
{
// found it;
-
+
}
else
{
#endif
-static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND)
+static int yaffs_PutChunkIntoFile(yaffs_Object *in,int chunkInInode, int chunkInNAND, int inScan)
{
yaffs_Tnode *tn;
yaffs_Device *dev = in->myDev;
+ int existingChunk;
+ yaffs_Tags existingTags;
+ yaffs_Tags newTags;
+ unsigned existingSerial, newSerial;
+
tn = yaffs_AddOrFindLevel0Tnode(dev,&in->variant.fileVariant, chunkInInode);
+
+ if(inScan)
+ {
+ // If we're scanning then we need to test for duplicates
+ // NB This does not need to be efficient since it should only ever
+ // happen when the power fails during a write, then only one
+ // chunk should ever be affected.
+
+ existingChunk = tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK];
+
+ if(existingChunk != 0)
+ {
+ // We have a duplicate now we need to decide which one to use
+ // To do this we get both sets of tags and compare serial numbers.
+ yaffs_ReadChunkTagsFromNAND(dev,chunkInInode, &newTags);
+ yaffs_ReadChunkTagsFromNAND(dev,existingChunk, &existingTags);
+ newSerial = newTags.serialNumber;
+ existingSerial = existingTags.serialNumber;
+ if(((existingSerial+1) & 3) == newSerial)
+ {
+ // Use new
+ // Delete the old one and drop through to update the tnode
+ yaffs_DeleteChunk(dev,existingChunk);
+ }
+ else
+ {
+ // Use existing.
+ // Delete the new one and return early so that the tnode isn't changed
+ yaffs_DeleteChunk(dev,chunkInInode);
+ return YAFFS_OK;
+ }
+ }
+ }
+
tn->level0[chunkInInode & YAFFS_TNODES_LEVEL0_MASK] = chunkInNAND;
+
return YAFFS_OK;
}
{
int block = chunkId / YAFFS_CHUNKS_PER_BLOCK;
int page = chunkId % YAFFS_CHUNKS_PER_BLOCK;
- yaffs_Tags tags;
+ yaffs_Spare spare;
+
+ yaffs_SpareInitialise(&spare);
- // Mark the deleted NAND page as deleted
- tags.chunkId = 0;
- tags.objectId = 0;
- tags.byteCount = 0;
- tags.ecc = 0;
+ spare.pageStatus = 0; // To mark it as deleted.
+
- yaffs_WriteChunkWithTagsToNAND(dev,chunkId,NULL,&tags);
+ yaffs_WriteChunkToNAND(dev,chunkId,NULL,&spare);
// Pull out of the management area.
+ // If the whole block became dirty, this will kick off an erasure.
if( dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
dev->blockInfo[block].blockState == YAFFS_BLOCK_STATE_FULL)
{
}
else
{
- T(("Bad news deteing chunk %d\n",chunkId));
+ T(("Bad news deleting chunk %d\n",chunkId));
}
}
newChunkId = yaffs_WriteNewChunkWithTagsToNAND(dev,buffer,&newTags,useReserve);
if(newChunkId >= 0)
{
- yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId);
+ yaffs_PutChunkIntoFile(in,chunkInInode,newChunkId,0);
if(prevChunkId >= 0)
switch(in->variantType)
{
- case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
+ case YAFFS_OBJECT_TYPE_UNKNOWN:
+ // Should not happen
break;
case YAFFS_OBJECT_TYPE_FILE:
oh->fileSize = in->variant.fileVariant.fileSize;
case YAFFS_OBJECT_TYPE_HARDLINK:
oh->equivalentObjectId = in->variant.hardLinkVariant.equivalentObjectId;
break;
- case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
+ case YAFFS_OBJECT_TYPE_DIRECTORY:
+ // Do nothing
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
strncpy(oh->alias,in->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
int retVal;
if(in->dirty)
{
+ T(("flushing object header\n"));
retVal = yaffs_UpdateObjectHeader(in,NULL);
}
else
char name[YAFFS_MAX_NAME_LENGTH+1];
hl = list_entry(obj->hardLinks.next,yaffs_Object,hardLinks);
+
list_del_init(&hl->hardLinks);
list_del_init(&hl->siblings);
yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
retVal = yaffs_ChangeObjectName(obj, hl->parent, name);
+
if(retVal == YAFFS_OK)
{
retVal = yaffs_DoGenericObjectDeletion(hl);
int chunk;
int c;
int deleted;
- int inuse;
yaffs_BlockState state;
yaffs_Object *hardList = NULL;
yaffs_Object *hl;
- __u32 pageBits;
+// int inuse;
+// __u32 pageBits;
yaffs_ObjectHeader *oh;
yaffs_Object *in;
__u8 chunkData[YAFFS_BYTES_PER_CHUNK];
+
+ // Scan all the blocks...
+
for(blk = dev->startBlock; blk <= dev->endBlock; blk++)
{
deleted = 0;
- pageBits = 0;
- inuse = 0;
- state = YAFFS_BLOCK_STATE_UNKNOWN;
+ dev->blockInfo[blk].pageBits = 0;
+ dev->blockInfo[blk].pagesInUse = 0;
+ state = YAFFS_BLOCK_STATE_SCANNING;
+
+ // Read each chunk in the block.
for(c = 0; c < YAFFS_CHUNKS_PER_BLOCK &&
- state == YAFFS_BLOCK_STATE_UNKNOWN; c++)
+ state == YAFFS_BLOCK_STATE_SCANNING; c++)
{
// Read the spare area and decide what to do
chunk = blk * YAFFS_CHUNKS_PER_BLOCK + c;
+
yaffs_ReadChunkFromNAND(dev,chunk,NULL,&spare);
// This block looks ok, now what's in this chunk?
yaffs_GetTagsFromSpare(&spare,&tags);
- if(tags.objectId == YAFFS_UNUSED_OBJECT_ID)
+ if(yaffs_countBits[spare.pageStatus] < 6)
+ {
+ // A deleted chunk
+ deleted++;
+ dev->nFreeChunks ++;
+ T((" %d %d deleted\n",blk,c));
+ }
+ else if(tags.objectId == YAFFS_UNUSED_OBJECT_ID)
{
// An unassigned chunk in the block
// This means that either the block is empty or
dev->nFreeChunks += (YAFFS_CHUNKS_PER_BLOCK - c);
}
- else if(tags.objectId == 0)
- {
- // A deleted chunk
- deleted++;
- dev->nFreeChunks ++;
- T((" %d %d deleted\n",blk,c));
- }
else if(tags.chunkId > 0)
{
// A data chunk.
- inuse++;
- pageBits |= ( 1 <<c);
+ dev->blockInfo[blk].pageBits |= (1 << c);
+ dev->blockInfo[blk].pagesInUse++;
+
in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,YAFFS_OBJECT_TYPE_FILE);
- // todo check for a clash (two data chunks with
+ // PutChunkIntoFIle checks for a clash (two data chunks with
// the same chunkId).
- yaffs_PutChunkIntoFile(in,tags.chunkId,chunk);
+ yaffs_PutChunkIntoFile(in,tags.chunkId,chunk,1);
T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));
}
else
{
// chunkId == 0, so it is an ObjectHeader.
- inuse++;
- pageBits |= ( 1 <<c);
+ // Thus, we read in the object header and make the object
+ dev->blockInfo[blk].pageBits |= (1 << c);
+ dev->blockInfo[blk].pagesInUse++;
+
yaffs_ReadChunkFromNAND(dev,chunk,chunkData,NULL);
+
oh = (yaffs_ObjectHeader *)chunkData;
in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
+
if(in->valid)
{
- // todo we have already filled this one. We have
- // a duplicate. Need to fix
+ // We have already filled this one. We have a duplicate and need to resolve it.
+
+ unsigned existingSerial = in->serial;
+ unsigned newSerial = tags.serialNumber;
+
+ if(((existingSerial+1) & 3) == newSerial)
+ {
+ // Use new one - destroy the exisiting one
+ yaffs_DeleteChunk(dev,in->chunkId);
+ in->valid = 0;
+ }
+ else
+ {
+ // Use existing - destroy this one.
+ yaffs_DeleteChunk(dev,chunk);
+ }
}
- // we don't have a duplicate...
+ if(!in->valid)
+ {
+ // we need to load this info
- in->valid = 1;
- in->variantType = oh->type;
-
- in->st_mode = oh->st_mode;
- in->st_uid = oh->st_uid;
- in->st_gid = oh->st_gid;
- in->st_atime = oh->st_atime;
- in->st_mtime = oh->st_mtime;
- in->st_ctime = oh->st_ctime;
- in->chunkId = chunk;
-
- in->sum = oh->sum;
- in->dirty = 0;
+ in->valid = 1;
+ in->variantType = oh->type;
+
+ in->st_mode = oh->st_mode;
+ in->st_uid = oh->st_uid;
+ in->st_gid = oh->st_gid;
+ in->st_atime = oh->st_atime;
+ in->st_mtime = oh->st_mtime;
+ in->st_ctime = oh->st_ctime;
+ in->chunkId = chunk;
+
+ in->sum = oh->sum;
+ in->dirty = 0;
- // directory stuff...
- // hook up to parent
-
- parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
- if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
- {
- // Set up as a directory
- parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
- INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
- }
- else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
- {
- // Hoosterman, another problem....
- // We're trying to use a non-directory as a directory
- // Todo ... handle
- }
+ // directory stuff...
+ // hook up to parent
+
+ parent = yaffs_FindOrCreateObjectByNumber(dev,oh->parentObjectId,YAFFS_OBJECT_TYPE_DIRECTORY);
+ if(parent->variantType == YAFFS_OBJECT_TYPE_UNKNOWN)
+ {
+ // Set up as a directory
+ parent->variantType = YAFFS_OBJECT_TYPE_DIRECTORY;
+ INIT_LIST_HEAD(&parent->variant.directoryVariant.children);
+ }
+ else if(parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ {
+ // Hoosterman, another problem....
+ // We're trying to use a non-directory as a directory
+ // Todo ... handle
+ }
- yaffs_AddObjectToDirectory(parent,in);
+ yaffs_AddObjectToDirectory(parent,in);
- // Note re hardlinks.
- // Since we might scan a hardlink before its equivalent object is scanned
- // we put them all in a list.
- // After scanning is complete, we should have all the objects, so we run through this
- // list and fix up all the chains.
-
- switch(in->variantType)
- {
- case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
- break;
- case YAFFS_OBJECT_TYPE_FILE:
- in->variant.fileVariant.fileSize = oh->fileSize;
- break;
- case YAFFS_OBJECT_TYPE_HARDLINK:
- in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
- (yaffs_Object *)(in->hardLinks.next) = hardList;
- hardList = in;
- break;
- case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
- break;
- case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
- in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
- break;
+ // Note re hardlinks.
+ // Since we might scan a hardlink before its equivalent object is scanned
+ // we put them all in a list.
+ // After scanning is complete, we should have all the objects, so we run through this
+ // list and fix up all the chains.
+
+ switch(in->variantType)
+ {
+ case YAFFS_OBJECT_TYPE_UNKNOWN: // Todo got a problem
+ break;
+ case YAFFS_OBJECT_TYPE_FILE:
+ in->variant.fileVariant.fileSize = oh->fileSize;
+ break;
+ case YAFFS_OBJECT_TYPE_HARDLINK:
+ in->variant.hardLinkVariant.equivalentObjectId = oh->equivalentObjectId;
+ (yaffs_Object *)(in->hardLinks.next) = hardList;
+ hardList = in;
+ break;
+ case YAFFS_OBJECT_TYPE_DIRECTORY: // Do nothing
+ break;
+ case YAFFS_OBJECT_TYPE_SYMLINK: // Do nothing
+ in->variant.symLinkVariant.alias = yaffs_CloneString(oh->alias);
+ break;
+ }
+ T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
}
- T((" %d %d header %d \"%s\" type %d\n",blk,c,tags.objectId,oh->name,in->variantType));
}
}
else
}
}
- if(state == YAFFS_BLOCK_STATE_UNKNOWN)
+ if(state == YAFFS_BLOCK_STATE_SCANNING)
{
- // If we got this far, then the block is fully allocated.
- // ie. Full or Dirty
- state = (inuse) ? YAFFS_BLOCK_STATE_FULL : YAFFS_BLOCK_STATE_DIRTY;
-
+ // If we got this far while scanning, then the block is fully allocated.
+ state = YAFFS_BLOCK_STATE_FULL;
}
- dev->blockInfo[blk].pageBits = pageBits;
- dev->blockInfo[blk].pagesInUse = inuse;
dev->blockInfo[blk].blockState = state;
+ // Now let's see if it was dirty
+ if( dev->blockInfo[blk].pagesInUse == 0 &&
+ dev->blockInfo[blk].blockState == YAFFS_BLOCK_STATE_FULL)
+ {
+ yaffs_BlockBecameDirty(dev,blk);
+ }
+
}
- // Todo fix up the hard link chains
+ // Fix up the hard link chains.
+ // We should now have scanned all the objects, now it's time to add these
+ // hardlinks.
while(hardList)
{
hl = hardList;
if(in)
{
+ // Add the hardlink pointers
hl->variant.hardLinkVariant.equivalentObject=in;
list_add(&hl->hardLinks,&in->hardLinks);
}
else
{
- //Todo Need to report this better.
+ //Todo Need to report/handle this better.
+ // Got a problem... hardlink to a non-existant object
hl->variant.hardLinkVariant.equivalentObject=NULL;
INIT_LIST_HEAD(&hl->hardLinks);
// GetEquivalentObject dereferences any hard links to get to the
// actual object.
-static yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
{
if(obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
{
yaffs_GetObjectName(obj,name,256);
- YPRINTF(("Object %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",
- yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
+ YPRINTF(("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d chunk %d type %d size %d\n",
+ obj->objectId,yaffs_GetObjectInode(obj), name, obj->dirty, obj->valid, obj->serial,
obj->sum, obj->chunkId, yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
#if 0