* Copyright (C) 2010, 2011 Sebastien Bourdeauducq
* Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de>
* Copyright (C) 2011-2012 embedded brains GmbH <rtems@embedded-brains.de>
+ * Copyright (C) 2019 Space Sciences and Engineering, LLC
+ * <jbrandmeyer@planetiq.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
static const rtems_filesystem_file_handlers_r yaffs_directory_handlers;
static const rtems_filesystem_file_handlers_r yaffs_file_handlers;
+static const rtems_filesystem_file_handlers_r yaffs_link_handlers;
static const rtems_filesystem_operations_table yaffs_ops;
/* locking */
case YAFFS_OBJECT_TYPE_DIRECTORY:
loc->handlers = &yaffs_directory_handlers;
break;
+ case YAFFS_OBJECT_TYPE_SYMLINK:
+ loc->handlers = &yaffs_link_handlers;
+ break;
default:
loc->handlers = &rtems_filesystem_handlers_default;
break;
obj = yaffs_get_equivalent_obj(obj);
if (obj != NULL) {
obj->dirty = 1;
- obj->yst_atime = (u32) actime;
- obj->yst_mtime = (u32) modtime;
- obj->yst_ctime = (u32) time(NULL);
+ obj->yst_atime = actime;
+ obj->yst_mtime = modtime;
+ obj->yst_ctime = time(NULL);
} else {
errno = EIO;
rv = -1;
if (obj != NULL) {
obj->yst_mode = mode;
obj->dirty = 1;
- yc = yaffs_flush_file(obj, 0, 0);
+ yc = yaffs_flush_file(obj, 0, 0, 0);
} else {
yc = YAFFS_FAIL;
}
obj->yst_uid = owner;
obj->yst_gid = group;
obj->dirty = 1;
- yc = yaffs_flush_file(obj, 0, 0);
+ yc = yaffs_flush_file(obj, 0, 0, 0);
} else {
yc = YAFFS_FAIL;
}
int yc;
ylock(dev);
- yc = yaffs_flush_file(obj, 0, 1);
+ yc = yaffs_flush_file(obj, 0, 1, 0);
if (rtems_filesystem_location_is_instance_root(&iop->pathinfo)) {
- yaffs_flush_whole_cache(dev);
+ yaffs_flush_whole_cache(dev, 0);
}
yunlock(dev);
struct yaffs_dev *dev = obj->my_dev;
ylock(dev);
- yaffs_flush_file(obj, 1, 0);
+ yaffs_flush_file(obj, 1, 0, 1);
yunlock(dev);
return 0;
mt_entry->mt_fs_root->location.node_access = dev->root_dir;
mt_entry->mt_fs_root->location.handlers = &yaffs_directory_handlers;
- yaffs_flush_whole_cache(dev);
+ yaffs_flush_whole_cache(dev, 0);
yunlock(dev);
return 0;
struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
ylock(dev);
- yaffs_flush_whole_cache(dev);
+ yaffs_flush_whole_cache(dev, 1);
+ yaffs_checkpoint_save(dev);
yaffs_deinitialise(dev);
yunlock(dev);
rtems_yaffs_os_unmount(dev);
yunlock(dev);
}
+/**
+ * Construct a link from parent/name to target.
+ */
+static int ryfs_symlink(const rtems_filesystem_location_info_t *parent_loc,
+ const char *name,
+ size_t namelen,
+ const char *target)
+{
+ struct yaffs_obj *parent_dir = ryfs_get_object_by_location(parent_loc);
+ struct yaffs_dev *dev = parent_dir->my_dev;
+ uint32_t mode;
+ struct yaffs_obj *created_link;
+ int ret;
+
+ ylock(dev);
+
+ mode = S_IFLNK |
+ ((S_IRWXU | S_IRWXG | S_IRWXO) & ~rtems_filesystem_umask);
+
+ created_link = yaffs_create_symlink(parent_dir, name, mode,
+ geteuid(), getegid(), target);
+
+ if (created_link != NULL) {
+ ret = 0;
+ } else {
+ errno = EINVAL;
+ ret = -1;
+ }
+
+ yunlock(dev);
+ return ret;
+}
+
+/**
+ * Read the target name of a symbolic link. Interpretation of the path name is
+ * up to the caller.
+ *
+ * @param loc The location of the symlink
+ * @param dst_buf A non-NULL pointer to the caller's buffer for the characters.
+ * @param dst_buf_size The size of the caller's buffer in characters.
+ *
+ * @retval -1 An error occurred, the error may be found via errno.
+ * @retval non-negative size of the actual contents in characters, including the
+ * terminating NULL.
+ */
+static ssize_t ryfs_readlink(const rtems_filesystem_location_info_t *loc,
+ char *dst_buf, size_t dst_buf_size)
+{
+ struct yaffs_obj *link = ryfs_get_object_by_location(loc);
+ struct yaffs_dev *dev = link->my_dev;
+
+ ylock(dev);
+ ssize_t chars_copied = -1;
+
+ link = yaffs_get_equivalent_obj(link);
+ if (!link) {
+ errno = EBADF;
+ goto error_locked;
+ }
+
+ if (link->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) {
+ errno = EINVAL;
+ goto error_locked;
+ }
+
+ // Source string length including the terminating NULL.
+ size_t src_buf_size = strlen(link->variant.symlink_variant.alias) + 1;
+ if (src_buf_size > dst_buf_size)
+ src_buf_size = dst_buf_size;
+ memcpy(dst_buf, link->variant.symlink_variant.alias, src_buf_size);
+ chars_copied = src_buf_size;
+
+error_locked:
+ yunlock(dev);
+ return chars_copied;
+}
+
static const rtems_filesystem_file_handlers_r yaffs_directory_handlers = {
.open_h = rtems_filesystem_default_open,
.close_h = rtems_filesystem_default_close,
.fcntl_h = rtems_filesystem_default_fcntl
};
+static const rtems_filesystem_file_handlers_r yaffs_link_handlers = {
+ .open_h = rtems_filesystem_default_open,
+ .close_h = rtems_filesystem_default_close,
+ .read_h = rtems_filesystem_default_read,
+ .write_h = rtems_filesystem_default_write,
+ .ioctl_h = rtems_filesystem_default_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek_file,
+ .fstat_h = ryfs_fstat,
+ .ftruncate_h = rtems_filesystem_default_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+};
+
static const rtems_filesystem_operations_table yaffs_ops = {
.lock_h = ryfs_lock,
.unlock_h = ryfs_unlock,
.unmount_h = rtems_filesystem_default_unmount,
.fsunmount_me_h = ryfs_fsunmount,
.utime_h = ryfs_utime,
- .symlink_h = rtems_filesystem_default_symlink,
- .readlink_h = rtems_filesystem_default_readlink,
+ .symlink_h = ryfs_symlink,
+ .readlink_h = ryfs_readlink,
.rename_h = ryfs_rename,
.statvfs_h = rtems_filesystem_default_statvfs
};