+int yaffs_access(const YCHAR *path, int amode)
+{
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *dir = NULL;
+ int notDir = 0;
+ int loop = 0;
+ 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 (amode & ~(R_OK | W_OK | X_OK)) {
+ yaffsfs_SetError(-EINVAL);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop);
+ 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 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))
+ access_ok = 0;
+ if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE))
+ access_ok = 0;
+ if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC))
+ access_ok = 0;
+
+ if (!access_ok)
+ yaffsfs_SetError(-EACCES);
+ else
+ retval = 0;
+ }
+
+ yaffsfs_Unlock();
+
+ return retval;
+
+}
+
+int yaffs_chmod(const YCHAR *path, mode_t mode)
+{
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *dir = NULL;
+ int retVal = -1;
+ int notDir = 0;
+ int loop = 0;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ if (yaffsfs_CheckPath(path) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ if (mode & ~(0777)) {
+ yaffsfs_SetError(-EINVAL);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop);
+ 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 if (obj->my_dev->read_only)
+ yaffsfs_SetError(-EROFS);
+ else
+ retVal = yaffsfs_DoChMod(obj, mode);
+
+ yaffsfs_Unlock();
+
+ return retVal;
+
+}
+
+int yaffs_fchmod(int fd, mode_t mode)
+{
+ struct yaffs_obj *obj;
+ int retVal = -1;
+
+ if (mode & ~(0777)) {
+ yaffsfs_SetError(-EINVAL);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+ obj = yaffsfs_HandleToObject(fd);
+
+ if (!obj)
+ yaffsfs_SetError(-EBADF);
+ else if (obj->my_dev->read_only)
+ yaffsfs_SetError(-EROFS);
+ else
+ retVal = yaffsfs_DoChMod(obj, mode);
+
+ yaffsfs_Unlock();
+
+ return retVal;
+}
+
+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 notDir = 0;
+ int loop = 0;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ if (yaffsfs_CheckPath(path) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
+ yaffsfs_SetError(-ENOMEM);
+ return -1;
+ }
+ if (alt_path)
+ path = alt_path;
+
+ yaffsfs_Lock();
+ parent = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop);
+ if (!parent && notDir)
+ yaffsfs_SetError(-ENOTDIR);
+ 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->my_dev->read_only)
+ yaffsfs_SetError(-EROFS);
+ else {
+ dir = yaffs_create_dir(parent, name, mode, 0, 0);
+ if (dir)
+ retVal = 0;
+ else if (yaffs_find_by_name(parent, name))
+ yaffsfs_SetError(-EEXIST); /* name exists */
+ else
+ yaffsfs_SetError(-ENOSPC); /* assume no space */
+ }
+
+ yaffsfs_Unlock();
+
+ kfree(alt_path);
+
+ return retVal;
+}
+
+int yaffs_rmdir(const YCHAR *path)
+{
+ int result;
+ YCHAR *alt_path;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ if (yaffsfs_CheckPath(path) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ if (yaffsfs_alt_dir_path(path, &alt_path) < 0) {
+ yaffsfs_SetError(-ENOMEM);
+ return -1;
+ }
+ if (alt_path)
+ path = alt_path;
+ result = yaffsfs_DoUnlink(path, 1);
+
+ kfree(alt_path);
+
+ return result;
+}
+
+void *yaffs_getdev(const YCHAR *path)
+{
+ struct yaffs_dev *dev = NULL;
+ YCHAR *dummy;
+ dev = yaffsfs_FindDevice(path, &dummy);
+ return (void *)dev;
+}
+
+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;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path);
+
+ if (yaffsfs_CheckPath(path) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ yaffsfs_InitHandles();
+
+ dev = yaffsfs_FindMountPoint(path);
+ if (dev) {
+ if (!dev->is_mounted) {
+ dev->read_only = read_only ? 1 : 0;
+ 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
+ yaffsfs_SetError(-EBUSY);
+ } else
+ yaffsfs_SetError(-ENODEV);
+
+ yaffsfs_Unlock();
+ return retVal;
+
+}
+
+int yaffs_mount2(const YCHAR *path, int readonly)
+{
+ return yaffs_mount_common(path, readonly, 0);
+}
+
+int yaffs_mount(const YCHAR *path)
+{
+ return yaffs_mount_common(path, 0, 0);
+}
+
+int yaffs_sync(const YCHAR *path)
+{
+ int retVal = -1;
+ struct yaffs_dev *dev = NULL;
+ YCHAR *dummy;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ if (yaffsfs_CheckPath(path) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ 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;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ 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) {
+ yaffs_flush_whole_cache(dev);
+
+ if (force || !yaffsfs_IsDevBusy(dev)) {
+ if (read_only)
+ yaffs_checkpoint_save(dev);
+ dev->read_only = read_only ? 1 : 0;
+ retVal = 0;
+ } else
+ yaffsfs_SetError(-EBUSY);
+
+ } else
+ yaffsfs_SetError(-EINVAL);
+
+ } else
+ yaffsfs_SetError(-ENODEV);
+
+ yaffsfs_Unlock();
+ return retVal;
+
+}
+
+int yaffs_unmount2(const YCHAR *path, int force)
+{
+ int retVal = -1;
+ struct yaffs_dev *dev = NULL;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ 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 inUse;
+ yaffs_flush_whole_cache(dev);
+ yaffs_checkpoint_save(dev);
+ inUse = yaffsfs_IsDevBusy(dev);
+ if (!inUse || force) {
+ if (inUse)
+ yaffsfs_BreakDeviceHandles(dev);
+ yaffs_deinitialise(dev);
+
+ retVal = 0;
+ } else
+ yaffsfs_SetError(-EBUSY);
+
+ } else
+ yaffsfs_SetError(-EINVAL);
+
+ } else
+ yaffsfs_SetError(-ENODEV);
+
+ yaffsfs_Unlock();
+ return retVal;
+
+}
+
+int yaffs_unmount(const YCHAR *path)
+{
+ return yaffs_unmount2(path, 0);
+}
+
+int yaffs_format(const YCHAR *path,
+ int unmount_flag,
+ int force_unmount_flag,
+ int remount_flag)
+{
+ int retVal = 0;
+ struct yaffs_dev *dev = NULL;
+ int result;
+
+ 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) {
+ int was_mounted = dev->is_mounted;
+
+ if (dev->is_mounted && unmount_flag) {
+ int inUse;
+ yaffs_flush_whole_cache(dev);
+ yaffs_checkpoint_save(dev);
+ inUse = yaffsfs_IsDevBusy(dev);
+ if (!inUse || force_unmount_flag) {
+ if (inUse)
+ yaffsfs_BreakDeviceHandles(dev);
+ yaffs_deinitialise(dev);
+ }
+ }
+
+ if(dev->is_mounted) {
+ yaffsfs_SetError(-EBUSY);
+ retVal = -1;
+ } else {
+ yaffs_format_dev(dev);
+ if(was_mounted && remount_flag) {
+ result = yaffs_guts_initialise(dev);
+ if (result == YAFFS_FAIL) {
+ yaffsfs_SetError(-ENOMEM);
+ retVal = -1;
+ }
+ }
+ }
+ } else {
+ yaffsfs_SetError(-ENODEV);
+ retVal = -1;
+ }
+
+ yaffsfs_Unlock();
+ return retVal;
+
+}
+
+
+Y_LOFF_T yaffs_freespace(const YCHAR *path)
+{
+ Y_LOFF_T retVal = -1;
+ struct yaffs_dev *dev = NULL;
+ YCHAR *dummy;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ 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 = yaffs_get_n_free_chunks(dev);
+ retVal *= dev->data_bytes_per_chunk;
+
+ } else
+ yaffsfs_SetError(-EINVAL);
+
+ yaffsfs_Unlock();
+ return retVal;
+}
+
+Y_LOFF_T yaffs_totalspace(const YCHAR *path)
+{
+ Y_LOFF_T retVal = -1;
+ struct yaffs_dev *dev = NULL;
+ YCHAR *dummy;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ 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;
+ retVal *= dev->param.chunks_per_block;
+ retVal *= dev->data_bytes_per_chunk;
+
+ } else
+ yaffsfs_SetError(-EINVAL);
+
+ yaffsfs_Unlock();
+ return retVal;
+}
+
+int yaffs_inodecount(const YCHAR *path)
+{
+ Y_LOFF_T retVal = -1;
+ struct yaffs_dev *dev = NULL;
+ YCHAR *dummy;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ 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)
+ yaffsfs_SetError(-EINVAL);
+
+ yaffsfs_Unlock();
+ 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)
+ INIT_LIST_HEAD(&dev->dev_list);
+
+ list_add(&dev->dev_list, &yaffsfs_deviceList);
+}
+
+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;
+}
+
+struct yaffs_dev *yaffs_next_dev(void)
+{
+ 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;
+}
+
+/* Directory search stuff. */
+
+static struct list_head search_contexts;
+
+static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContext *dsc)
+{
+ if (dsc &&
+ dsc->dirObj &&
+ dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) {
+
+ 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 {
+ /* Hey someone isn't playing nice! */
+ }
+}
+
+static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContext *dsc)
+{
+ 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 (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;
+ struct yaffsfs_DirSearchContext *dsc;
+
+ /* 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, struct yaffsfs_DirSearchContext,
+ others);
+ if (dsc->nextReturn == obj)
+ yaffsfs_DirAdvance(dsc);
+ }
+ }
+
+}
+
+static yaffs_DIR *yaffsfs_opendir_no_lock(const YCHAR *dirname)
+{
+ yaffs_DIR *dir = NULL;
+ struct yaffs_obj *obj = NULL;
+ struct yaffsfs_DirSearchContext *dsc = NULL;
+ int notDir = 0;
+ int loop = 0;
+
+ if (yaffsfs_CheckMemRegion(dirname, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return NULL;
+ }
+
+ if (yaffsfs_CheckPath(dirname) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return NULL;
+ }
+
+ obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, ¬Dir, &loop);
+
+ 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;
+
+ 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(struct yaffsfs_DirSearchContext));
+ 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);
+
+ list_add(&dsc->others, &search_contexts);
+ yaffsfs_SetDirRewound(dsc);
+ }
+ }
+ return dir;
+}
+
+yaffs_DIR *yaffs_opendir(const YCHAR *dirname)
+{
+ yaffs_DIR *ret;
+
+ yaffsfs_Lock();
+ ret = yaffsfs_opendir_no_lock(dirname);
+ yaffsfs_Unlock();
+ return ret;
+}
+
+struct yaffs_dirent *yaffsfs_readdir_no_lock(yaffs_DIR * dirp)
+{
+ struct yaffsfs_DirSearchContext *dsc;
+ struct yaffs_dirent *retVal = NULL;
+
+ dsc = (struct yaffsfs_DirSearchContext *) dirp;
+
+
+ if (dsc && dsc->inUse) {
+ yaffsfs_SetError(0);
+ 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) {
+ /* this should not happen! */
+ yaffs_strcpy(dsc->de.d_name, _Y("zz"));
+ }
+ dsc->de.d_reclen = sizeof(struct yaffs_dirent);
+ retVal = &dsc->de;
+ yaffsfs_DirAdvance(dsc);
+ } else
+ retVal = NULL;
+ } else
+ yaffsfs_SetError(-EBADF);
+
+ return retVal;
+
+}
+struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp)
+{
+ struct yaffs_dirent *ret;
+
+ yaffsfs_Lock();
+ ret = yaffsfs_readdir_no_lock(dirp);
+ yaffsfs_Unlock();
+ return ret;
+}
+
+static void yaffsfs_rewinddir_no_lock(yaffs_DIR *dirp)
+{
+ struct yaffsfs_DirSearchContext *dsc;
+
+ dsc = (struct yaffsfs_DirSearchContext *) dirp;
+
+ if (yaffsfs_CheckMemRegion(dirp, sizeof(*dsc), 0) < 0)
+ return;
+
+ yaffsfs_SetDirRewound(dsc);
+
+}
+
+void yaffs_rewinddir(yaffs_DIR *dirp)
+{
+ yaffsfs_Lock();
+ yaffsfs_rewinddir_no_lock(dirp);
+ yaffsfs_Unlock();
+}
+
+struct yaffs_dirent *yaffs_readdir_fd(int fd)
+{
+ struct yaffs_dirent *ret = NULL;
+ struct yaffsfs_FileDes *f;
+
+ yaffsfs_Lock();
+ f = yaffsfs_HandleToFileDes(fd);
+ if(f && f->isDir)
+ ret = yaffsfs_readdir_no_lock(f->v.dir);
+ yaffsfs_Unlock();
+ return ret;
+}
+
+void yaffs_rewinddir_fd(int fd)
+{
+ struct yaffsfs_FileDes *f;
+
+ yaffsfs_Lock();
+ f = yaffsfs_HandleToFileDes(fd);
+ if(f && f->isDir)
+ yaffsfs_rewinddir_no_lock(f->v.dir);
+ yaffsfs_Unlock();
+}
+
+
+static int yaffsfs_closedir_no_lock(yaffs_DIR *dirp)
+{
+ struct yaffsfs_DirSearchContext *dsc;
+
+ dsc = (struct yaffsfs_DirSearchContext *) dirp;
+
+ if (yaffsfs_CheckMemRegion(dirp, sizeof(*dsc), 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ dsc->inUse = 0;
+ list_del(&dsc->others); /* unhook from list */
+
+ return 0;
+}
+int yaffs_closedir(yaffs_DIR *dirp)
+{
+ int ret;
+
+ yaffsfs_Lock();
+ ret = yaffsfs_closedir_no_lock(dirp);
+ yaffsfs_Unlock();
+ return ret;
+}
+
+/* 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 notDir = 0;
+ int loop = 0;
+
+ if (yaffsfs_CheckMemRegion(oldpath, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(newpath, 0, 0) < 0) {
+ 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, ¬Dir, &loop);
+ if (!parent && notDir)
+ yaffsfs_SetError(-ENOTDIR);
+ else if (loop)
+ yaffsfs_SetError(-ELOOP);
+ else if (!parent || yaffs_strnlen(name, 5) < 1)
+ yaffsfs_SetError(-ENOENT);
+ 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)
+ retVal = 0;
+ else if (yaffsfs_FindObject
+ (NULL, newpath, 0, 0, NULL, NULL, NULL))
+ yaffsfs_SetError(-EEXIST);
+ else
+ yaffsfs_SetError(-ENOSPC);
+ }
+
+ yaffsfs_Unlock();
+
+ return retVal;
+
+}
+
+int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz)
+{
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *dir = NULL;
+ int retVal = -1;
+ int notDir = 0;
+ int loop = 0;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(buf, bufsiz, 1) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop);
+
+ if (!dir && notDir)
+ yaffsfs_SetError(-ENOTDIR);
+ else if (loop)
+ yaffsfs_SetError(-ELOOP);
+ else if (!dir || !obj)
+ yaffsfs_SetError(-ENOENT);
+ 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);
+ retVal = 0;
+ }
+ yaffsfs_Unlock();
+ return retVal;
+}
+
+int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath)
+{
+ /* Creates a link called newpath to existing oldpath */
+ struct yaffs_obj *obj = NULL;
+ struct yaffs_obj *lnk = NULL;
+ 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_CheckMemRegion(oldpath, 0, 0) < 0 ||
+ yaffsfs_CheckMemRegion(linkpath, 0, 0) < 0) {
+ 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, ¬DirObj, &objLoop);
+ lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL);
+ lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname,
+ 0, ¬DirLnk, &lnkLoop);
+
+ if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk))
+ yaffsfs_SetError(-ENOTDIR);
+ 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(-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)
+ yaffsfs_SetError(-EXDEV);
+ else {
+ retVal = yaffsfs_CheckNameLength(newname);
+
+ if (retVal == 0) {
+ lnk = yaffs_link_obj(lnk_dir, newname, obj);
+ if (lnk)
+ retVal = 0;
+ else {
+ yaffsfs_SetError(-ENOSPC);
+ retVal = -1;
+ }
+ }
+ }
+ yaffsfs_Unlock();
+
+ return retVal;
+}
+
+int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t 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
+ */
+int yaffs_n_handles(const YCHAR *path)
+{
+ struct yaffs_obj *obj;
+
+ if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ if (yaffsfs_CheckPath(path) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL);
+
+ if (obj)
+ return yaffsfs_CountHandles(obj);
+ else
+ return -1;
+}
+
+int yaffs_get_error(void)
+{
+ return yaffsfs_GetLastError();
+}
+
+int yaffs_set_error(int error)
+{
+ yaffsfs_SetError(error);
+ return 0;
+}
+
+int yaffs_dump_dev(const YCHAR *path)
+{
+#if 1
+ (void) path;
+#else
+ YCHAR *rest;
+
+ struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest);
+
+ 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);
+
+ }
+#endif
+ return 0;
+}