*/
//yaffs_guts.c
-const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.11 2005-07-27 02:00:48 charles Exp $";
+const char *yaffs_guts_c_version="$Id: yaffs_guts.c,v 1.16 2005-08-09 03:52:23 charles Exp $";
#include "yportenv.h"
static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev,int number,yaffs_ObjectType type);
static void yaffs_AddObjectToDirectory(yaffs_Object *directory, yaffs_Object *obj);
-static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink);
+static int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink, int shadows);
static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
static int yaffs_CheckStructures(void);
static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level, int chunkOffset,int *limit);
return yaffs_TagsCompatabilityQueryNANDBlock(dev,blockNo,state,sequenceNumber);
}
-int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
+static int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,int blockInNAND)
{
int result;
return sum;
}
-void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
+static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
{
#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
if(name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
}
-int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
+static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk, yaffs_ExtendedTags *tags, int objectId, int chunkInInode)
{
int j;
-int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
+static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
{
static int x = 0;
int i;
return n;
}
-void yaffs_HashObject(yaffs_Object *in)
+static void yaffs_HashObject(yaffs_Object *in)
{
int bucket = yaffs_HashFunction(in->objectId);
yaffs_Device *dev = in->myDev;
return theObject;
}
-yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
+static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev, int number,yaffs_ObjectType type)
{
yaffs_Object *theObject = NULL;
}
-YCHAR *yaffs_CloneString(const YCHAR *str)
+static YCHAR *yaffs_CloneString(const YCHAR *str)
{
YCHAR *newStr = NULL;
// equivalentObject only has meaning for a hard link;
// aliasString only has meaning for a sumlink.
// rdev only has meaning for devices (a subset of special objects)
-yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
+static yaffs_Object *yaffs_MknodObject( yaffs_ObjectType type,
yaffs_Object *parent,
const YCHAR *name,
__u32 mode,
}
if(/*yaffs_GetNumberOfFreeChunks(dev) <= 0 || */
- yaffs_UpdateObjectHeader(in,name,0,0) < 0)
+ yaffs_UpdateObjectHeader(in,name,0,0,0) < 0)
{
// Could not create the object header, fail the creation
yaffs_DestroyObject(in);
}
-static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force)
+static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir, const YCHAR *newName,int force,int shadows)
{
int unlinkOp;
int deleteOp;
+
+ yaffs_Object * existingTarget;
if(newDir == NULL)
{
deleteOp = (newDir == obj->myDev->deletedDir);
+ existingTarget = yaffs_FindObjectByName(newDir,newName);
+
// If the object is a file going into the unlinked directory, then it is OK to just stuff it in since
// duplicate names are allowed.
// Otherwise only proceed if the new name does not exist and if we're putting it into a directory.
if( (unlinkOp||
deleteOp ||
force ||
- !yaffs_FindObjectByName(newDir,newName)) &&
+ (shadows > 0) ||
+ !existingTarget) &&
newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
{
yaffs_SetObjectName(obj,newName);
if(unlinkOp) obj->unlinked = 1;
// If it is a deletion then we mark it as a shrink for gc purposes.
- if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp) >= 0)
+ if(yaffs_UpdateObjectHeader(obj,newName,0,deleteOp,shadows) >= 0)
{
return YAFFS_OK;
}
int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName, yaffs_Object *newDir, const YCHAR *newName)
{
yaffs_Object *obj;
+ yaffs_Object *existingTarget;
int force = 0;
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
#endif
obj = yaffs_FindObjectByName(oldDir,oldName);
+
if(obj && obj->renameAllowed)
{
- return yaffs_ChangeObjectName(obj,newDir,newName,force);
+
+ // Now do the handling for an existing target, if there is one
+
+ existingTarget = yaffs_FindObjectByName(newDir,newName);
+ if(existingTarget &&
+ existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+ !list_empty(&existingTarget->variant.directoryVariant.children))
+ {
+ // There is a target that is a non-empty directory, so we have to 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
+ yaffs_ChangeObjectName(obj,newDir,newName,force,existingTarget->objectId);
+ yaffs_Unlink(newDir,newName);
+ }
+
+
+ return yaffs_ChangeObjectName(obj,newDir,newName,force,0);
}
return YAFFS_FAIL;
}
}
-int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
+static int yaffs_GarbageCollectBlock(yaffs_Device *dev,int block)
{
int oldChunk;
int newChunk;
tags.serialNumber++;
dev->nGCCopies++;
+
+ if(tags.chunkId == 0)
+ {
+ // It is an object Id,
+ // We need to nuke the shrinkheader flags first
+ // We no longer want the shrinkHeader flag since its work is done
+ // and if it is left in place it will mess up scanning.
+ // Also, clear out any shadowing stuff
+
+ yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *)buffer;
+ oh->isShrink = 0;
+ oh->shadowsObject = -1;
+ tags.extraShadows = 0;
+ tags.extraIsShrinkHeader = 0;
+ }
newChunk = yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags,1);
// The idea is to help clear out space in a more spread-out manner.
// Dunno if it really does anything useful.
//
-int yaffs_CheckGarbageCollection(yaffs_Device *dev)
+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
{
int block;
int aggressive;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
-int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
+static int yaffs_FindChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
{
//Get the Tnode, then get the level 0 offset chunk offset
yaffs_Tnode *tn;
return retVal;
}
-int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
+static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in,int chunkInInode,yaffs_ExtendedTags *tags)
{
//Get the Tnode, then get the level 0 offset chunk offset
yaffs_Tnode *tn;
-int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
+static int yaffs_ReadChunkDataFromObject(yaffs_Object *in,int chunkInInode, __u8 *buffer)
{
int chunkInNAND = yaffs_FindChunkInFile(in,chunkInInode,NULL);
-int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
+static int yaffs_WriteChunkDataToObject(yaffs_Object *in,int chunkInInode, const __u8 *buffer,int nBytes,int useReserve)
{
// Find old chunk Need to do this to get serial number
// Write new one and patch into tree.
// UpdateObjectHeader updates the header on NAND for an object.
// If name is not NULL, then that new name is used.
//
-int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink)
+int yaffs_UpdateObjectHeader(yaffs_Object *in,const YCHAR *name, int force,int isShrink,int shadows)
{
yaffs_BlockInfo *bi;
oh->type = in->variantType;
oh->yst_mode = in->yst_mode;
+
+ // shadowing
+ oh->shadowsObject = shadows;
#ifdef CONFIG_YAFFS_WINCE
oh->win_atime[0] = in->win_atime[0];
newTags.extraFileLength = oh->fileSize;
newTags.extraIsShrinkHeader = oh->isShrink;
newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+ newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
newTags.extraObjectType = in->variantType;
// Create new chunk in NAND
return yaffs_GetFileSize(in);
}
+ if(newSize == oldFileSize)
+ {
+ return oldFileSize;
+ }
+
if(newSize < oldFileSize)
{
in->variant.fileVariant.fileSize = newSize;
yaffs_PruneFileStructure(dev,&in->variant.fileVariant);
-
- // Write a new object header to show we've shrunk the file
- // Do this only if the file is not in the deleted directories.
- if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
- in->parent->objectId != YAFFS_OBJECTID_DELETED
- )
- {
- yaffs_UpdateObjectHeader(in,NULL, 0, 1);
- }
-
-
- return newSize;
-
}
- else
+
+ // Write a new object header.
+ // show we've shrunk the file, if need be
+ // Do this only if the file is not in the deleted directories.
+ if(in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+ in->parent->objectId != YAFFS_OBJECTID_DELETED
+ )
{
- return oldFileSize;
+ yaffs_UpdateObjectHeader(in,NULL, 0, (newSize < oldFileSize) ? 1 : 0 ,0);
}
+
+
+ return newSize;
}
#endif
}
- retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
+ retVal = (yaffs_UpdateObjectHeader(in,NULL,0,0,0) >= 0)? YAFFS_OK : YAFFS_FAIL;
}
else
{
if(in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir))
{
// Move to the unlinked directory so we have a record that it was deleted.
- yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
+ yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
}
#endif
if(immediateDeletion)
{
- retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0);
+ retVal = yaffs_ChangeObjectName(in, in->myDev->deletedDir,NULL,0,0);
T(YAFFS_TRACE_TRACING,(TSTR("yaffs: immediate deletion of file %d" TENDSTR),in->objectId));
in->deleted=1;
in->myDev->nDeletedFiles++;
}
else
{
- retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0);
+ retVal = yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,NULL,0,0);
}
}
yaffs_GetObjectName(hl,name,YAFFS_MAX_NAME_LENGTH+1);
- retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0);
+ retVal = yaffs_ChangeObjectName(obj, hl->parent, name,0,0);
if(retVal == YAFFS_OK)
{
//////////////// Initialisation Scanning /////////////////
+static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
+{
+ yaffs_Object *obj;
+
+ if(!backwardScanning)
+ {
+ // Handle YAFFS1 forward scanning case
+ // For YAFFS1 we always do the deletion
+
+ }
+ else
+ { // Handle YAFFS2 case (backward scanning)
+ // If the shadowed object exists then ignore.
+ if(yaffs_FindObjectByNumber(dev,objId))
+ {
+ return;
+ }
+ }
+
+ // Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+ // We put it in unlinked dir to be cleaned up after the scanning
+ obj = yaffs_FindOrCreateObjectByNumber(dev,objId,YAFFS_OBJECT_TYPE_FILE);
+ yaffs_AddObjectToDirectory(dev->unlinkedDir,obj);
+ obj->variant.fileVariant.shrinkSize = 0;
+ obj->valid = 1; // So that we don't read any other infor for this file
+
+}
+
#if 0
// For now we use the SmartMedia check.
// We look at the blockStatus byte in the first two chunks
in = yaffs_FindOrCreateObjectByNumber(dev,tags.objectId,oh->type);
+ if(oh->shadowsObject > 0)
+ {
+ yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
+ }
+
if(in->valid)
{
// We have already filled this one. We have a duplicate and need to resolve it.
}
+ // Handle the unlinked files. Since they were left in an unlinked state we should
+ // just delete them.
{
struct list_head *i;
struct list_head *n;
isShrink = 1;
}
- if(in->variant.fileVariant.shrinkSize > thisSize)
+ if(isShrink &&
+ in->variant.fileVariant.shrinkSize > thisSize)
{
in->variant.fileVariant.shrinkSize = thisSize;
}
in->yst_rdev = oh->yst_rdev;
#endif
in->chunkId = chunk;
+
+ if(oh->shadowsObject > 0)
+ {
+ yaffs_HandleShadowedObject(dev,oh->shadowsObject,1);
+ }
+
yaffs_SetObjectName(in,oh->name);
in->dirty = 0;
if(in->variant.fileVariant.scannedFileSize < oh->fileSize)
{
+ // This covers the case where the file size is > than where the data is
+ // This will happen if the file is resized to be larger than its current
+ // data extents.
in->variant.fileVariant.fileSize = oh->fileSize;
in->variant.fileVariant.scannedFileSize = in->variant.fileVariant.fileSize;
- }
+ }
-
-
- if(in->variant.fileVariant.shrinkSize > oh->fileSize)
+ if(oh->isShrink &&
+ in->variant.fileVariant.shrinkSize > oh->fileSize)
{
in->variant.fileVariant.shrinkSize = oh->fileSize;
- }
-
+ }
break;
case YAFFS_OBJECT_TYPE_HARDLINK:
yaffs_Object *l;
+ if(!name)
+ {
+ return NULL;
+ }
if(!directory)
{
if(valid & ATTR_SIZE) yaffs_ResizeFile(obj,attr->ia_size);
- yaffs_UpdateObjectHeader(obj,NULL,1,0);
+ yaffs_UpdateObjectHeader(obj,NULL,1,0,0);
return YAFFS_OK;
///////////////////////// Initialisation code ///////////////////////////
-int yaffs_CheckDevFunctions(const yaffs_Device *dev)
+static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
{
// Common functions, gotta have