yaffsfs.c: Fix NULL dereference in yaffs_unmount2_reldev()
[yaffs2.git] / direct / yaffsfs.c
index a01155ff9320b66051e465d6809aaa14b792e654..823f7edcfc21c9dd7e2247e1da8781e8a74eb7e1 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
  *
- * Copyright (C) 2002-2011 Aleph One Ltd.
- *   for Toby Churchill Ltd and Brightstar Engineering
+ * Copyright (C) 2002-2018 Aleph One Ltd.
  *
  * Created by Charles Manning <charles@aleph1.co.uk>
  *
@@ -19,6 +18,7 @@
 
 #include "string.h"
 
+#define YAFFS_MAX_RW_SIZE      0x70000000
 #define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
 
 #ifndef NULL
@@ -346,8 +346,10 @@ static int yaffsfs_PutFileDes(int fdId)
                fd = &yaffsfs_fd[fdId];
                fd->handleCount--;
                if (fd->handleCount < 1) {
-                       if (fd->isDir)
+                       if (fd->isDir) {
                                yaffsfs_closedir_no_lock(fd->v.dir);
+                               fd->v.dir = NULL;
+                       }
                        if (fd->inodeId >= 0) {
                                yaffsfs_PutInode(fd->inodeId);
                                fd->inodeId = -1;
@@ -398,7 +400,7 @@ static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev)
  *  Stuff to handle names.
  */
 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
-
+#ifndef CONFIG_YAFFS_WINCE
 static int yaffs_toupper(YCHAR a)
 {
        if (a >= 'a' && a <= 'z')
@@ -406,6 +408,7 @@ static int yaffs_toupper(YCHAR a)
        else
                return a;
 }
+#endif
 
 static int yaffsfs_Match(YCHAR a, YCHAR b)
 {
@@ -432,7 +435,7 @@ static int yaffsfs_IsPathDivider(YCHAR ch)
        return 0;
 }
 
-static int yaffsfs_CheckNameLength(const char *name)
+static int yaffsfs_CheckNameLength(const YCHAR *name)
 {
        int retVal = 0;
 
@@ -514,17 +517,17 @@ static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path,
                thisMatchLength = 0;
                matching = 1;
 
+
                if(!p)
                        continue;
 
-               while (matching && *p && *leftOver) {
-                       /* Skip over any /s */
-                       while (yaffsfs_IsPathDivider(*p))
-                               p++;
+               /* Skip over any leading  /s */
+               while (yaffsfs_IsPathDivider(*p))
+                       p++;
+               while (yaffsfs_IsPathDivider(*leftOver))
+                       leftOver++;
 
-                       /* Skip over any /s */
-                       while (yaffsfs_IsPathDivider(*leftOver))
-                               leftOver++;
+               while (matching && *p && *leftOver) {
 
                        /* Now match the text part */
                        while (matching &&
@@ -538,6 +541,16 @@ static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path,
                                        matching = 0;
                                }
                        }
+
+                       if ((*p && !yaffsfs_IsPathDivider(*p)) ||
+                           (*leftOver && !yaffsfs_IsPathDivider(*leftOver)))
+                               matching = 0;
+                       else {
+                               while (yaffsfs_IsPathDivider(*p))
+                                       p++;
+                               while (yaffsfs_IsPathDivider(*leftOver))
+                                       leftOver++;
+                       }
                }
 
                /* Skip over any /s in leftOver */
@@ -558,7 +571,6 @@ static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path,
                        retval = dev;
                        longestMatch = thisMatchLength;
                }
-
        }
        return retval;
 }
@@ -737,7 +749,20 @@ static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir,
        if (dirOut)
                *dirOut = dir;
 
-       if (dir && *name)
+       /* At this stage we have looked up directory part and have the name part
+        * in name if there is one.
+        *
+        *  eg /nand/x/ will give us a name of ""
+        *     /nand/x will give us a name of "x"
+        *
+        * Since the name part might be "." or ".." which need to be fixed.
+        */
+       if (dir && (yaffs_strcmp(name, _Y("..")) == 0)) {
+               dir = dir->parent;
+               obj = dir;
+       } else if (dir && (yaffs_strcmp(name, _Y(".")) == 0))
+               obj = dir;
+       else if (dir && *name)
                obj = yaffs_find_by_name(dir, name);
        else
                obj = dir;
