Merge branch '32-bit-loff_t'
[yaffs2.git] / direct / yaffsfs.c
index b7d337f1fa92568754abdbbe0b1fd7fec6087c05..d208e25df0b4fdf002bae73547caddcbc7892107 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  *
- * Copyright (C) 2002-2010 Aleph One Ltd.
+ * Copyright (C) 2002-2011 Aleph One Ltd.
  *   for Toby Churchill Ltd and Brightstar Engineering
  *
  * Created by Charles Manning <charles@aleph1.co.uk>
@@ -17,7 +17,7 @@
 #include "yportenv.h"
 #include "yaffs_trace.h"
 
-#include <string.h> /* for memset */
+#include "string.h"
 
 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
 
 #define NULL ((void *)0)
 #endif
 
-
 /* YAFFSFS_RW_SIZE must be a power of 2 */
 #define YAFFSFS_RW_SHIFT (13)
 #define YAFFSFS_RW_SIZE  (1<<YAFFSFS_RW_SHIFT)
 
 /* Some forward references */
 static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory,
-                       const YCHAR *path,
-                       int symDepth, int getEquiv,
-                       struct yaffs_obj **dirOut);
+                                           const YCHAR *path,
+                                           int symDepth, int getEquiv,
+                                           struct yaffs_obj **dirOut,
+                                           int *notDir, int *loop);
 
 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj);
 
@@ -42,37 +42,65 @@ unsigned int yaffs_wr_attempts;
 
 /*
  * Handle management.
- * There are open inodes in yaffsfs_Inode.
- * There are open handles in yaffsfs_Handle.
+ * There are open inodes in struct yaffsfs_Inode.
+ * There are open file descriptors in yaffsfs_FileDes.
+ * There are open handles in yaffsfs_FileDes.
  *
  * Things are structured this way to be like the Linux VFS model
  * so that interactions with the yaffs guts calls are similar.
  * That means more common code paths and less special code.
  * That means better testing etc.
+ *
+ * We have 3 layers because:
+ * A handle is different than an fd because you can use dup()
+ * to create a new handle that accesses the *same* fd. The two
+ * handles will use the same offset (part of the fd). We only close
+ * down the fd when there are no more handles accessing it.
+ *
+ * More than one fd can currently access one file, but each fd
+ * has its own permsiions and offset.
  */
 
-typedef struct {
-       int count;      /* Number of handles accessing this inode */
+struct yaffsfs_Inode {
+       int count;              /* Number of handles accessing this inode */
        struct yaffs_obj *iObj;
-} yaffsfs_Inode;
-
-typedef struct{
-       u8      reading:1;
-       u8      writing:1;
-       u8      append:1;
-       u8      shareRead:1;
-       u8      shareWrite:1;
-       int     inodeId:12;     /* Index to corresponding yaffsfs_Inode */
-       int     useCount:10;    /* Use count for this handle */
-       u32 position;           /* current position in file */
-}yaffsfs_Handle;
-
-static yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
-static yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
-static int yaffsfs_handlesInitialised;
+};
+
+struct yaffsfs_FileDes {
+       u8 reading:1;
+       u8 writing:1;
+       u8 append:1;
+       u8 shareRead:1;
+       u8 shareWrite:1;
+       int inodeId:12;         /* Index to corresponding yaffsfs_Inode */
+       int handleCount:10;     /* Number of handles for this fd */
+       Y_LOFF_T position;      /* current position in file */
+};
+
+struct yaffsfs_Handle {
+       short int fdId;
+       short int useCount;
+};
+
+
+struct yaffsfs_DirSearchContxt {
+       struct yaffs_dirent de; /* directory entry */
+       YCHAR name[NAME_MAX + 1];       /* name of directory being searched */
+       struct yaffs_obj *dirObj;       /* ptr to directory being searched */
+       struct yaffs_obj *nextReturn;   /* obj  returned by next readddir */
+       struct list_head others;
+       int offset:20;
+       unsigned inUse:1;
+};
+
+static struct yaffsfs_DirSearchContxt yaffsfs_dsc[YAFFSFS_N_DSC];
+static struct yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES];
+static struct yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES];
+static struct yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES];
 
+static int yaffsfs_handlesInitialised;
 
-unsigned yaffs_set_trace(unsigned  tm) 
+unsigned yaffs_set_trace(unsigned tm)
 {
        yaffs_trace_mask = tm;
        return yaffs_trace_mask;
@@ -91,38 +119,53 @@ unsigned yaffs_get_trace(void)
 static void yaffsfs_InitHandles(void)
 {
        int i;
-       if(yaffsfs_handlesInitialised)
-                return;
+       if (yaffsfs_handlesInitialised)
+               return;
+
+       memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode));
+       memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd));
+       memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle));
+       memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc));
 
-       memset(yaffsfs_inode,0,sizeof(yaffsfs_inode));
-       memset(yaffsfs_handle,0,sizeof(yaffsfs_handle));
-       for(i = 0; i < YAFFSFS_N_HANDLES; i++)
-               yaffsfs_handle[i].inodeId = -1;
+       for (i = 0; i < YAFFSFS_N_HANDLES; i++)
+               yaffsfs_fd[i].inodeId = -1;
+       for (i = 0; i < YAFFSFS_N_HANDLES; i++)
+               yaffsfs_handle[i].fdId = -1;
 }
 
-yaffsfs_Handle *yaffsfs_GetHandlePointer(int h)
+static struct yaffsfs_Handle *yaffsfs_HandleToPointer(int h)
 {
-       if(h < 0 || h >= YAFFSFS_N_HANDLES)
-               return NULL;
+       if (h >= 0 && h < YAFFSFS_N_HANDLES)
+               return &yaffsfs_handle[h];
+       return NULL;
+}
+
+static struct yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle)
+{
+       struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
+
+       if (h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES)
+               return &yaffsfs_fd[h->fdId];
 
-       return &yaffsfs_handle[h];
+       return NULL;
 }
 
-yaffsfs_Inode *yaffsfs_GetInodePointer(int handle)
+static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle)
 {
-       yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
+       struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle);
 
-       if(h && h->useCount > 0 && h->inodeId >= 0 && h->inodeId < YAFFSFS_N_HANDLES)
-               return  &yaffsfs_inode[h->inodeId];
+       if (fd && fd->handleCount > 0 &&
+           fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES)
+               return &yaffsfs_inode[fd->inodeId];
 
        return NULL;
 }
 
-struct yaffs_obj *yaffsfs_GetHandleObject(int handle)
+static struct yaffs_obj *yaffsfs_HandleToObject(int handle)
 {
-       yaffsfs_Inode *in = yaffsfs_GetInodePointer(handle);
+       struct yaffsfs_Inode *in = yaffsfs_HandleToInode(handle);
 
-       if(in)
+       if (in)
                return in->iObj;
 
        return NULL;
@@ -137,13 +180,13 @@ static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj)
 {
        int i;
        int ret = -1;
-       
-       if(obj)
+
+       if (obj)
                obj = yaffs_get_equivalent_obj(obj);
 
-       /* Look for it in open inode table*/
-       for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
-               if(yaffsfs_inode[i].iObj == obj)
+       /* Look for it in open inode table */
+       for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) {
+               if (yaffsfs_inode[i].iObj == obj)
                        ret = i;
        }
        return ret;
