X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_guts.c;h=c01f00c8b6b37239d9562a6bbf8461d486ce8308;hp=6efa94f57d268a8b4d2beddbcdb996eb20907024;hb=107910497be0a0d0e4a8ab357c403fc2a234323b;hpb=780469359d1051ab37ab281b0520137d73fee2e9 diff --git a/yaffs_guts.c b/yaffs_guts.c index 6efa94f..c01f00c 100644 --- a/yaffs_guts.c +++ b/yaffs_guts.c @@ -25,6 +25,7 @@ #include "yaffs_yaffs1.h" #include "yaffs_yaffs2.h" #include "yaffs_bitmap.h" +#include "yaffs_verify.h" #include "yaffs_nand.h" #include "yaffs_packedtags2.h" @@ -87,30 +88,22 @@ static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve, static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in); -static void yaffs_VerifyDirectory(yaffs_Object *directory); -#ifdef YAFFS_PARANOID -static int yaffs_CheckFileSanity(yaffs_Object *in); -#else -#define yaffs_CheckFileSanity(in) -#endif - static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in); static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId); static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode, yaffs_ExtendedTags *tags); -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, - unsigned pos); -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, - yaffs_FileStructure *fStruct, - __u32 chunkId); - static int yaffs_VerifyChunkWritten(yaffs_Device *dev, int chunkInNAND, const __u8 *data, yaffs_ExtendedTags *tags); + +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize); +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev,YCHAR *ohName, const YCHAR *name); + + /* Function to calculate chunk and offset */ static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut, @@ -301,460 +294,7 @@ int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer) * Verification code */ -static int yaffs_SkipVerification(yaffs_Device *dev) -{ - dev=dev; - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); -} - -static int yaffs_SkipFullVerification(yaffs_Device *dev) -{ - dev=dev; - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL)); -} - -static int yaffs_SkipNANDVerification(yaffs_Device *dev) -{ - dev=dev; - return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND)); -} - -static const char *blockStateName[] = { -"Unknown", -"Needs scanning", -"Scanning", -"Empty", -"Allocating", -"Full", -"Dirty", -"Checkpoint", -"Collecting", -"Dead" -}; - - -static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n) -{ - int actuallyUsed; - int inUse; - - if (yaffs_SkipVerification(dev)) - return; - - /* Report illegal runtime states */ - if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES) - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState)); - - switch (bi->blockState) { - case YAFFS_BLOCK_STATE_UNKNOWN: - case YAFFS_BLOCK_STATE_SCANNING: - case YAFFS_BLOCK_STATE_NEEDS_SCANNING: - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR), - n, blockStateName[bi->blockState])); - } - - /* Check pages in use and soft deletions are legal */ - - actuallyUsed = bi->pagesInUse - bi->softDeletions; - - if (bi->pagesInUse < 0 || bi->pagesInUse > dev->param.nChunksPerBlock || - bi->softDeletions < 0 || bi->softDeletions > dev->param.nChunksPerBlock || - actuallyUsed < 0 || actuallyUsed > dev->param.nChunksPerBlock) - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR), - n, bi->pagesInUse, bi->softDeletions)); - - - /* Check chunk bitmap legal */ - inUse = yaffs_CountChunkBits(dev, n); - if (inUse != bi->pagesInUse) - T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR), - n, bi->pagesInUse, inUse)); - - /* Check that the sequence number is valid. - * Ten million is legal, but is very unlikely - */ - - yaffs2_VerifyBlock(dev,bi,n); -} - - - -static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, - int n) -{ - yaffs_VerifyBlock(dev, bi, n); - - /* After collection the block should be in the erased state */ - /* This will need to change if we do partial gc */ - - if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && - bi->blockState != YAFFS_BLOCK_STATE_EMPTY) { - T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR), - n, bi->blockState)); - } -} - -void yaffs_VerifyBlocks(yaffs_Device *dev) -{ - int i; - int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES]; - int nIllegalBlockStates = 0; - - if (yaffs_SkipVerification(dev)) - return; - - memset(nBlocksPerState, 0, sizeof(nBlocksPerState)); - for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) { - yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i); - yaffs_VerifyBlock(dev, bi, i); - - if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES) - nBlocksPerState[bi->blockState]++; - else - nIllegalBlockStates++; - } - - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); - T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR))); - - T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates)); - if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1) - T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR))); - - for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) - T(YAFFS_TRACE_VERIFY, - (TSTR("%s %d blocks"TENDSTR), - blockStateName[i], nBlocksPerState[i])); - - if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]) - T(YAFFS_TRACE_VERIFY, - (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR), - dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])); - - if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]) - T(YAFFS_TRACE_VERIFY, - (TSTR("Erased block count wrong dev %d count %d"TENDSTR), - dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])); - - if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1) - T(YAFFS_TRACE_VERIFY, - (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR), - nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING])); - - T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR))); - -} - -/* - * Verify the object header. oh must be valid, but obj and tags may be NULL in which - * case those tests will not be performed. - */ -static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; - - if (!(tags && obj && oh)) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Verifying object header tags %p obj %p oh %p"TENDSTR), - tags, obj, oh)); - return; - } - - if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || - oh->type > YAFFS_OBJECT_TYPE_MAX) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header type is illegal value 0x%x"TENDSTR), - tags->objectId, oh->type)); - - if (tags->objectId != obj->objectId) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch objectId %d"TENDSTR), - tags->objectId, obj->objectId)); - - - /* - * Check that the object's parent ids match if parentCheck requested. - * - * Tests do not apply to the root object. - */ - - if (parentCheck && tags->objectId > 1 && !obj->parent) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR), - tags->objectId, oh->parentObjectId)); - - if (parentCheck && obj->parent && - oh->parentObjectId != obj->parent->objectId && - (oh->parentObjectId != YAFFS_OBJECTID_UNLINKED || - obj->parent->objectId != YAFFS_OBJECTID_DELETED)) - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR), - tags->objectId, oh->parentObjectId, obj->parent->objectId)); - - if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header name is NULL"TENDSTR), - obj->objectId)); - - if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */ - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d header name is 0xFF"TENDSTR), - obj->objectId)); -} - - -#if 0 -/* Not being used, but don't want to throw away yet */ -static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn, - __u32 level, int chunkOffset) -{ - int i; - yaffs_Device *dev = obj->myDev; - int ok = 1; - - if (tn) { - if (level > 0) { - - for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { - if (tn->internal[i]) { - ok = yaffs_VerifyTnodeWorker(obj, - tn->internal[i], - level - 1, - (chunkOffset<objectId; - - chunkOffset <<= YAFFS_TNODES_LEVEL0_BITS; - - for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) { - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); - - if (theChunk > 0) { - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */ - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); - if (tags.objectId != objectId || tags.chunkId != chunkOffset) { - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), - objectId, chunkOffset, theChunk, - tags.objectId, tags.chunkId)); - } - } - chunkOffset++; - } - } - } - - return ok; - -} - -#endif - -static void yaffs_VerifyFile(yaffs_Object *obj) -{ - int requiredTallness; - int actualTallness; - __u32 lastChunk; - __u32 x; - __u32 i; - yaffs_Device *dev; - yaffs_ExtendedTags tags; - yaffs_Tnode *tn; - __u32 objectId; - - if (!obj) - return; - - if (yaffs_SkipVerification(obj->myDev)) - return; - - dev = obj->myDev; - objectId = obj->objectId; - - /* Check file size is consistent with tnode depth */ - lastChunk = obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1; - x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS; - requiredTallness = 0; - while (x > 0) { - x >>= YAFFS_TNODES_INTERNAL_BITS; - requiredTallness++; - } - - actualTallness = obj->variant.fileVariant.topLevel; - - /* Check that the chunks in the tnode tree are all correct. - * We do this by scanning through the tnode tree and - * checking the tags for every chunk match. - */ - - if (yaffs_SkipNANDVerification(dev)) - return; - - for (i = 1; i <= lastChunk; i++) { - tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i); - - if (tn) { - __u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i); - if (theChunk > 0) { - /* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */ - yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags); - if (tags.objectId != objectId || tags.chunkId != i) { - T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR), - objectId, i, theChunk, - tags.objectId, tags.chunkId)); - } - } - } - } -} - - -static void yaffs_VerifyHardLink(yaffs_Object *obj) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; - - /* Verify sane equivalent object */ -} - -static void yaffs_VerifySymlink(yaffs_Object *obj) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; - - /* Verify symlink string */ -} - -static void yaffs_VerifySpecial(yaffs_Object *obj) -{ - if (obj && yaffs_SkipVerification(obj->myDev)) - return; -} - -static void yaffs_VerifyObject(yaffs_Object *obj) -{ - yaffs_Device *dev; - - __u32 chunkMin; - __u32 chunkMax; - - __u32 chunkIdOk; - __u32 chunkInRange; - __u32 chunkShouldNotBeDeleted; - __u32 chunkValid; - - if (!obj) - return; - - if (obj->beingCreated) - return; - - dev = obj->myDev; - - if (yaffs_SkipVerification(dev)) - return; - - /* Check sane object header chunk */ - - chunkMin = dev->internalStartBlock * dev->param.nChunksPerBlock; - chunkMax = (dev->internalEndBlock+1) * dev->param.nChunksPerBlock - 1; - - chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax); - chunkIdOk = chunkInRange || (obj->hdrChunk == 0); - chunkValid = chunkInRange && - yaffs_CheckChunkBit(dev, - obj->hdrChunk / dev->param.nChunksPerBlock, - obj->hdrChunk % dev->param.nChunksPerBlock); - chunkShouldNotBeDeleted = chunkInRange && !chunkValid; - - if (!obj->fake && - (!chunkIdOk || chunkShouldNotBeDeleted)) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has chunkId %d %s %s"TENDSTR), - obj->objectId, obj->hdrChunk, - chunkIdOk ? "" : ",out of range", - chunkShouldNotBeDeleted ? ",marked as deleted" : "")); - } - - if (chunkValid && !yaffs_SkipNANDVerification(dev)) { - yaffs_ExtendedTags tags; - yaffs_ObjectHeader *oh; - __u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__); - - oh = (yaffs_ObjectHeader *)buffer; - - yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer, - &tags); - - yaffs_VerifyObjectHeader(obj, oh, &tags, 1); - - yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); - } - - /* Verify it has a parent */ - if (obj && !obj->fake && - (!obj->parent || obj->parent->myDev != dev)) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR), - obj->objectId, obj->parent)); - } - - /* Verify parent is a directory */ - if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR), - obj->objectId, obj->parent->variantType)); - } - - switch (obj->variantType) { - case YAFFS_OBJECT_TYPE_FILE: - yaffs_VerifyFile(obj); - break; - case YAFFS_OBJECT_TYPE_SYMLINK: - yaffs_VerifySymlink(obj); - break; - case YAFFS_OBJECT_TYPE_DIRECTORY: - yaffs_VerifyDirectory(obj); - break; - case YAFFS_OBJECT_TYPE_HARDLINK: - yaffs_VerifyHardLink(obj); - break; - case YAFFS_OBJECT_TYPE_SPECIAL: - yaffs_VerifySpecial(obj); - break; - case YAFFS_OBJECT_TYPE_UNKNOWN: - default: - T(YAFFS_TRACE_VERIFY, - (TSTR("Obj %d has illegaltype %d"TENDSTR), - obj->objectId, obj->variantType)); - break; - } -} - -void yaffs_VerifyObjects(yaffs_Device *dev) -{ - yaffs_Object *obj; - int i; - struct ylist_head *lh; - - if (yaffs_SkipVerification(dev)) - return; - - /* Iterate through the objects in each hash entry */ - - for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { - ylist_for_each(lh, &dev->objectBucket[i].list) { - if (lh) { - obj = ylist_entry(lh, yaffs_Object, hashLink); - yaffs_VerifyObject(obj); - } - } - } -} /* @@ -1087,6 +627,18 @@ void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name) obj->sum = yaffs_CalcNameSum(name); } +void yaffs_SetObjectNameFromOH(yaffs_Object *obj, const yaffs_ObjectHeader *oh) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + YCHAR tmpName[YAFFS_MAX_NAME_LENGTH+1]; + memset(tmpName,0,sizeof(tmpName)); + yaffs_LoadNameFromObjectHeader(obj->myDev,tmpName,oh->name,YAFFS_MAX_NAME_LENGTH+1); + yaffs_SetObjectName(obj,tmpName); +#else + yaffs_SetObjectName(obj,oh->name); +#endif +} + /*-------------------- TNODES ------------------- * List of spare tnodes @@ -1154,7 +706,7 @@ void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos, } } -static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, +__u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos) { __u32 *map = (__u32 *)tn; @@ -1191,7 +743,7 @@ static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn, */ /* FindLevel0Tnode finds the level 0 tnode, if one exists. */ -static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, +yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev, yaffs_FileStructure *fStruct, __u32 chunkId) { @@ -2554,7 +2106,6 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, int newChunk; int markNAND; int retVal = YAFFS_OK; - int cleanups = 0; int i; int isCheckpointBlock; int matchingChunk; @@ -2677,9 +2228,9 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, if (object->nDataChunks <= 0) { /* remeber to clean up the object */ - dev->gcCleanupList[cleanups] = + dev->gcCleanupList[dev->nCleanups] = tags.objectId; - cleanups++; + dev->nCleanups++; } markNAND = 0; } else if (0) { @@ -2765,8 +2316,23 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, yaffs_ReleaseTempBuffer(dev, buffer, __LINE__); + + } + + yaffs_VerifyCollectedBlock(dev, bi, block); + + + + if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { + /* + * The gc did not complete. Set block state back to FULL + * because checkpointing does not restore gc. + */ + bi->blockState = YAFFS_BLOCK_STATE_FULL; + } else { + /* The gc completed. */ /* Do any required cleanups */ - for (i = 0; i < cleanups; i++) { + for (i = 0; i < dev->nCleanups; i++) { /* Time to delete the file too */ object = yaffs_FindObjectByNumber(dev, @@ -2786,20 +2352,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, } - } - - yaffs_VerifyCollectedBlock(dev, bi, block); - - - if (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) { - /* - * The gc did not complete. Set block state back to FULL - * because checkpointing does not restore gc. - */ - bi->blockState = YAFFS_BLOCK_STATE_FULL; - } else { - /* The gc completed. */ chunksAfter = yaffs_GetErasedChunks(dev); if (chunksBefore >= chunksAfter) { T(YAFFS_TRACE_GC, @@ -2809,6 +2362,7 @@ static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block, } dev->gcBlock = 0; dev->gcChunk = 0; + dev->nCleanups = 0; } dev->gcDisable = 0; @@ -3030,10 +2584,12 @@ static int yaffs_CheckGarbageCollection(yaffs_Device *dev, int background) if (dev->gcBlock < 1 && !aggressive) { dev->gcBlock = yaffs2_FindRefreshBlock(dev); dev->gcChunk = 0; + dev->nCleanups=0; } if (dev->gcBlock < 1) { dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive, background); dev->gcChunk = 0; + dev->nCleanups=0; } if (dev->gcBlock > 0) { @@ -3152,63 +2708,6 @@ static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode, return retVal; } -#ifdef YAFFS_PARANOID - -static int yaffs_CheckFileSanity(yaffs_Object *in) -{ - int chunk; - int nChunks; - int fSize; - int failed = 0; - int objId; - yaffs_Tnode *tn; - yaffs_Tags localTags; - yaffs_Tags *tags = &localTags; - int theChunk; - int chunkDeleted; - - if (in->variantType != YAFFS_OBJECT_TYPE_FILE) - return YAFFS_FAIL; - - objId = in->objectId; - fSize = in->variant.fileVariant.fileSize; - nChunks = - (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk; - - for (chunk = 1; chunk <= nChunks; chunk++) { - tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant, - chunk); - - if (tn) { - - theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk); - - if (yaffs_CheckChunkBits - (dev, theChunk / dev->param.nChunksPerBlock, - theChunk % dev->param.nChunksPerBlock)) { - - yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk, - tags, - &chunkDeleted); - if (yaffs_TagsMatch - (tags, in->objectId, chunk, chunkDeleted)) { - /* found it; */ - - } - } else { - - failed = 1; - } - - } else { - /* T(("No level 0 found for %d\n", chunk)); */ - } - } - - return failed ? YAFFS_FAIL : YAFFS_OK; -} - -#endif int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode, int chunkInNAND, int inScan) @@ -3475,7 +2974,7 @@ static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode, if (prevChunkId > 0) yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__); - yaffs_CheckFileSanity(in); + yaffs_VerifyFileSanity(in); } return newChunkId; @@ -3558,7 +3057,7 @@ int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force, if (name && *name) { memset(oh->name, 0, sizeof(oh->name)); - yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH); + yaffs_LoadObjectHeaderFromName(dev,oh->name,name); } else if (prevChunkId > 0) memcpy(oh->name, oldName, sizeof(oh->name)); else @@ -4872,7 +4371,7 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) in->yst_rdev = oh->yst_rdev; #endif - yaffs_SetObjectName(in, oh->name); + yaffs_SetObjectNameFromOH(in, oh); if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) { in->variant.symLinkVariant.alias = @@ -4887,82 +4386,6 @@ static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in) /*------------------------------ Directory Functions ----------------------------- */ -static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj) -{ - struct ylist_head *lh; - yaffs_Object *listObj; - - int count = 0; - - if (!obj) { - T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR))); - YBUG(); - return; - } - - if (yaffs_SkipVerification(obj->myDev)) - return; - - if (!obj->parent) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR))); - YBUG(); - return; - } - - if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR))); - YBUG(); - } - - /* Iterate through the objects in each hash entry */ - - ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) { - if (lh) { - listObj = ylist_entry(lh, yaffs_Object, siblings); - yaffs_VerifyObject(listObj); - if (obj == listObj) - count++; - } - } - - if (count != 1) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count)); - YBUG(); - } -} - -static void yaffs_VerifyDirectory(yaffs_Object *directory) -{ - struct ylist_head *lh; - yaffs_Object *listObj; - - if (!directory) { - YBUG(); - return; - } - - if (yaffs_SkipFullVerification(directory->myDev)) - return; - - if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType)); - YBUG(); - } - - /* Iterate through the objects in each hash entry */ - - ylist_for_each(lh, &directory->variant.directoryVariant.children) { - if (lh) { - listObj = ylist_entry(lh, yaffs_Object, siblings); - if (listObj->parent != directory) { - T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent)); - YBUG(); - } - yaffs_VerifyObjectInDirectory(listObj); - } - } -} - /* *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new * link (ie. name) is created or deleted in the directory. @@ -4984,6 +4407,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj) yaffs_Device *dev; if(!obj) return; +#ifndef CONFIG_YAFFS_WINCE dev = obj->myDev; obj->dirty = 1; @@ -4998,6 +4422,7 @@ static void yaffs_UpdateParent(yaffs_Object *obj) } else yaffs_UpdateObjectHeader(obj, NULL, 0, 0, 0, NULL); +#endif } void yaffs_UpdateDirtyDirectories(yaffs_Device *dev) @@ -5198,36 +4623,124 @@ yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj) return obj; } -int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) -{ - memset(name, 0, buffSize * sizeof(YCHAR)); - - yaffs_CheckObjectDetailsLoaded(obj); +/* + * A note or two on object names. + * * If the object name is missing, we then make one up in the form objnnn + * + * * ASCII names are stored in the object header's name field from byte zero + * * Unicode names are historically stored starting from byte zero. + * + * Then there are automatic Unicode names... + * The purpose of these is to save names in a way that can be read as + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII + * system to share files. + * + * These automatic unicode are stored slightly differently... + * - If the name can fit in the ASCII character space then they are saved as + * ascii names as per above. + * - If the name needs Unicode then the name is saved in Unicode + * starting at oh->name[1]. - if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { - yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); - } else if (obj->hdrChunk <= 0) { + */ +static void yaffs_FixNullName(yaffs_Object * obj,YCHAR * name, int buffSize) +{ + /* Create an object name if we could not find one. */ + if(yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH) == 0){ YCHAR locName[20]; YCHAR numString[20]; YCHAR *x = &numString[19]; unsigned v = obj->objectId; numString[19] = 0; - while (v > 0) { + while(v>0){ x--; *x = '0' + (v % 10); v /= 10; } /* make up a name */ yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX); - yaffs_strcat(locName, x); + yaffs_strcat(locName,x); yaffs_strncpy(name, locName, buffSize - 1); + } +} +static void yaffs_LoadNameFromObjectHeader(yaffs_Device *dev,YCHAR *name, const YCHAR *ohName, int bufferSize) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + if(dev->param.autoUnicode){ + if(*ohName){ + /* It is an ASCII name, so do an ASCII to unicode conversion */ + const char *asciiOhName = (const char *)ohName; + int n = bufferSize - 1; + while(n > 0 && *asciiOhName){ + *name = *asciiOhName; + name++; + asciiOhName++; + n--; + } + } else + yaffs_strncpy(name,ohName+1, bufferSize -1); + } else +#endif + yaffs_strncpy(name, ohName, bufferSize - 1); +} + + +static void yaffs_LoadObjectHeaderFromName(yaffs_Device *dev, YCHAR *ohName, const YCHAR *name) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + + int isAscii; + YCHAR *w; + + if(dev->param.autoUnicode){ + + isAscii = 1; + w = name; + + /* Figure out if the name will fit in ascii character set */ + while(isAscii && *w){ + if((*w) & 0xff00) + isAscii = 0; + w++; + } + + if(isAscii){ + /* It is an ASCII name, so do a unicode to ascii conversion */ + char *asciiOhName = (char *)ohName; + int n = YAFFS_MAX_NAME_LENGTH - 1; + while(n > 0 && *name){ + *asciiOhName= *name; + name++; + asciiOhName++; + n--; + } + } else{ + /* It is a unicode name, so save starting at the second YCHAR */ + *ohName = 0; + yaffs_strncpy(ohName+1,name, YAFFS_MAX_NAME_LENGTH -2); + } } + else +#endif + yaffs_strncpy(ohName,name, YAFFS_MAX_NAME_LENGTH - 1); + +} + +int yaffs_GetObjectName(yaffs_Object * obj, YCHAR * name, int buffSize) +{ + memset(name, 0, buffSize * sizeof(YCHAR)); + + yaffs_CheckObjectDetailsLoaded(obj); + + if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) { + yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1); + } #ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM - else if (obj->shortName[0]) - yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1); + else if (obj->shortName[0]) { + yaffs_strcpy(name, obj->shortName); + } #endif - else { + else if(obj->hdrChunk > 0) { int result; __u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__); @@ -5240,15 +4753,17 @@ int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize) obj->hdrChunk, buffer, NULL); } - yaffs_strncpy(name, oh->name, buffSize - 1); - name[buffSize-1]=0; + yaffs_LoadNameFromObjectHeader(obj->myDev,name,oh->name,buffSize); yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__); } - return yaffs_strnlen(name,buffSize-1); + yaffs_FixNullName(obj,name,buffSize); + + return yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH); } + int yaffs_GetObjectFileLength(yaffs_Object *obj) { /* Dereference any hard linking */ @@ -5385,7 +4900,7 @@ int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr) #endif -static int yaffs_DoXMod(yaffs_Object *obj, int set, const char *name, const void *value, int size, int flags) +static int yaffs_DoXMod(yaffs_Object *obj, int set, const YCHAR *name, const void *value, int size, int flags) { yaffs_XAttrMod xmod; @@ -5424,7 +4939,7 @@ static int yaffs_ApplyXMod(yaffs_Device *dev, char *buffer, yaffs_XAttrMod *xmod return retval; } -static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int size) +static int yaffs_DoXFetch(yaffs_Object *obj, const YCHAR *name, void *value, int size) { char *buffer = NULL; int result; @@ -5460,17 +4975,17 @@ static int yaffs_DoXFetch(yaffs_Object *obj, const char *name, void *value, int return retval; } -int yaffs_SetXAttribute(yaffs_Object *obj, const char *name, const void * value, int size, int flags) +int yaffs_SetXAttribute(yaffs_Object *obj, const YCHAR *name, const void * value, int size, int flags) { return yaffs_DoXMod(obj, 1, name, value, size, flags); } -int yaffs_RemoveXAttribute(yaffs_Object *obj, const char *name) +int yaffs_RemoveXAttribute(yaffs_Object *obj, const YCHAR *name) { return yaffs_DoXMod(obj, 0, name, NULL, 0, 0); } -int yaffs_GetXAttribute(yaffs_Object *obj, const char *name, void *value, int size) +int yaffs_GetXAttribute(yaffs_Object *obj, const YCHAR *name, void *value, int size) { return yaffs_DoXFetch(obj, name, value, size); } @@ -5902,7 +5417,7 @@ void yaffs_Deinitialise(yaffs_Device *dev) } } -static int yaffs_CountFreeChunks(yaffs_Device *dev) +int yaffs_CountFreeChunks(yaffs_Device *dev) { int nFree=0; int b; @@ -5969,27 +5484,6 @@ int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev) } -static int yaffs_freeVerificationFailures; - -void yaffs_VerifyFreeChunks(yaffs_Device *dev) -{ - int counted; - int difference; - - if (yaffs_SkipVerification(dev)) - return; - - counted = yaffs_CountFreeChunks(dev); - - difference = dev->nFreeChunks - counted; - - if (difference) { - T(YAFFS_TRACE_ALWAYS, - (TSTR("Freechunks verification failure %d %d %d" TENDSTR), - dev->nFreeChunks, counted, difference)); - yaffs_freeVerificationFailures++; - } -} /*---------------------------------------- YAFFS test code ----------------------*/