/*
- * YAFFS: Yet another FFS. A NAND-flash specific file system.
- * yaffsfs.c The interface functions for using YAFFS via a "direct" interface.
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
*
- * Copyright (C) 2002 Aleph One Ltd.
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ * for Toby Churchill Ltd and Brightstar Engineering
*
* Created by Charles Manning <charles@aleph1.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
*/
#include "yaffsfs.h"
#endif
-const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.6 2005-09-20 05:05:40 charles Exp $";
+const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.18 2007-07-18 19:40:38 charles Exp $";
// configurationList is the list of devices that are supported
static yaffsfs_DeviceConfiguration *yaffsfs_configurationList;
// Handle management.
//
+
+unsigned int yaffs_wr_attempts;
+
typedef struct
{
__u8 inUse:1; // this handle is in use
// yaffsfs_FindDevice
// yaffsfs_FindRoot
// Scan the configuration list to find the root.
+// Curveballs: Should match paths that end in '/' too
+// Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
static yaffs_Device *yaffsfs_FindDevice(const char *path, char **restOfPath)
{
yaffsfs_DeviceConfiguration *cfg = yaffsfs_configurationList;
const char *leftOver;
const char *p;
+ yaffs_Device *retval = NULL;
+ int thisMatchLength;
+ int longestMatch = -1;
+ // Check all configs, choose the one that:
+ // 1) Actually matches a prefix (ie /a amd /abc will not match
+ // 2) Matches the longest.
while(cfg && cfg->prefix && cfg->dev)
{
leftOver = path;
p = cfg->prefix;
- while(*p && *leftOver && yaffsfs_Match(*p,*leftOver))
+ thisMatchLength = 0;
+
+ while(*p && //unmatched part of prefix
+ strcmp(p,"/") && // the rest of the prefix is not / (to catch / at end)
+ *leftOver &&
+ yaffsfs_Match(*p,*leftOver))
{
p++;
leftOver++;
+ thisMatchLength++;
}
- if(!*p && (!*leftOver || *leftOver == '/'))
+ if((!*p || strcmp(p,"/") == 0) && // end of prefix
+ (!*leftOver || *leftOver == '/') && // no more in this path name part
+ (thisMatchLength > longestMatch))
{
// Matched prefix
*restOfPath = (char *)leftOver;
- return cfg->dev;
+ retval = cfg->dev;
+ longestMatch = thisMatchLength;
}
cfg++;
}
- return NULL;
+ return retval;
}
static yaffs_Object *yaffsfs_FindRoot(const char *path, char **restOfPath)
}
-int yaffs_truncate(int fd, unsigned int newSize)
+int yaffs_truncate(int fd, off_t newSize)
{
yaffsfs_Handle *h = NULL;
yaffs_Object *obj = NULL;
{
yaffsfs_SetError(-ENOTDIR);
}
- else if(isDirectory && obj->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
- {
- yaffsfs_SetError(-ENOTDIR);
- }
else
{
result = yaffs_Unlink(dir,name);
buf->st_gid = 0;;
buf->st_rdev = obj->yst_rdev;
buf->st_size = yaffs_GetObjectFileLength(obj);
- buf->st_blksize = obj->myDev->nBytesPerChunk;
+ buf->st_blksize = obj->myDev->nDataBytesPerChunk;
buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
buf->yst_atime = obj->yst_atime;
buf->yst_ctime = obj->yst_ctime;
int yaffs_mkdir(const char *path, mode_t mode)
{
yaffs_Object *parent = NULL;
- yaffs_Object *dir;
+ yaffs_Object *dir = NULL;
char *name;
int retVal= -1;
yaffsfs_Lock();
parent = yaffsfs_FindDirectory(NULL,path,&name,0);
- dir = yaffs_MknodDirectory(parent,name,mode,0,0);
+ if(parent)
+ dir = yaffs_MknodDirectory(parent,name,mode,0,0);
if(dir)
{
retVal = 0;
{
int i;
int inUse;
+
+ yaffs_FlushEntireDeviceCache(dev);
+ yaffs_CheckpointSave(dev);
+
for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++)
{
if(yaffsfs_handle[i].inUse && yaffsfs_handle[i].obj->myDev == dev)
}
-off_t yaffs_freespace(const char *path)
+loff_t yaffs_freespace(const char *path)
{
- off_t retVal=-1;
+ loff_t retVal=-1;
yaffs_Device *dev=NULL;
char *dummy;
if(dev && dev->isMounted)
{
retVal = yaffs_GetNumberOfFreeChunks(dev);
- retVal *= dev->nBytesPerChunk;
+ retVal *= dev->nDataBytesPerChunk;
}
else
dir = (yaffs_DIR *)dsc;
if(dsc)
{
+ memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
dsc->magic = YAFFS_MAGIC;
- memset(dsc->name,0,NAME_MAX+1);
+ dsc->dirObj = obj;
strncpy(dsc->name,dirname,NAME_MAX);
INIT_LIST_HEAD(&dsc->others);
INIT_LIST_HEAD(&search_contexts);
list_add(&dsc->others,&search_contexts);
- }
+ yaffsfs_SetDirRewound(dsc); }
}
yaffsfs_SetError(0);
if(dsc->nextReturn){
dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId;
+ dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
dsc->de.d_off = dsc->offset++;
- yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX+1);
+ yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
+ if(strlen(dsc->de.d_name) == 0)
+ {
+ // this should not happen!
+ strcpy(dsc->de.d_name,"zz");
+ }
dsc->de.d_reclen = sizeof(struct yaffs_dirent);
retVal = &dsc->de;
yaffsfs_DirAdvance(dsc);
return retVal;
}
-int yaffs_link(const char *oldpath, const char *newpath);
+int yaffs_link(const char *oldpath, const char *newpath)
+{
+ // Creates a link called newpath to existing oldpath
+ yaffs_Object *obj = NULL;
+ yaffs_Object *target = NULL;
+ int retVal = 0;
+
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_FindObject(NULL,oldpath,0);
+ target = yaffsfs_FindObject(NULL,newpath,0);
+
+ if(!obj)
+ {
+ yaffsfs_SetError(-ENOENT);
+ retVal = -1;
+ }
+ else if(target)
+ {
+ yaffsfs_SetError(-EEXIST);
+ retVal = -1;
+ }
+ else
+ {
+ yaffs_Object *newdir = NULL;
+ yaffs_Object *link = NULL;
+
+ char *newname;
+
+ newdir = yaffsfs_FindDirectory(NULL,newpath,&newname,0);
+
+ if(!newdir)
+ {
+ yaffsfs_SetError(-ENOTDIR);
+ retVal = -1;
+ }
+ else if(newdir->myDev != obj->myDev)
+ {
+ yaffsfs_SetError(-EXDEV);
+ retVal = -1;
+ }
+ if(newdir && strlen(newname) > 0)
+ {
+ link = yaffs_Link(newdir,newname,obj);
+ if(link)
+ retVal = 0;
+ else
+ {
+ yaffsfs_SetError(-ENOSPC);
+ retVal = -1;
+ }
+
+ }
+ }
+ yaffsfs_Unlock();
+
+ return retVal;
+}
+
int yaffs_mknod(const char *pathname, mode_t mode, dev_t dev);
int yaffs_DumpDevStruct(const char *path)