/*
* 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>
*
#include "string.h"
+#define YAFFS_MAX_RW_SIZE 0x70000000
#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5
#ifndef NULL
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;
* Stuff to handle names.
*/
#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
-
+#ifndef CONFIG_YAFFS_WINCE
static int yaffs_toupper(YCHAR a)
{
if (a >= 'a' && a <= 'z')
else
return a;
}
+#endif
static int yaffsfs_Match(YCHAR a, YCHAR b)
{
return 0;
}
-static int yaffsfs_CheckNameLength(const char *name)
+static int yaffsfs_CheckNameLength(const YCHAR *name)
{
int retVal = 0;
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 &&
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 */
retval = dev;
longestMatch = thisMatchLength;
}
-
}
return retval;
}
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;
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);
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 ? */
if (handle < 0) {
yaffsfs_SetError(-ENFILE);
- errorReported = 1;
+ errorReported = __LINE__;
} else {
fd = yaffsfs_HandleToFileDes(handle);
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__;
}
}
*/
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. */
(!shareRead && alreadyReading) ||
(!sharedWriteAllowed && writeRequested) ||
(!shareWrite && alreadyWriting)) {
- openDenied = 1;
+ openDenied = __LINE__;
yaffsfs_SetError(-EBUSY);
- errorReported = 1;
+ errorReported = __LINE__;
}
}
¬Dir, &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__;
}
}
/* 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) {
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 */
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;
}
else {
/* clean up */
if(!f->isDir)
- yaffs_flush_file(obj, 1, 0);
+ yaffs_flush_file(obj, 1, 0, 1);
yaffsfs_PutHandle(handle);
retVal = 0;
}
/* 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 {
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;
while (nbyte > 0) {
nToRead = YAFFSFS_RW_SIZE -
(pos & (YAFFSFS_RW_SIZE - 1));
- if (nToRead > nbyte)
+ if (nToRead > (int)nbyte)
nToRead = nbyte;
/* Tricky bit...
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;
nToWrite = YAFFSFS_RW_SIZE -
(pos & (YAFFSFS_RW_SIZE - 1));
- if (nToWrite > nbyte)
+ if (nToWrite > (int)nbyte)
nToWrite = nbyte;
/* Tricky bit...
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 &&
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;
const struct yaffs_utimbuf *buf)
{
int retVal = -1;
- int result;
-
struct yaffs_utimbuf local;
obj = yaffs_get_equivalent_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;
}
}
obj->dirty = 1;
- result = yaffs_flush_file(obj, 0, 0);
+ result = yaffs_flush_file(obj, 0, 0, 0);
retVal = 0;
} else
/* bad handle */
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;
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)
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;
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;
}
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);
}
int force, int read_only)
{
int retVal = -1;
+ int was_read_only;
if (yaffsfs_CheckMemRegion(path, 0, 0) < 0) {
yaffsfs_SetError(-EFAULT);
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);
{
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();
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) {
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) {
}
obj = yaffsfs_FindObject(reldir, dirname, 0, 1, NULL, ¬Dir, &loop);
+ obj = yaffsfs_FollowLink(obj, 0, &loop);
if (!obj && notDir)
yaffsfs_SetError(-ENOTDIR);
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);
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);
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;
return 0;
}
+
int yaffs_closedir(yaffs_DIR *dirp)
{
int ret;
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