*/
const char *yaffs_guts_c_version =
- "$Id: yaffs_guts.c,v 1.88 2009-08-11 01:28:42 charles Exp $";
+ "$Id: yaffs_guts.c,v 1.98 2009-12-07 01:17:33 charles Exp $";
#include "yportenv.h"
yaffs_FileStructure *fStruct,
__u32 chunkId);
-
/* Function to calculate chunk and offset */
static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
{
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
- if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
+ if (name && yaffs_strnlen(name,YAFFS_SHORT_NAME_LENGTH+1) <= YAFFS_SHORT_NAME_LENGTH)
yaffs_strcpy(obj->shortName, name);
else
obj->shortName[0] = _Y('\0');
}
-void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
+void yaffs_LoadLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
unsigned val)
{
__u32 *map = (__u32 *)tn;
if (tn) {
tn->internal[0] = fStruct->top;
fStruct->top = tn;
+ fStruct->topLevel++;
} else {
T(YAFFS_TRACE_ERROR,
- (TSTR("yaffs: no more tnodes" TENDSTR)));
+ (TSTR("yaffs: no more tnodes" TENDSTR)));
+ return NULL;
}
}
-
- fStruct->topLevel = requiredTallness;
}
/* Traverse down to level 0, adding anything we need */
if ((l > 1) && !tn->internal[x]) {
/* Add missing non-level-zero tnode */
tn->internal[x] = yaffs_GetTnode(dev);
+ if(!tn->internal[x])
+ return NULL;
} else if (l == 1) {
/* Looking from level 1 at level 0 */
} else if (!tn->internal[x]) {
/* Don't have one, none passed in */
tn->internal[x] = yaffs_GetTnode(dev);
+ if(!tn->internal[x])
+ return NULL;
}
}
for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
theChunk % dev->nChunksPerBlock)) {
- yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
- tags);
- if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
- /* found it; */
+
+ if(dev->chunkGroupSize == 1)
return theChunk;
+ else {
+ yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+ tags);
+ if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+ /* found it; */
+ return theChunk;
+ }
}
}
theChunk++;
}
- yaffs_PutLevel0Tnode(dev, tn, i, 0);
+ yaffs_LoadLevel0Tnode(dev, tn, i, 0);
}
}
* a block.
*/
yaffs_SoftDeleteChunk(dev, theChunk);
- yaffs_PutLevel0Tnode(dev, tn, i, 0);
+ yaffs_LoadLevel0Tnode(dev, tn, i, 0);
}
}
list = YMALLOC(sizeof(yaffs_ObjectList));
if (!newObjects || !list) {
- if (newObjects)
+ if (newObjects){
YFREE(newObjects);
- if (list)
+ newObjects = NULL;
+ }
+ if (list){
YFREE(list);
+ list = NULL;
+ }
T(YAFFS_TRACE_ALLOCATE,
(TSTR("yaffs: Could not allocate more objects" TENDSTR)));
return YAFFS_FAIL;
#ifdef VALGRIND_TEST
YFREE(tn);
+ tn = NULL;
#else
/* Link into the free list. */
tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
if (number < 0)
number = yaffs_CreateNewObjectNumber(dev);
- theObject = yaffs_AllocateEmptyObject(dev);
- if (!theObject)
- return NULL;
-
if (type == YAFFS_OBJECT_TYPE_FILE) {
tn = yaffs_GetTnode(dev);
- if (!tn) {
- yaffs_FreeObject(theObject);
+ if (!tn)
return NULL;
- }
}
+ theObject = yaffs_AllocateEmptyObject(dev);
+ if (!theObject){
+ if(tn)
+ yaffs_FreeTnode(dev,tn);
+ return NULL;
+ }
+
+
if (theObject) {
theObject->fake = 0;
theObject->renameAllowed = 1;
static YCHAR *yaffs_CloneString(const YCHAR *str)
{
YCHAR *newStr = NULL;
+ int len;
- if (str && *str) {
- newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
- if (newStr)
- yaffs_strcpy(newStr, str);
- }
+ if (!str)
+ str = _Y("");
+ len = yaffs_strnlen(str,YAFFS_MAX_ALIAS_LENGTH);
+ newStr = YMALLOC((len + 1) * sizeof(YCHAR));
+ if (newStr){
+ yaffs_strncpy(newStr, str,len);
+ newStr[len] = 0;
+ }
return newStr;
}
/*
* Mknod (create) a new object.
* equivalentObject only has meaning for a hard link;
- * aliasString only has meaning for a sumlink.
+ * aliasString only has meaning for a symlink.
* rdev only has meaning for devices (a subset of special objects)
*/
if (yaffs_FindObjectByName(parent, name))
return NULL;
- in = yaffs_CreateNewObject(dev, -1, type);
-
- if (!in)
- return YAFFS_FAIL;
-
if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
str = yaffs_CloneString(aliasString);
- if (!str) {
- yaffs_FreeObject(in);
+ if (!str)
return NULL;
- }
+ }
+
+ in = yaffs_CreateNewObject(dev, -1, type);
+
+ if (!in){
+ if(str)
+ YFREE(str);
+ return NULL;
}
+
if (in) {
in->hdrChunk = 0;
in->valid = 1;
yaffs_Object *obj = NULL;
yaffs_Object *existingTarget = NULL;
int force = 0;
+ int result;
+ yaffs_Device *dev;
if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
YBUG();
+ dev = oldDir->myDev;
+
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
/* Special case for case insemsitive systems (eg. WinCE).
* While look-up is case insensitive, the name isn't.
force = 1;
#endif
- else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+ if(yaffs_strnlen(newName,YAFFS_MAX_NAME_LENGTH+1) > YAFFS_MAX_NAME_LENGTH)
/* ENAMETOOLONG */
return YAFFS_FAIL;
return YAFFS_FAIL; /* EEXIST or ENOTEMPTY */
} else if (existingTarget && existingTarget != obj) {
/* Nuke the target first, using shadowing,
- * but only if it isn't the same object
+ * but only if it isn't the same object.
+ *
+ * Note we must disable gc otherwise it can mess up the shadowing.
+ *
*/
+ dev->isDoingGC=1;
yaffs_ChangeObjectName(obj, newDir, newName, force,
existingTarget->objectId);
+ existingTarget->isShadowed = 1;
yaffs_UnlinkObject(existingTarget);
+ dev->isDoingGC=0;
}
+
+ result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+
yaffs_UpdateParent(oldDir);
if(newDir != oldDir)
yaffs_UpdateParent(newDir);
-
- return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+
+ return result;
}
return YAFFS_FAIL;
}
if (tags.chunkId == 0) {
/* It is an object Id,
* We need to nuke the shrinkheader flags first
+ * Also need to clean up shadowing.
* We no longer want the shrinkHeader flag since its work is done
* and if it is left in place it will mess up scanning.
*/
oh = (yaffs_ObjectHeader *)buffer;
oh->isShrink = 0;
tags.extraIsShrinkHeader = 0;
+ oh->shadowsObject = 0;
+ oh->inbandShadowsObject = 0;
+ tags.extraShadows = 0;
yaffs_VerifyObjectHeader(object, oh, &tags, 1);
}
/* Delete the entry in the filestructure (if found) */
if (retVal != -1)
- yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
+ yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, 0);
}
return retVal;
/* NB inScan is zero unless scanning.
* For forward scanning, inScan is > 0;
* for backward scanning inScan is < 0
+ *
+ * chunkInNAND = 0 is a dummy insert to make sure the tnodes are there.
*/
yaffs_Tnode *tn;
NULL);
if (!tn)
return YAFFS_FAIL;
+
+ if(!chunkInNAND)
+ /* Dummy insert, bail now */
+ return YAFFS_OK;
+
existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
if (existingChunk == 0)
in->nDataChunks++;
- yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
+ yaffs_LoadLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
return YAFFS_OK;
}
(TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
YBUG();
}
-
+
+ /*
+ * If there isn't already a chunk there then do a dummy
+ * insert to make sue we have the desired tnode structure.
+ */
+ if(prevChunkId < 1 &&
+ yaffs_PutChunkIntoFile(in, chunkInInode, 0, 0) != YAFFS_OK)
+ return -1;
+
newChunkId =
yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
useReserve);
- if (newChunkId >= 0) {
+ if (newChunkId > 0) {
yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
if (prevChunkId > 0)
int newChunkId;
yaffs_ExtendedTags newTags;
yaffs_ExtendedTags oldTags;
+ YCHAR *alias = NULL;
__u8 *buffer = NULL;
YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
/* Do nothing */
break;
case YAFFS_OBJECT_TYPE_SYMLINK:
+ alias = in->variant.symLinkVariant.alias;
+ if(!alias)
+ alias = _Y("no alias");
yaffs_strncpy(oh->alias,
- in->variant.symLinkVariant.alias,
+ alias,
YAFFS_MAX_ALIAS_LENGTH);
oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
break;
}
- /* Write a new object header.
+ /* Write a new object header to reflect the resize.
* show we've shrunk the file, if need be
- * Do this only if the file is not in the deleted directories.
+ * Do this only if the file is not in the deleted directories
+ * and is not shadowed.
*/
if (in->parent &&
+ !in->isShadowed &&
in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
in->parent->objectId != YAFFS_OBJECTID_DELETED)
yaffs_UpdateObjectHeader(in, NULL, 0,
loff_t yaffs_GetFileSize(yaffs_Object *obj)
{
+ YCHAR *alias = NULL;
obj = yaffs_GetEquivalentObject(obj);
switch (obj->variantType) {
case YAFFS_OBJECT_TYPE_FILE:
return obj->variant.fileVariant.fileSize;
case YAFFS_OBJECT_TYPE_SYMLINK:
- return yaffs_strlen(obj->variant.symLinkVariant.alias);
+ alias = obj->variant.symLinkVariant.alias;
+ if(!alias)
+ return 0;
+ return yaffs_strnlen(alias,YAFFS_MAX_ALIAS_LENGTH);
default:
return 0;
}
-int yaffs_FlushFile(yaffs_Object *in, int updateTime)
+int yaffs_FlushFile(yaffs_Object *in, int updateTime, int dataSync)
{
int retVal;
if (in->dirty) {
yaffs_FlushFilesChunkCache(in);
- if (updateTime) {
+ if(dataSync) /* Only sync data */
+ retVal=YAFFS_OK;
+ else {
+ if (updateTime) {
#ifdef CONFIG_YAFFS_WINCE
- yfsd_WinFileTimeNow(in->win_mtime);
+ yfsd_WinFileTimeNow(in->win_mtime);
#else
- in->yst_mtime = Y_CURRENT_TIME;
+ in->yst_mtime = Y_CURRENT_TIME;
#endif
- }
+ }
- retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
- 0) ? YAFFS_OK : YAFFS_FAIL;
+ retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+ 0) ? YAFFS_OK : YAFFS_FAIL;
+ }
} else {
retVal = YAFFS_OK;
}
static int yaffs_DeleteSymLink(yaffs_Object *in)
{
- YFREE(in->variant.symLinkVariant.alias);
+ if(in->variant.symLinkVariant.alias)
+ YFREE(in->variant.symLinkVariant.alias);
+ in->variant.symLinkVariant.alias=NULL;
return yaffs_DoGenericObjectDeletion(in);
}
/* Handle YAFFS2 case (backward scanning)
* If the shadowed object exists then ignore.
*/
- if (yaffs_FindObjectByNumber(dev, objId))
+ obj = yaffs_FindObjectByNumber(dev, objId);
+ if(obj)
return;
}
YAFFS_OBJECT_TYPE_FILE);
if (!obj)
return;
+ obj->isShadowed = 1;
yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
obj->variant.fileVariant.shrinkSize = 0;
obj->valid = 1; /* So that we don't read any other info for this file */
}
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ * This code assumes that we don't ever change the current relationships between
+ * directories:
+ * rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
+ * lostNfound->parent == rootDir
+ *
+ * This fixes the problem where directories might have inadvertently been deleted
+ * leaving the object "hanging" without being rooted in the directory tree.
+ */
+
+static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
+{
+ return (obj == dev->deletedDir ||
+ obj == dev->unlinkedDir||
+ obj == dev->rootDir);
+}
+
+static void yaffs_FixHangingObjects(yaffs_Device *dev)
+{
+ yaffs_Object *obj;
+ yaffs_Object *parent;
+ int i;
+ struct ylist_head *lh;
+ struct ylist_head *n;
+ int depthLimit;
+ int hanging;
+
+
+ /* Iterate through the objects in each hash entry,
+ * looking at each object.
+ * Make sure it is rooted.
+ */
+
+ for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+ ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, hashLink);
+ parent= obj->parent;
+
+ if(yaffs_HasNULLParent(dev,obj)){
+ /* These directories are not hanging */
+ hanging = 0;
+ }
+ else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ hanging = 1;
+ else if(yaffs_HasNULLParent(dev,parent))
+ hanging = 0;
+ else {
+ /*
+ * Need to follow the parent chain to see if it is hanging.
+ */
+ hanging = 0;
+ depthLimit=100;
+
+ while(parent != dev->rootDir &&
+ parent->parent &&
+ parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ depthLimit > 0){
+ parent = parent->parent;
+ depthLimit--;
+ }
+ if(parent != dev->rootDir)
+ hanging = 1;
+ }
+ if(hanging){
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Hanging object %d moved to lost and found" TENDSTR),
+ obj->objectId));
+ yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
+{
+ yaffs_Object *obj;
+ struct ylist_head *lh;
+ struct ylist_head *n;
+
+ if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+ YBUG();
+
+ ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
+ if (lh) {
+ obj = ylist_entry(lh, yaffs_Object, siblings);
+ if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
+ yaffs_DeleteDirectoryContents(obj);
+
+ T(YAFFS_TRACE_SCAN,
+ (TSTR("Deleting lost_found object %d" TENDSTR),
+ obj->objectId));
+
+ /* Need to use UnlinkObject since Delete would not handle
+ * hardlinked objects correctly.
+ */
+ yaffs_UnlinkObject(obj);
+ }
+ }
+
+}
+
+static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
+{
+ yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
+}
+
static int yaffs_Scan(yaffs_Device *dev)
{
yaffs_ExtendedTags tags;
}
if (!in ||
-#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
- !in->valid ||
-#endif
+ (!in->valid && dev->disableLazyLoad) ||
tags.extraShadows ||
(!in->valid &&
(tags.objectId == YAFFS_OBJECTID_ROOT ||
}
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
else if (obj->shortName[0])
- yaffs_strcpy(name, obj->shortName);
+ yaffs_strncpy(name, obj->shortName,YAFFS_SHORT_NAME_LENGTH+1);
#endif
else {
int result;
NULL);
}
yaffs_strncpy(name, oh->name, buffSize - 1);
+ name[buffSize-1]=0;
yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
}
- return yaffs_strlen(name);
+ return yaffs_strnlen(name,buffSize-1);
}
int yaffs_GetObjectFileLength(yaffs_Object *obj)
if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
return obj->variant.fileVariant.fileSize;
- if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
- return yaffs_strlen(obj->variant.symLinkVariant.alias);
- else {
+ if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK){
+ if(!obj->variant.symLinkVariant.alias)
+ return 0;
+ return yaffs_strnlen(obj->variant.symLinkVariant.alias,YAFFS_MAX_ALIAS_LENGTH);
+ } else {
/* Only a directory should drop through to here */
return obj->myDev->nDataBytesPerChunk;
}
init_failed = 1;
yaffs_StripDeletedObjects(dev);
+ yaffs_FixHangingObjects(dev);
+ if(dev->emptyLostAndFound)
+ yaffs_EmptyLostAndFound(dev);
}
if (init_failed) {
yaffs_VerifyFreeChunks(dev);
yaffs_VerifyBlocks(dev);
+ /* Clean up any aborted checkpoint data */
+ if(!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
+ yaffs_InvalidateCheckpoint(dev);
T(YAFFS_TRACE_TRACING,
(TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));