+}
+
+int yaffs_fsync(int handle)
+{
+ return yaffs_Dofsync(handle, 0);
+}
+
+int yaffs_flush(int handle)
+{
+ return yaffs_fsync(handle);
+}
+
+int yaffs_fdatasync(int handle)
+{
+ return yaffs_Dofsync(handle, 1);
+}
+
+int yaffs_close(int handle)
+{
+ struct yaffsfs_Handle *h = NULL;
+ struct yaffs_obj *obj = NULL;
+ int retVal = -1;
+
+ yaffsfs_Lock();
+
+ h = yaffsfs_HandleToPointer(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if (!h || !obj)
+ yaffsfs_SetError(-EBADF);
+ else {
+ /* clean up */
+ yaffs_flush_file(obj, 1, 0);
+ yaffsfs_PutHandle(handle);
+ retVal = 0;
+ }
+
+ yaffsfs_Unlock();
+
+ return retVal;
+}
+
+static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte,
+ int isPread, loff_t offset)
+{
+ struct yaffsfs_FileDes *fd = NULL;
+ struct yaffs_obj *obj = NULL;
+ loff_t pos = 0;
+ loff_t startPos = 0;
+ loff_t endPos = 0;
+ int nRead = 0;
+ int nToRead = 0;
+ int totalRead = 0;
+ loff_t maxRead;
+ u8 *buf = (u8 *) vbuf;
+
+ if (!vbuf) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+ fd = yaffsfs_HandleToFileDes(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if (!fd || !obj) {
+ /* bad handle */
+ yaffsfs_SetError(-EBADF);
+ totalRead = -1;
+ } else if (!fd->reading) {
+ /* Not a reading handle */
+ yaffsfs_SetError(-EINVAL);
+ totalRead = -1;
+ } else if (nbyte > YAFFS_MAX_FILE_SIZE) {
+ yaffsfs_SetError(-EINVAL);
+ totalRead = -1;
+ } else {
+ if (isPread)
+ startPos = offset;
+ else
+ startPos = fd->position;
+
+ pos = startPos;
+
+ if (yaffs_get_obj_length(obj) > pos)
+ maxRead = yaffs_get_obj_length(obj) - pos;
+ else
+ maxRead = 0;
+
+ if (nbyte > maxRead)
+ nbyte = maxRead;
+
+ 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) {
+ totalRead = -1;
+ nbyte = 0;
+ }
+
+ while (nbyte > 0) {
+ nToRead = YAFFSFS_RW_SIZE -
+ (pos & (YAFFSFS_RW_SIZE - 1));
+ if (nToRead > nbyte)
+ nToRead = nbyte;
+
+ /* Tricky bit...
+ * Need to reverify object in case the device was
+ * unmounted in another thread.
+ */
+ obj = yaffsfs_HandleToObject(handle);
+ if (!obj)
+ nRead = 0;
+ else
+ nRead = yaffs_file_rd(obj, buf, pos, nToRead);
+
+ if (nRead > 0) {
+ totalRead += nRead;
+ pos += nRead;
+ buf += nRead;
+ }
+
+ if (nRead == nToRead)
+ nbyte -= nRead;
+ else
+ nbyte = 0; /* no more to read */
+
+ if (nbyte > 0) {
+ yaffsfs_Unlock();
+ yaffsfs_Lock();
+ }
+
+ }
+
+ yaffsfs_PutHandle(handle);
+
+ if (!isPread) {
+ if (totalRead >= 0)
+ fd->position = startPos + totalRead;
+ else
+ yaffsfs_SetError(-EINVAL);
+ }
+
+ }
+
+ yaffsfs_Unlock();
+
+ return (totalRead >= 0) ? totalRead : -1;
+
+}
+
+int yaffs_read(int handle, void *buf, unsigned int nbyte)
+{
+ return yaffsfs_do_read(handle, buf, nbyte, 0, 0);
+}
+
+int yaffs_pread(int handle, void *buf, unsigned int nbyte, loff_t offset)
+{
+ return yaffsfs_do_read(handle, buf, nbyte, 1, offset);
+}
+
+static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte,
+ int isPwrite, loff_t offset)
+{
+ struct yaffsfs_FileDes *fd = NULL;
+ struct yaffs_obj *obj = NULL;
+ loff_t pos = 0;
+ loff_t startPos = 0;
+ 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();
+ fd = yaffsfs_HandleToFileDes(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if (!fd || !obj) {
+ /* bad handle */
+ yaffsfs_SetError(-EBADF);
+ totalWritten = -1;
+ } else if (!fd->writing) {
+ yaffsfs_SetError(-EINVAL);
+ totalWritten = -1;
+ } else if (obj->my_dev->read_only) {
+ yaffsfs_SetError(-EROFS);
+ totalWritten = -1;
+ } else {
+ if (fd->append)
+ startPos = yaffs_get_obj_length(obj);
+ else if (isPwrite)
+ startPos = offset;
+ else
+ startPos = fd->position;
+
+ 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) {
+ totalWritten = -1;
+ nbyte = 0;
+ }
+
+ while (nbyte > 0) {
+
+ nToWrite = YAFFSFS_RW_SIZE -
+ (pos & (YAFFSFS_RW_SIZE - 1));
+ if (nToWrite > nbyte)
+ nToWrite = nbyte;
+
+ /* Tricky bit...
+ * Need to reverify object in case the device was
+ * remounted or unmounted in another thread.
+ */
+ 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) {
+ totalWritten += nWritten;
+ pos += nWritten;
+ buf += nWritten;
+ }
+
+ if (nWritten == nToWrite)
+ nbyte -= nToWrite;
+ else
+ nbyte = 0;
+
+ if (nWritten < 1 && totalWritten < 1) {
+ yaffsfs_SetError(-ENOSPC);
+ totalWritten = -1;
+ }
+
+ if (nbyte > 0) {
+ yaffsfs_Unlock();
+ yaffsfs_Lock();
+ }
+ }
+
+ yaffsfs_PutHandle(handle);
+
+ if (!isPwrite) {
+ if (totalWritten > 0)
+ fd->position = startPos + totalWritten;
+ else
+ yaffsfs_SetError(-EINVAL);
+ }
+ }
+
+ yaffsfs_Unlock();
+
+ return (totalWritten >= 0) ? totalWritten : -1;
+}
+
+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, loff_t offset)
+{
+ return yaffsfs_do_write(fd, buf, nbyte, 1, offset);
+}
+
+int yaffs_truncate(const YCHAR *path, 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) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ 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 if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE)
+ yaffsfs_SetError(-EISDIR);
+ 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);
+
+ yaffsfs_Unlock();
+
+ return (result) ? 0 : -1;
+}
+
+int yaffs_ftruncate(int handle, loff_t new_size)
+{
+ struct yaffsfs_FileDes *fd = NULL;
+ struct yaffs_obj *obj = NULL;
+ int result = 0;
+
+ yaffsfs_Lock();
+ fd = yaffsfs_HandleToFileDes(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if (!fd || !obj)
+ /* bad handle */
+ yaffsfs_SetError(-EBADF);
+ 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);
+ yaffsfs_Unlock();
+
+ return (result) ? 0 : -1;
+
+}
+
+loff_t yaffs_lseek(int handle, loff_t offset, int whence)
+{
+ struct yaffsfs_FileDes *fd = NULL;
+ struct yaffs_obj *obj = NULL;
+ loff_t pos = -1;
+ loff_t fSize = -1;
+
+ yaffsfs_Lock();
+ fd = yaffsfs_HandleToFileDes(handle);
+ obj = yaffsfs_HandleToObject(handle);
+
+ if (!fd || !obj)
+ yaffsfs_SetError(-EBADF);
+ else if (offset > YAFFS_MAX_FILE_SIZE)
+ yaffsfs_SetError(-EINVAL);
+ else {
+ if (whence == SEEK_SET) {
+ if (offset >= 0)
+ pos = offset;
+ } 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)
+ pos = fSize + offset;
+ }
+
+ if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE)
+ fd->position = pos;
+ else {
+ yaffsfs_SetError(-EINVAL);
+ pos = -1;
+ }
+ }
+
+ yaffsfs_Unlock();
+
+ return pos;
+}
+
+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) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL);
+ dir = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop);
+
+ if (!dir && notDir)
+ yaffsfs_SetError(-ENOTDIR);
+ else if (loop)
+ yaffsfs_SetError(-ELOOP);
+ else if (!dir)
+ yaffsfs_SetError(-ENOENT);
+ else if (yaffs_strncmp(name, _Y("."), 2) == 0)
+ yaffsfs_SetError(-EINVAL);
+ 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)
+ 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);
+
+ if (result == YAFFS_FAIL && isDirectory)
+ yaffsfs_SetError(-ENOTEMPTY);
+ }
+
+ yaffsfs_Unlock();
+
+ return (result == YAFFS_FAIL) ? -1 : 0;
+}
+
+int yaffs_unlink(const YCHAR *path)
+{
+ return yaffsfs_DoUnlink(path, 0);
+}
+
+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 rename_allowed = 1;
+ int notOldDir = 0;
+ int notNewDir = 0;
+ int oldLoop = 0;
+ int newLoop = 0;
+
+ YCHAR *alt_newpath = NULL;
+
+ if (!oldPath || !newPath) {
+ yaffsfs_SetError(-EFAULT);
+ return -1;
+ }
+
+ if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ 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,
+ ¬OldDir, &oldLoop);
+ newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0,
+ ¬NewDir, &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 && notOldDir) || (!newdir && notNewDir)) {
+ yaffsfs_SetError(-ENOTDIR);
+ rename_allowed = 0;
+ } 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) {
+ yaffsfs_SetError(-EROFS);
+ rename_allowed = 0;
+ } 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) {
+ /*
+ * 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
+ */
+
+ struct yaffs_obj *xx = newdir;
+
+ while (rename_allowed && xx) {
+ if (xx == obj)
+ rename_allowed = 0;
+ xx = xx->parent;
+ }
+ if (!rename_allowed)
+ yaffsfs_SetError(-EINVAL);
+ }
+
+ 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)
+{
+ 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;
+
+ if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY)
+ buf->st_mode |= S_IFDIR;
+ else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK)
+ buf->st_mode |= S_IFLNK;
+ 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;
+#if CONFIG_YAFFS_WINCE
+ buf->yst_wince_atime[0] = obj->win_atime[0];
+ buf->yst_wince_atime[1] = obj->win_atime[1];
+ buf->yst_wince_ctime[0] = obj->win_ctime[0];
+ buf->yst_wince_ctime[1] = obj->win_ctime[1];
+ 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;
+#endif
+ retVal = 0;
+ }
+ return retVal;
+}
+
+static int yaffsfs_DoStatOrLStat(const YCHAR *path,
+ struct yaffs_stat *buf, int doLStat)
+{
+ 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) {
+ yaffsfs_SetError(-ENAMETOOLONG);
+ return -1;
+ }
+
+ yaffsfs_Lock();
+
+ obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop);
+
+ if (!doLStat && obj)
+ 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 = yaffsfs_DoStat(obj, buf);
+
+ yaffsfs_Unlock();
+
+ return retVal;