*/
//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.13 2005-08-01 04:53:01 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)
+ {
+ // Nuke the target first, using shadowing
+ 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;
// 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
in->parent->objectId != YAFFS_OBJECTID_DELETED
)
{
- yaffs_UpdateObjectHeader(in,NULL, 0, 1);
+ yaffs_UpdateObjectHeader(in,NULL, 0, 1,0);
}
#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 /////////////////
+void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId, int backwardScanning)
+{
+ //Todo
+}
+
#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;
in->yst_rdev = oh->yst_rdev;
#endif
in->chunkId = chunk;
+
+ if(oh->shadowsObject > 0)
+ {
+ yaffs_HandleShadowedObject(dev,oh->shadowsObject,0);
+ }
+
yaffs_SetObjectName(in,oh->name);
in->dirty = 0;
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