@@ -157,50 +200,48 @@ static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj)
 {
        int i;
        int ret;
-       yaffsfs_Inode *in = NULL;
-       
-       if(obj)
+       struct yaffsfs_Inode *in = NULL;
+
+       if (obj)
                obj = yaffs_get_equivalent_obj(obj);
 
-        ret = yaffsfs_FindInodeIdForObject(obj);
+       ret = yaffsfs_FindInodeIdForObject(obj);
 
-       for(i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++){
-               if(!yaffsfs_inode[i].iObj)
+       for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) {
+               if (!yaffsfs_inode[i].iObj)
                        ret = i;
        }
 
-       if(ret>=0){
+       if (ret >= 0) {
                in = &yaffsfs_inode[ret];
-               if(!in->iObj)
+               if (!in->iObj)
                        in->count = 0;
                in->iObj = obj;
                in->count++;
        }
-       
-       
+
        return ret;
 }
 
-
 static int yaffsfs_CountHandles(struct yaffs_obj *obj)
 {
        int i = yaffsfs_FindInodeIdForObject(obj);
 
-       if(i >= 0)
+       if (i >= 0)
                return yaffsfs_inode[i].count;
        else
                return 0;
 }
 
-static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
+static void yaffsfs_ReleaseInode(struct yaffsfs_Inode *in)
 {
        struct yaffs_obj *obj;
-       
+
        obj = in->iObj;
 
-       if(obj->unlinked)
+       if (obj->unlinked)
                yaffs_del_obj(obj);
-       
+
        obj->my_inode = NULL;
        in->iObj = NULL;
 
@@ -208,54 +249,76 @@ static void yaffsfs_ReleaseInode(yaffsfs_Inode *in)
 
 static void yaffsfs_PutInode(int inodeId)
 {
-       if(inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES){
-               yaffsfs_Inode *in = & yaffsfs_inode[inodeId];
+       if (inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES) {
+               struct yaffsfs_Inode *in = &yaffsfs_inode[inodeId];
                in->count--;
-               if(in->count <= 0){
+               if (in->count <= 0) {
                        yaffsfs_ReleaseInode(in);
                        in->count = 0;
                }
-       }       
+       }
 }
 
+static int yaffsfs_NewHandle(struct yaffsfs_Handle **hptr)
+{
+       int i;
+       struct yaffsfs_Handle *h;
+
+       for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+               h = &yaffsfs_handle[i];
+               if (h->useCount < 1) {
+                       memset(h, 0, sizeof(struct yaffsfs_Handle));
+                       h->fdId = -1;
+                       h->useCount = 1;
+                       if (hptr)
+                               *hptr = h;
+                       return i;
+               }
+       }
+       return -1;
+}
 
-/*
- * yaffsfs_GetHandle
- * Grab a handle (when opening a file)
- */
-
-static int yaffsfs_GetNewHandle(void)
+static int yaffsfs_NewHandleAndFileDes(void)
 {
        int i;
-       yaffsfs_Handle *h;
+       struct yaffsfs_FileDes *fd;
+       struct yaffsfs_Handle *h = NULL;
+       int handle = yaffsfs_NewHandle(&h);
 
-       for(i = 0; i < YAFFSFS_N_HANDLES; i++){
-               h = yaffsfs_GetHandlePointer(i);
-               if(!h){
-                       /* todo bug: should never happen */
-               }
-               if(h->useCount < 1){
-                       memset(h,0,sizeof(yaffsfs_Handle));
-                       h->inodeId=-1;
-                       h->useCount=1;
-                       return i;
+       if (handle < 0)
+               return -1;
+
+       for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+               fd = &yaffsfs_fd[i];
+               if (fd->handleCount < 1) {
+                       memset(fd, 0, sizeof(struct yaffsfs_FileDes));
+                       fd->inodeId = -1;
+                       fd->handleCount = 1;
+                       h->fdId = i;
+                       return handle;
                }
        }
+
+       /* Dump the handle because we could not get a fd */
+       h->useCount = 0;
        return -1;
 }
 
 /*
  * yaffs_get_handle
  * Increase use of handle when reading/writing a file
+ * Also gets the file descriptor.
  */
+
 static int yaffsfs_GetHandle(int handle)
 {
-       yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
+       struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
 
-       if(h && h->useCount > 0){       
+       if (h && h->useCount > 0) {
                h->useCount++;
+               return 0;
        }
-       return 0;
+       return -1;
 }
 
 /*
@@ -263,58 +326,92 @@ static int yaffsfs_GetHandle(int handle)
  * Let go of a handle when closing a file or aborting an open or
  * ending a read or write.
  */
+
+static int yaffsfs_PutFileDes(int fdId)
+{
+       struct yaffsfs_FileDes *fd;
+
+       if (fdId >= 0 && fdId < YAFFSFS_N_HANDLES) {
+               fd = &yaffsfs_fd[fdId];
+               fd->handleCount--;
+               if (fd->handleCount < 1) {
+                       if (fd->inodeId >= 0) {
+                               yaffsfs_PutInode(fd->inodeId);
+                               fd->inodeId = -1;
+                       }
+               }
+       }
+       return 0;
+}
+
 static int yaffsfs_PutHandle(int handle)
 {
-       yaffsfs_Handle *h = yaffsfs_GetHandlePointer(handle);
+       struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle);
 
-       if(h && h->useCount > 0){       
+       if (h && h->useCount > 0) {
                h->useCount--;
-               if(h->useCount < 1){
-                       if(h->inodeId >= 0){
-                               yaffsfs_PutInode(h->inodeId);
-                               h->inodeId = -1;
-                       }
+               if (h->useCount < 1) {
+                       yaffsfs_PutFileDes(h->fdId);
+                       h->fdId = -1;
                }
        }
+
        return 0;
 }
 
 static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev)
 {
-       yaffsfs_Handle *h;
+       struct yaffsfs_FileDes *fd;
+       struct yaffsfs_Handle *h;
        struct yaffs_obj *obj;
        int i;
-       for(i = 0; i < YAFFSFS_N_HANDLES; i++){
-               h = yaffsfs_GetHandlePointer(i);
-               obj = yaffsfs_GetHandleObject(i);
-               if(h && h->useCount>0 && obj && obj->my_dev == dev){
+       for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+               h = yaffsfs_HandleToPointer(i);
+               fd = yaffsfs_HandleToFileDes(i);
+               obj = yaffsfs_HandleToObject(i);
+               if (h && h->useCount > 0) {
                        h->useCount = 0;
-                       yaffsfs_PutInode(h->inodeId);
-                       h->inodeId = -1;
+                       h->fdId = 0;
+               }
+               if (fd && fd->handleCount > 0 && obj && obj->my_dev == dev) {
+                       fd->handleCount = 0;
+                       yaffsfs_PutInode(fd->inodeId);
+                       fd->inodeId = -1;
                }
        }
 }
 
-
-
-
 /*
  *  Stuff to handle names.
  */
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
 
+static int yaffs_toupper(YCHAR a)
+{
+       if (a >= 'a' && a <= 'z')
+               return (a - 'a') + 'A';
+       else
+               return a;
+}
 
-int yaffsfs_Match(YCHAR a, YCHAR b)
+static int yaffsfs_Match(YCHAR a, YCHAR b)
+{
+       return (yaffs_toupper(a) == yaffs_toupper(b));
+}
+#else
+static int yaffsfs_Match(YCHAR a, YCHAR b)
 {
        /* case sensitive */
        return (a == b);
 }
+#endif
 
-int yaffsfs_IsPathDivider(YCHAR ch)
+static int yaffsfs_IsPathDivider(YCHAR ch)
 {
        const YCHAR *str = YAFFS_PATH_DIVIDERS;
 
-       while(*str){
-               if(*str == ch)
+       while (*str) {
+               if (*str == ch)
                        return 1;
                str++;
        }
@@ -322,21 +419,53 @@ int yaffsfs_IsPathDivider(YCHAR ch)
        return 0;
 }
 
-int yaffsfs_CheckNameLength(const char *name)
+static int yaffsfs_CheckNameLength(const char *name)
 {
-       int retVal = 0;         
+       int retVal = 0;
 
-       int nameLength = yaffs_strnlen(name,YAFFS_MAX_NAME_LENGTH+1);
-               
-       if(nameLength == 0){
+       int nameLength = yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH + 1);
+
+       if (nameLength == 0) {
                yaffsfs_SetError(-ENOENT);
                retVal = -1;
-       } else if (nameLength > YAFFS_MAX_NAME_LENGTH){
+       } else if (nameLength > YAFFS_MAX_NAME_LENGTH) {
                yaffsfs_SetError(-ENAMETOOLONG);
                retVal = -1;
        }
 
-       return retVal;  
+       return retVal;
+}
+
+static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
+{
+       YCHAR *alt_path = NULL;
+       int path_length;
+       int i;
+
+       /*
+        * We don't have a definition for max path length.
+        * We will use 3 * max name length instead.
+        */
+       *ret_path = NULL;
+       path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1);
+
+       /* If the last character is a path divider, then we need to
+        * trim it back so that the name look-up works properly.
+        * eg. /foo/new_dir/ -> /foo/newdir
+        * Curveball: Need to handle multiple path dividers:
+        * eg. /foof/sdfse///// -> /foo/sdfse
+        */
+       if (path_length > 0 && yaffsfs_IsPathDivider(path[path_length - 1])) {
+               alt_path = kmalloc(path_length + 1, 0);
+               if (!alt_path)
+                       return -1;
+               yaffs_strcpy(alt_path, path);
+               for (i = path_length - 1;
+                    i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); i--)
+                       alt_path[i] = (YCHAR) 0;
+       }
+       *ret_path = alt_path;
+       return 0;
 }
 
 LIST_HEAD(yaffsfs_deviceList);
@@ -348,7 +477,8 @@ LIST_HEAD(yaffsfs_deviceList);
  * Curveballs: Should match paths that end in '/' too
  * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match
  */
-static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPath)
+static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path,
+                                           YCHAR **restOfPath)
 {
        struct list_head *cfg;
        const YCHAR *leftOver;
@@ -364,31 +494,30 @@ static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPat
         * 1) Actually matches a prefix (ie /a amd /abc will not match
         * 2) Matches the longest.
         */
-       list_for_each(cfg, &yaffsfs_deviceList){
+       list_for_each(cfg, &yaffsfs_deviceList) {
                dev = list_entry(cfg, struct yaffs_dev, dev_list);
                leftOver = path;
                p = dev->param.name;
                thisMatchLength = 0;
                matching = 1;
 
-
-               while(matching && *p && *leftOver){
+               while (matching && *p && *leftOver) {
                        /* Skip over any /s */
-                       while(yaffsfs_IsPathDivider(*p))
-                             p++;
+                       while (yaffsfs_IsPathDivider(*p))
+                               p++;
 
                        /* Skip over any /s */
-                       while(yaffsfs_IsPathDivider(*leftOver))
-                             leftOver++;
+                       while (yaffsfs_IsPathDivider(*leftOver))
+                               leftOver++;
 
                        /* Now match the text part */
-                       while(matching &&
-                             *p && !yaffsfs_IsPathDivider(*p) &&
-                             *leftOver && !yaffsfs_IsPathDivider(*leftOver)){
-                               if(yaffsfs_Match(*p,*leftOver)){
-                                       p++;
-                                       leftOver++;
-                                       thisMatchLength++;
+                       while (matching &&
+                              *p && !yaffsfs_IsPathDivider(*p) &&
+                              *leftOver && !yaffsfs_IsPathDivider(*leftOver)) {
+                               if (yaffsfs_Match(*p, *leftOver)) {
+                                       p++;
+                                       leftOver++;
+                                       thisMatchLength++;
                                } else {
                                        matching = 0;
                                }
@@ -396,21 +525,20 @@ static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPat
                }
 
                /* Skip over any /s in leftOver */
-               while(yaffsfs_IsPathDivider(*leftOver))
-                     leftOver++;
+               while (yaffsfs_IsPathDivider(*leftOver))
+                       leftOver++;
 
-               // Skip over any /s in p
-               while(yaffsfs_IsPathDivider(*p))
-                     p++;
+               /*Skip over any /s in p */
+               while (yaffsfs_IsPathDivider(*p))
+                       p++;
 
-               // p should now be at the end of the string (ie. fully matched)
-               if(*p)
+               /* p should now be at the end of the string if fully matched */
+               if (*p)
                        matching = 0;
 
-               if( matching && (thisMatchLength > longestMatch))
-               {
-                       // Matched prefix
-                       *restOfPath = (YCHAR *)leftOver;
+               if (matching && (thisMatchLength > longestMatch)) {
+                       /* Matched prefix */
+                       *restOfPath = (YCHAR *) leftOver;
                        retval = dev;
                        longestMatch = thisMatchLength;
                }
@@ -421,17 +549,18 @@ static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, YCHAR **restOfPat
 
 static int yaffsfs_CheckPath(const YCHAR *path)
 {
-       int n=0;
-       int divs=0;
-       while(*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100){
-               if(yaffsfs_IsPathDivider(*path)){
-                       n=0;
+       int n = 0;
+       int divs = 0;
+
+       while (*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100) {
+               if (yaffsfs_IsPathDivider(*path)) {
+                       n = 0;
                        divs++;
                } else
                        n++;
                path++;
        }
-       
+
        return (*path) ? -1 : 0;
 }
 
@@ -439,45 +568,51 @@ static int yaffsfs_CheckPath(const YCHAR *path)
 static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path)
 {
        struct yaffs_dev *dev;
-       YCHAR *restOfPath=NULL;
-       dev = yaffsfs_FindDevice(path,&restOfPath);
-       if(dev && restOfPath && *restOfPath)
+       YCHAR *restOfPath = NULL;
+
+       dev = yaffsfs_FindDevice(path, &restOfPath);
+       if (dev && restOfPath && *restOfPath)
                dev = NULL;
        return dev;
 }
 
-static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path, YCHAR **restOfPath)
+static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path,
+                                         YCHAR **restOfPath)
 {
-
        struct yaffs_dev *dev;
 
-       dev= yaffsfs_FindDevice(path,restOfPath);
-       if(dev && dev->is_mounted){
+       dev = yaffsfs_FindDevice(path, restOfPath);
+       if (dev && dev->is_mounted)
                return dev->root_dir;
-       }
+
        return NULL;
 }
 
-static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,int symDepth)
+static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,
+                                           int symDepth, int *loop)
 {
 
-       if(obj)
+       if (obj)
                obj = yaffs_get_equivalent_obj(obj);
 
-       while(obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK){
+       while (obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) {
                YCHAR *alias = obj->variant.symlink_variant.alias;
 
-               if(yaffsfs_IsPathDivider(*alias))
+               if (yaffsfs_IsPathDivider(*alias))
                        /* Starts with a /, need to scan from root up */
-                       obj = yaffsfs_FindObject(NULL,alias,symDepth++,1,NULL);
+                       obj = yaffsfs_FindObject(NULL, alias, symDepth++,
+                                                1, NULL, NULL, loop);
                else
-                       /* Relative to here, so use the parent of the symlink as a start */
-                       obj = yaffsfs_FindObject(obj->parent,alias,symDepth++,1,NULL);
+                       /*
+                        * Relative to here so use the parent of the
+                        * symlink as a start
+                        */
+                       obj = yaffsfs_FindObject(obj->parent, alias, symDepth++,
+                                                1, NULL, NULL, loop);
        }
        return obj;
 }
 
-
 /*
  * yaffsfs_FindDirectory
  * Parse a path to determine the directory and the name within the directory.
@@ -485,61 +620,68 @@ static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj,int symDepth)
  * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx"
  */
 static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir,
-                               const YCHAR *path, YCHAR **name, int symDepth)
+                                                const YCHAR *path,
+                                                YCHAR **name, int symDepth,
+                                                int *notDir, int *loop)
 {
        struct yaffs_obj *dir;
        YCHAR *restOfPath;
-       YCHAR str[YAFFS_MAX_NAME_LENGTH+1];
+       YCHAR str[YAFFS_MAX_NAME_LENGTH + 1];
        int i;
 
-       if(symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES)
+       if (symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) {
+               if (loop)
+                       *loop = 1;
                return NULL;
+       }
 
-       if(startDir){
+       if (startDir) {
                dir = startDir;
-               restOfPath = (YCHAR *)path;
-       }
-       else
-               dir = yaffsfs_FindRoot(path,&restOfPath);
+               restOfPath = (YCHAR *) path;
+       } else
+               dir = yaffsfs_FindRoot(path, &restOfPath);
 
-       while(dir){
+       while (dir) {
                /*
                 * parse off /.
                 * curve ball: also throw away surplus '/'
                 * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff"
                 */
-               while(yaffsfs_IsPathDivider(*restOfPath))
-                       restOfPath++; /* get rid of '/' */
+               while (yaffsfs_IsPathDivider(*restOfPath))
+                       restOfPath++;   /* get rid of '/' */
 
                *name = restOfPath;
                i = 0;
 
-               while(*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)){
-                       if (i < YAFFS_MAX_NAME_LENGTH){
+               while (*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) {
+                       if (i < YAFFS_MAX_NAME_LENGTH) {
                                str[i] = *restOfPath;
-                               str[i+1] = '\0';
+                               str[i + 1] = '\0';
                                i++;
                        }
                        restOfPath++;
                }
 
-               if(!*restOfPath)
+               if (!*restOfPath)
                        /* got to the end of the string */
                        return dir;
-               else{
-                       if(yaffs_strcmp(str,_Y(".")) == 0)
-                       {
+               else {
+                       if (yaffs_strcmp(str, _Y(".")) == 0) {
                                /* Do nothing */
-                       }
-                       else if(yaffs_strcmp(str,_Y("..")) == 0)
+                       } else if (yaffs_strcmp(str, _Y("..")) == 0) {
                                dir = dir->parent;
-                       else{
-                               dir = yaffs_find_by_name(dir,str);
+                       } else {
+                               dir = yaffs_find_by_name(dir, str);
 
-                               dir = yaffsfs_FollowLink(dir,symDepth);
+                               dir = yaffsfs_FollowLink(dir, symDepth, loop);
 
-                               if(dir && dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+                               if (dir && dir->variant_type !=
+                                   YAFFS_OBJECT_TYPE_DIRECTORY) {
+                                       if (notDir)
+                                               *notDir = 1;
                                        dir = NULL;
+                               }
+
                        }
                }
        }
@@ -547,69 +689,87 @@ static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir,
        return NULL;
 }
 
-static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relativeDirectory,
-                                       const YCHAR *path,YCHAR **name,int symDepth)
+static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir,
+                                              const YCHAR *path,
+                                              YCHAR **name,
+                                              int symDepth,
+                                              int *notDir, int *loop)
 {
-       return yaffsfs_DoFindDirectory(relativeDirectory,path,name,symDepth);
+       return yaffsfs_DoFindDirectory(relDir, path, name, symDepth, notDir,
+                                               loop);
 }
 
 /*
  * yaffsfs_FindObject turns a path for an existing object into the object
  */
-static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory,
-                       const YCHAR *path,int symDepth, int getEquiv,
-                       struct yaffs_obj **dirOut)
+static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir,
+                                           const YCHAR *path, int symDepth,
+                                           int getEquiv,
+                                           struct yaffs_obj **dirOut,
+                                           int *notDir, int *loop)
 {
        struct yaffs_obj *dir;
        struct yaffs_obj *obj;
        YCHAR *name;
 
-       dir = yaffsfs_FindDirectory(relativeDirectory,path,&name,symDepth);
+       dir =
+           yaffsfs_FindDirectory(relDir, path, &name, symDepth, notDir, loop);
 
-       if(dirOut)
-               *dirOut =  dir;
+       if (dirOut)
+               *dirOut = dir;
 
-       if(dir && *name)
-               obj = yaffs_find_by_name(dir,name);
+       if (dir && *name)
+               obj = yaffs_find_by_name(dir, name);
        else
                obj = dir;
 
-       if(getEquiv)
+       if (getEquiv)
                obj = yaffs_get_equivalent_obj(obj);
 
        return obj;
 }
 
+/*************************************************************************
+ *     Start of yaffsfs visible functions.
+ *************************************************************************/
 
-int yaffs_dup(int fd)
+int yaffs_dup(int handle)
 {
-       int newHandle = -1;
-       yaffsfs_Handle *oldPtr = NULL;
-       yaffsfs_Handle *newPtr = NULL;
+       int newHandleNumber = -1;
+       struct yaffsfs_FileDes *existingFD = NULL;
+       struct yaffsfs_Handle *existingHandle = NULL;
+       struct yaffsfs_Handle *newHandle = NULL;
 
        yaffsfs_Lock();
-
-       oldPtr = yaffsfs_GetHandlePointer(fd);
-       if(oldPtr && oldPtr->useCount > 0)
-               newHandle = yaffsfs_GetNewHandle();
-       if(newHandle >= 0)
-               newPtr = yaffsfs_GetHandlePointer(newHandle);
-
-       if(newPtr){
-               *newPtr = *oldPtr;
-               return newHandle;
+       existingHandle = yaffsfs_HandleToPointer(handle);
+       existingFD = yaffsfs_HandleToFileDes(handle);
+       if (existingFD)
+               newHandleNumber = yaffsfs_NewHandle(&newHandle);
+       if (newHandle) {
+               newHandle->fdId = existingHandle->fdId;
+               existingFD->handleCount++;
        }
 
-       if(!oldPtr)
+       yaffsfs_Unlock();
+
+       if (!existingFD)
                yaffsfs_SetError(-EBADF);
-       else
+       else if (!newHandle)
                yaffsfs_SetError(-ENOMEM);
 
-       return -1;
+       return newHandleNumber;
 
 }
 
+static int yaffsfs_TooManyObjects(struct yaffs_dev *dev)
+{
+       int current_objects = dev->n_obj - dev->n_deleted_files;
 
+       if (dev->param.max_objects && current_objects > dev->param.max_objects)
+               return 1;
+       else
+               return 0;
+}
 
 int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
 {
@@ -617,12 +777,12 @@ int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
        struct yaffs_obj *dir = NULL;
        YCHAR *name;
        int handle = -1;
-       yaffsfs_Handle *yh = NULL;
+       struct yaffsfs_FileDes *fd = NULL;
        int openDenied = 0;
        int symDepth = 0;
        int errorReported = 0;
-       int rwflags = oflag & ( O_RDWR | O_RDONLY | O_WRONLY);
-       u8 shareRead = (sharing & YAFFS_SHARE_READ) ?  1 : 0;
+       int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY);
+       u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0;
        u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0;
        u8 sharedReadAllowed;
        u8 sharedWriteAllowed;
@@ -630,18 +790,25 @@ int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
        u8 alreadyWriting;
        u8 readRequested;
        u8 writeRequested;
+       int notDir = 0;
+       int loop = 0;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        /* O_EXCL only has meaning if O_CREAT is specified */
-       if(!(oflag & O_CREAT))
+       if (!(oflag & O_CREAT))
                oflag &= ~(O_EXCL);
 
        /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */
-       if(oflag & O_CREAT) & (oflag & O_EXCL))
+       if ((oflag & O_CREAT) & (oflag & O_EXCL))
                oflag &= ~(O_TRUNC);
 
        /* Todo: Are there any more flag combos to sanitise ? */
@@ -653,92 +820,98 @@ int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
 
        yaffsfs_Lock();
 
-       handle = yaffsfs_GetNewHandle();
+       handle = yaffsfs_NewHandleAndFileDes();
 
-       if(handle < 0){
+       if (handle < 0) {
                yaffsfs_SetError(-ENFILE);
                errorReported = 1;
        } else {
 
-               yh = yaffsfs_GetHandlePointer(handle);
+               fd = yaffsfs_HandleToFileDes(handle);
 
                /* try to find the exisiting object */
-               obj = yaffsfs_FindObject(NULL,path,0,1,NULL);
+               obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
 
-               obj = yaffsfs_FollowLink(obj,symDepth++);
+               obj = yaffsfs_FollowLink(obj, symDepth++, &loop);
 
-               if(obj &&
-                       obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
-                       obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+               if (obj &&
+                   obj->variant_type != YAFFS_OBJECT_TYPE_FILE &&
+                   obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
                        obj = NULL;
 
-
-               if(obj){
+               if (obj) {
 
                        /* The file already exists or it might be a directory */
 
-                       /* If it is a directory then we can't open it as a file */
-                       if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+                       /* A directory can't be opened as a file */
+                       if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
                                openDenied = 1;
                                yaffsfs_SetError(-EISDIR);
                                errorReported = 1;
                        }
 
-                       /* Open should fail if O_CREAT and O_EXCL are specified since
-                        * the file exists
+                       /* Open should fail if O_CREAT and O_EXCL are specified
+                        * for a file that exists.
                         */
-                       if(!errorReported && (oflag & O_EXCL) && (oflag & O_CREAT)){
+                       if (!errorReported &&
+                           (oflag & O_EXCL) && (oflag & O_CREAT)) {
                                openDenied = 1;
                                yaffsfs_SetError(-EEXIST);
                                errorReported = 1;
                        }
 
                        /* Check file permissions */
-                       ifreadRequested && !(obj->yst_mode & S_IREAD))
+                       if (readRequested && !(obj->yst_mode & S_IREAD))
                                openDenied = 1;
 
-                       ifwriteRequested && !(obj->yst_mode & S_IWRITE))
+                       if (writeRequested && !(obj->yst_mode & S_IWRITE))
                                openDenied = 1;
 
-                       if(openDenied && !errorReported ) {
-                               /* Error if the file exists but permissions are refused. */
+                       if (!errorReported && writeRequested &&
+                           obj->my_dev->read_only) {
+                               openDenied = 1;
+                               yaffsfs_SetError(-EROFS);
+                               errorReported = 1;
+                       }
+
+                       if (openDenied && !errorReported) {
                                yaffsfs_SetError(-EACCES);
                                errorReported = 1;
                        }
 
                        /* Check sharing of an existing object. */
-                       if(!openDenied){
-                               yaffsfs_Handle *hx;
+                       if (!openDenied) {
+                               struct yaffsfs_FileDes *fdx;
                                int i;
+
                                sharedReadAllowed = 1;
                                sharedWriteAllowed = 1;
                                alreadyReading = 0;
                                alreadyWriting = 0;
-                               for( i = 0; i < YAFFSFS_N_HANDLES; i++){
-                                       hx = &yaffsfs_handle[i];
-                                       if(hx->useCount > 0 &&
-                                               hx->inodeId >= 0 &&
-                                               yaffsfs_inode[hx->inodeId].iObj == obj){
-                                               if(!hx->shareRead)
+                               for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+                                       fdx = &yaffsfs_fd[i];
+                                       if (fdx->handleCount > 0 &&
+                                           fdx->inodeId >= 0 &&
+                                           yaffsfs_inode[fdx->inodeId].iObj
+                                           == obj) {
+                                               if (!fdx->shareRead)
                                                        sharedReadAllowed = 0;
-                                               if(!hx->shareWrite)
+                                               if (!fdx->shareWrite)
                                                        sharedWriteAllowed = 0;
-                                               if(hx->reading)
+                                               if (fdx->reading)
                                                        alreadyReading = 1;
-                                               if(hx->writing)
+                                               if (fdx->writing)
                                                        alreadyWriting = 1;
                                        }
                                }
 
-
-
-                               if((!sharedReadAllowed && readRequested)|| 
-                                       (!shareRead  && alreadyReading) ||
-                                       (!sharedWriteAllowed && writeRequested) ||
-                                       (!shareWrite && alreadyWriting)){
+                               if ((!sharedReadAllowed && readRequested) ||
+                                   (!shareRead && alreadyReading) ||
+                                   (!sharedWriteAllowed && writeRequested) ||
+                                   (!shareWrite && alreadyWriting)) {
                                        openDenied = 1;
                                        yaffsfs_SetError(-EBUSY);
-                                       errorReported=1;
+                                       errorReported = 1;
                                }
                        }
 
@@ -747,61 +920,71 @@ int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
                /* If we could not open an existing object, then let's see if
                 * the directory exists. If not, error.
                 */
-               if(!obj && !errorReported){
-                       dir = yaffsfs_FindDirectory(NULL,path,&name,0);
-                       if(!dir){
+               if (!obj && !errorReported) {
+                       dir = yaffsfs_FindDirectory(NULL, path, &name, 0,
+                                                   &notDir, &loop);
+                       if (!dir && notDir) {
                                yaffsfs_SetError(-ENOTDIR);
                                errorReported = 1;
+                       } else if (loop) {
+                               yaffsfs_SetError(-ELOOP);
+                               errorReported = 1;
+                       } else if (!dir) {
+                               yaffsfs_SetError(-ENOENT);
+                               errorReported = 1;
                        }
                }
 
-               if(!obj && dir && !errorReported && (oflag & O_CREAT)) {
-                       /* Let's see if we can create this file if it does not exist. */
-                       if(dir->my_dev->read_only){
-                               yaffsfs_SetError(-EINVAL);
+               if (!obj && dir && !errorReported && (oflag & O_CREAT)) {
+                       /* Let's see if we can create this file */
+                       if (dir->my_dev->read_only) {
+                               yaffsfs_SetError(-EROFS);
+                               errorReported = 1;
+                       } else if (yaffsfs_TooManyObjects(dir->my_dev)) {
+                               yaffsfs_SetError(-ENFILE);
                                errorReported = 1;
                        } else
-                               obj = yaffs_create_file(dir,name,mode,0,0);
+                               obj = yaffs_create_file(dir, name, mode, 0, 0);
 
-                       if(!obj && !errorReported){
+                       if (!obj && !errorReported) {
                                yaffsfs_SetError(-ENOSPC);
                                errorReported = 1;
                        }
                }
 
-               if(!obj && dir && !errorReported && !(oflag & O_CREAT)) {
-                       /* Error if the file does not exist and CREAT is not set. */
+               if (!obj && dir && !errorReported && !(oflag & O_CREAT)) {
                        yaffsfs_SetError(-ENOENT);
                        errorReported = 1;
                }
 
-               if(obj && !openDenied) {
+               if (obj && !openDenied) {
                        int inodeId = yaffsfs_GetInodeIdForObject(obj);
 
-                       if(inodeId<0) {
+                       if (inodeId < 0) {
                                /*
-                                * Todo: Fix any problem if inodes run out, though that
-                                * can't happen if the number of inode items >= number of handles. 
+                                * Todo: Fix any problem if inodes run out,
+                                * That can't happen if the number of inode
+                                * items >= number of handles.
                                 */
                        }
-                       
-                       yh->inodeId = inodeId;
-                       yh->reading = readRequested;
-                       yh->writing = writeRequested;
-                       yh->append =  (oflag & O_APPEND) ? 1 : 0;
-                       yh->position = 0;
-                       yh->shareRead = shareRead;
-                       yh->shareWrite = shareWrite;
+
+                       fd->inodeId = inodeId;
+                       fd->reading = readRequested;
+                       fd->writing = writeRequested;
+                       fd->append = (oflag & O_APPEND) ? 1 : 0;
+                       fd->position = 0;
+                       fd->shareRead = shareRead;
+                       fd->shareWrite = shareWrite;
 
                        /* Hook inode to object */
-                        obj->my_inode = (void*) &yaffsfs_inode[inodeId];
+                       obj->my_inode = (void *)&yaffsfs_inode[inodeId];
 
-                        if((oflag & O_TRUNC) && yh->writing)
-                                yaffs_resize_file(obj,0);
+                       if ((oflag & O_TRUNC) && fd->writing)
+                               yaffs_resize_file(obj, 0);
                } else {
                        yaffsfs_PutHandle(handle);
-                       if(!errorReported) 
-                               yaffsfs_SetError(0); /* Problem */
+                       if (!errorReported)
+                               yaffsfs_SetError(0);    /* Problem */
                        handle = -1;
                }
        }
@@ -813,25 +996,26 @@ int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing)
 
 int yaffs_open(const YCHAR *path, int oflag, int mode)
 {
-       return yaffs_open_sharing(path, oflag, mode, YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
+       return yaffs_open_sharing(path, oflag, mode,
+                                 YAFFS_SHARE_READ | YAFFS_SHARE_WRITE);
 }
 
-int yaffs_Dofsync(int fd,int datasync)
+static int yaffs_Dofsync(int handle, int datasync)
 {
-       yaffsfs_Handle *h = NULL;
-       int retVal = 0;
+       int retVal = -1;
+       struct yaffs_obj *obj;
 
        yaffsfs_Lock();
 
-       h = yaffsfs_GetHandlePointer(fd);
+       obj = yaffsfs_HandleToObject(handle);
 
-       if(h && h->useCount > 0)
-               /* flush the file */
-               yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,datasync);
-       else {
-               /* bad handle */
+       if (!obj)
                yaffsfs_SetError(-EBADF);
-               retVal = -1;
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else {
+               yaffs_flush_file(obj, 1, datasync);
+               retVal = 0;
        }
 
        yaffsfs_Unlock();
@@ -839,39 +1023,39 @@ int yaffs_Dofsync(int fd,int datasync)
        return retVal;
 }
 
-int yaffs_fsync(int fd)
+int yaffs_fsync(int handle)
 {
-       return yaffs_Dofsync(fd,0);
+       return yaffs_Dofsync(handle, 0);
 }
 
-int yaffs_flush(int fd)
+int yaffs_flush(int handle)
 {
-       return yaffs_fsync(fd);
+       return yaffs_fsync(handle);
 }
 
-int yaffs_fdatasync(int fd)
+int yaffs_fdatasync(int handle)
 {
-       return yaffs_Dofsync(fd,1);
+       return yaffs_Dofsync(handle, 1);
 }
 
-int yaffs_close(int fd)
+int yaffs_close(int handle)
 {
-       yaffsfs_Handle *h = NULL;
-       int retVal = 0;
+       struct yaffsfs_Handle *h = NULL;
+       struct yaffs_obj *obj = NULL;
+       int retVal = -1;
 
        yaffsfs_Lock();
 
-       h = yaffsfs_GetHandlePointer(fd);
+       h = yaffsfs_HandleToPointer(handle);
+       obj = yaffsfs_HandleToObject(handle);
 
-       if(h && h->useCount > 0) {
+       if (!h || !obj)
+               yaffsfs_SetError(-EBADF);
+       else {
                /* clean up */
-               yaffs_flush_file(yaffsfs_inode[h->inodeId].iObj,1,0);
-               yaffsfs_PutHandle(fd);
+               yaffs_flush_file(obj, 1, 0);
+               yaffsfs_PutHandle(handle);
                retVal = 0;
-       } else {
-               /* bad handle */
-               yaffsfs_SetError(-EBADF);
-               retVal = -1;
        }
 
        yaffsfs_Unlock();
@@ -879,103 +1063,106 @@ int yaffs_close(int fd)
        return retVal;
 }
 
-
-
-int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int offset)
+static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
+                   int isPread, Y_LOFF_T offset)
 {
-       yaffsfs_Handle *h = NULL;
+       struct yaffsfs_FileDes *fd = NULL;
        struct yaffs_obj *obj = NULL;
-       int pos = 0;
-       int startPos = 0;
-       int endPos = 0;
+       Y_LOFF_T pos = 0;
+       Y_LOFF_T startPos = 0;
+       Y_LOFF_T endPos = 0;
        int nRead = 0;
        int nToRead = 0;
        int totalRead = 0;
-       unsigned int maxRead;
-       u8 *buf = (u8 *)vbuf;
+       Y_LOFF_T maxRead;
+       u8 *buf = (u8 *) vbuf;
+
+       if (!vbuf) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
        yaffsfs_Lock();
-       h = yaffsfs_GetHandlePointer(fd);
-       obj = yaffsfs_GetHandleObject(fd);
+       fd = yaffsfs_HandleToFileDes(handle);
+       obj = yaffsfs_HandleToObject(handle);
 
-       if(!h || !obj){
+       if (!fd || !obj) {
                /* bad handle */
                yaffsfs_SetError(-EBADF);
                totalRead = -1;
-       } else if(!h->reading){
+       } else if (!fd->reading) {
                /* Not a reading handle */
                yaffsfs_SetError(-EINVAL);
                totalRead = -1;
-       } else if(nbyte > YAFFS_MAX_FILE_SIZE){
+       } else if (nbyte > YAFFS_MAX_FILE_SIZE) {
                yaffsfs_SetError(-EINVAL);
                totalRead = -1;
        } else {
-               if(isPread)
+               if (isPread)
                        startPos = offset;
                else
-                       startPos = h->position;
+                       startPos = fd->position;
 
                pos = startPos;
-                                       
-               if(yaffs_get_obj_length(obj) > pos)
+
+               if (yaffs_get_obj_length(obj) > pos)
                        maxRead = yaffs_get_obj_length(obj) - pos;
                else
                        maxRead = 0;
 
-               if(nbyte > maxRead)
+               if (nbyte > maxRead)
                        nbyte = maxRead;
 
-
-               yaffsfs_GetHandle(fd);
+               yaffsfs_GetHandle(handle);
 
                endPos = pos + nbyte;
 
-               if(pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
-                       nbyte > YAFFS_MAX_FILE_SIZE ||
-                       endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE){
+               if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
+                   nbyte > YAFFS_MAX_FILE_SIZE ||
+                   endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
                        totalRead = -1;
                        nbyte = 0;
                }
 
-               while(nbyte > 0) {
-                       nToRead = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
-                       if(nToRead > nbyte)
+               while (nbyte > 0) {
+                       nToRead = YAFFSFS_RW_SIZE -
+                           (pos & (YAFFSFS_RW_SIZE - 1));
+                       if (nToRead > nbyte)
                                nToRead = nbyte;
 
-                       /* Tricky bit... 
+                       /* Tricky bit...
                         * Need to reverify object in case the device was
                         * unmounted in another thread.
                         */
-                       obj = yaffsfs_GetHandleObject(fd);
-                       if(!obj)
+                       obj = yaffsfs_HandleToObject(handle);
+                       if (!obj)
                                nRead = 0;
                        else
-                               nRead = yaffs_file_rd(obj,buf,pos,nToRead);
+                               nRead = yaffs_file_rd(obj, buf, pos, nToRead);
 
-                       if(nRead > 0){
+                       if (nRead > 0) {
                                totalRead += nRead;
                                pos += nRead;
                                buf += nRead;
                        }
 
-                       if(nRead == nToRead)
-                               nbyte-=nRead;
+                       if (nRead == nToRead)
+                               nbyte -= nRead;
                        else
-                               nbyte = 0; /* no more to read */
-                                       
-                                       
-                       if(nbyte > 0){
+                               nbyte = 0;      /* no more to read */
+
+                       if (nbyte > 0) {
                                yaffsfs_Unlock();
                                yaffsfs_Lock();
                        }
 
                }
 
-               yaffsfs_PutHandle(fd);
+               yaffsfs_PutHandle(handle);
 
-               if(!isPread) {
-                       if(totalRead >= 0)
-                               h->position = startPos + totalRead;
+               if (!isPread) {
+                       if (totalRead >= 0)
+                               fd->position = startPos + totalRead;
                        else
                                yaffsfs_SetError(-EINVAL);
                }
@@ -988,102 +1175,113 @@ int yaffsfs_do_read(int fd, void *vbuf, unsigned int nbyte, int isPread, int off
 
 }
 
-int yaffs_read(int fd, void *buf, unsigned int nbyte)
+int yaffs_read(int handle, void *buf, unsigned int nbyte)
 {
-       return yaffsfs_do_read(fd, buf, nbyte, 0, 0);
+       return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
 }
 
-int yaffs_pread(int fd, void *buf, unsigned int nbyte, unsigned int offset)
+int yaffs_pread(int handle, void *buf, unsigned int nbyte, Y_LOFF_T offset)
 {
-       return yaffsfs_do_read(fd, buf, nbyte, 1, offset);
+       return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
 }
 
-int yaffsfs_do_write(int fd, const void *vbuf, unsigned int nbyte, int isPwrite, int offset)
+static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
+                    int isPwrite, Y_LOFF_T offset)
 {
-       yaffsfs_Handle *h = NULL;
+       struct yaffsfs_FileDes *fd = NULL;
        struct yaffs_obj *obj = NULL;
-       int pos = 0;
-       int startPos = 0;
-       int endPos;
+       Y_LOFF_T pos = 0;
+       Y_LOFF_T startPos = 0;
+       Y_LOFF_T endPos;
        int nWritten = 0;
        int totalWritten = 0;
        int write_trhrough = 0;
        int nToWrite = 0;
        const u8 *buf = (const u8 *)vbuf;
 
+       if (!vbuf) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
        yaffsfs_Lock();
-       h = yaffsfs_GetHandlePointer(fd);
-       obj = yaffsfs_GetHandleObject(fd);
+       fd = yaffsfs_HandleToFileDes(handle);
+       obj = yaffsfs_HandleToObject(handle);
 
-       if(!h || !obj){
+       if (!fd || !obj) {
                /* bad handle */
                yaffsfs_SetError(-EBADF);
                totalWritten = -1;
-       } else if( h && obj && (!h->writing || obj->my_dev->read_only)){
+       } else if (!fd->writing) {
                yaffsfs_SetError(-EINVAL);
-               totalWritten=-1;
+               totalWritten = -1;
+       } else if (obj->my_dev->read_only) {
+               yaffsfs_SetError(-EROFS);
+               totalWritten = -1;
        } else {
-               if(h->append)
+               if (fd->append)
                        startPos = yaffs_get_obj_length(obj);
-               else if(isPwrite)
+               else if (isPwrite)
                        startPos = offset;
                else
-                       startPos = h->position;
+                       startPos = fd->position;
 
-               yaffsfs_GetHandle(fd);
+               yaffsfs_GetHandle(handle);
                pos = startPos;
                endPos = pos + nbyte;
 
-               if(pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
-                       nbyte > YAFFS_MAX_FILE_SIZE ||
-                       endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE){
+               if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
+                   nbyte > YAFFS_MAX_FILE_SIZE ||
+                   endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
                        totalWritten = -1;
                        nbyte = 0;
                }
 
-               while(nbyte > 0) {
+               while (nbyte > 0) {
 
-                       nToWrite = YAFFSFS_RW_SIZE - (pos & (YAFFSFS_RW_SIZE -1));
-                       if(nToWrite > nbyte)
+                       nToWrite = YAFFSFS_RW_SIZE -
+                           (pos & (YAFFSFS_RW_SIZE - 1));
+                       if (nToWrite > nbyte)
                                nToWrite = nbyte;
 
-                       /* Tricky bit... 
+                       /* Tricky bit...
                         * Need to reverify object in case the device was
                         * remounted or unmounted in another thread.
                         */
-                       obj = yaffsfs_GetHandleObject(fd);
-                       if(!obj || obj->my_dev->read_only)
+                       obj = yaffsfs_HandleToObject(handle);
+                       if (!obj || obj->my_dev->read_only)
                                nWritten = 0;
                        else
-                               nWritten = yaffs_wr_file(obj,buf,pos,nToWrite,
-                                                       write_trhrough);
-                       if(nWritten > 0){
+                               nWritten =
+                                   yaffs_wr_file(obj, buf, pos, nToWrite,
+                                                 write_trhrough);
+                       if (nWritten > 0) {
                                totalWritten += nWritten;
                                pos += nWritten;
                                buf += nWritten;
                        }
 
-                       if(nWritten == nToWrite)
+                       if (nWritten == nToWrite)
                                nbyte -= nToWrite;
                        else
                                nbyte = 0;
 
-                       if(nWritten < 1 && totalWritten < 1){
+                       if (nWritten < 1 && totalWritten < 1) {
                                yaffsfs_SetError(-ENOSPC);
                                totalWritten = -1;
                        }
 
-                       if(nbyte > 0){
+                       if (nbyte > 0) {
                                yaffsfs_Unlock();
                                yaffsfs_Lock();
                        }
                }
 
-               yaffsfs_PutHandle(fd);
+               yaffsfs_PutHandle(handle);
 
-               if(!isPwrite){
-                       if(totalWritten > 0)
-                               h->position = startPos + totalWritten;
+               if (!isPwrite) {
+                       if (totalWritten > 0)
+                               fd->position = startPos + totalWritten;
                        else
                                yaffsfs_SetError(-EINVAL);
                }
@@ -1099,102 +1297,115 @@ int yaffs_write(int fd, const void *buf, unsigned int nbyte)
        return yaffsfs_do_write(fd, buf, nbyte, 0, 0);
 }
 
-int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, unsigned int offset)
+int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, Y_LOFF_T offset)
 {
        return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
 }
 
-
-int yaffs_truncate(const YCHAR *path,off_t new_size)
+int yaffs_truncate(const YCHAR *path, Y_LOFF_T new_size)
 {
        struct yaffs_obj *obj = NULL;
        struct yaffs_obj *dir = NULL;
        int result = YAFFS_FAIL;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+       obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir)
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj)
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
-       else if(obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
                yaffsfs_SetError(-EISDIR);
-       else if(obj->my_dev->read_only)
-               yaffsfs_SetError(-EACCES);
-       else if(new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
                yaffsfs_SetError(-EINVAL);
        else
-               result = yaffs_resize_file(obj,new_size);
+               result = yaffs_resize_file(obj, new_size);
 
        yaffsfs_Unlock();
 
        return (result) ? 0 : -1;
 }
 
-int yaffs_ftruncate(int fd, off_t new_size)
+int yaffs_ftruncate(int handle, Y_LOFF_T new_size)
 {
-       yaffsfs_Handle *h = NULL;
+       struct yaffsfs_FileDes *fd = NULL;
        struct yaffs_obj *obj = NULL;
        int result = 0;
 
        yaffsfs_Lock();
-       h = yaffsfs_GetHandlePointer(fd);
-       obj = yaffsfs_GetHandleObject(fd);
+       fd = yaffsfs_HandleToFileDes(handle);
+       obj = yaffsfs_HandleToObject(handle);
 
-       if(!h || !obj)
+       if (!fd || !obj)
                /* bad handle */
                yaffsfs_SetError(-EBADF);
-       else if(obj->my_dev->read_only)
-               yaffsfs_SetError(-EACCES);
-       else if( new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
+       else if (!fd->writing)
+               yaffsfs_SetError(-EINVAL);
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE)
                yaffsfs_SetError(-EINVAL);
        else
                /* resize the file */
-               result = yaffs_resize_file(obj,new_size);
+               result = yaffs_resize_file(obj, new_size);
        yaffsfs_Unlock();
 
        return (result) ? 0 : -1;
 
 }
 
-off_t yaffs_lseek(int fd, off_t offset, int whence)
+Y_LOFF_T yaffs_lseek(int handle, Y_LOFF_T offset, int whence)
 {
-       yaffsfs_Handle *h = NULL;
+       struct yaffsfs_FileDes *fd = NULL;
        struct yaffs_obj *obj = NULL;
-       int pos = -1;
-       int fSize = -1;
+       Y_LOFF_T pos = -1;
+       Y_LOFF_T fSize = -1;
 
        yaffsfs_Lock();
-       h = yaffsfs_GetHandlePointer(fd);
-       obj = yaffsfs_GetHandleObject(fd);
+       fd = yaffsfs_HandleToFileDes(handle);
+       obj = yaffsfs_HandleToObject(handle);
 
-       if(!h || !obj)
+       if (!fd || !obj)
                yaffsfs_SetError(-EBADF);
-       else if(offset > YAFFS_MAX_FILE_SIZE)
+       else if (offset > YAFFS_MAX_FILE_SIZE)
                yaffsfs_SetError(-EINVAL);
        else {
-               if(whence == SEEK_SET){
-                       if(offset >= 0)
+               if (whence == SEEK_SET) {
+                       if (offset >= 0)
                                pos = offset;
-               } else if(whence == SEEK_CUR) {
-                       if( (h->position + offset) >= 0)
-                               pos = (h->position + offset);
-               } else if(whence == SEEK_END) {
+               } else if (whence == SEEK_CUR) {
+                       if ((fd->position + offset) >= 0)
+                               pos = (fd->position + offset);
+               } else if (whence == SEEK_END) {
                        fSize = yaffs_get_obj_length(obj);
-                       if(fSize >= 0 && (fSize + offset) >= 0)
+                       if (fSize >= 0 && (fSize + offset) >= 0)
                                pos = fSize + offset;
-               } 
+               }
 
-               if(pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
-                       h->position = pos;
-               else{
+               if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
+                       fd->position = pos;
+               else {
                        yaffsfs_SetError(-EINVAL);
                        pos = -1;
                }
@@ -1205,38 +1416,54 @@ off_t yaffs_lseek(int fd, off_t offset, int whence)
        return pos;
 }
 
-
-int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
+static int yaffsfs_DoUnlink(const YCHAR *path, int isDirectory)
 {
        struct yaffs_obj *dir = NULL;
        struct yaffs_obj *obj = NULL;
        YCHAR *name;
        int result = YAFFS_FAIL;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,0,NULL);
-       dir = yaffsfs_FindDirectory(NULL,path,&name,0);
+       obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL);
+       dir = yaffsfs_FindDirectory(NULL, path, &name, 0, &notDir, &loop);
 
-       if(!dir)
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj)
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir)
                yaffsfs_SetError(-ENOENT);
-       else if(obj->my_dev->read_only)
+       else if (yaffs_strncmp(name, _Y("."), 2) == 0)
                yaffsfs_SetError(-EINVAL);
-       else if(!isDirectory && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+       else if (!obj)
+               yaffsfs_SetError(-ENOENT);
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else if (!isDirectory &&
+                obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
                yaffsfs_SetError(-EISDIR);
-       else if(isDirectory && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+       else if (isDirectory &&
+                obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
                yaffsfs_SetError(-ENOTDIR);
+       else if (isDirectory && obj == obj->my_dev->root_dir)
+               yaffsfs_SetError(-EBUSY);       /* Can't rmdir a root */
        else {
-               result = yaffs_unlinker(dir,name);
+               result = yaffs_unlinker(dir, name);
 
-               if(result == YAFFS_FAIL && isDirectory)
+               if (result == YAFFS_FAIL && isDirectory)
                        yaffsfs_SetError(-ENOTEMPTY);
        }
 
@@ -1245,10 +1472,9 @@ int yaffsfs_DoUnlink(const YCHAR *path,int isDirectory)
        return (result == YAFFS_FAIL) ? -1 : 0;
 }
 
-
 int yaffs_unlink(const YCHAR *path)
 {
-       return yaffsfs_DoUnlink(path,0);
+       return yaffsfs_DoUnlink(path, 0);
 }
 
 int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
@@ -1256,87 +1482,131 @@ int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath)
        struct yaffs_obj *olddir = NULL;
        struct yaffs_obj *newdir = NULL;
        struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *newobj = NULL;
        YCHAR *oldname;
        YCHAR *newname;
-       int result= YAFFS_FAIL;
+       int result = YAFFS_FAIL;
        int rename_allowed = 1;
+       int notOldDir = 0;
+       int notNewDir = 0;
+       int oldLoop = 0;
+       int newLoop = 0;
 
-       yaffsfs_Lock();
+       YCHAR *alt_newpath = NULL;
+
+       if (!oldPath || !newPath) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(newPath) < 0){
+       if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
-       olddir = yaffsfs_FindDirectory(NULL,oldPath,&oldname,0);
-       newdir = yaffsfs_FindDirectory(NULL,newPath,&newname,0);
-       obj = yaffsfs_FindObject(NULL,oldPath,0,0,NULL);
+       if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) {
+               yaffsfs_SetError(-ENOMEM);
+               return -1;
+       }
+       if (alt_newpath)
+               newPath = alt_newpath;
+
+       yaffsfs_Lock();
+
+       olddir = yaffsfs_FindDirectory(NULL, oldPath, &oldname, 0,
+                                      &notOldDir, &oldLoop);
+       newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0,
+                                      &notNewDir, &newLoop);
+       obj = yaffsfs_FindObject(NULL, oldPath, 0, 0, NULL, NULL, NULL);
+       newobj = yaffsfs_FindObject(NULL, newPath, 0, 0, NULL, NULL, NULL);
+
+       /* If the object being renamed is a directory and the
+        * path ended with a "/" then the olddir == obj.
+        * We pass through NULL for the old name to tell the lower layers
+        * to use olddir as the object.
+        */
+
+       if (olddir == obj)
+               oldname = NULL;
 
-       if(!olddir || !newdir) {
+       if ((!olddir && notOldDir) || (!newdir && notNewDir)) {
                yaffsfs_SetError(-ENOTDIR);
                rename_allowed = 0;
-       } else if(!obj) {
+       } else if (oldLoop || newLoop) {
+               yaffsfs_SetError(-ELOOP);
+               rename_allowed = 0;
+       } else if (olddir && oldname &&
+                       yaffs_strncmp(oldname, _Y("."), 2) == 0) {
+               yaffsfs_SetError(-EINVAL);
+               rename_allowed = 0;
+       } else if (!olddir || !newdir || !obj) {
                yaffsfs_SetError(-ENOENT);
                rename_allowed = 0;
-       } else if(obj->my_dev->read_only){
+       } else if (obj->my_dev->read_only) {
                yaffsfs_SetError(-EROFS);
                rename_allowed = 0;
-       } else if(olddir->my_dev != newdir->my_dev) {
+       } else if (yaffs_is_non_empty_dir(newobj)) {
+               yaffsfs_SetError(-ENOTEMPTY);
+               rename_allowed = 0;
+       } else if (olddir->my_dev != newdir->my_dev) {
                /* Rename must be on same device */
                yaffsfs_SetError(-EXDEV);
                rename_allowed = 0;
-       } else if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+       } else if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
                /*
                 * It is a directory, check that it is not being renamed to
                 * being its own decendent.
-                * Do this by tracing from the new directory back to the root, checking for obj
+                * Do this by tracing from the new directory back to the root,
+                * checking for obj
                 */
 
                struct yaffs_obj *xx = newdir;
 
-               while( rename_allowed && xx){
-                       if(xx == obj)
+               while (rename_allowed && xx) {
+                       if (xx == obj)
                                rename_allowed = 0;
                        xx = xx->parent;
                }
-               if(!rename_allowed)
+               if (!rename_allowed)
                        yaffsfs_SetError(-EINVAL);
        }
 
-       if(rename_allowed)
-               result = yaffs_rename_obj(olddir,oldname,newdir,newname);
+       if (rename_allowed)
+               result = yaffs_rename_obj(olddir, oldname, newdir, newname);
 
        yaffsfs_Unlock();
 
+       kfree(alt_newpath);
+
        return (result == YAFFS_FAIL) ? -1 : 0;
 }
 
-
-static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
+static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf)
 {
        int retVal = -1;
 
        obj = yaffs_get_equivalent_obj(obj);
 
-       if(obj && buf){
-               buf->st_dev = (int)obj->my_dev->os_context;
-               buf->st_ino = obj->obj_id;
-               buf->st_mode = obj->yst_mode & ~S_IFMT; /* clear out file type bits */
+       if (obj && buf) {
+               buf->st_dev = (int)obj->my_dev->os_context;
+               buf->st_ino = obj->obj_id;
+               buf->st_mode = obj->yst_mode & ~S_IFMT;
 
-               if(obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+               if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
                        buf->st_mode |= S_IFDIR;
-               else if(obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+               else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
                        buf->st_mode |= S_IFLNK;
-               else if(obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
+               else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE)
                        buf->st_mode |= S_IFREG;
 
-               buf->st_nlink = yaffs_get_obj_link_count(obj);
-               buf->st_uid = 0;
-               buf->st_gid = 0;;
-               buf->st_rdev = obj->yst_rdev;
-               buf->st_size = yaffs_get_obj_length(obj);
-               buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
-               buf->st_blocks = (buf->st_size + buf->st_blksize -1)/buf->st_blksize;
+               buf->st_nlink = yaffs_get_obj_link_count(obj);
+               buf->st_uid = 0;
+               buf->st_gid = 0;
+               buf->st_rdev = obj->yst_rdev;
+               buf->st_size = yaffs_get_obj_length(obj);
+               buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
+               buf->st_blocks = (buf->st_size + buf->st_blksize - 1) /
+                   buf->st_blksize;
 #if CONFIG_YAFFS_WINCE
                buf->yst_wince_atime[0] = obj->win_atime[0];
                buf->yst_wince_atime[1] = obj->win_atime[1];
@@ -1345,40 +1615,49 @@ static int yaffsfs_DoStat(struct yaffs_obj *obj,struct yaffs_stat *buf)
                buf->yst_wince_mtime[0] = obj->win_mtime[0];
                buf->yst_wince_mtime[1] = obj->win_mtime[1];
 #else
-               buf->yst_atime = obj->yst_atime;
-               buf->yst_ctime = obj->yst_ctime;
-               buf->yst_mtime = obj->yst_mtime;
+               buf->yst_atime = obj->yst_atime;
+               buf->yst_ctime = obj->yst_ctime;
+               buf->yst_mtime = obj->yst_mtime;
 #endif
                retVal = 0;
        }
        return retVal;
 }
 
-static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int doLStat)
+static int yaffsfs_DoStatOrLStat(const YCHAR *path,
+                                struct yaffs_stat *buf, int doLStat)
 {
-       struct yaffs_obj *obj=NULL;
-       struct yaffs_obj *dir=NULL;
-
+       struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *dir = NULL;
        int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path || !buf) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
 
-       if(!doLStat && obj)
-               obj = yaffsfs_FollowLink(obj,0);
+       if (!doLStat && obj)
+               obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir)
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj)
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
        else
-               retVal = yaffsfs_DoStat(obj,buf);
+               retVal = yaffsfs_DoStat(obj, buf);
 
        yaffsfs_Unlock();
 
@@ -1388,12 +1667,12 @@ static int yaffsfs_DoStatOrLStat(const YCHAR *path, struct yaffs_stat *buf,int d
 
 int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf)
 {
-       return yaffsfs_DoStatOrLStat(path,buf,0);
+       return yaffsfs_DoStatOrLStat(path, buf, 0);
 }
 
 int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf)
 {
-       return yaffsfs_DoStatOrLStat(path,buf,1);
+       return yaffsfs_DoStatOrLStat(path, buf, 1);
 }
 
 int yaffs_fstat(int fd, struct yaffs_stat *buf)
@@ -1402,11 +1681,16 @@ int yaffs_fstat(int fd, struct yaffs_stat *buf)
 
        int retVal = -1;
 
+       if (!buf) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(obj)
-               retVal = yaffsfs_DoStat(obj,buf);
+       if (obj)
+               retVal = yaffsfs_DoStat(obj, buf);
        else
                /* bad handle */
                yaffsfs_SetError(-EBADF);
@@ -1416,40 +1700,68 @@ int yaffs_fstat(int fd, struct yaffs_stat *buf)
        return retVal;
 }
 
-#ifndef CONFIG_YAFFS_WINCE
-/* xattrib functions */
+static int yaffsfs_DoUtime(struct yaffs_obj *obj,
+                          const struct yaffs_utimbuf *buf)
+{
+       int retVal = -1;
+       int result;
 
+       struct yaffs_utimbuf local;
 
-static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags, int follow)
-{
-       struct yaffs_obj *obj;
-       struct yaffs_obj *dir;
+       obj = yaffs_get_equivalent_obj(obj);
+
+       if (obj && obj->my_dev->read_only) {
+               yaffsfs_SetError(-EROFS);
+               return -1;
+       }
+
+       if (!buf) {
+               local.actime = Y_CURRENT_TIME;
+               local.modtime = local.actime;
+               buf = &local;
+       }
+
+       if (obj) {
+               obj->yst_atime = buf->actime;
+               obj->yst_mtime = buf->modtime;
+               obj->dirty = 1;
+               result = yaffs_flush_file(obj, 0, 0);
+               retVal = result == YAFFS_OK ? 0 : -1;
+       }
+
+       return retVal;
+}
 
+int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf)
+{
+       struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *dir = NULL;
        int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
-
-       if(follow)
-               obj = yaffsfs_FollowLink(obj,0);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
-       else {
-               retVal = yaffs_set_xattrib(obj,name,data,size,flags);
-               if(retVal< 0){
-                       yaffsfs_SetError(retVal);
-                       retVal = -1;
-               }
-       }
+       else
+               retVal = yaffsfs_DoUtime(obj, buf);
 
        yaffsfs_Unlock();
 
@@ -1457,33 +1769,66 @@ static int yaffs_do_setxattr(const YCHAR *path, const char *name, const void *da
 
 }
 
-int yaffs_setxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
-{
-       return yaffs_do_setxattr(path, name, data, size, flags, 1);
-}
-
-int yaffs_lsetxattr(const YCHAR *path, const char *name, const void *data, int size, int flags)
-{
-       return yaffs_do_setxattr(path, name, data, size, flags, 0);
-}
-
-
-
-int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int flags)
+int yaffs_futime(int fd, const struct yaffs_utimbuf *buf)
 {
        struct yaffs_obj *obj;
 
        int retVal = -1;
 
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(!obj) 
+       if (obj)
+               retVal = yaffsfs_DoUtime(obj, buf);
+       else
+               /* bad handle */
                yaffsfs_SetError(-EBADF);
-       else {
-               retVal = yaffs_set_xattrib(obj,name,data,size,flags);
-               if(retVal< 0){
-                       yaffsfs_SetError(retVal);
+
+       yaffsfs_Unlock();
+
+       return retVal;
+}
+
+#ifndef CONFIG_YAFFS_WINCE
+/* xattrib functions */
+
+static int yaffs_do_setxattr(const YCHAR *path, const char *name,
+                            const void *data, int size, int flags, int follow)
+{
+       struct yaffs_obj *obj;
+       struct yaffs_obj *dir;
+       int notDir = 0;
+       int loop = 0;
+
+       int retVal = -1;
+
+       if (!path || !name || !data) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
+               yaffsfs_SetError(-ENAMETOOLONG);
+               return -1;
+       }
+
+       yaffsfs_Lock();
+
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+
+       if (follow)
+               obj = yaffsfs_FollowLink(obj, 0, &loop);
+
+       if (!dir && notDir)
+               yaffsfs_SetError(-ENOTDIR);
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
+               yaffsfs_SetError(-ENOENT);
+       else {
+               retVal = yaffs_set_xattrib(obj, name, data, size, flags);
+               if (retVal < 0) {
+                       yaffsfs_SetError(retVal);
                        retVal = -1;
                }
        }
@@ -1491,34 +1836,86 @@ int yaffs_fsetxattr(int fd, const char *name, const void *data, int size, int fl
        yaffsfs_Unlock();
 
        return retVal;
+
+}
+
+int yaffs_setxattr(const YCHAR *path, const char *name,
+                  const void *data, int size, int flags)
+{
+       return yaffs_do_setxattr(path, name, data, size, flags, 1);
 }
 
-static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, int size, int follow)
+int yaffs_lsetxattr(const YCHAR *path, const char *name,
+                   const void *data, int size, int flags)
+{
+       return yaffs_do_setxattr(path, name, data, size, flags, 0);
+}
+
+int yaffs_fsetxattr(int fd, const char *name,
+                   const void *data, int size, int flags)
 {
        struct yaffs_obj *obj;
-       struct yaffs_obj *dir;
 
        int retVal = -1;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!name || !data) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       yaffsfs_Lock();
+       obj = yaffsfs_HandleToObject(fd);
+
+       if (!obj)
+               yaffsfs_SetError(-EBADF);
+       else {
+               retVal = yaffs_set_xattrib(obj, name, data, size, flags);
+               if (retVal < 0) {
+                       yaffsfs_SetError(retVal);
+                       retVal = -1;
+               }
+       }
+
+       yaffsfs_Unlock();
+
+       return retVal;
+}
+
+static int yaffs_do_getxattr(const YCHAR *path, const char *name,
+                            void *data, int size, int follow)
+{
+       struct yaffs_obj *obj;
+       struct yaffs_obj *dir;
+       int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path || !name || !data) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
 
-       if(follow)
-               obj = yaffsfs_FollowLink(obj,0);
+       if (follow)
+               obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
        else {
-               retVal = yaffs_get_xattrib(obj,name,data,size);
-               if(retVal< 0){
+               retVal = yaffs_get_xattrib(obj, name, data, size);
+               if (retVal < 0) {
                        yaffsfs_SetError(retVal);
                        retVal = -1;
                }
@@ -1531,27 +1928,31 @@ static int yaffs_do_getxattr(const YCHAR *path, const char *name, void *data, in
 
 int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size)
 {
-       return yaffs_do_getxattr( path, name, data, size, 1);
+       return yaffs_do_getxattr(path, name, data, size, 1);
 }
+
 int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size)
 {
-       return yaffs_do_getxattr( path, name, data, size, 0);
+       return yaffs_do_getxattr(path, name, data, size, 0);
 }
 
-
-
 int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
 {
        struct yaffs_obj *obj;
 
        int retVal = -1;
 
+       if (!name || !data) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(obj) {
-               retVal = yaffs_get_xattrib(obj,name,data,size);
-               if(retVal< 0){
+       if (obj) {
+               retVal = yaffs_get_xattrib(obj, name, data, size);
+               if (retVal < 0) {
                        yaffsfs_SetError(retVal);
                        retVal = -1;
                }
@@ -1564,32 +1965,41 @@ int yaffs_fgetxattr(int fd, const char *name, void *data, int size)
        return retVal;
 }
 
-static int yaffs_do_listxattr(const YCHAR *path, char *data, int size, int follow)
+static int yaffs_do_listxattr(const YCHAR *path, char *data,
+                             int size, int follow)
 {
-       struct yaffs_obj *obj=NULL;
-       struct yaffs_obj *dir=NULL;
-
+       struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *dir = NULL;
        int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path || !data) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1,&dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
 
-       if(follow)
-               obj = yaffsfs_FollowLink(obj,0);
+       if (follow)
+               obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
        else {
-               retVal = yaffs_list_xattrib(obj, data,size);
-               if(retVal< 0){
+               retVal = yaffs_list_xattrib(obj, data, size);
+               if (retVal < 0) {
                        yaffsfs_SetError(retVal);
                        retVal = -1;
                }
@@ -1617,12 +2027,17 @@ int yaffs_flistxattr(int fd, char *data, int size)
 
        int retVal = -1;
 
+       if (!data) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(obj) {
-               retVal = yaffs_list_xattrib(obj,data,size);
-               if(retVal< 0){
+       if (obj) {
+               retVal = yaffs_list_xattrib(obj, data, size);
+               if (retVal < 0) {
                        yaffsfs_SetError(retVal);
                        retVal = -1;
                }
@@ -1635,32 +2050,41 @@ int yaffs_flistxattr(int fd, char *data, int size)
        return retVal;
 }
 
-static int yaffs_do_removexattr(const YCHAR *path, const char *name, int follow)
+static int yaffs_do_removexattr(const YCHAR *path, const char *name,
+                               int follow)
 {
-       struct yaffs_obj *obj=NULL;
-       struct yaffs_obj *dir=NULL;
-
+       struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *dir = NULL;
+       int notDir = 0;
+       int loop = 0;
        int retVal = -1;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path || !name) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
 
-       if(follow)
-               obj = yaffsfs_FollowLink(obj,0);
+       if (follow)
+               obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
        else {
-               retVal = yaffs_remove_xattrib(obj,name);
-               if(retVal< 0){
+               retVal = yaffs_remove_xattrib(obj, name);
+               if (retVal < 0) {
                        yaffsfs_SetError(retVal);
                        retVal = -1;
                }
@@ -1688,16 +2112,21 @@ int yaffs_fremovexattr(int fd, const char *name)
 
        int retVal = -1;
 
+       if (!name) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(obj){
-               retVal = yaffs_remove_xattrib(obj,name);
-               if(retVal< 0){
+       if (obj) {
+               retVal = yaffs_remove_xattrib(obj, name);
+               if (retVal < 0) {
                        yaffsfs_SetError(retVal);
                        retVal = -1;
                }
-       }else
+       } else
                /* bad handle */
                yaffsfs_SetError(-EBADF);
 
@@ -1708,73 +2137,71 @@ int yaffs_fremovexattr(int fd, const char *name)
 #endif
 
 #ifdef CONFIG_YAFFS_WINCE
-int yaffs_get_wince_times(int fd, unsigned *wctime, unsigned *watime, unsigned *wmtime)
+int yaffs_get_wince_times(int fd, unsigned *wctime,
+                         unsigned *watime, unsigned *wmtime)
 {
        struct yaffs_obj *obj;
 
        int retVal = -1;
 
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(obj){
+       if (obj) {
 
-               if(wctime){
+               if (wctime) {
                        wctime[0] = obj->win_ctime[0];
                        wctime[1] = obj->win_ctime[1];
                }
-               if(watime){
+               if (watime) {
                        watime[0] = obj->win_atime[0];
                        watime[1] = obj->win_atime[1];
                }
-               if(wmtime){
+               if (wmtime) {
                        wmtime[0] = obj->win_mtime[0];
                        wmtime[1] = obj->win_mtime[1];
                }
 
-
                retVal = 0;
        } else
                /*  bad handle */
-               yaffsfs_SetError(-EBADF);               
-       
+               yaffsfs_SetError(-EBADF);
+
        yaffsfs_Unlock();
-       
+
        return retVal;
 }
 
-
-int yaffs_set_wince_times(int fd, 
-                                                 const unsigned *wctime, 
-                                                 const unsigned *watime, 
-                                                  const unsigned *wmtime)
+int yaffs_set_wince_times(int fd,
+                         const unsigned *wctime,
+                         const unsigned *watime, const unsigned *wmtime)
 {
-        struct yaffs_obj *obj;
-        int result;
-        int retVal = -1;
+       struct yaffs_obj *obj;
+       int result;
+       int retVal = -1;
 
-        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       yaffsfs_Lock();
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(obj){
+       if (obj) {
 
-               if(wctime){
+               if (wctime) {
                        obj->win_ctime[0] = wctime[0];
                        obj->win_ctime[1] = wctime[1];
                }
-               if(watime){
-                        obj->win_atime[0] = watime[0];
-                        obj->win_atime[1] = watime[1];
-                }
-                if(wmtime){
-                        obj->win_mtime[0] = wmtime[0];
-                        obj->win_mtime[1] = wmtime[1];
-                }
-
-                obj->dirty = 1;
-                result = yaffs_flush_file(obj,0,0);
-                retVal = 0;
-        } else
+               if (watime) {
+                       obj->win_atime[0] = watime[0];
+                       obj->win_atime[1] = watime[1];
+               }
+               if (wmtime) {
+                       obj->win_mtime[0] = wmtime[0];
+                       obj->win_mtime[1] = wmtime[1];
+               }
+
+               obj->dirty = 1;
+               result = yaffs_flush_file(obj, 0, 0);
+               retVal = 0;
+       } else
                /* bad handle */
                yaffsfs_SetError(-EBADF);
 
@@ -1785,60 +2212,69 @@ int yaffs_set_wince_times(int fd,
 
 #endif
 
-
-static int yaffsfs_DoChMod(struct yaffs_obj *obj,mode_t mode)
+static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode)
 {
        int result = -1;
 
-       if(obj)
+       if (obj)
                obj = yaffs_get_equivalent_obj(obj);
 
-       if(obj) {
+       if (obj) {
                obj->yst_mode = mode;
                obj->dirty = 1;
-               result = yaffs_flush_file(obj,0,0);
+               result = yaffs_flush_file(obj, 0, 0);
        }
 
        return result == YAFFS_OK ? 0 : -1;
 }
 
-
 int yaffs_access(const YCHAR *path, int amode)
 {
-       struct yaffs_obj *obj=NULL;
-       struct yaffs_obj *dir=NULL;
-
+       struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *dir = NULL;
+       int notDir = 0;
+       int loop = 0;
        int retval = -1;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
-       if(amode & ~(R_OK | W_OK | X_OK)){
+       if (amode & ~(R_OK | W_OK | X_OK)) {
                yaffsfs_SetError(-EINVAL);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+       obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
+       else if ((amode & W_OK) && obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
        else {
                int access_ok = 1;
 
-               if((amode & R_OK) && !(obj->yst_mode & S_IREAD))
+               if ((amode & R_OK) && !(obj->yst_mode & S_IREAD))
                        access_ok = 0;
-               if((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
+               if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
                        access_ok = 0;
-               if((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
+               if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
                        access_ok = 0;
 
-               if(!access_ok)
+               if (!access_ok)
                        yaffsfs_SetError(-EACCES);
                else
                        retval = 0;
@@ -1850,35 +2286,44 @@ int yaffs_access(const YCHAR *path, int amode)
 
 }
 
-
 int yaffs_chmod(const YCHAR *path, mode_t mode)
 {
-       struct yaffs_obj *obj=NULL;
-       struct yaffs_obj *dir=NULL;
+       struct yaffs_obj *obj = NULL;
+       struct yaffs_obj *dir = NULL;
        int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
-       if(mode & ~(0777)){
+       if (mode & ~(0777)) {
                yaffsfs_SetError(-EINVAL);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
+       obj = yaffsfs_FollowLink(obj, 0, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
-       else if(obj->my_dev->read_only)
+       else if (obj->my_dev->read_only)
                yaffsfs_SetError(-EROFS);
        else
-               retVal = yaffsfs_DoChMod(obj,mode);
+               retVal = yaffsfs_DoChMod(obj, mode);
 
        yaffsfs_Unlock();
 
@@ -1886,110 +2331,86 @@ int yaffs_chmod(const YCHAR *path, mode_t mode)
 
 }
 
-
 int yaffs_fchmod(int fd, mode_t mode)
 {
        struct yaffs_obj *obj;
        int retVal = -1;
 
-       if(mode & ~(0777)){
+       if (mode & ~(0777)) {
                yaffsfs_SetError(-EINVAL);
                return -1;
        }
 
        yaffsfs_Lock();
-       obj = yaffsfs_GetHandleObject(fd);
+       obj = yaffsfs_HandleToObject(fd);
 
-       if(!obj)
+       if (!obj)
                yaffsfs_SetError(-EBADF);
-       else if(obj->my_dev->read_only)
+       else if (obj->my_dev->read_only)
                yaffsfs_SetError(-EROFS);
        else
-               retVal = yaffsfs_DoChMod(obj,mode);
+               retVal = yaffsfs_DoChMod(obj, mode);
 
        yaffsfs_Unlock();
 
        return retVal;
 }
 
-
-static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path)
-{
-       YCHAR *alt_path = NULL;
-       int path_length;
-       int i;
-
-       /*
-        * We don't have a definition for max path length.
-        * We will use 3 * max name length instead.
-        */
-       *ret_path = NULL;
-       path_length = strnlen(path,(YAFFS_MAX_NAME_LENGTH+1)*3 +1);
-
-       /* If the last character is a path divider, then we need to
-        * trim it back so that the name look-up works properly.
-        * eg. /foo/new_dir/ -> /foo/newdir
-        * Curveball: Need to handle multiple path dividers:
-        * eg. /foof/sdfse///// -> /foo/sdfse
-        */
-       if(path_length > 0 && 
-               yaffsfs_IsPathDivider(path[path_length-1])){
-               alt_path = YMALLOC(path_length + 1);
-               if(!alt_path)
-                       return -1;
-               strcpy(alt_path, path);
-               for(i = path_length-1;
-                       i >= 0 && yaffsfs_IsPathDivider(alt_path[i]);
-                       i--)
-                       alt_path[i] = (YCHAR) 0;
-       }
-       *ret_path = alt_path;
-       return 0;
-}
-
 int yaffs_mkdir(const YCHAR *path, mode_t mode)
 {
        struct yaffs_obj *parent = NULL;
        struct yaffs_obj *dir = NULL;
        YCHAR *name;
        YCHAR *alt_path = NULL;
-       int retVal= -1;
+       int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
-       if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
+       if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
                yaffsfs_SetError(-ENOMEM);
                return -1;
        }
-       if(alt_path)
+       if (alt_path)
                path = alt_path;
-       
+
        yaffsfs_Lock();
-       parent = yaffsfs_FindDirectory(NULL,path,&name,0);
-       if(!parent)
+       parent = yaffsfs_FindDirectory(NULL, path, &name, 0, &notDir, &loop);
+       if (!parent && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(parent && yaffs_strnlen(name,5) == 0){
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!parent)
+               yaffsfs_SetError(-ENOENT);
+       else if (yaffsfs_TooManyObjects(parent->my_dev))
+               yaffsfs_SetError(-ENFILE);
+       else if (yaffs_strnlen(name, 5) == 0) {
                /* Trying to make the root itself */
                yaffsfs_SetError(-EEXIST);
-       } else if(parent && parent->my_dev->read_only)
+       } else if (parent->my_dev->read_only)
                yaffsfs_SetError(-EROFS);
        else {
-               dir = yaffs_create_dir(parent,name,mode,0,0);
-               if(dir)
+               dir = yaffs_create_dir(parent, name, mode, 0, 0);
+               if (dir)
                        retVal = 0;
-               else if (yaffs_find_by_name(parent,name))
-                       yaffsfs_SetError(-EEXIST); /* the name already exists */
+               else if (yaffs_find_by_name(parent, name))
+                       yaffsfs_SetError(-EEXIST);      /* name exists */
                else
-                       yaffsfs_SetError(-ENOSPC); /* just assume no space */
+                       yaffsfs_SetError(-ENOSPC);      /* assume no space */
        }
 
        yaffsfs_Unlock();
 
-       if(alt_path)
-               YFREE(alt_path);
+       kfree(alt_path);
 
        return retVal;
 }
@@ -1999,41 +2420,51 @@ int yaffs_rmdir(const YCHAR *path)
        int result;
        YCHAR *alt_path;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
-       if(yaffsfs_alt_dir_path(path, &alt_path) < 0){
+       if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
                yaffsfs_SetError(-ENOMEM);
                return -1;
        }
-       if(alt_path)
+       if (alt_path)
                path = alt_path;
-       result =  yaffsfs_DoUnlink(path,1);
-       if(alt_path)
-               YFREE(alt_path);
+       result = yaffsfs_DoUnlink(path, 1);
+
+       kfree(alt_path);
+
        return result;
 }
 
-
-void * yaffs_getdev(const YCHAR *path)
+void *yaffs_getdev(const YCHAR *path)
 {
-       struct yaffs_dev *dev=NULL;
+       struct yaffs_dev *dev = NULL;
        YCHAR *dummy;
-       dev = yaffsfs_FindDevice(path,&dummy);
+       dev = yaffsfs_FindDevice(path, &dummy);
        return (void *)dev;
 }
 
-int yaffs_mount2(const YCHAR *path,int read_only)
+int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt)
 {
-       int retVal=-1;
-       int result=YAFFS_FAIL;
-       struct yaffs_dev *dev=NULL;
+       int retVal = -1;
+       int result = YAFFS_FAIL;
+       struct yaffs_dev *dev = NULL;
 
-       T(YAFFS_TRACE_MOUNT,(TSTR("yaffs: Mounting %s" TENDSTR),path));
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path);
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
@@ -2043,16 +2474,23 @@ int yaffs_mount2(const YCHAR *path,int read_only)
        yaffsfs_InitHandles();
 
        dev = yaffsfs_FindMountPoint(path);
-       if(dev){
-               if(!dev->is_mounted){
+       if (dev) {
+               if (!dev->is_mounted) {
                        dev->read_only = read_only ? 1 : 0;
-                       result = yaffs_guts_initialise(dev);
-                       if(result == YAFFS_FAIL)
+                       if (skip_checkpt) {
+                               u8 skip = dev->param.skip_checkpt_rd;
+                               dev->param.skip_checkpt_rd = 1;
+                               result = yaffs_guts_initialise(dev);
+                               dev->param.skip_checkpt_rd = skip;
+                       } else {
+                               result = yaffs_guts_initialise(dev);
+                       }
+
+                       if (result == YAFFS_FAIL)
                                yaffsfs_SetError(-ENOMEM);
                        retVal = result ? 0 : -1;
 
-               }
-               else
+               } else
                        yaffsfs_SetError(-EBUSY);
        } else
                yaffsfs_SetError(-ENODEV);
@@ -2062,73 +2500,91 @@ int yaffs_mount2(const YCHAR *path,int read_only)
 
 }
 
+int yaffs_mount2(const YCHAR *path, int readonly)
+{
+       return yaffs_mount_common(path, readonly, 0);
+}
+
 int yaffs_mount(const YCHAR *path)
 {
-       return yaffs_mount2(path,0);
+       return yaffs_mount_common(path, 0, 0);
 }
 
 int yaffs_sync(const YCHAR *path)
 {
-        int retVal=-1;
-        struct yaffs_dev *dev=NULL;
-        YCHAR *dummy;
+       int retVal = -1;
+       struct yaffs_dev *dev = NULL;
+       YCHAR *dummy;
+
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
-        
-        yaffsfs_Lock();
-        dev = yaffsfs_FindDevice(path,&dummy);
-        if(dev){
-                if(dev->is_mounted){
-                        
-                        yaffs_flush_whole_cache(dev);
-                        yaffs_checkpoint_save(dev);
-                        retVal = 0;
-                        
-                } else
-                        yaffsfs_SetError(-EINVAL);
-                        
-        }else
-                yaffsfs_SetError(-ENODEV);
 
-        yaffsfs_Unlock();
-        return retVal;  
+       yaffsfs_Lock();
+       dev = yaffsfs_FindDevice(path, &dummy);
+       if (dev) {
+               if (!dev->is_mounted)
+                       yaffsfs_SetError(-EINVAL);
+               else if (dev->read_only)
+                       yaffsfs_SetError(-EROFS);
+               else {
+
+                       yaffs_flush_whole_cache(dev);
+                       yaffs_checkpoint_save(dev);
+                       retVal = 0;
+
+               }
+       } else
+               yaffsfs_SetError(-ENODEV);
+
+       yaffsfs_Unlock();
+       return retVal;
 }
 
+static int yaffsfs_IsDevBusy(struct yaffs_dev *dev)
+{
+       int i;
+       struct yaffs_obj *obj;
+
+       for (i = 0; i < YAFFSFS_N_HANDLES; i++) {
+               obj = yaffsfs_HandleToObject(i);
+               if (obj && obj->my_dev == dev)
+                       return 1;
+       }
+       return 0;
+}
 
 int yaffs_remount(const YCHAR *path, int force, int read_only)
 {
-        int retVal=-1;
-       struct yaffs_dev *dev=NULL;
-       yaffsfs_Handle *yh;
+       int retVal = -1;
+       struct yaffs_dev *dev = NULL;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
        dev = yaffsfs_FindMountPoint(path);
-       if(dev){
-               if(dev->is_mounted){
-                       int i;
-                       int inUse;
-
+       if (dev) {
+               if (dev->is_mounted) {
                        yaffs_flush_whole_cache(dev);
 
-                       for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse && !force; i++){
-                               yh = & yaffsfs_handle[i];
-                               if(yh->useCount>0 && 
-                                       yaffsfs_inode[yh->inodeId].iObj->my_dev == dev)
-                                       inUse = 1; /* the device is in use, can't unmount */
-                       }
-
-                       if(!inUse || force){
-                               if(read_only)
+                       if (force || !yaffsfs_IsDevBusy(dev)) {
+                               if (read_only)
                                        yaffs_checkpoint_save(dev);
-                               dev->read_only =  read_only ? 1 : 0;
+                               dev->read_only = read_only ? 1 : 0;
                                retVal = 0;
                        } else
                                yaffsfs_SetError(-EBUSY);
@@ -2136,8 +2592,7 @@ int yaffs_remount(const YCHAR *path, int force, int read_only)
                } else
                        yaffsfs_SetError(-EINVAL);
 
-       }
-       else
+       } else
                yaffsfs_SetError(-ENODEV);
 
        yaffsfs_Unlock();
@@ -2147,32 +2602,29 @@ int yaffs_remount(const YCHAR *path, int force, int read_only)
 
 int yaffs_unmount2(const YCHAR *path, int force)
 {
-        int retVal=-1;
-       struct yaffs_dev *dev=NULL;
+       int retVal = -1;
+       struct yaffs_dev *dev = NULL;
+
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
        dev = yaffsfs_FindMountPoint(path);
-       if(dev){
-               if(dev->is_mounted){
-                       int i;
+       if (dev) {
+               if (dev->is_mounted) {
                        int inUse;
-
                        yaffs_flush_whole_cache(dev);
                        yaffs_checkpoint_save(dev);
-
-                       for(i = inUse = 0; i < YAFFSFS_N_HANDLES && !inUse; i++){
-                               if(yaffsfs_handle[i].useCount > 0 && 
-                               yaffsfs_inode[yaffsfs_handle[i].inodeId].iObj->my_dev == dev)
-                                       inUse = 1; /* the device is in use, can't unmount */
-                       }
-
-                       if(!inUse || force){
-                               if(inUse)
+                       inUse = yaffsfs_IsDevBusy(dev);
+                       if (!inUse || force) {
+                               if (inUse)
                                        yaffsfs_BreakDeviceHandles(dev);
                                yaffs_deinitialise(dev);
 
@@ -2193,23 +2645,28 @@ int yaffs_unmount2(const YCHAR *path, int force)
 
 int yaffs_unmount(const YCHAR *path)
 {
-       return yaffs_unmount2(path,0);
+       return yaffs_unmount2(path, 0);
 }
 
-loff_t yaffs_freespace(const YCHAR *path)
+Y_LOFF_T yaffs_freespace(const YCHAR *path)
 {
-       loff_t retVal=-1;
-       struct yaffs_dev *dev=NULL;
+       Y_LOFF_T retVal = -1;
+       struct yaffs_dev *dev = NULL;
        YCHAR *dummy;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
-       dev = yaffsfs_FindDevice(path,&dummy);
-       if(dev  && dev->is_mounted){
+       dev = yaffsfs_FindDevice(path, &dummy);
+       if (dev && dev->is_mounted) {
                retVal = yaffs_get_n_free_chunks(dev);
                retVal *= dev->data_bytes_per_chunk;
 
@@ -2220,22 +2677,27 @@ loff_t yaffs_freespace(const YCHAR *path)
        return retVal;
 }
 
-loff_t yaffs_totalspace(const YCHAR *path)
+Y_LOFF_T yaffs_totalspace(const YCHAR *path)
 {
-       loff_t retVal=-1;
-       struct yaffs_dev *dev=NULL;
+       Y_LOFF_T retVal = -1;
+       struct yaffs_dev *dev = NULL;
        YCHAR *dummy;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
-       dev = yaffsfs_FindDevice(path,&dummy);
-       if(dev  && dev->is_mounted){
-               retVal = (dev->param.end_block - dev->param.start_block + 1) - 
-                       dev->param.n_reserved_blocks;
+       dev = yaffsfs_FindDevice(path, &dummy);
+       if (dev && dev->is_mounted) {
+               retVal = (dev->param.end_block - dev->param.start_block + 1) -
+                   dev->param.n_reserved_blocks;
                retVal *= dev->param.chunks_per_block;
                retVal *= dev->data_bytes_per_chunk;
 
@@ -2248,40 +2710,52 @@ loff_t yaffs_totalspace(const YCHAR *path)
 
 int yaffs_inodecount(const YCHAR *path)
 {
-       loff_t retVal= -1;
-       struct yaffs_dev *dev=NULL;
+       Y_LOFF_T retVal = -1;
+       struct yaffs_dev *dev = NULL;
        YCHAR *dummy;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
-       dev = yaffsfs_FindDevice(path,&dummy);
-       if(dev  && dev->is_mounted) {
-          int n_obj = dev->n_obj;
-          if(n_obj > dev->n_hardlinks)
-               retVal = n_obj - dev->n_hardlinks;
-       }
-       
-       if(retVal < 0)
+       dev = yaffsfs_FindDevice(path, &dummy);
+       if (dev && dev->is_mounted) {
+               int n_obj = dev->n_obj;
+               if (n_obj > dev->n_hardlinks)
+                       retVal = n_obj - dev->n_hardlinks;
+       }
+
+       if (retVal < 0)
                yaffsfs_SetError(-EINVAL);
-       
+
        yaffsfs_Unlock();
-       return retVal;  
+       return retVal;
 }
 
-
 void yaffs_add_device(struct yaffs_dev *dev)
 {
+       struct list_head *cfg;
+       /* First check that the device is not in the list. */
+
+       list_for_each(cfg, &yaffsfs_deviceList) {
+               if (dev == list_entry(cfg, struct yaffs_dev, dev_list))
+                       return;
+       }
+
        dev->is_mounted = 0;
        dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback;
 
-       if(!dev->dev_list.next)
+       if (!dev->dev_list.next)
                INIT_LIST_HEAD(&dev->dev_list);
 
-       list_add(&dev->dev_list,&yaffsfs_deviceList);
+       list_add(&dev->dev_list, &yaffsfs_deviceList);
 }
 
 void yaffs_remove_device(struct yaffs_dev *dev)
@@ -2289,94 +2763,97 @@ void yaffs_remove_device(struct yaffs_dev *dev)
        list_del_init(&dev->dev_list);
 }
 
+/* Functions to iterate through devices. NB Use with extreme care! */
 
+static struct list_head *dev_iterator;
+void yaffs_dev_rewind(void)
+{
+       dev_iterator = yaffsfs_deviceList.next;
+}
 
-
-/* Directory search stuff. */
-
-/*
- * Directory search context
- *
- * NB this is an opaque structure.
- */
-
-
-typedef struct
+struct yaffs_dev *yaffs_next_dev(void)
 {
-       u32 magic;
-       yaffs_dirent de;                /* directory entry being used by this dsc */
-       YCHAR name[NAME_MAX+1];         /* name of directory being searched */
-        struct yaffs_obj *dirObj;           /* ptr to directory being searched */
-        struct yaffs_obj *nextReturn;       /* obj to be returned by next readddir */
-        int offset;
-        struct list_head others;       
-} yaffsfs_DirectorySearchContext;
+       struct yaffs_dev *retval;
 
+       if (!dev_iterator)
+               return NULL;
+       if (dev_iterator == &yaffsfs_deviceList)
+               return NULL;
 
+       retval = list_entry(dev_iterator, struct yaffs_dev, dev_list);
+       dev_iterator = dev_iterator->next;
+       return retval;
+}
 
-static struct list_head search_contexts;
+/* Directory search stuff. */
 
+static struct list_head search_contexts;
 
-static void yaffsfs_SetDirRewound(yaffsfs_DirectorySearchContext *dsc)
+static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt *dsc)
 {
-       if(dsc &&
-          dsc->dirObj &&
-          dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+       if (dsc &&
+           dsc->dirObj &&
+           dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
 
-           dsc->offset = 0;
+               dsc->offset = 0;
 
-           if( list_empty(&dsc->dirObj->variant.dir_variant.children))
-                dsc->nextReturn = NULL;
-           else
-                dsc->nextReturn = list_entry(dsc->dirObj->variant.dir_variant.children.next,
-                                                struct yaffs_obj,siblings);
-        } else {
+               if (list_empty(&dsc->dirObj->variant.dir_variant.children))
+                       dsc->nextReturn = NULL;
+               else
+                       dsc->nextReturn =
+                           list_entry(dsc->dirObj->variant.dir_variant.
+                                      children.next, struct yaffs_obj,
+                                      siblings);
+       } else {
                /* Hey someone isn't playing nice! */
        }
 }
 
-static void yaffsfs_DirAdvance(yaffsfs_DirectorySearchContext *dsc)
+static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt *dsc)
 {
-       if(dsc &&
-          dsc->dirObj &&
-           dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+       if (dsc &&
+           dsc->dirObj &&
+           dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
 
-           if( dsc->nextReturn == NULL ||
-               list_empty(&dsc->dirObj->variant.dir_variant.children))
-                dsc->nextReturn = NULL;
-           else {
-                   struct list_head *next = dsc->nextReturn->siblings.next;
+               if (dsc->nextReturn == NULL ||
+                   list_empty(&dsc->dirObj->variant.dir_variant.children))
+                       dsc->nextReturn = NULL;
+               else {
+                       struct list_head *next = dsc->nextReturn->siblings.next;
 
-                   if( next == &dsc->dirObj->variant.dir_variant.children)
-                        dsc->nextReturn = NULL; /* end of list */
-                   else
-                        dsc->nextReturn = list_entry(next,struct yaffs_obj,siblings);
-           }
-        } else {
-                /* Hey someone isn't playing nice! */
+                       if (next == &dsc->dirObj->variant.dir_variant.children)
+                               dsc->nextReturn = NULL; /* end of list */
+                       else
+                               dsc->nextReturn = list_entry(next,
+                                                            struct yaffs_obj,
+                                                            siblings);
+               }
+       } else {
+               /* Hey someone isn't playing nice! */
        }
 }
 
 static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
 {
 
-        struct list_head *i;
-        yaffsfs_DirectorySearchContext *dsc;
+       struct list_head *i;
+       struct yaffsfs_DirSearchContxt *dsc;
 
-        /* if search contexts not initilised then skip */
-        if(!search_contexts.next)
-                return;
+       /* if search contexts not initilised then skip */
+       if (!search_contexts.next)
+               return;
 
-        /* Iterate through 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);
-                }
+       /* Iterate through 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, struct yaffsfs_DirSearchContxt,
+                                        others);
+                       if (dsc->nextReturn == obj)
+                               yaffsfs_DirAdvance(dsc);
+               }
        }
 
 }
@@ -2384,62 +2861,84 @@ static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj)
 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
 {
        yaffs_DIR *dir = NULL;
-       struct yaffs_obj *obj = NULL;
-       yaffsfs_DirectorySearchContext *dsc = NULL;
+       struct yaffs_obj *obj = NULL;
+       struct yaffsfs_DirSearchContxt *dsc = NULL;
+       int notDir = 0;
+       int loop = 0;
 
-       if(yaffsfs_CheckPath(dirname) < 0){
+       if (!dirname) {
+               yaffsfs_SetError(-EFAULT);
+               return NULL;
+       }
+
+       if (yaffsfs_CheckPath(dirname) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
-               return -1;
+               return NULL;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,dirname,0,1,NULL);
+       obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, &notDir, &loop);
 
-       if(obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY){
+       if (!obj && notDir)
+               yaffsfs_SetError(-ENOTDIR);
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!obj)
+               yaffsfs_SetError(-ENOENT);
+       else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY)
+               yaffsfs_SetError(-ENOTDIR);
+       else {
+               int i;
 
-               dsc = YMALLOC(sizeof(yaffsfs_DirectorySearchContext));
-               dir = (yaffs_DIR *)dsc;
+               for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) {
+                       if (!yaffsfs_dsc[i].inUse)
+                               dsc = &yaffsfs_dsc[i];
+               }
+
+               dir = (yaffs_DIR *) dsc;
 
-               if(dsc){
-                       memset(dsc,0,sizeof(yaffsfs_DirectorySearchContext));
-                        dsc->magic = YAFFS_MAGIC;
-                        dsc->dirObj = obj;
-                        yaffs_strncpy(dsc->name,dirname,NAME_MAX);
-                        INIT_LIST_HEAD(&dsc->others);
+               if (dsc) {
+                       memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContxt));
+                       dsc->inUse = 1;
+                       dsc->dirObj = obj;
+                       yaffs_strncpy(dsc->name, dirname, NAME_MAX);
+                       INIT_LIST_HEAD(&dsc->others);
 
-                        if(!search_contexts.next)
-                                INIT_LIST_HEAD(&search_contexts);
+                       if (!search_contexts.next)
+                               INIT_LIST_HEAD(&search_contexts);
 
-                        list_add(&dsc->others,&search_contexts);       
-                        yaffsfs_SetDirRewound(dsc);
+                       list_add(&dsc->others, &search_contexts);
+                       yaffsfs_SetDirRewound(dsc);
                }
 
-        }
+       }
 
        yaffsfs_Unlock();
 
        return dir;
 }
 
-struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
+struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp)
 {
-       yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
+       struct yaffsfs_DirSearchContxt *dsc;
        struct yaffs_dirent *retVal = NULL;
 
+       dsc = (struct yaffsfs_DirSearchContxt *) dirp;
        yaffsfs_Lock();
 
-       if(dsc && dsc->magic == YAFFS_MAGIC){
+       if (dsc && dsc->inUse) {
                yaffsfs_SetError(0);
-               if(dsc->nextReturn){
-                       dsc->de.d_ino = yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
+               if (dsc->nextReturn) {
+                       dsc->de.d_ino =
+                           yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id;
                        dsc->de.d_dont_use = (unsigned)dsc->nextReturn;
                        dsc->de.d_off = dsc->offset++;
-                       yaffs_get_obj_name(dsc->nextReturn,dsc->de.d_name,NAME_MAX);
-                       if(yaffs_strnlen(dsc->de.d_name,NAME_MAX+1) == 0)
-                       {
+                       yaffs_get_obj_name(dsc->nextReturn,
+                                          dsc->de.d_name, NAME_MAX);
+                       if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) {
                                /* this should not happen! */
-                               yaffs_strcpy(dsc->de.d_name,_Y("zz"));
+                               yaffs_strcpy(dsc->de.d_name, _Y("zz"));
                        }
                        dsc->de.d_reclen = sizeof(struct yaffs_dirent);
                        retVal = &dsc->de;
@@ -2455,10 +2954,11 @@ struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp)
 
 }
 
-
 void yaffs_rewinddir(yaffs_DIR *dirp)
 {
-       yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
+       struct yaffsfs_DirSearchContxt *dsc;
+
+       dsc = (struct yaffsfs_DirSearchContxt *) dirp;
 
        yaffsfs_Lock();
 
@@ -2467,47 +2967,64 @@ void yaffs_rewinddir(yaffs_DIR *dirp)
        yaffsfs_Unlock();
 }
 
-
 int yaffs_closedir(yaffs_DIR *dirp)
 {
-       yaffsfs_DirectorySearchContext *dsc = (yaffsfs_DirectorySearchContext *)dirp;
+       struct yaffsfs_DirSearchContxt *dsc;
+
+       dsc = (struct yaffsfs_DirSearchContxt *) dirp;
+
+       if (!dsc) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
-        yaffsfs_Lock();
-        dsc->magic = 0;
-        list_del(&dsc->others); /* unhook from list */
-        YFREE(dsc);
-        yaffsfs_Unlock();
-        return 0;
+       yaffsfs_Lock();
+       dsc->inUse = 0;
+       list_del(&dsc->others); /* unhook from list */
+       yaffsfs_Unlock();
+       return 0;
 }
 
 /* End of directory stuff */
 
-
 int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath)
 {
        struct yaffs_obj *parent = NULL;
        struct yaffs_obj *obj;
        YCHAR *name;
-       int retVal= -1;
-       int mode = 0; /* ignore for now */
+       int retVal = -1;
+       int mode = 0;           /* ignore for now */
+       int notDir = 0;
+       int loop = 0;
 
-       if(yaffsfs_CheckPath(newpath) < 0){
+       if (!oldpath || !newpath) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
+
        yaffsfs_Lock();
-       parent = yaffsfs_FindDirectory(NULL,newpath,&name,0);
-       if(!parent)
+       parent = yaffsfs_FindDirectory(NULL, newpath, &name, 0, &notDir, &loop);
+       if (!parent && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if( strlen(name) < 1)
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!parent || yaffs_strnlen(name, 5) < 1)
                yaffsfs_SetError(-ENOENT);
-       else if(parent->my_dev->read_only)
+       else if (yaffsfs_TooManyObjects(parent->my_dev))
+               yaffsfs_SetError(-ENFILE);
+       else if (parent->my_dev->read_only)
                yaffsfs_SetError(-EROFS);
-       else if(parent){
-               obj = yaffs_create_symlink(parent,name,mode,0,0,oldpath);
-               if(obj)
+       else if (parent) {
+               obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath);
+               if (obj)
                        retVal = 0;
-               else if (yaffsfs_FindObject(NULL,newpath,0,0, NULL))
+               else if (yaffsfs_FindObject
+                        (NULL, newpath, 0, 0, NULL, NULL, NULL))
                        yaffsfs_SetError(-EEXIST);
                else
                        yaffsfs_SetError(-ENOSPC);
@@ -2523,22 +3040,31 @@ int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
 {
        struct yaffs_obj *obj = NULL;
        struct yaffs_obj *dir = NULL;
-       int retVal= -1;
+       int retVal = -1;
+       int notDir = 0;
+       int loop = 0;
+
+       if (!path || !buf) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,path,0,1, &dir);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, &notDir, &loop);
 
-       if(!dir) 
+       if (!dir && notDir)
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj) 
+       else if (loop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!dir || !obj)
                yaffsfs_SetError(-ENOENT);
-       else if(obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
+       else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK)
                yaffsfs_SetError(-EINVAL);
        else {
                YCHAR *alias = obj->variant.symlink_variant.alias;
-               memset(buf,0,bufsiz);
-               yaffs_strncpy(buf,alias,bufsiz - 1);
+               memset(buf, 0, bufsiz);
+               yaffs_strncpy(buf, alias, bufsiz - 1);
                retVal = 0;
        }
        yaffsfs_Unlock();
@@ -2553,37 +3079,52 @@ int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
        struct yaffs_obj *obj_dir = NULL;
        struct yaffs_obj *lnk_dir = NULL;
        int retVal = -1;
+       int notDirObj = 0;
+       int notDirLnk = 0;
+       int objLoop = 0;
+       int lnkLoop = 0;
        YCHAR *newname;
 
-       if(yaffsfs_CheckPath(linkpath) < 0){
+       if (!oldpath || !linkpath) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
        yaffsfs_Lock();
 
-       obj = yaffsfs_FindObject(NULL,oldpath,0,1,&obj_dir);
-       lnk = yaffsfs_FindObject(NULL,linkpath,0,0,NULL);
-       lnk_dir = yaffsfs_FindDirectory(NULL,linkpath,&newname,0);
+       obj = yaffsfs_FindObject(NULL, oldpath, 0, 1,
+                                &obj_dir, &notDirObj, &objLoop);
+       lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL);
+       lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname,
+                                       0, &notDirLnk, &lnkLoop);
 
-       if(!obj_dir || !lnk_dir)
+       if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk))
                yaffsfs_SetError(-ENOTDIR);
-       else if(!obj)
+       else if (objLoop || lnkLoop)
+               yaffsfs_SetError(-ELOOP);
+       else if (!obj_dir || !lnk_dir || !obj)
                yaffsfs_SetError(-ENOENT);
-       else if(obj->my_dev->read_only)
-               yaffsfs_SetError(-EINVAL);
-       else if(lnk)
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else if (yaffsfs_TooManyObjects(obj->my_dev))
+               yaffsfs_SetError(-ENFILE);
+       else if (lnk)
                yaffsfs_SetError(-EEXIST);
-       else if(lnk_dir->my_dev != obj->my_dev)
+       else if (lnk_dir->my_dev != obj->my_dev)
                yaffsfs_SetError(-EXDEV);
-       else {          
+       else {
                retVal = yaffsfs_CheckNameLength(newname);
-               
-               if(retVal == 0) {
-                       lnk = yaffs_link_obj(lnk_dir,newname,obj);
-                       if(lnk)
+
+               if (retVal == 0) {
+                       lnk = yaffs_link_obj(lnk_dir, newname, obj);
+                       if (lnk)
                                retVal = 0;
-                       else{
+                       else {
                                yaffsfs_SetError(-ENOSPC);
                                retVal = -1;
                        }
@@ -2596,19 +3137,18 @@ int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
 
 int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev)
 {
-       pathname=pathname;
-       mode=mode;
-       dev=dev;
+       (void) pathname;
+       (void) mode;
+       (void) dev;
 
        yaffsfs_SetError(-EINVAL);
        return -1;
 }
 
-
 /*
  * D E B U G   F U N C T I O N S
  */
+
 /*
  * yaffs_n_handles()
  * Returns number of handles attached to the object
@@ -2617,14 +3157,19 @@ int yaffs_n_handles(const YCHAR *path)
 {
        struct yaffs_obj *obj;
 
-       if(yaffsfs_CheckPath(path) < 0){
+       if (!path) {
+               yaffsfs_SetError(-EFAULT);
+               return -1;
+       }
+
+       if (yaffsfs_CheckPath(path) < 0) {
                yaffsfs_SetError(-ENAMETOOLONG);
                return -1;
        }
 
-       obj = yaffsfs_FindObject(NULL,path,0,1,NULL);
+       obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
 
-       if(obj)
+       if (obj)
                return yaffsfs_CountHandles(obj);
        else
                return -1;
@@ -2644,34 +3189,30 @@ int yaffs_set_error(int error)
 int yaffs_dump_dev(const YCHAR *path)
 {
 #if 1
-       path=path;
+       (void) path;
 #else
        YCHAR *rest;
 
-       struct yaffs_obj *obj = yaffsfs_FindRoot(path,&rest);
+       struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest);
 
-       if(obj){
+       if (obj) {
                struct yaffs_dev *dev = obj->my_dev;
 
                printf("\n"
-                          "n_page_writes.......... %d\n"
-                          "n_page_reads........... %d\n"
-                          "n_erasures....... %d\n"
-                          "n_gc_copies............ %d\n"
-                          "garbageCollections... %d\n"
-                          "passiveGarbageColl'ns %d\n"
-                          "\n",
-                               dev->n_page_writes,
-                               dev->n_page_reads,
-                               dev->n_erasures,
-                               dev->n_gc_copies,
-                               dev->garbageCollections,
-                               dev->passiveGarbageCollections
-               );
+                      "n_page_writes.......... %d\n"
+                      "n_page_reads........... %d\n"
+                      "n_erasures....... %d\n"
+                      "n_gc_copies............ %d\n"
+                      "garbageCollections... %d\n"
+                      "passiveGarbageColl'ns %d\n"
+                      "\n",
+                      dev->n_page_writes,
+                      dev->n_page_reads,
+                      dev->n_erasures,
+                      dev->n_gc_copies,
+                      dev->garbageCollections, dev->passiveGarbageCollections);
 
        }
-
 #endif
        return 0;
 }
-