@@ -813,7 +838,7 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
        int notDir = 0;
        int loop = 0;
        int is_dir = 0;
-       yaffs_DIR *dsc;
+       yaffs_DIR *dsc = NULL;
 
        if (yaffsfs_CheckMemRegion(path, 0, 0)< 0) {
                yaffsfs_SetError(-EFAULT);
@@ -830,7 +855,7 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                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 ? */
@@ -846,7 +871,7 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
 
        if (handle < 0) {
                yaffsfs_SetError(-ENFILE);
-               errorReported = 1;
+               errorReported = __LINE__;
        } else {
 
                fd = yaffsfs_HandleToFileDes(handle);
@@ -867,21 +892,22 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                        is_dir = (obj->variant_type ==
                                        YAFFS_OBJECT_TYPE_DIRECTORY);
 
-                       /* A directory can't be opened except for read */
-                       if ( is_dir &&
-                           (writeRequested || !readRequested ||
-                               (oflag & ~O_RDONLY))) {
-                               openDenied = 1;
-                               yaffsfs_SetError(-EISDIR);
-                               errorReported = 1;
+                       /*
+                        * A directory can't be opened except for read, so we
+                        * ignore other flags
+                        */
+                       if (is_dir) {
+                               writeRequested = 0;
+                               readRequested = 1;
+                               rwflags = O_RDONLY;
                        }
 
                        if(is_dir) {
                                dsc = yaffsfs_opendir_reldir_no_lock(reldir, path);
                                if (!dsc) {
-                                       openDenied = 1;
+                                       openDenied = __LINE__;
                                        yaffsfs_SetError(-ENFILE);
-                                       errorReported = 1;
+                                       errorReported = __LINE__;
                                }
                        }
 
@@ -890,28 +916,28 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                         */
                        if (!errorReported &&
                            (oflag & O_EXCL) && (oflag & O_CREAT)) {
-                               openDenied = 1;
+                               openDenied = __LINE__;
                                yaffsfs_SetError(-EEXIST);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        }
 
                        /* Check file permissions */
-                       if (readRequested && !(obj->yst_mode & S_IREAD))
-                               openDenied = 1;
+                       if (readRequested && !(obj->yst_mode & S_IRUSR))
+                               openDenied = __LINE__;
 
-                       if (writeRequested && !(obj->yst_mode & S_IWRITE))
-                               openDenied = 1;
+                       if (writeRequested && !(obj->yst_mode & S_IWUSR))
+                               openDenied = __LINE__;
 
                        if (!errorReported && writeRequested &&
                            obj->my_dev->read_only) {
-                               openDenied = 1;
+                               openDenied = __LINE__;
                                yaffsfs_SetError(-EROFS);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        }
 
                        if (openDenied && !errorReported) {
                                yaffsfs_SetError(-EACCES);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        }
 
                        /* Check sharing of an existing object. */
@@ -944,9 +970,9 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                                    (!shareRead && alreadyReading) ||
                                    (!sharedWriteAllowed && writeRequested) ||
                                    (!shareWrite && alreadyWriting)) {
-                                       openDenied = 1;
+                                       openDenied = __LINE__;
                                        yaffsfs_SetError(-EBUSY);
-                                       errorReported = 1;
+                                       errorReported = __LINE__;
                                }
                        }
 
@@ -960,13 +986,13 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                                                    &notDir, &loop);
                        if (!dir && notDir) {
                                yaffsfs_SetError(-ENOTDIR);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        } else if (loop) {
                                yaffsfs_SetError(-ELOOP);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        } else if (!dir) {
                                yaffsfs_SetError(-ENOENT);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        }
                }
 
