X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=direct%2Fyaffsfs.c;h=67671ea6b69e90ce155b7cb68437f9c99ed34792;hp=9109da7f1df5d635de725d95b590a4806159e65e;hb=e1b8e63260986ab7afec3c379e7a320677c95846;hpb=40b1e54e4e59aaeb6bafabcda5df47bddc5ecfee diff --git a/direct/yaffsfs.c b/direct/yaffsfs.c index 9109da7..67671ea 100644 --- a/direct/yaffsfs.c +++ b/direct/yaffsfs.c @@ -25,32 +25,15 @@ #endif -const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.4 2005-07-03 05:48:11 charles Exp $"; +const char *yaffsfs_c_version="$Id: yaffsfs.c,v 1.12 2006-05-08 10:13:35 charles Exp $"; // configurationList is the list of devices that are supported static yaffsfs_DeviceConfiguration *yaffsfs_configurationList; -// -// Directory search context -// -// NB this is an opaque structure. - -struct yaffsfs_ObjectListEntry -{ - int objectId; - struct yaffsfs_ObjectListEntry *next; -}; - - -typedef struct -{ - __u32 magic; - yaffs_dirent de; - struct yaffsfs_ObjectListEntry *list; - char name[NAME_MAX+1]; - -} yaffsfs_DirectorySearchContext; +/* Some forward references */ +static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth); +static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj); // Handle management. @@ -67,10 +50,6 @@ typedef struct }yaffsfs_Handle; -static yaffs_Object *yaffsfs_FindObject(yaffs_Object *relativeDirectory, const char *path, int symDepth); - - - static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; // yaffsfs_InitHandle @@ -165,30 +144,47 @@ int yaffsfs_Match(char a, char b) // 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) @@ -410,19 +406,19 @@ int yaffs_open(const char *path, int oflag, int mode) // Check file permissions if( (oflag & (O_RDWR | O_WRONLY)) == 0 && // ie O_RDONLY - !(obj->st_mode & S_IREAD)) + !(obj->yst_mode & S_IREAD)) { openDenied = 1; } if( (oflag & O_RDWR) && - !(obj->st_mode & S_IREAD)) + !(obj->yst_mode & S_IREAD)) { openDenied = 1; } if( (oflag & (O_RDWR | O_WRONLY)) && - !(obj->st_mode & S_IWRITE)) + !(obj->yst_mode & S_IWRITE)) { openDenied = 1; } @@ -835,7 +831,7 @@ static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf) { buf->st_dev = (int)obj->myDev->genericDevice; buf->st_ino = obj->objectId; - buf->st_mode = obj->st_mode & ~S_IFMT; // clear out file type bits + buf->st_mode = obj->yst_mode & ~S_IFMT; // clear out file type bits if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) { @@ -853,13 +849,13 @@ static int yaffsfs_DoStat(yaffs_Object *obj,struct yaffs_stat *buf) buf->st_nlink = yaffs_GetObjectLinkCount(obj); buf->st_uid = 0; buf->st_gid = 0;; - buf->st_rdev = obj->st_rdev; + buf->st_rdev = obj->yst_rdev; buf->st_size = yaffs_GetObjectFileLength(obj); buf->st_blksize = obj->myDev->nBytesPerChunk; buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize; - buf->st_atime = obj->st_atime; - buf->st_ctime = obj->st_ctime; - buf->st_mtime = obj->st_mtime; + buf->yst_atime = obj->yst_atime; + buf->yst_ctime = obj->yst_ctime; + buf->yst_mtime = obj->yst_mtime; retVal = 0; } return retVal; @@ -940,7 +936,7 @@ static int yaffsfs_DoChMod(yaffs_Object *obj,mode_t mode) if(obj) { - obj->st_mode = mode; + obj->yst_mode = mode; obj->dirty = 1; result = yaffs_FlushFile(obj,0); } @@ -1003,13 +999,14 @@ int yaffs_fchmod(int fd, mode_t mode) 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; @@ -1079,6 +1076,10 @@ int yaffs_unmount(const char *path) { 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) @@ -1140,6 +1141,8 @@ off_t yaffs_freespace(const char *path) return retVal; } + + void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList) { @@ -1154,6 +1157,7 @@ void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList) while(cfg && cfg->prefix && cfg->dev) { cfg->dev->isMounted = 0; + cfg->dev->removeObjectCallback = yaffsfs_RemoveObjectCallback; cfg++; } @@ -1164,6 +1168,93 @@ void yaffs_initialise(yaffsfs_DeviceConfiguration *cfgList) // // Directory search stuff. +// +// Directory search context +// +// NB this is an opaque structure. + + +typedef struct +{ + __u32 magic; + yaffs_dirent de; /* directory entry being used by this dsc */ + char name[NAME_MAX+1]; /* name of directory being searched */ + yaffs_Object *dirObj; /* ptr to directory being searched */ + yaffs_Object *nextReturn; /* obj to be returned by next readddir */ + int offset; + struct list_head others; +} yaffsfs_DirectorySearchContext; + + + +static struct list_head search_contexts; + + +static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc) +{ + if(dsc && + dsc->dirObj && + dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){ + + dsc->offset = 0; + + if( list_empty(&dsc->dirObj->variant.directoryVariant.children)){ + dsc->nextReturn = NULL; + } else { + dsc->nextReturn = list_entry(dsc->dirObj->variant.directoryVariant.children.next, + yaffs_Object,siblings); + } + } else { + /* Hey someone isn't playing nice! */ + } +} + +static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc) +{ + if(dsc && + dsc->dirObj && + dsc->dirObj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY){ + + if( dsc->nextReturn == NULL || + list_empty(&dsc->dirObj->variant.directoryVariant.children)){ + dsc->nextReturn = NULL; + } else { + struct list_head *next = dsc->nextReturn->siblings.next; + + if( next == &dsc->dirObj->variant.directoryVariant.children) + dsc->nextReturn = NULL; /* end of list */ + else + dsc->nextReturn = list_entry(next,yaffs_Object,siblings); + } + } else { + /* Hey someone isn't playing nice! */ + } +} + +static void yaffsfs_RemoveObjectCallback(yaffs_Object *obj) +{ + + struct list_head *i; + yaffsfs_DirectorySearchContext *dsc; + + /* if search contexts not initilised then skip */ + if(!search_contexts.next) + return; + + /* Iteratethrough the directory search contexts. + * If any are the one being removed, then advance the dsc to + * the next one to prevent a hanging ptr. + */ + list_for_each(i, &search_contexts) { + if (i) { + dsc = list_entry(i, yaffsfs_DirectorySearchContext,others); + if(dsc->nextReturn == obj) + yaffsfs_DirAdvance(dsc); + } + } + +} + yaffs_DIR *yaffs_opendir(const char *dirname) { yaffs_DIR *dir = NULL; @@ -1181,11 +1272,17 @@ yaffs_DIR *yaffs_opendir(const char *dirname) dir = (yaffs_DIR *)dsc; if(dsc) { + memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext)); dsc->magic = YAFFS_MAGIC; - dsc->list = NULL; - memset(dsc->name,0,NAME_MAX+1); + dsc->dirObj = obj; strncpy(dsc->name,dirname,NAME_MAX); - } + INIT_LIST_HEAD(&dsc->others); + + if(!search_contexts.next) + INIT_LIST_HEAD(&search_contexts); + + list_add(&dsc->others,&search_contexts); + yaffsfs_SetDirRewound(dsc); } } @@ -1198,75 +1295,20 @@ struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) { yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; struct yaffs_dirent *retVal = NULL; - struct list_head *i; - yaffs_Object *entry = NULL; - int offset; - yaffs_Object *obj = NULL; - struct yaffsfs_ObjectListEntry *list = NULL; - int inList = 0; yaffsfs_Lock(); - offset = -1; - - if(dsc && dsc->magic == YAFFS_MAGIC) - { + if(dsc && dsc->magic == YAFFS_MAGIC){ yaffsfs_SetError(0); - - obj = yaffsfs_FindObject(NULL,dsc->name,0); - - if(obj && obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) - { - - list_for_each(i,&obj->variant.directoryVariant.children) - { - offset++; - entry = (i) ? list_entry(i, yaffs_Object,siblings) : NULL; - - if(entry) - { - list = dsc->list; - inList = 0; - while(list && !inList) - { - if(list->objectId == entry->objectId) - { - inList = 1; - } - list = list->next; - } - - if(!inList) goto foundNew; - } - - } - - foundNew: - - if(!inList && entry) - { - //This is the entry we're going to return; - struct yaffsfs_ObjectListEntry *le; - - le = YMALLOC(sizeof(struct yaffsfs_ObjectListEntry)); - - if(le) - { - le->next = dsc->list; - le->objectId = entry->objectId; - dsc->list = le; - - dsc->de.d_ino = yaffs_GetEquivalentObject(entry)->objectId; - dsc->de.d_off = offset; - yaffs_GetObjectName(entry,dsc->de.d_name,NAME_MAX+1); - dsc->de.d_reclen = sizeof(struct yaffs_dirent); - - retVal = &dsc->de; - } - - } - } - + if(dsc->nextReturn){ + dsc->de.d_ino = yaffs_GetEquivalentObject(dsc->nextReturn)->objectId; + dsc->de.d_off = dsc->offset++; + yaffs_GetObjectName(dsc->nextReturn,dsc->de.d_name,NAME_MAX+1); + dsc->de.d_reclen = sizeof(struct yaffs_dirent); + retVal = &dsc->de; + yaffsfs_DirAdvance(dsc); + } else + retVal = NULL; } else { @@ -1279,29 +1321,15 @@ struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) } -void yaffsfs_ListClear(yaffsfs_DirectorySearchContext *dsc) -{ - - struct yaffsfs_ObjectListEntry *le; - - if(dsc && dsc->magic == YAFFS_MAGIC) - { - while(dsc->list) - { - le = dsc->list; - dsc->list = dsc->list->next; - YFREE(le); - } - } - -} void yaffs_rewinddir(yaffs_DIR *dirp) { yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; - + yaffsfs_Lock(); - yaffsfs_ListClear(dsc); + + yaffsfs_SetDirRewound(dsc); + yaffsfs_Unlock(); } @@ -1311,13 +1339,14 @@ int yaffs_closedir(yaffs_DIR *dirp) yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp; yaffsfs_Lock(); - yaffsfs_ListClear(dsc); dsc->magic = 0; + list_del(&dsc->others); /* unhook from list */ YFREE(dsc); yaffsfs_Unlock(); return 0; } +// end of directory stuff int yaffs_symlink(const char *oldpath, const char *newpath) @@ -1378,7 +1407,66 @@ int yaffs_readlink(const char *path, char *buf, int bufsiz) 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)