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>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * As a special exception, linking other files with the object code from
13 * this one to produce an executable application does not by itself cause
14 * the resulting executable application to be covered by the GNU General
16 * This exception does not however invalidate any other reasons why the
17 * executable file might be covered by the GNU Public License. In particular,
18 * the other YAFFS files are not covered by this exception, and using them
19 * in a proprietary application requires a paid license from Aleph One.
23 #include <rtems/libio_.h>
24 #include <rtems/seterr.h>
25 #include <rtems/userenv.h>
34 #include "yaffs_guts.h"
35 #include "yaffs_trace.h"
36 #include "yaffs_packedtags2.h"
38 #include "rtems_yaffs.h"
42 static const rtems_filesystem_file_handlers_r yaffs_directory_handlers;
43 static const rtems_filesystem_file_handlers_r yaffs_file_handlers;
44 static const rtems_filesystem_operations_table yaffs_ops;
48 static void ylock(struct yaffs_dev *dev)
50 rtems_yaffs_os_context *os_context = dev->os_context;
51 (*os_context->lock)(dev, os_context);
54 static void yunlock(struct yaffs_dev *dev)
56 rtems_yaffs_os_context *os_context = dev->os_context;
57 (*os_context->unlock)(dev, os_context);
60 static void rtems_yaffs_os_unmount(struct yaffs_dev *dev)
62 rtems_yaffs_os_context *os_context = dev->os_context;
63 (*os_context->unmount)(dev, os_context);
66 static struct yaffs_obj *ryfs_get_object_by_location(
67 const rtems_filesystem_location_info_t *loc
70 return loc->node_access;
73 static struct yaffs_obj *ryfs_get_object_by_iop(
74 const rtems_libio_t *iop
77 return iop->pathinfo.node_access;
80 static struct yaffs_dev *ryfs_get_device_by_mt_entry(
81 const rtems_filesystem_mount_table_entry_t *mt_entry
84 return mt_entry->fs_info;
87 static void ryfs_set_location(rtems_filesystem_location_info_t *loc, struct yaffs_obj *obj)
89 loc->node_access = obj;
91 switch (obj->variant_type) {
92 case YAFFS_OBJECT_TYPE_FILE:
93 loc->handlers = &yaffs_file_handlers;
95 case YAFFS_OBJECT_TYPE_DIRECTORY:
96 loc->handlers = &yaffs_directory_handlers;
99 loc->handlers = &rtems_filesystem_handlers_default;
104 static bool ryfs_eval_is_directory(
105 rtems_filesystem_eval_path_context_t *ctx,
109 rtems_filesystem_location_info_t *currentloc =
110 rtems_filesystem_eval_path_get_currentloc(ctx);
111 struct yaffs_obj *obj = ryfs_get_object_by_location(currentloc);
113 obj = yaffs_get_equivalent_obj(obj);
115 return obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY;
118 static const char *ryfs_make_string(char *buf, const char *src, size_t len)
122 return memcpy(buf, src, len);
125 static struct yaffs_obj *ryfs_search_in_directory(
126 struct yaffs_obj *dir,
131 if (rtems_filesystem_is_parent_directory(token, tokenlen)) {
133 } else if (!rtems_filesystem_is_current_directory(token, tokenlen)) {
134 if (tokenlen < YAFFS_MAX_NAME_LENGTH) {
135 char buf [YAFFS_MAX_NAME_LENGTH + 1];
137 dir = yaffs_find_by_name(
139 ryfs_make_string(buf, token, tokenlen)
149 static rtems_filesystem_eval_path_generic_status ryfs_eval_token(
150 rtems_filesystem_eval_path_context_t *ctx,
156 rtems_filesystem_eval_path_generic_status status =
157 RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
158 rtems_filesystem_location_info_t *currentloc =
159 rtems_filesystem_eval_path_get_currentloc(ctx);
160 struct yaffs_obj *dir = ryfs_get_object_by_location(currentloc);
161 bool access_ok = rtems_filesystem_eval_path_check_access(
165 (uid_t) dir->yst_uid,
170 struct yaffs_obj *entry = ryfs_search_in_directory(dir, token, tokenlen);
173 bool terminal = !rtems_filesystem_eval_path_has_path(ctx);
174 int eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
175 bool follow_hard_link = (eval_flags & RTEMS_FS_FOLLOW_HARD_LINK) != 0;
176 bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
177 enum yaffs_obj_type type = entry->variant_type;
179 rtems_filesystem_eval_path_clear_token(ctx);
181 if (type == YAFFS_OBJECT_TYPE_HARDLINK && (follow_hard_link || !terminal)) {
182 entry = yaffs_get_equivalent_obj(entry);
185 if (type == YAFFS_OBJECT_TYPE_SYMLINK && (follow_sym_link || !terminal)) {
186 const char *target = entry->variant.symlink_variant.alias;
188 rtems_filesystem_eval_path_recursive(ctx, target, strlen(target));
190 ryfs_set_location(currentloc, entry);
193 status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
197 status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
204 static const rtems_filesystem_eval_path_generic_config ryfs_eval_config = {
205 .is_directory = ryfs_eval_is_directory,
206 .eval_token = ryfs_eval_token
209 static void ryfs_eval_path(rtems_filesystem_eval_path_context_t *ctx)
211 rtems_filesystem_eval_path_generic(ctx, NULL, &ryfs_eval_config);
214 /* Helper functions */
216 static int ryfs_mknod(
217 const rtems_filesystem_location_info_t *parentloc,
225 struct yaffs_obj *parent = ryfs_get_object_by_location(parentloc);
226 struct yaffs_obj *(*create)(
227 struct yaffs_obj *parent,
234 switch (mode & S_IFMT) {
236 create = yaffs_create_file;
239 create = yaffs_create_dir;
248 char buf [YAFFS_MAX_NAME_LENGTH + 1];
249 struct yaffs_obj *entry = (*create)(
251 ryfs_make_string(buf, name, namelen),
266 static int ryfs_utime(
267 const rtems_filesystem_location_info_t *loc,
273 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
275 obj = yaffs_get_equivalent_obj(obj);
278 obj->yst_atime = (u32) actime;
279 obj->yst_mtime = (u32) modtime;
280 obj->yst_ctime = (u32) time(NULL);
289 static int ryfs_rename(
290 const rtems_filesystem_location_info_t *old_parent_loc,
291 const rtems_filesystem_location_info_t *old_loc,
292 const rtems_filesystem_location_info_t *new_parent_loc,
298 struct yaffs_obj *obj = ryfs_get_object_by_location(old_loc);
299 char old_name_buf [YAFFS_MAX_NAME_LENGTH + 1];
300 char new_name_buf [YAFFS_MAX_NAME_LENGTH + 1];
303 yaffs_get_obj_name(obj, old_name_buf, sizeof(old_name_buf));
304 yc = yaffs_rename_obj(
307 ryfs_get_object_by_location(new_parent_loc),
308 ryfs_make_string(new_name_buf, name, namelen)
310 if (yc != YAFFS_OK) {
318 static ssize_t ryfs_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
320 struct yaffs_obj *obj;
321 struct yaffs_dev *dev;
322 struct dirent *de = (struct dirent *)buffer;
325 struct list_head *next;
328 obj = (struct yaffs_obj *)iop->pathinfo.node_access;
330 maxcount = count / sizeof(struct dirent);
334 if(iop->offset == 0) {
335 if(list_empty(&obj->variant.dir_variant.children))
338 iop->data1 = list_entry(obj->variant.dir_variant.children.next, struct yaffs_obj, siblings);
342 while((i < maxcount) && (iop->data1 != NULL)) {
343 de[i].d_ino = (long)yaffs_get_equivalent_obj((struct yaffs_obj *)iop->data1)->obj_id;
345 yaffs_get_obj_name((struct yaffs_obj *)iop->data1, de[i].d_name, NAME_MAX);
346 de[i].d_reclen = sizeof(struct dirent);
347 de[i].d_namlen = (unsigned short)strnlen(de[i].d_name, NAME_MAX);
350 next = ((struct yaffs_obj *)iop->data1)->siblings.next;
351 if(next == &obj->variant.dir_variant.children)
352 iop->data1 = NULL; /* end of list */
354 iop->data1 = list_entry(next, struct yaffs_obj, siblings);
357 readlen = (ssize_t)(i * sizeof(struct dirent));
358 iop->offset = iop->offset + readlen;
365 static int ryfs_fstat(const rtems_filesystem_location_info_t *loc, struct stat *buf)
368 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
369 struct yaffs_dev *dev = obj->my_dev;
370 rtems_yaffs_os_context *os_context = dev->os_context;
374 obj = yaffs_get_equivalent_obj(obj);
376 buf->st_dev = os_context->dev;
377 buf->st_ino = obj->obj_id;
378 buf->st_mode = obj->yst_mode;
379 buf->st_nlink = (nlink_t) yaffs_get_obj_link_count(obj);
380 buf->st_rdev = obj->yst_rdev;
381 buf->st_size = yaffs_get_obj_length(obj);
382 buf->st_blksize = obj->my_dev->data_bytes_per_chunk;
383 buf->st_blocks = (blkcnt_t)
384 ((buf->st_size + buf->st_blksize - 1) / buf->st_blksize);
385 buf->st_uid = (uid_t) obj->yst_uid;
386 buf->st_gid = (gid_t) obj->yst_gid;
387 buf->st_atime = (time_t) obj->yst_atime;
388 buf->st_ctime = (time_t) obj->yst_ctime;
389 buf->st_mtime = (time_t) obj->yst_mtime;
400 static int ryfs_fchmod(const rtems_filesystem_location_info_t *loc, mode_t mode)
403 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
406 obj = yaffs_get_equivalent_obj(obj);
408 obj->yst_mode = mode;
410 yc = yaffs_flush_file(obj, 0, 0,0);
415 if (yc != YAFFS_OK) {
423 static int ryfs_chown(
424 const rtems_filesystem_location_info_t *loc,
430 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
433 obj = yaffs_get_equivalent_obj(obj);
435 obj->yst_uid = owner;
436 obj->yst_gid = group;
438 yc = yaffs_flush_file(obj, 0, 0, 0);
443 if (yc != YAFFS_OK) {
451 static int ryfs_fsync_or_fdatasync(rtems_libio_t *iop)
454 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
455 struct yaffs_dev *dev = obj->my_dev;
459 yc = yaffs_flush_file(obj, 0, 1, 0);
460 if (rtems_filesystem_location_is_instance_root(&iop->pathinfo)) {
461 yaffs_flush_whole_cache(dev, 0);
465 if (yc != YAFFS_OK) {
473 static int ryfs_rmnod(
474 const rtems_filesystem_location_info_t *parentloc,
475 const rtems_filesystem_location_info_t *loc
479 struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
480 int yc = yaffs_del_obj(obj);
482 if (yc != YAFFS_OK) {
490 static int ryfs_file_open(rtems_libio_t *iop, const char *pathname, int oflag, mode_t mode)
492 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
493 struct yaffs_dev *dev = obj->my_dev;
497 length = yaffs_get_obj_length(obj);
498 if ((iop->flags & LIBIO_FLAGS_APPEND) != 0) {
499 iop->offset = length;
506 static int ryfs_file_close(rtems_libio_t *iop)
508 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
509 struct yaffs_dev *dev = obj->my_dev;
512 yaffs_flush_file(obj, 1, 0, 1);
518 static ssize_t ryfs_file_read(rtems_libio_t *iop, void *buffer, size_t count)
520 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
521 struct yaffs_dev *dev = obj->my_dev;
528 ol = yaffs_get_obj_length(obj);
529 if(iop->offset >= ol)
532 maxread = (size_t)(ol - (int)iop->offset);
536 nr = yaffs_file_rd(obj, buffer, iop->offset, (int)count);
549 static ssize_t ryfs_file_write(rtems_libio_t *iop, const void *buffer, size_t count)
551 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
552 struct yaffs_dev *dev = obj->my_dev;
554 int max_size = INT_MAX;
562 offset = iop->offset;
563 if (offset < max_size) {
564 size_t max_count = max_size - (size_t) offset;
566 if (count > max_count) {
570 rv = yaffs_wr_file(obj, buffer, offset, (int) count, 0);
585 static int ryfs_file_ftruncate(rtems_libio_t *iop, off_t length)
588 struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
589 struct yaffs_dev *dev = obj->my_dev;
593 yc = yaffs_resize_file(obj, length);
596 if (yc != YAFFS_OK) {
604 int rtems_yaffs_mount_handler(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
606 const rtems_yaffs_mount_data *mount_data = data;
607 struct yaffs_dev *dev = mount_data->dev;
609 if (dev->read_only && mt_entry->writeable) {
615 if (yaffs_guts_initialise(dev) == YAFFS_FAIL) {
621 mt_entry->fs_info = dev;
622 mt_entry->ops = &yaffs_ops;
623 mt_entry->mt_fs_root->location.node_access = dev->root_dir;
624 mt_entry->mt_fs_root->location.handlers = &yaffs_directory_handlers;
626 yaffs_flush_whole_cache(dev, 0);
632 static void ryfs_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
634 struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
637 yaffs_flush_whole_cache(dev, 1);
638 yaffs_deinitialise(dev);
640 rtems_yaffs_os_unmount(dev);
643 static void ryfs_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
645 struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
650 static void ryfs_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
652 struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
657 static const rtems_filesystem_file_handlers_r yaffs_directory_handlers = {
658 .open_h = rtems_filesystem_default_open,
659 .close_h = rtems_filesystem_default_close,
660 .read_h = ryfs_dir_read,
661 .write_h = rtems_filesystem_default_write,
662 .ioctl_h = rtems_filesystem_default_ioctl,
663 .lseek_h = rtems_filesystem_default_lseek_directory,
664 .fstat_h = ryfs_fstat,
665 .ftruncate_h = rtems_filesystem_default_ftruncate_directory,
666 .fsync_h = ryfs_fsync_or_fdatasync,
667 .fdatasync_h = ryfs_fsync_or_fdatasync,
668 .fcntl_h = rtems_filesystem_default_fcntl
671 static const rtems_filesystem_file_handlers_r yaffs_file_handlers = {
672 .open_h = ryfs_file_open,
673 .close_h = ryfs_file_close,
674 .read_h = ryfs_file_read,
675 .write_h = ryfs_file_write,
676 .ioctl_h = rtems_filesystem_default_ioctl,
677 .lseek_h = rtems_filesystem_default_lseek_file,
678 .fstat_h = ryfs_fstat,
679 .ftruncate_h = ryfs_file_ftruncate,
680 .fsync_h = ryfs_fsync_or_fdatasync,
681 .fdatasync_h = ryfs_fsync_or_fdatasync,
682 .fcntl_h = rtems_filesystem_default_fcntl
685 static const rtems_filesystem_operations_table yaffs_ops = {
687 .unlock_h = ryfs_unlock,
688 .eval_path_h = ryfs_eval_path,
689 .link_h = rtems_filesystem_default_link,
690 .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
691 .mknod_h = ryfs_mknod,
692 .rmnod_h = ryfs_rmnod,
693 .fchmod_h = ryfs_fchmod,
694 .chown_h = ryfs_chown,
695 .clonenod_h = rtems_filesystem_default_clonenode,
696 .freenod_h = rtems_filesystem_default_freenode,
697 .mount_h = rtems_filesystem_default_mount,
698 .unmount_h = rtems_filesystem_default_unmount,
699 .fsunmount_me_h = ryfs_fsunmount,
700 .utime_h = ryfs_utime,
701 .symlink_h = rtems_filesystem_default_symlink,
702 .readlink_h = rtems_filesystem_default_readlink,
703 .rename_h = ryfs_rename,
704 .statvfs_h = rtems_filesystem_default_statvfs