@@ -974,22 +1000,22 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                        /* Let's see if we can create this file */
                        if (dir->my_dev->read_only) {
                                yaffsfs_SetError(-EROFS);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        } else if (yaffsfs_TooManyObjects(dir->my_dev)) {
                                yaffsfs_SetError(-ENFILE);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        } else
                                obj = yaffs_create_file(dir, name, mode, 0, 0);
 
                        if (!obj && !errorReported) {
                                yaffsfs_SetError(-ENOSPC);
-                               errorReported = 1;
+                               errorReported = __LINE__;
                        }
                }
 
                if (!obj && dir && !errorReported && !(oflag & O_CREAT)) {
                        yaffsfs_SetError(-ENOENT);
-                       errorReported = 1;
+                       errorReported = __LINE__;
                }
 
                if (obj && !openDenied) {
@@ -1022,6 +1048,9 @@ int yaffs_open_sharing_reldir(struct yaffs_obj *reldir, const YCHAR *path,
                        if (!is_dir && (oflag & O_TRUNC) && fd->writing)
                                yaffs_resize_file(obj, 0);
                } else {
+                       if (dsc)
+                               yaffsfs_closedir_no_lock(dsc);
+                       dsc = NULL;
                        yaffsfs_PutHandle(handle);
                        if (!errorReported)
                                yaffsfs_SetError(0);    /* Problem */
@@ -1077,7 +1106,7 @@ static int yaffs_Dofsync(int handle, int datasync)
        else if (obj->my_dev->read_only)
                yaffsfs_SetError(-EROFS);
        else {
-               yaffs_flush_file(obj, 1, datasync);
+               yaffs_flush_file(obj, 1, datasync, 0);
                retVal = 0;
        }
 
@@ -1119,7 +1148,7 @@ int yaffs_close(int handle)
        else {
                /* clean up */
                if(!f->isDir)
-                       yaffs_flush_file(obj, 1, 0);
+                       yaffs_flush_file(obj, 1, 0, 1);
                yaffsfs_PutHandle(handle);
                retVal = 0;
        }
@@ -1160,7 +1189,7 @@ static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
                /* Not a reading handle */
                yaffsfs_SetError(-EINVAL);
                totalRead = -1;
-       } else if (nbyte > YAFFS_MAX_FILE_SIZE) {
+       } else if (nbyte > YAFFS_MAX_RW_SIZE) {
                yaffsfs_SetError(-EINVAL);
                totalRead = -1;
        } else {
@@ -1184,7 +1213,7 @@ static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
                endPos = pos + nbyte;
 
                if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
-                   nbyte > YAFFS_MAX_FILE_SIZE ||
+                   nbyte > YAFFS_MAX_RW_SIZE ||
                    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
                        totalRead = -1;
                        nbyte = 0;
@@ -1193,7 +1222,7 @@ static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
                while (nbyte > 0) {
                        nToRead = YAFFSFS_RW_SIZE -
                            (pos & (YAFFSFS_RW_SIZE - 1));
-                       if (nToRead > nbyte)
+                       if (nToRead > (int)nbyte)
                                nToRead = nbyte;
 
                        /* Tricky bit...
@@ -1297,7 +1326,7 @@ static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
                endPos = pos + nbyte;
 
                if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE ||
-                   nbyte > YAFFS_MAX_FILE_SIZE ||
+                   nbyte > YAFFS_MAX_RW_SIZE ||
                    endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) {
                        totalWritten = -1;
                        nbyte = 0;
@@ -1307,7 +1336,7 @@ static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
 
                        nToWrite = YAFFSFS_RW_SIZE -
                            (pos & (YAFFSFS_RW_SIZE - 1));
-                       if (nToWrite > nbyte)
+                       if (nToWrite > (int)nbyte)
                                nToWrite = nbyte;
 
                        /* Tricky bit...
@@ -1566,6 +1595,56 @@ int yaffs_unlink(const YCHAR *path)
        return yaffs_unlink_reldir(NULL, path);
 }
 
+int yaffs_funlink(int fd)
+{
+       struct yaffs_obj *obj;
+       int retVal = -1;
+
+       yaffsfs_Lock();
+       obj = yaffsfs_HandleToObject(fd);
+
+       if (!obj)
+               yaffsfs_SetError(-EBADF);
+       else if (obj->my_dev->read_only)
+               yaffsfs_SetError(-EROFS);
+       else if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY &&
+                       !(list_empty(&obj->variant.dir_variant.children)))
+               yaffsfs_SetError(-ENOTEMPTY);
+       else if (obj == obj->my_dev->root_dir)
+               yaffsfs_SetError(-EBUSY);       /* Can't rmdir a root */
+       else if (yaffs_unlink_obj(obj) == YAFFS_OK)
+                       retVal = 0;
+
+       yaffsfs_Unlock();
+
+       return retVal;
+}
+
+int yaffs_fgetfl(int fd, int *flags)
+{
+       struct yaffsfs_FileDes *fdp = yaffsfs_HandleToFileDes(fd);
+       int retVal;
+
+       yaffsfs_Lock();
+
+       if(!flags || !fdp) {
+               yaffsfs_SetError(-EINVAL);
+               retVal = -1;
+       } else {
+               if (fdp->reading && fdp->writing)
+                       *flags = O_RDWR;
+               else if (fdp->writing)
+                       *flags = O_WRONLY;
+               else
+                       *flags = O_RDONLY;
+               retVal = 0;
+       }
+
+       yaffsfs_Unlock();
+       return retVal;
+}
+
+
 static int rename_file_over_dir(struct yaffs_obj *obj, struct yaffs_obj *newobj)
 {
        if (obj && obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY &&
@@ -1713,7 +1792,7 @@ static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf)
        obj = yaffs_get_equivalent_obj(obj);
 
        if (obj && buf) {
-               buf->st_dev = (int)obj->my_dev->os_context;
+               buf->st_dev = 0;
                buf->st_ino = obj->obj_id;
                buf->st_mode = obj->yst_mode & ~S_IFMT;
 
@@ -1854,8 +1933,6 @@ static int yaffsfs_DoUtime(struct yaffs_obj *obj,
                           const struct yaffs_utimbuf *buf)
 {
        int retVal = -1;
-       int result;
-
        struct yaffs_utimbuf local;
 
        obj = yaffs_get_equivalent_obj(obj);
@@ -1865,19 +1942,27 @@ static int yaffsfs_DoUtime(struct yaffs_obj *obj,
                return -1;
        }
 
+#if !CONFIG_YAFFS_WINCE
+       // if the the buffer is null then create one with the fields set to the current time.
        if (!buf) {
                local.actime = Y_CURRENT_TIME;
                local.modtime = local.actime;
                buf = &local;
        }
 
+       // copy the buffer's time into the obj.
        if (obj) {
+               int result;
+
                obj->yst_atime = buf->actime;
                obj->yst_mtime = buf->modtime;
+
+               // set the obj to dirty to cause it to be written to flash during the next flush operation.
                obj->dirty = 1;
-               result = yaffs_flush_file(obj, 0, 0);
+               result = yaffs_flush_file(obj, 0, 0, 0);
                retVal = result == YAFFS_OK ? 0 : -1;
        }
+#endif
 
        return retVal;
 }
@@ -2460,7 +2545,7 @@ int yaffs_set_wince_times(int fd,
                }
 
                obj->dirty = 1;
-               result = yaffs_flush_file(obj, 0, 0);
+               result = yaffs_flush_file(obj, 0, 0, 0);
                retVal = 0;
        } else
                /* bad handle */
@@ -2483,7 +2568,7 @@ static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode)
        if (obj) {
                obj->yst_mode = mode;
                obj->dirty = 1;
-               result = yaffs_flush_file(obj, 0, 0);
+               result = yaffs_flush_file(obj, 0, 0, 0);
        }
 
        return result == YAFFS_OK ? 0 : -1;
@@ -2528,11 +2613,11 @@ int yaffs_access_reldir(struct yaffs_obj *reldir, const YCHAR *path, int amode)
        else {
                int access_ok = 1;
 
-               if ((amode & R_OK) && !(obj->yst_mode & S_IREAD))
+               if ((amode & R_OK) && !(obj->yst_mode & S_IRUSR))
                        access_ok = 0;
-               if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
+               if ((amode & W_OK) && !(obj->yst_mode & S_IWUSR))
                        access_ok = 0;
-               if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
+               if ((amode & X_OK) && !(obj->yst_mode & S_IXUSR))
                        access_ok = 0;
 
                if (!access_ok)
@@ -2838,7 +2923,9 @@ int yaffs_mount(const YCHAR *path)
        return yaffs_mount_common(NULL, path, 0, 0);
 }
 
-int yaffs_sync_common(struct yaffs_dev *dev, const YCHAR *path)
+static int yaffs_sync_common(struct yaffs_dev *dev,
+                            const YCHAR *path,
+                            int do_checkpt)
 {
        int retVal = -1;
        YCHAR *dummy;
@@ -2866,8 +2953,9 @@ int yaffs_sync_common(struct yaffs_dev *dev, const YCHAR *path)
                        yaffsfs_SetError(-EROFS);
                else {
 
-                       yaffs_flush_whole_cache(dev);
-                       yaffs_checkpoint_save(dev);
+                       yaffs_flush_whole_cache(dev, 0);
+                       if (do_checkpt)
+                               yaffs_checkpoint_save(dev);
                        retVal = 0;
 
                }
@@ -2878,14 +2966,75 @@ int yaffs_sync_common(struct yaffs_dev *dev, const YCHAR *path)
        return retVal;
 }
 
+int yaffs_sync_files_reldev(struct yaffs_dev *dev)
+{
+       return yaffs_sync_common(dev, NULL, 0);
+}
+
+int yaffs_sync_files(const YCHAR *path)
+{
+       return yaffs_sync_common(NULL, path, 0);
+}
+
 int yaffs_sync_reldev(struct yaffs_dev *dev)
 {
-       return yaffs_sync_common(dev, NULL);
+       return yaffs_sync_common(dev, NULL, 1);
 }
 
 int yaffs_sync(const YCHAR *path)
 {
-       return yaffs_sync_common(NULL, path);
+       return yaffs_sync_common(NULL, path, 1);
+}
+
+
+static int yaffsfs_bg_gc_common(struct yaffs_dev *dev,
+                               const YCHAR *path,
+                               int urgency)
+{
+       int retVal = -1;
+       YCHAR *dummy;
+
+       if (!dev) {
+               if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+                       yaffsfs_SetError(-EFAULT);
+                       return -1;
+               }
+
+               if (yaffsfs_CheckPath(path) < 0) {
+                       yaffsfs_SetError(-ENAMETOOLONG);
+                       return -1;
+               }
+       }
+
+       yaffsfs_Lock();
+       if (!dev)
+               dev = yaffsfs_FindDevice(path, &dummy);
+
+       if (dev) {
+               if (!dev->is_mounted)
+                       yaffsfs_SetError(-EINVAL);
+               else
+                       retVal = yaffs_bg_gc(dev, urgency);
+       } else
+               yaffsfs_SetError(-ENODEV);
+
+       yaffsfs_Unlock();
+       return retVal;
+}
+
+/* Background gc functions.
+ * These return 0 when bg done or greater than 0 when gc has been
+ * done and there is still a lot of garbage to be cleaned up.
+ */
+
+int yaffs_do_background_gc(const YCHAR *path, int urgency)
+{
+       return yaffsfs_bg_gc_common(NULL, path, urgency);
+}
+
+int yaffs_do_background_gc_reldev(struct yaffs_dev *dev, int urgency)
+{
+       return yaffsfs_bg_gc_common(dev, NULL, urgency);
 }
 
 static int yaffsfs_IsDevBusy(struct yaffs_dev *dev)
@@ -2905,6 +3054,7 @@ int yaffs_remount_common(struct yaffs_dev *dev, const YCHAR *path,
                       int force, int read_only)
 {
        int retVal = -1;
+       int was_read_only;
 
        if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
                yaffsfs_SetError(-EFAULT);
@@ -2922,12 +3072,16 @@ int yaffs_remount_common(struct yaffs_dev *dev, const YCHAR *path,
 
        if (dev) {
                if (dev->is_mounted) {
-                       yaffs_flush_whole_cache(dev);
+                       yaffs_flush_whole_cache(dev, 0);
 
                        if (force || !yaffsfs_IsDevBusy(dev)) {
                                if (read_only)
                                        yaffs_checkpoint_save(dev);
+                               was_read_only = dev->read_only;
                                dev->read_only = read_only ? 1 : 0;
+                               if (was_read_only && !read_only) {
+                                       yaffs_guts_cleanup(dev);
+                               }
                                retVal = 0;
                        } else
                                yaffsfs_SetError(-EBUSY);
@@ -2956,14 +3110,17 @@ int yaffs_unmount2_common(struct yaffs_dev *dev, const YCHAR *path, int force)
 {
        int retVal = -1;
 
-       if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
-               yaffsfs_SetError(-EFAULT);
-               return -1;
-       }
 
-       if (yaffsfs_CheckPath(path) < 0) {
-               yaffsfs_SetError(-ENAMETOOLONG);
-               return -1;
+       if (!dev) {
+               if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+                       yaffsfs_SetError(-EFAULT);
+                       return -1;
+               }
+
+               if (yaffsfs_CheckPath(path) < 0) {
+                       yaffsfs_SetError(-ENAMETOOLONG);
+                       return -1;
+               }
        }
 
        yaffsfs_Lock();
@@ -2973,7 +3130,7 @@ int yaffs_unmount2_common(struct yaffs_dev *dev, const YCHAR *path, int force)
        if (dev) {
                if (dev->is_mounted) {
                        int inUse;
-                       yaffs_flush_whole_cache(dev);
+                       yaffs_flush_whole_cache(dev, 0);
                        yaffs_checkpoint_save(dev);
                        inUse = yaffsfs_IsDevBusy(dev);
                        if (!inUse || force) {
@@ -3046,7 +3203,7 @@ int yaffs_format_common(struct yaffs_dev *dev,
 
                if (dev->is_mounted && unmount_flag) {
                        int inUse;
-                       yaffs_flush_whole_cache(dev);
+                       yaffs_flush_whole_cache(dev, 0);
                        yaffs_checkpoint_save(dev);
                        inUse = yaffsfs_IsDevBusy(dev);
                        if (!inUse || force_unmount_flag) {
@@ -3365,6 +3522,7 @@ static yaffs_DIR *yaffsfs_opendir_reldir_no_lock(struct yaffs_obj *reldir,
        }
 
        obj = yaffsfs_FindObject(reldir, dirname, 0, 1, NULL, &notDir, &loop);
+       obj = yaffsfs_FollowLink(obj, 0, &loop);
 
        if (!obj && notDir)
                yaffsfs_SetError(-ENOTDIR);
@@ -3410,6 +3568,12 @@ yaffs_DIR *yaffs_opendir_reldir(struct yaffs_obj *reldir, const YCHAR *dirname)
        yaffsfs_Unlock();
        return ret;
 }
+
+yaffs_DIR *yaffs_opendir_reldev(struct yaffs_dev *dev, const YCHAR *dirname)
+{
+       return yaffs_opendir_reldir(ROOT_DIR(dev), dirname);
+}
+
 yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
 {
        return yaffs_opendir_reldir(NULL, dirname);
@@ -3428,7 +3592,7 @@ struct yaffs_dirent *yaffsfs_readdir_no_lock(yaffs_DIR * dirp)
                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_dont_use = 0;
                        dsc->de.d_off = dsc->offset++;
                        yaffs_get_obj_name(dsc->nextReturn,
                                           dsc->de.d_name, NAME_MAX);
@@ -3484,7 +3648,7 @@ struct yaffs_dirent *yaffs_readdir_fd(int fd)
 
        yaffsfs_Lock();
        f = yaffsfs_HandleToFileDes(fd);
-       if(f && f->isDir)
+       if(f && f->isDir && f->v.dir)
                ret = yaffsfs_readdir_no_lock(f->v.dir);
        yaffsfs_Unlock();
        return ret;
@@ -3518,6 +3682,7 @@ static int yaffsfs_closedir_no_lock(yaffs_DIR *dirp)
 
        return 0;
 }
+
 int yaffs_closedir(yaffs_DIR *dirp)
 {
        int ret;
@@ -3764,6 +3929,11 @@ int yaffs_set_error(int error)
        return 0;
 }
 
+struct yaffs_obj * yaffs_get_obj_from_fd(int handle)
+{
+       return yaffsfs_HandleToObject(handle);
+}
+
 int yaffs_dump_dev_reldir(struct yaffs_obj *reldir, const YCHAR *path)
 {
 #if 1