4 * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
5 * Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de>
6 * Copyright (C) 2011-2012 embedded brains GmbH <rtems@embedded-brains.de>
7 * Copyright (C) 2019 Space Sciences and Engineering, LLC
8 * <jbrandmeyer@planetiq.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * As a special exception, linking other files with the object code from
15 * this one to produce an executable application does not by itself cause
16 * the resulting executable application to be covered by the GNU General
18 * This exception does not however invalidate any other reasons why the
19 * executable file might be covered by the GNU Public License. In particular,
20 * the other YAFFS files are not covered by this exception, and using them
21 * in a proprietary application requires a paid license from Aleph One.
25 #include <rtems/libio_.h>
26 #include <rtems/seterr.h>
27 #include <rtems/userenv.h>
36 #include "yaffs_guts.h"
37 #include "yaffs_trace.h"
38 #include "yaffs_packedtags2.h"
40 #include "rtems_yaffs.h"
44 static const rtems_filesystem_file_handlers_r yaffs_directory_handlers;
45 static const rtems_filesystem_file_handlers_r yaffs_file_handlers;
46 static const rtems_filesystem_file_handlers_r yaffs_link_handlers;
47 static const rtems_filesystem_operations_table yaffs_ops;
51 static void ylock(struct yaffs_dev *dev)
53 rtems_yaffs_os_context *os_context = dev->os_context;
54 (*os_context->lock)(dev, os_context);
57 static void yunlock(struct yaffs_dev *dev)
59 rtems_yaffs_os_context *os_context = dev->os_context;
60 (*os_context->unlock)(dev, os_context);
63 static void rtems_yaffs_os_unmount(struct yaffs_dev *dev)
65 rtems_yaffs_os_context *os_context = dev->os_context;
66 (*os_context->unmount)(dev, os_context);
69 static struct yaffs_obj *ryfs_get_object_by_location(
70 const rtems_filesystem_location_info_t *loc
73 return loc->node_access;
76 static struct yaffs_obj *ryfs_get_object_by_iop(
77 const rtems_libio_t *iop
80 return iop->pathinfo.node_access;
83 static struct yaffs_dev *ryfs_get_device_by_mt_entry(
84 const rtems_filesystem_mount_table_entry_t *mt_entry
87 return mt_entry->fs_info;
90 static void ryfs_set_location(rtems_filesystem_location_info_t *loc, struct yaffs_obj *obj)
92 loc->node_access = obj;
94 switch (obj->variant_type) {
95 case YAFFS_OBJECT_TYPE_FILE:
96 loc->handlers = &yaffs_file_handlers;
98 case YAFFS_OBJECT_TYPE_DIRECTORY:
99 loc->handlers = &yaffs_directory_handlers;
101 case YAFFS_OBJECT_TYPE_SYMLINK:
102 loc->handlers = &yaffs_link_handlers;
105 loc->handlers = &rtems_filesystem_handlers_default;
110 static bool ryfs_eval_is_directory(
111 rtems_filesystem_eval_path_context_t *ctx,
115 rtems_filesystem_location_info_t *currentloc =
116 rtems_filesystem_eval_path_get_currentloc(ctx);
117 struct yaffs_obj *obj = ryfs_get_object_by_location(currentloc);
119 obj = yaffs_get_equivalent_obj(obj);
121 return obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY;
124 static const char *ryfs_make_string(char *buf, const char *src, size_t len)
128 return memcpy(buf, src, len);
131 static struct yaffs_obj *ryfs_search_in_directory(
132 struct yaffs_obj *dir,
137 if (rtems_filesystem_is_parent_directory(token, tokenlen)) {
139 } else if (!rtems_filesystem_is_current_directory(token, tokenlen)) {
140 if (tokenlen < YAFFS_MAX_NAME_LENGTH) {
141 char buf [YAFFS_MAX_NAME_LENGTH + 1];
143 dir = yaffs_find_by_name(
145 ryfs_make_string(buf, token, tokenlen)
155 static rtems_filesystem_eval_path_generic_status ryfs_eval_token(
156 rtems_filesystem_eval_path_context_t *ctx,
162 rtems_filesystem_eval_path_generic_status status =
163 RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
164 rtems_filesystem_location_info_t *currentloc =
165 rtems_filesystem_eval_path_get_currentloc(ctx);
166 struct yaffs_obj *dir = ryfs_get_object_by_location(currentloc);
167 bool access_ok = rtems_filesystem_eval_path_check_access(
171 (uid_t) dir->yst_uid,
176 struct yaffs_obj *entry = ryfs_search_in_directory(dir, token, tokenlen);
179 bool terminal = !rtems_filesystem_eval_path_has_path(ctx);
180 int eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
181 bool follow_hard_link = (eval_flags & RTEMS_FS_FOLLOW_HARD_LINK) != 0;
182 bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
183 enum yaffs_obj_type type = entry->variant_type;
185 rtems_filesystem_eval_path_clear_token(ctx);
187 if (type == YAFFS_OBJECT_TYPE_HARDLINK && (follow_hard_link || !terminal)) {
188 entry = yaffs_get_equivalent_obj(entry);
191 if (type == YAFFS_OBJECT_TYPE_SYMLINK && (follow_sym_link || !terminal)) {
192 const char *target = entry->variant.symlink_variant.alias;
194 rtems_filesystem_eval_path_recursive(ctx, target, strlen(target));
196 ryfs_set_location(currentloc, entry);
199 status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
203 status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
210 static const rtems_filesystem_eval_path_generic_config ryfs_eval_config = {
211 .is_directory = ryfs_eval_is_directory,
212 .eval_token = ryfs_eval_token
215 static void ryfs_eval_path(rtems_filesystem_eval_path_context_t *ctx)
217 rtems_filesystem_eval_path_generic(ctx, NULL, &ryfs_eval_config);
220 /* Helper functions */
222 static int ryfs_mknod(
223 const rtems_filesystem_location_info_t *parentloc,
231 struct yaffs_obj *parent = ryfs_get_object_by_location(parentloc);
232 struct yaffs_obj *(*create)(
233 struct yaffs_obj *parent,
240 switch (mode & S_IFMT) {
242 create = yaffs_create_file;
245 create = yaffs_create_dir;
254 char buf [YAFFS_MAX_NAME_LENGTH + 1];
255 struct yaffs_obj *entry = (*create)(
257 ryfs_make_string(buf, name, namelen),
272 static int ryfs_utime(
273 const rtems_filesystem_location_info_t *loc,
279 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
281 obj = yaffs_get_equivalent_obj(obj);
284 obj->yst_atime = (u32) actime;
285 obj->yst_mtime = (u32) modtime;
286 obj->yst_ctime = (u32) time(NULL);
295 static int ryfs_rename(
296 const rtems_filesystem_location_info_t *old_parent_loc,
297 const rtems_filesystem_location_info_t *old_loc,
298 const rtems_filesystem_location_info_t *new_parent_loc,
304 struct yaffs_obj *obj = ryfs_get_object_by_location(old_loc);
305 char old_name_buf [YAFFS_MAX_NAME_LENGTH + 1];
306 char new_name_buf [YAFFS_MAX_NAME_LENGTH + 1];
309 yaffs_get_obj_name(obj, old_name_buf, sizeof(old_name_buf));
310 yc = yaffs_rename_obj(
313 ryfs_get_object_by_location(new_parent_loc),
314 ryfs_make_string(new_name_buf, name, namelen)
316 if (yc != YAFFS_OK) {
324 static ssize_t ryfs_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
326 struct yaffs_obj *obj;
327 struct yaffs_dev *dev;
328 struct dirent *de = (struct dirent *)buffer;
331 struct list_head *next;
334 obj = (struct yaffs_obj *)iop->pathinfo.node_access;
336 maxcount = count / sizeof(struct dirent);
340 if(iop->offset == 0) {
341 if(list_empty(&obj->variant.dir_variant.children))
344 iop->data1 = list_entry(obj->variant.dir_variant.children.next, struct yaffs_obj, siblings);
348 while((i < maxcount) && (iop->data1 != NULL)) {
349 de[i].d_ino = (long)yaffs_get_equivalent_obj((struct yaffs_obj *)iop->data1)->obj_id;
351 yaffs_get_obj_name((struct yaffs_obj *)iop->data1, de[i].d_name, NAME_MAX);
352 de[i].d_reclen = sizeof(struct dirent);
353 de[i].d_namlen = (unsigned short)strnlen(de[i].d_name, NAME_MAX);
356 next = ((struct yaffs_obj *)iop->data1)->siblings.next;
357 if(next == &obj->variant.dir_variant.children)
358 iop->data1 = NULL; /* end of list */
360 iop->data1 = list_entry(next, struct yaffs_obj, siblings);
363 readlen = (ssize_t)(i * sizeof(struct dirent));
364 iop->offset = iop->offset + readlen;
371 static int ryfs_fstat(const rtems_filesystem_location_info_t *loc, struct stat *buf)
374 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
375 struct yaffs_dev *dev = obj->my_dev;
376 rtems_yaffs_os_context *os_context = dev->os_context;
380 obj = yaffs_get_equivalent_obj(obj);
382 buf->st_dev = os_context->dev;
383 buf->st_ino = obj->obj_id;
384 buf->st_mode = obj->yst_mode;
385 buf->st_nlink = (nlink_t) yaffs_get_obj_link_count(obj);
386 buf->st_rdev = obj->yst_rdev;
387 buf->st_size = yaffs_get_obj_length(obj);
388 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
389 buf->st_blocks = (blkcnt_t)
390 ((buf->st_size + buf->st_blksize - 1) / buf->st_blksize);
391 buf->st_uid = (uid_t) obj->yst_uid;
392 buf->st_gid = (gid_t) obj->yst_gid;
393 buf->st_atime = (time_t) obj->yst_atime;
394 buf->st_ctime = (time_t) obj->yst_ctime;
395 buf->st_mtime = (time_t) obj->yst_mtime;
406 static int ryfs_fchmod(const rtems_filesystem_location_info_t *loc, mode_t mode)
409 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
412 obj = yaffs_get_equivalent_obj(obj);
414 obj->yst_mode = mode;
416 yc = yaffs_flush_file(obj, 0, 0, 0);
421 if (yc != YAFFS_OK) {
429 static int ryfs_chown(
430 const rtems_filesystem_location_info_t *loc,
436 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
439 obj = yaffs_get_equivalent_obj(obj);
441 obj->yst_uid = owner;
442 obj->yst_gid = group;
444 yc = yaffs_flush_file(obj, 0, 0, 0);
449 if (yc != YAFFS_OK) {
457 static int ryfs_fsync_or_fdatasync(rtems_libio_t *iop)
460 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
461 struct yaffs_dev *dev = obj->my_dev;
465 yc = yaffs_flush_file(obj, 0, 1, 0);
466 if (rtems_filesystem_location_is_instance_root(&iop->pathinfo)) {
467 yaffs_flush_whole_cache(dev, 0);
471 if (yc != YAFFS_OK) {
479 static int ryfs_rmnod(
480 const rtems_filesystem_location_info_t *parentloc,
481 const rtems_filesystem_location_info_t *loc
485 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
486 int yc = yaffs_del_obj(obj);
488 if (yc != YAFFS_OK) {
496 static int ryfs_file_open(rtems_libio_t *iop, const char *pathname, int oflag, mode_t mode)
498 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
499 struct yaffs_dev *dev = obj->my_dev;
503 length = yaffs_get_obj_length(obj);
504 if ((iop->flags & LIBIO_FLAGS_APPEND) != 0) {
505 iop->offset = length;
512 static int ryfs_file_close(rtems_libio_t *iop)
514 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
515 struct yaffs_dev *dev = obj->my_dev;
518 yaffs_flush_file(obj, 1, 0, 1);
524 static ssize_t ryfs_file_read(rtems_libio_t *iop, void *buffer, size_t count)
526 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
527 struct yaffs_dev *dev = obj->my_dev;
534 ol = yaffs_get_obj_length(obj);
535 if(iop->offset >= ol)
538 maxread = (size_t)(ol - (int)iop->offset);
542 nr = yaffs_file_rd(obj, buffer, iop->offset, (int)count);
555 static ssize_t ryfs_file_write(rtems_libio_t *iop, const void *buffer, size_t count)
557 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
558 struct yaffs_dev *dev = obj->my_dev;
560 int max_size = INT_MAX;
568 offset = iop->offset;
569 if (offset < max_size) {
570 size_t max_count = max_size - (size_t) offset;
572 if (count > max_count) {
576 rv = yaffs_wr_file(obj, buffer, offset, (int) count, 0);
591 static int ryfs_file_ftruncate(rtems_libio_t *iop, off_t length)
594 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
595 struct yaffs_dev *dev = obj->my_dev;
599 yc = yaffs_resize_file(obj, length);
602 if (yc != YAFFS_OK) {
610 int rtems_yaffs_mount_handler(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
612 const rtems_yaffs_mount_data *mount_data = data;
613 struct yaffs_dev *dev = mount_data->dev;
615 if (dev->read_only && mt_entry->writeable) {
621 if (yaffs_guts_initialise(dev) == YAFFS_FAIL) {
627 mt_entry->fs_info = dev;
628 mt_entry->ops = &yaffs_ops;
629 mt_entry->mt_fs_root->location.node_access = dev->root_dir;
630 mt_entry->mt_fs_root->location.handlers = &yaffs_directory_handlers;
632 yaffs_flush_whole_cache(dev, 0);
638 static void ryfs_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
640 struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
643 yaffs_flush_whole_cache(dev, 1);
644 yaffs_checkpoint_save(dev);
645 yaffs_deinitialise(dev);
647 rtems_yaffs_os_unmount(dev);
650 static void ryfs_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
652 struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
657 static void ryfs_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
659 struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
665 * Construct a link from parent/name to target.
667 static int ryfs_symlink(const rtems_filesystem_location_info_t *parent_loc,
672 struct yaffs_obj *parent_dir = ryfs_get_object_by_location(parent_loc);
673 struct yaffs_dev *dev = parent_dir->my_dev;
675 struct yaffs_obj *created_link;
681 ((S_IRWXU | S_IRWXG | S_IRWXO) & ~rtems_filesystem_umask);
683 created_link = yaffs_create_symlink(parent_dir, name, mode,
684 geteuid(), getegid(), target);
686 if (created_link != NULL) {
698 * Read the target name of a symbolic link. Interpretation of the path name is
701 * @param loc The location of the symlink
702 * @param dst_buf A non-NULL pointer to the caller's buffer for the characters.
703 * @param dst_buf_size The size of the caller's buffer in characters.
705 * @retval -1 An error occurred, the error may be found via errno.
706 * @retval non-negative size of the actual contents in characters, including the
709 static ssize_t ryfs_readlink(const rtems_filesystem_location_info_t *loc,
710 char *dst_buf, size_t dst_buf_size)
712 struct yaffs_obj *link = ryfs_get_object_by_location(loc);
713 struct yaffs_dev *dev = link->my_dev;
716 ssize_t chars_copied = -1;
718 link = yaffs_get_equivalent_obj(link);
724 if (link->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) {
729 // Source string length including the terminating NULL.
730 size_t src_buf_size = strlen(link->variant.symlink_variant.alias) + 1;
731 if (src_buf_size > dst_buf_size)
732 src_buf_size = dst_buf_size;
733 memcpy(dst_buf, link->variant.symlink_variant.alias, src_buf_size);
734 chars_copied = src_buf_size;
741 static const rtems_filesystem_file_handlers_r yaffs_directory_handlers = {
742 .open_h = rtems_filesystem_default_open,
743 .close_h = rtems_filesystem_default_close,
744 .read_h = ryfs_dir_read,
745 .write_h = rtems_filesystem_default_write,
746 .ioctl_h = rtems_filesystem_default_ioctl,
747 .lseek_h = rtems_filesystem_default_lseek_directory,
748 .fstat_h = ryfs_fstat,
749 .ftruncate_h = rtems_filesystem_default_ftruncate_directory,
750 .fsync_h = ryfs_fsync_or_fdatasync,
751 .fdatasync_h = ryfs_fsync_or_fdatasync,
752 .fcntl_h = rtems_filesystem_default_fcntl
755 static const rtems_filesystem_file_handlers_r yaffs_file_handlers = {
756 .open_h = ryfs_file_open,
757 .close_h = ryfs_file_close,
758 .read_h = ryfs_file_read,
759 .write_h = ryfs_file_write,
760 .ioctl_h = rtems_filesystem_default_ioctl,
761 .lseek_h = rtems_filesystem_default_lseek_file,
762 .fstat_h = ryfs_fstat,
763 .ftruncate_h = ryfs_file_ftruncate,
764 .fsync_h = ryfs_fsync_or_fdatasync,
765 .fdatasync_h = ryfs_fsync_or_fdatasync,
766 .fcntl_h = rtems_filesystem_default_fcntl
769 static const rtems_filesystem_file_handlers_r yaffs_link_handlers = {
770 .open_h = rtems_filesystem_default_open,
771 .close_h = rtems_filesystem_default_close,
772 .read_h = rtems_filesystem_default_read,
773 .write_h = rtems_filesystem_default_write,
774 .ioctl_h = rtems_filesystem_default_ioctl,
775 .lseek_h = rtems_filesystem_default_lseek_file,
776 .fstat_h = ryfs_fstat,
777 .ftruncate_h = rtems_filesystem_default_ftruncate,
778 .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
779 .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
780 .fcntl_h = rtems_filesystem_default_fcntl,
783 static const rtems_filesystem_operations_table yaffs_ops = {
785 .unlock_h = ryfs_unlock,
786 .eval_path_h = ryfs_eval_path,
787 .link_h = rtems_filesystem_default_link,
788 .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
789 .mknod_h = ryfs_mknod,
790 .rmnod_h = ryfs_rmnod,
791 .fchmod_h = ryfs_fchmod,
792 .chown_h = ryfs_chown,
793 .clonenod_h = rtems_filesystem_default_clonenode,
794 .freenod_h = rtems_filesystem_default_freenode,
795 .mount_h = rtems_filesystem_default_mount,
796 .unmount_h = rtems_filesystem_default_unmount,
797 .fsunmount_me_h = ryfs_fsunmount,
798 .utime_h = ryfs_utime,
799 .symlink_h = ryfs_symlink,
800 .readlink_h = ryfs_readlink,
801 .rename_h = ryfs_rename,
802 .statvfs_h = rtems_filesystem_default_statvfs