vecswap(pb, pn - r, r);
r = pb - pa;
if (r > es)
- yaffs_qsort(a, r / es, es, cmp);
+ qsort(a, r / es, es, cmp);
r = pd - pc;
if (r > es) {
/* Iterate rather than recurse to save stack space */
n = r / es;
goto loop;
}
-/* yaffs_qsort(pn - r, r / es, es, cmp);*/
+/* qsort(pn - r, r / es, es, cmp);*/
}
#define __YPORTENV_H__
+#ifdef __rtems__
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define CONFIG_YAFFS_DIRECT 1
+#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM 1
+#define CONFIG_YAFFS_YAFFS2 1
+#define CONFIG_YAFFS_PROVIDE_DEFS 1
+#define CONFIG_YAFFSFS_PROVIDE_VALUES 1
+#define CONFIG_YAFFS_DEFINES_TYPES 1
+#define NO_Y_INLINE 1
+#define loff_t off_t
+
+#endif /* __rtems__ */
+
/* Definition of types */
#ifdef CONFIG_YAFFS_DEFINES_TYPES
typedef unsigned char u8;
typedef signed int s32;
#endif
-
#ifdef CONFIG_YAFFS_PROVIDE_DEFS
/* File types */
--- /dev/null
+#
+# This file was originally written to work from the yaffs2 base directory
+# which required deleting some of the Linux files.
+#
+# This is now modified to run from the yaffs2/rtems directory and copies in
+# all files as symbolic links.
+#
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+include $(RTEMS_MAKEFILE_PATH)/make/target.cfg
+
+INSTALL_BASE = $(RTEMS_MAKEFILE_PATH)/lib
+
+BUILDDIR = build-$(RTEMS_BSP)
+
+CPPFLAGS += -I.
+
+DEPFLAGS = -MT $@ -MD -MP -MF $(basename $@).d
+
+GCCFLAGS = -g -I . -B $(INSTALL_BASE) -specs bsp_specs -qrtems
+
+CFLAGS += $(DEPFLAGS) $(GCCFLAGS)
+
+# Files to be made into local symlinks
+YCORE_SYMLINKS = \
+ yaffs_ecc.c \
+ yaffs_endian.c \
+ yaffs_guts.c \
+ yaffs_packedtags1.c \
+ yaffs_tagscompat.c \
+ yaffs_packedtags2.c \
+ yaffs_nand.c \
+ yaffs_checkptrw.c \
+ yaffs_nameval.c \
+ yaffs_allocator.c \
+ yaffs_bitmap.c \
+ yaffs_yaffs1.c \
+ yaffs_yaffs2.c \
+ yaffs_verify.c \
+ yaffs_summary.c \
+ yaffs_tagsmarshall.c\
+ yaffs_ecc.h \
+ yaffs_guts.h \
+ yaffs_packedtags1.h \
+ yaffs_tagscompat.h \
+ yaffs_packedtags2.h \
+ yaffs_nand.h \
+ yaffs_checkptrw.h \
+ yaffs_nameval.h \
+ yaffs_attribs.h \
+ yaffs_allocator.h \
+ yaffs_bitmap.h \
+ yaffs_yaffs1.h \
+ yaffs_yaffs2.h \
+ yaffs_verify.h \
+ yaffs_summary.h \
+ yaffs_trace.h \
+ yaffs_endian.h \
+ yaffs_getblockinfo.h \
+ yaffs_tagsmarshall.h
+
+
+DIRECT_SYMLINKS = \
+ yaffs_attribs.c \
+ yaffs_hweight.c \
+ yaffs_hweight.h \
+ yportenv.h \
+ ydirectenv.h \
+ yaffscfg.h \
+ yaffs_osglue.h \
+ yaffs_list.h \
+ yaffsfs.h
+
+DIRECT_QSORT_SYMLINKS = \
+ qsort.c
+
+ALL_SYMLINKS = $(YCORE_SYMLINKS) $(DIRECT_SYMLINKS) $(DIRECT_QSORT_SYMLINKS)
+
+
+INCLUDES = rtems_yaffs.h \
+ yportenv.h \
+ ydirectenv.h \
+ yaffs_osglue.h \
+ yaffs_hweight.h \
+ yaffscfg.h \
+ yaffs_list.h \
+ yaffsfs.h \
+ yaffs_guts.h \
+ yaffs_packedtags2.h \
+ yaffs_ecc.h
+
+LIB = $(BUILDDIR)/libyaffs2.a
+LIB_PIECES = yaffs_ecc \
+ yaffs_endian \
+ yaffs_guts \
+ yaffs_packedtags1 \
+ yaffs_tagscompat \
+ yaffs_tagsmarshall\
+ yaffs_packedtags2 \
+ yaffs_nand \
+ yaffs_checkptrw \
+ qsort \
+ yaffs_nameval \
+ yaffs_attribs \
+ yaffs_allocator \
+ yaffs_bitmap \
+ yaffs_yaffs1 \
+ yaffs_yaffs2 \
+ yaffs_verify \
+ yaffs_summary \
+ yaffs_hweight \
+ rtems_yaffs \
+ rtems_yaffs_os_context \
+ rtems_yaffs_os_glue
+LIB_OBJS = $(LIB_PIECES:%=$(BUILDDIR)/%.o)
+LIB_DEPS = $(LIB_PIECES:%=$(BUILDDIR)/%.d)
+
+all: $(BUILDDIR) $(ALL_SYMLINKS) $(LIB)
+
+symlinks:$(ALL_SYMLINKS)
+
+$(YCORE_SYMLINKS):
+ ln -s ../$@ $@
+
+$(DIRECT_SYMLINKS):
+ ln -s ../direct/$@ $@
+
+$(DIRECT_QSORT_SYMLINKS):
+ ln -s ../direct/optional_sort/$@ $@
+
+$(BUILDDIR):
+ mkdir $(BUILDDIR)
+
+$(LIB): $(LIB_OBJS)
+ $(AR) rcu $@ $^
+ $(RANLIB) $@
+
+$(BUILDDIR)/%.o: %.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
+
+clean:
+ rm -rf $(BUILDDIR) $(ALL_SYMLINKS)
+
+install: all
+ mkdir -p $(INSTALL_BASE)/include/yaffs
+ install -m 644 $(LIB) $(INSTALL_BASE)
+ install -m 644 $(INCLUDES) $(INSTALL_BASE)/include/yaffs
+
+.PHONY: clean install
+
+-include $(LIB_DEPS)
--- /dev/null
+
+
+Building with Makeifle
+
+Assuming the BSP is the sparc erc32 BSP in:
+/home/charles/quick-start/rtems/5/sparc-rtems5/erc32/
+
+
+
+Set up environment variuables
+
+export RTEMS_MAKEFILE_PATH=/home/charles/quick-start/rtems/5/sparc-rtems5/erc32/
+export PATH=/home/charles/quick-start/rtems/5/bin/:$PATH
+
+Now we can build and install the Yaffs library:
+
+$cd /opt/y/git/yaffs2/rtems
+
+$make -f Makefile.rtems clean
+$make -f Makefile.rtems all
+ output is build-erc32/libyaffs2.a
+$make -f Makefile.rtems install
+ mkdir -p /home/charles/quick-start/rtems/5/sparc-rtems5/erc32/lib/include/yaffs
+ install -m 644 build-erc32/libyaffs2.a /home/charles/quick-start/rtems/5/sparc-rtems5/erc32/lib
+ install -m 644 rtems_yaffs.h yportenv.h ydirectenv.h yaffs_osglue.h yaffs_hweight.h yaffscfg.h yaffs_list.h yaffsfs.h yaffs_guts.h yaffs_packedtags2.h yaffs_ecc.h /home/charles/quick-start/rtems/5/sparc-rtems5/erc32/lib/include/yaffs
+
+
+Building test application
+
+
+$ cd rtems-y-test/
+
+
+
+Running
+
+$ sparc-rtems5-sis hello_world_c/o-optimize/hello.exe
+
+ SIS - SPARC/RISCV instruction simulator 2.20, copyright Jiri Gaisler 2019
+ Bug-reports to jiri@gaisler.se
+
+ ERC32 emulation enabled
+
+ Loaded hello_world_c/o-optimize/hello.exe, entry 0x02000000
+sis> go
+resuming at 0x02000000
+
+
+*** HELLO WORLD TEST ***
+Hello World 123
+*** END OF HELLO WORLD TEST ***
+
+*** FATAL ***
+fatal source: 5 (RTEMS_FATAL_SOURCE_EXIT)
+fatal code: 0 (0x00000000)
+RTEMS version: 5.0.0.e22554535796fc29a7ed7c5e2338128e324a621d-modified
+RTEMS tools: 7.5.0 20191114 (RTEMS 5, RSB 5 (599c4d7c87fa), Newlib d14714c69)
+executing thread ID: 0x08a010001
+executing thread name: UI1
+cpu 0 in error mode (tt = 0x101)
+ 125619 0200c0e0: 91d02000 ta 0x0
+sis>
+
+
+Running with GDB
+
+Open a second terminal to run sis in gdb mode
+
+$ sparc-rtems5-sis -gdb
+
+ SIS - SPARC/RISCV instruction simulator 2.20, copyright Jiri Gaisler 2019
+ Bug-reports to jiri@gaisler.se
+
+ ERC32 emulation enabled
+
+gdb: listening on port 1234 connected
+X2000000,0:#40
+
+
+*** HELLO WORLD TEST ***
+Hello World 123
+*** END OF HELLO WORLD TEST ***
+
+*** FATAL ***
+fatal source: 5 (RTEMS_FATAL_SOURCE_EXIT)
+fatal code: 0 (0x00000000)
+RTEMS version: 5.0.0.e22554535796fc29a7ed7c5e2338128e324a621d-modified
+RTEMS tools: 7.5.0 20191114 (RTEMS 5, RSB 5 (599c4d7c87fa), Newlib d14714c69)
+executing thread ID: 0x08a010001
+executing thread name: UI1
+
+
+
+
+
+
+From other window use gdb
+
+
+
+$ sparc-rtems5-gdb hello.exe
+GNU gdb (GDB) 8.3
+Copyright (C) 2019 Free Software Foundation, Inc.
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+This is free software: you are free to change and redistribute it.
+There is NO WARRANTY, to the extent permitted by law.
+Type "show copying" and "show warranty" for details.
+This GDB was configured as "--host=x86_64-linux-gnu --target=sparc-rtems5".
+Type "show configuration" for configuration details.
+For bug reporting instructions, please see:
+<http://www.gnu.org/software/gdb/bugs/>.
+Find the GDB manual and other documentation resources online at:
+ <http://www.gnu.org/software/gdb/documentation/>.
+
+For help, type "help".
+Type "apropos word" to search for commands related to "word"...
+Reading symbols from hello.exe...
+(gdb) target remote :1234
+:1234: Connection timed out.
+(gdb) target remote :1234
+Remote debugging using :1234
+0x00000000 in ?? ()
+(gdb) load
+Loading section .text, size 0x12880 lma 0x2000000
+Loading section .rtemsroset, size 0x40 lma 0x2012880
+Loading section .data, size 0x530 lma 0x20138c0
+Start address 0x2000000, load size 77296
+Transfer rate: 2434 KB/sec, 270 bytes/write.
+(gdb) c
+Continuing.
+
+Program received signal SIGTERM, Terminated.
+syscall () at /home/charles/quick-start/src/rtems/c/src/../../cpukit/score/cpu/sparc/syscall.S:44
+44 ta 0 ! syscall 1, halt with %g1,%g2,%g3 info
+(gdb)
+
--- /dev/null
+#
+# Makefile for yaffs-rtems-test.exe
+#
+
+#
+# RTEMS_MAKEFILE_PATH is typically set in an environment variable
+#
+
+EXEC=yaffs-rtems-test.exe
+PGM=${ARCH}/$(EXEC)
+
+# optional managers required
+MANAGERS=all
+
+# C source names
+CSRCS = yaffs-rtems-basic-test.c
+CSRCS += yaffs-rtems-test-wrapper.c yaffs-rtems-flashsim.c
+COBJS_ = $(CSRCS:.c=.o)
+COBJS = $(COBJS_:%=${ARCH}/%)
+
+# C++ source names
+CXXSRCS =
+CXXOBJS_ = $(CXXSRCS:.cc=.o)
+CXXOBJS = $(CXXOBJS_:%=${ARCH}/%)
+
+# AS source names
+ASSRCS =
+ASOBJS_ = $(ASSRCS:.s=.o)
+ASOBJS = $(ASOBJS_:%=${ARCH}/%)
+
+# Libraries
+#LIBS = -lrtemsall -lc -lyaffs2
+LINK_LIBS = -lyaffs2
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+
+include $(RTEMS_CUSTOM)
+include $(PROJECT_ROOT)/make/leaf.cfg
+
+OBJS= $(COBJS) $(CXXOBJS) $(ASOBJS)
+
+all: ${ARCH} $(PGM)
+
+#Create symlinks
+yaffs-rtems-test-wrapper.c: ../common/yaffs-rtems-test-wrapper.c
+ ln -sf $^ $@
+
+yaffs-rtems-flashsim.c: ../common/yaffs-rtems-flashsim.c
+ ln -sf $^ $@
+
+yaffs-rtems-flashsim.h: ../common/yaffs-rtems-flashsim.h
+ ln -sf $^ $@
+
+$(OBJS): yaffs-rtems-flashsim.h
+
+$(PGM): $(OBJS)
+ $(make-exe)
+
--- /dev/null
+The basic tests test common fs operations such as open, close, read, write etc.
+
+Multiple files and directories are opened, created, read, deleted, truncated etc.
+
--- /dev/null
+/*
+ * Simple test program -- demonstrating use of IMFS
+ */
+
+#include <bsp.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <dirent.h>
+
+#include <rtems/libio.h>
+#include <yaffs/rtems_yaffs.h>
+
+void set_uint8_t_buffer(uint8_t *buf, uint32_t n, uint8_t start, uint8_t inc)
+{
+ while (n) {
+ *buf = start;
+ buf++;
+ start += inc;
+ n--;
+ }
+}
+
+void make_test_file_name(char *out, int out_size, char *root_path, char *dir, char *file, int index)
+{
+ if (index >= 0)
+ snprintf(out, out_size, "%s/%s/%s-%d",
+ root_path, dir, file, index);
+ else
+ snprintf(out, out_size, "%s/%s/%s",
+ root_path, dir, file);
+}
+
+void make_test_dir_name(char *out, int out_size, char *root_path, char *dir)
+{
+ snprintf(out, out_size, "%s/%s", root_path, dir);
+}
+
+void dump_directory_tree_worker(const char *dname,int recursive)
+{
+ DIR *d;
+ struct dirent *de;
+ struct stat s;
+ char str[1000];
+
+ d = opendir(dname);
+
+ if(!d) {
+ printf("opendir failed\n");
+ } else {
+ while((de = readdir(d)) != NULL) {
+ sprintf(str,"%s/%s",dname,de->d_name);
+
+ lstat(str,&s);
+
+ printf("%s inode %d length %d mode 0%o ",
+ str, (int)s.st_ino, (int)s.st_size, s.st_mode);
+ switch(s.st_mode & S_IFMT) {
+ case S_IFREG: printf("data file"); break;
+ case S_IFDIR: printf("directory"); break;
+ case S_IFLNK: printf("symlink -->");
+ if(readlink(str,str,100) < 0)
+ printf("no alias");
+ else
+ printf("\"%s\"",str);
+ break;
+ default: printf("unknown mode"); break;
+ }
+
+ printf("\n");
+
+ if((s.st_mode & S_IFMT) == S_IFDIR && recursive)
+ dump_directory_tree_worker(str,1);
+ }
+ closedir(d);
+ }
+}
+
+static void dump_directory_tree(const char *dname)
+{
+ printf("Directory tree of %s\n", dname);
+ dump_directory_tree_worker(dname,1);
+}
+
+
+void recursively_delete(char *objname)
+{
+ struct stat s;
+ DIR *d;
+ struct dirent *de;
+ char str[500];
+
+
+ //printf("deleting %s\n", objname);
+ lstat(objname, &s);
+
+ switch(s.st_mode & S_IFMT) {
+ case S_IFREG:
+ printf("delete data file %s returns %d\n",
+ objname, unlink(objname));
+ break;
+ case S_IFLNK:
+ printf("delete symlink %s returns %d\n",
+ objname, unlink(objname));
+ break;
+ case S_IFDIR:
+ d = opendir(objname);
+ if(!d) {
+ printf("opendir failed\n");
+ } else {
+ while((de = readdir(d)) != NULL) {
+ snprintf(str, sizeof(str), "%s/%s",
+ objname, de->d_name);
+ recursively_delete(str);
+ }
+ closedir(d);
+ }
+ printf("delete directory %s returns %d\n",
+ objname, rmdir(objname));
+ break;
+ }
+}
+
+
+
+void dumpDir(const char *dname)
+{
+ dump_directory_tree_worker(dname,0);
+}
+
+int basic_file_test(char *root_path, char *test_path)
+{
+ char fname[100];
+ char dname[100];
+ int fd;
+ int ret;
+ uint8_t buf[100];
+ uint8_t buf2[100];
+
+ make_test_dir_name(dname, sizeof(dname), root_path, test_path);
+ make_test_file_name(fname, sizeof(fname), root_path, test_path, "file", -1);
+
+ ret = mkdir(dname, 0777);
+
+ if (ret < 0) {
+ perror("mkdir");
+ return ret;
+ }
+
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0777);
+ printf("open %s = %d\n", fname, fd);
+ if (fd < 0) {
+ perror("opening test file");
+ return fd;
+ }
+
+ set_uint8_t_buffer(buf, sizeof(buf), 0xAA, 1);
+
+ ret = write(fd, buf, sizeof(buf));
+
+ printf("write returned %d\n", ret);
+
+ if (ret < 0) {
+ perror("writing file");
+ return ret;
+ }
+
+ ret = fdatasync(fd);
+
+ if (ret < 0) {
+ perror("fdatasync problem");
+ return ret;
+ }
+
+ ret = lseek(fd, 0, SEEK_END);
+
+ printf("lseek end ret = %d\n", ret);
+
+ ret = lseek(fd, 0, SEEK_SET);
+ printf("lseek start ret = %d\n", ret);
+
+ ret = read(fd, buf2, sizeof(buf2));
+
+ printf("reading file ret = %d\n", ret);
+
+ if (ret < 0) {
+ perror("reading file");
+ return ret;
+ }
+
+ dump_directory_tree(root_path);
+
+ if (memcmp(buf, buf2, sizeof(buf)) == 0) {
+ printf("buffers match\n");
+ return 0;
+ } else {
+ printf("buffers do not match\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+
+int create_delete_files_pass(char *root_path, char *test_path, int n_files, int del_when_done)
+{
+ char fname[100];
+ char lname[100];
+ char dname[100];
+ int *fds = NULL;
+ int ret;
+ int i;
+ uint8_t buf[100];
+ uint8_t buf2[100];
+
+ fds = malloc(n_files * sizeof (int));
+
+ if (!fds) {
+ printf("Failed to malloc\n");
+ ret = -1;
+ goto err;
+ }
+
+ make_test_dir_name(dname, sizeof(dname), root_path, test_path);
+
+ recursively_delete(dname);
+
+ ret = access(dname, F_OK);
+ printf("access of non-existing expects -1 returned %d\n", ret);
+
+ if (ret != -1) {
+ printf("access should have been -1, was %d\n", ret);
+ ret = -1;
+ goto err;
+ }
+
+ ret = mkdir(dname, 0777);
+
+ if (ret < 0) {
+ perror("mkdir");
+ goto err;
+ }
+
+ ret = access(dname, F_OK);
+ printf("access of existing returned %d\n", ret);
+
+ if (ret < 0) {
+ perror("access of existing directory");
+ goto err;
+ }
+
+ for (i = 0; i < n_files; i++) {
+ int link_fd;
+
+ make_test_file_name(fname, sizeof(fname), root_path, test_path, "file-", i);
+ make_test_file_name(lname, sizeof(lname), root_path, test_path, "link-", i);
+
+ ret = symlink(fname, lname);
+
+ if (ret < 0) {
+ perror("creating symlink");
+ goto err;
+ }
+
+ fds[i] = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0777);
+ printf("open %s = %d\n", fname, fds[i]);
+
+ if (fds[i] < 0) {
+ perror("opening test file");
+ ret = fds[i];
+ goto err;
+ }
+
+
+ link_fd = open(lname, O_RDWR, 0777);
+ printf("opening link %s = %d\n", lname, link_fd);
+
+ if (link_fd < 0) {
+ perror("opening symlink file");
+ ret = link_fd;
+ goto err;
+ }
+ close(link_fd);
+
+ }
+
+ set_uint8_t_buffer(buf, sizeof(buf), 0xAA, 1);
+
+ for(i = 0; i < n_files; i++) {
+ ret = write(fds[i], buf, sizeof(buf));
+ printf("write returned %d\n", ret);
+ if (ret < 0) {
+ perror("writing file");
+ goto err;
+ }
+ }
+
+ for(i = 0; i < n_files; i++) {
+ int trunc_size = sizeof(buf2)/2;
+
+ ret = lseek(fds[i], 0, SEEK_END);
+
+ printf("lseek end ret = %d\n", ret);
+
+ ret = lseek(fds[i], 0, SEEK_SET);
+ printf("lseek start ret = %d\n", ret);
+
+ ret = read(fds[i], buf2, sizeof(buf2));
+
+ printf("reading file ret = %d\n", ret);
+ if (ret < 0) {
+ perror("reading file");
+ goto err;
+ }
+ ret = ftruncate(fds[i], trunc_size);
+
+ if (ret < 0) {
+ perror("ftruncate");
+ goto err;
+ }
+
+ ret = lseek(fds[i], 0, SEEK_END);
+ if (ret != trunc_size) {
+ printf("truncated size is %d but lseek returned %d\n",
+ trunc_size, ret);
+ ret = -1;
+ goto err;
+ }
+
+
+ }
+
+ for(i = 0; i < n_files; i++) {
+ ret = close(fds[i]);
+ if (ret < 0) {
+ perror("closing file");
+ goto err;
+ }
+ }
+
+ dump_directory_tree(root_path);
+
+ if (memcmp(buf, buf2, sizeof(buf)) == 0) {
+ printf("buffers match\n");
+ ret = 0;
+ } else {
+ printf("buffers do not match\n");
+ ret = -1;
+ }
+
+ if (del_when_done)
+ recursively_delete(dname);
+err:
+ free(fds);
+
+ return ret;
+}
+
+int create_delete_files(char *root_path, char *test_path, int n_files, int n_passes)
+{
+ int i;
+ int ret;
+ for (i = 0; i < n_passes; i++) {
+ printf("\nCreate and Delete Files Pass %d\n", i);
+ ret = create_delete_files_pass(root_path, test_path, n_files, 1);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+#define YPATH "/yaffs_mount_pt"
+#define FNAME YPATH"/test"
+#define DIRNAME YPATH"/dirtest"
+
+void check_fail(int ret)
+{
+ if (ret < 0)
+ printf("Test failed\n");
+}
+
+void run_the_test(void)
+{
+ check_fail(basic_file_test(YPATH, "basic-test-dir"));
+ check_fail(create_delete_files(YPATH, "create-del-test-dir", 15, 50));
+
+ printf("\n\n\nAll Yaffs Tests passed Ok\n\n\n");
+}
--- /dev/null
+/*
+ * Modified verion of yramsim.c.
+ */
+#include "yaffs-rtems-flashsim.h"
+
+#include <string.h>
+#include "../../yaffs_guts.h"
+
+
+
+#define N_RAM_SIM_DEVS 1
+
+#define DATA_SIZE 2048
+#define SPARE_SIZE 64
+#define PAGE_SIZE (DATA_SIZE + SPARE_SIZE)
+#define PAGES_PER_BLOCK 64
+
+
+#if 0
+#define dout printf
+#else
+#define dout(...) do { } while(0)
+#endif
+
+
+
+uint32_t stats_reads;
+uint32_t stats_writes;
+uint32_t stats_erases;
+
+typedef struct {
+ unsigned char page[PAGES_PER_BLOCK][PAGE_SIZE];
+ unsigned blockOk;
+} Block;
+
+typedef struct {
+ Block **blockList;
+ int nBlocks;
+} SimData;
+
+
+SimData *simDevs[N_RAM_SIM_DEVS];
+
+static SimData *DevToSim(struct yaffs_dev *dev)
+{
+ return (SimData*)(dev->driver_context);
+}
+
+
+static void CheckInitialised(void)
+{
+
+}
+
+static int yramsim_erase_internal(SimData *sim, unsigned blockId,int force)
+{
+ if(blockId < 0 || blockId >= sim->nBlocks){
+ return 0;
+ }
+
+ if(!sim->blockList[blockId]){
+ return 0;
+ }
+
+ if(!force && !sim->blockList[blockId]->blockOk){
+ return 0;
+ }
+
+ memset(sim->blockList[blockId],0xff,sizeof(Block));
+ sim->blockList[blockId]->blockOk = 1;
+
+ return 1;
+}
+
+
+
+
+static int yramsim_initialise(struct yaffs_dev *dev)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+ return blockList != NULL;
+}
+
+
+static int yramsim_deinitialise(struct yaffs_dev *dev)
+{
+ return 1;
+}
+
+static int yramsim_rd_chunk (struct yaffs_dev *dev, int pageId,
+ u8 *data, int dataLength,
+ u8 *spare, int spareLength,
+ enum yaffs_ecc_result *ecc_result)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+
+ unsigned blockId = pageId / PAGES_PER_BLOCK;
+ unsigned pageOffset = pageId % PAGES_PER_BLOCK;
+ unsigned char * d;
+ unsigned char *s;
+
+ stats_reads++;
+
+ if(blockId >= sim->nBlocks ||
+ pageOffset >= PAGES_PER_BLOCK ||
+ dataLength >DATA_SIZE ||
+ spareLength > SPARE_SIZE ||
+ !blockList[blockId]->blockOk){
+ return YAFFS_FAIL;
+ }
+
+ d = blockList[blockId]->page[pageOffset];
+ s = d + DATA_SIZE;
+
+ if(data)
+ memcpy(data,d,dataLength);
+
+ if(spare)
+ memcpy(spare,s,spareLength);
+
+ if (ecc_result)
+ *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
+
+ return YAFFS_OK;
+}
+
+static int yramsim_wr_chunk (struct yaffs_dev *dev, int pageId,
+ const u8 *data, int dataLength,
+ const u8 *spare, int spareLength)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+
+ unsigned blockId = pageId / PAGES_PER_BLOCK;
+ unsigned pageOffset = pageId % PAGES_PER_BLOCK;
+ unsigned char * d;
+ unsigned char *s;
+
+ dout("wr_chunk\n");
+
+ stats_writes++;
+
+ if(blockId >= sim->nBlocks ||
+ pageOffset >= PAGES_PER_BLOCK ||
+ dataLength >DATA_SIZE ||
+ spareLength > SPARE_SIZE ||
+ !blockList[blockId]->blockOk){
+ return YAFFS_FAIL;
+ }
+
+ d = blockList[blockId]->page[pageOffset];
+ s = d + DATA_SIZE;
+
+ if(data)
+ memcpy(d,data,dataLength);
+
+ if(spare)
+ memcpy(s,spare,spareLength);
+
+ return YAFFS_OK;
+}
+
+
+static int yramsim_erase(struct yaffs_dev *dev, int blockId)
+{
+ SimData *sim = DevToSim(dev);
+
+ stats_erases++;
+
+ CheckInitialised();
+ return yramsim_erase_internal(sim,blockId,0);
+}
+
+static int yramsim_check_block_bad(struct yaffs_dev *dev, int blockId)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+ if(blockId >= sim->nBlocks){
+ return YAFFS_FAIL;
+ }
+
+ return blockList[blockId]->blockOk ? YAFFS_OK : YAFFS_FAIL;
+}
+
+static int yramsim_mark_block_bad(struct yaffs_dev *dev, int blockId)
+{
+ SimData *sim = DevToSim(dev);
+ Block **blockList = sim->blockList;
+ if(blockId >= sim->nBlocks){
+ return YAFFS_FAIL;
+ }
+
+ blockList[blockId]->blockOk = 0;
+
+ return YAFFS_OK;
+}
+
+
+static SimData *yramsim_alloc_sim_data(u32 devId, u32 nBlocks)
+{
+ int ok = 1;
+
+ Block **blockList;
+ SimData *sim;
+ Block *b;
+ u32 i;
+
+ if(devId >= N_RAM_SIM_DEVS)
+ return NULL;
+
+ sim = simDevs[devId];
+
+ if(sim)
+ return sim;
+
+ sim = malloc(sizeof (SimData));
+ if(!sim)
+ return NULL;
+
+ simDevs[devId] = sim;
+
+ blockList = malloc(nBlocks * sizeof(Block *));
+
+ sim->blockList = blockList;
+ sim->nBlocks = nBlocks;
+ if(!blockList){
+ free(sim);
+ return NULL;
+ }
+
+ for(i = 0; i < nBlocks; i++)
+ blockList[i] = NULL;
+
+ for(i = 0; i < nBlocks && ok; i++){
+ b= malloc(sizeof(Block));
+ if(b){
+ blockList[i] = b;
+ yramsim_erase_internal(sim,i,1);
+ }
+ else
+ ok = 0;
+ }
+
+ if(!ok){
+ for(i = 0; i < nBlocks; i++)
+ if(blockList[i]){
+ free(blockList[i]);
+ blockList[i] = NULL;
+ }
+ free(blockList);
+ blockList = NULL;
+ free(sim);
+ sim = NULL;
+ }
+
+ return sim;
+}
+
+
+struct yaffs_dev *yramsim_CreateRamSim(const YCHAR *name,
+ u32 devId, u32 nBlocks,
+ u32 start_block, u32 end_block)
+{
+ SimData *sim;
+ struct yaffs_dev *dev;
+ struct yaffs_param *p;
+ struct yaffs_driver *d;
+
+ sim = yramsim_alloc_sim_data(devId, nBlocks);
+
+ dev = malloc(sizeof(*dev));
+
+ if(!sim || !dev){
+ free(sim);
+ free(dev);
+ printf("Flash Sim creation failed. sim = %p, dev = %p\n",
+ sim, dev);
+ return NULL;
+ }
+
+ memset(dev, 0, sizeof(*dev));
+
+ if(start_block >= sim->nBlocks)
+ start_block = 0;
+ if(end_block == 0 || end_block >= sim->nBlocks)
+ end_block = sim->nBlocks - 1;
+
+ p = &dev->param;
+ p->name = strdup(name);
+ p->start_block = start_block;
+ p->end_block = end_block;
+ p->total_bytes_per_chunk = DATA_SIZE;
+ p->spare_bytes_per_chunk= SPARE_SIZE;
+ p->chunks_per_block = PAGES_PER_BLOCK;
+ p->n_reserved_blocks = 2;
+ p->use_nand_ecc = 1;
+ p->inband_tags = 0;
+ p->is_yaffs2 = 1;
+
+ d= &dev->drv;
+ d->drv_initialise_fn = yramsim_initialise;
+ d->drv_deinitialise_fn = yramsim_deinitialise;
+ d->drv_read_chunk_fn = yramsim_rd_chunk;
+ d->drv_write_chunk_fn = yramsim_wr_chunk;
+ d->drv_erase_fn = yramsim_erase;
+ d->drv_check_bad_fn = yramsim_check_block_bad;
+ d->drv_mark_bad_fn = yramsim_mark_block_bad;
+
+ dev->driver_context= (void *)sim;
+
+ printf("Created simulated flash device %p\n", dev);
+ return dev;
+}
+
+struct yaffs_dev *yaffs_rtems_flashsim_setup(void)
+{
+ return yramsim_CreateRamSim("ramsim",
+ 0, 100,
+ 0, 99);
+}
+
+
+void yaffs_rtems_flashsim_dump_status(void)
+{
+ printf("\nFlashsim stats\n");
+ printf("reads.....%d\n", stats_reads);
+ printf("writes....%d\n", stats_writes);
+ printf("erases....%d\n", stats_erases);
+}
--- /dev/null
+#ifndef __YAFFS_FLASH_SIM_H__
+#define __YAFFS_FLASH_SIM_H__
+
+struct yaffs_dev;
+
+struct yaffs_dev *yaffs_rtems_flashsim_setup(void);
+
+void yaffs_rtems_flashsim_dump_status(void);
+
+#endif
+
--- /dev/null
+/*
+ * Simple test program -- demonstrating use of IMFS
+ */
+
+#include <bsp.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rtems/libio.h>
+#include <yaffs/rtems_yaffs.h>
+
+#include "yaffs-rtems-flashsim.h"
+
+#define YPATH "/yaffs_mount_pt"
+//#define YPATH ""
+
+void yaffs_bug_fn(const char *file_name, int line_no)
+{
+ printf("Yaffs bug at %s:%d\n", file_name, line_no);
+}
+
+int filesystem_init(const char *mount_target)
+{
+ struct yaffs_dev *device;
+ rtems_yaffs_default_os_context *os_context;
+ rtems_yaffs_mount_data mount_args;
+
+
+ rtems_filesystem_register(RTEMS_FILESYSTEM_TYPE_YAFFS,
+ rtems_yaffs_mount_handler);
+
+ // We mount the filesystem by passing an appropriate
+ // rtems_yaffs_mount_data as the last argument to mount(). mount_data is
+ // used to pass a yaffs_dev pointer by-value.
+
+
+ device = yaffs_rtems_flashsim_setup();
+
+ // Initialize callback storage for RTEMS's VFS inside the yaffs_dev.
+ os_context = malloc(sizeof(rtems_yaffs_default_os_context));
+ rtems_yaffs_initialize_default_os_context(os_context);
+
+ device->os_context = os_context;
+
+ mount_args.dev = device;
+
+ if (mount_and_make_target_path(NULL,
+ mount_target,
+ RTEMS_FILESYSTEM_TYPE_YAFFS,
+ RTEMS_FILESYSTEM_READ_WRITE,
+ &mount_args) < 0) {
+ perror("mount_and_make");
+ return errno;
+ } else {
+ chmod(mount_target, 0777); /* Make partition rw/modifiable */
+ return 0;
+ }
+}
+
+extern int run_the_test(void);
+
+rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ int err;
+
+ printf("Starting\n");
+
+ err = filesystem_init(YPATH);
+
+ printf("filesystem_init(\"%s\") returned %d\n", YPATH, err);
+
+ run_the_test();
+
+ yaffs_rtems_flashsim_dump_status();
+
+ exit(0);
+}
+
+
+
+
+#if 0
+So basically, we are registering our NAND-specific callbacks with YAFFS
+and registering the RTEMS-YAFFS filesystem callbacks with RTEMS.
+The rtems_filesystem_register() associates the mount() system call with
+a callback function to handle that system call, in this case
+rtems_yaffs_mount_handler(). rtems_yaffs_mount_handler() and
+RTEMS_FILESYSTEM_TYPE_YAFFS (just a string) are provided
+by the rtems-yaffs fork.
+
+mount_and_make_target_path() is provided by RTEMS: it combines a
+mkdir -p` with mount(), passing the mount_args to the
+previously-registered handler.
+#endif
+
+
+/* configuration information */
+
+/* NOTICE: the clock driver is explicitly disabled */
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+
+#define CONFIGURE_USE_IMFS_AS_BASE_FILESYSTEM
+#define CONFIGURE_MAXIMUM_FILE_DESCRIPTORS 32
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_MAXIMUM_SEMAPHORES 20
+
+#define CONFIGURE_INIT
+
+#include <rtems/confdefs.h>
+/* end of file */
--- /dev/null
+#
+# Makefile for rtems-fsx.exe
+#
+
+#
+# RTEMS_MAKEFILE_PATH is typically set in an environment variable
+#
+
+EXEC=rtems-fsx.exe
+PGM=${ARCH}/$(EXEC)
+
+# optional managers required
+MANAGERS=all
+
+# C source names
+CSRCS = rtems-fsx.c
+CSRCS += yaffs-rtems-test-wrapper.c yaffs-rtems-flashsim.c
+COBJS_ = $(CSRCS:.c=.o)
+COBJS = $(COBJS_:%=${ARCH}/%)
+
+# C++ source names
+CXXSRCS =
+CXXOBJS_ = $(CXXSRCS:.cc=.o)
+CXXOBJS = $(CXXOBJS_:%=${ARCH}/%)
+
+# AS source names
+ASSRCS =
+ASOBJS_ = $(ASSRCS:.s=.o)
+ASOBJS = $(ASOBJS_:%=${ARCH}/%)
+
+# Libraries
+#LIBS = -lrtemsall -lc -lyaffs2
+LINK_LIBS = -lyaffs2
+
+include $(RTEMS_MAKEFILE_PATH)/Makefile.inc
+
+include $(RTEMS_CUSTOM)
+include $(PROJECT_ROOT)/make/leaf.cfg
+
+OBJS= $(COBJS) $(CXXOBJS) $(ASOBJS)
+
+all: ${ARCH} $(PGM)
+
+#Create symlinks
+yaffs-rtems-test-wrapper.c: ../common/yaffs-rtems-test-wrapper.c
+ ln -sf $^ $@
+
+yaffs-rtems-flashsim.c: ../common/yaffs-rtems-flashsim.c
+ ln -sf $^ $@
+
+yaffs-rtems-flashsim.h: ../common/yaffs-rtems-flashsim.h
+ ln -sf $^ $@
+
+$(OBJS): yaffs-rtems-flashsim.h
+
+$(PGM): $(OBJS)
+ $(make-exe)
+
--- /dev/null
+FSX is a file system exerciser originally written at Apple for
+stress testing file system operations, particularly those related to
+seeking, truncating etc.
+
+A good output looks like:
+
+Starting
+Created simulated flash device 0x2d24348
+yaffs: 0 blocks to be sorted...
+filesystem_init("/yaffs_mount_pt") returned 0
+mkdir returned 0
+fsx_init done
+truncating to largest ever: 0x1cbf7
+truncating to largest ever: 0x27453
+truncating to largest ever: 0x2d9bd
+truncating to largest ever: 0x36c22
+truncating to largest ever: 0x3e9f5
+truncating to largest ever: 0x3eff0
+truncating to largest ever: 0x3fd22
+truncating to largest ever: 0x3fe0b
+truncating to largest ever: 0x3fe29
+truncating to largest ever: 0x3ff4b
+All operations completed A-OK!
+fsx wanted to exit with 0
+
+Flashsim stats
+reads.....44373
+writes....46000
+erases....644
+
+
+
+To run for longer or shorter periods modify this line:
+ return fsx_main(FSX_TEST_DIR, 10000);
+
+
+This program has been run overnight (using a very large value) and no
+problems were observed.
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 1998-2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.2 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * WARNING--WARNING--WARNING
+ * This is not the original fsx.c. It has been modified to run with
+ * yaffs direct. Seek out the original fsx.c if you want to do anything
+ * else.
+ *
+ *
+ *
+ * File: fsx.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * File system exerciser.
+ *
+ * Rewrite and enhancements 1998-2001 Conrad Minshall -- conrad@mac.com
+ *
+ * Various features from Joe Sokol, Pat Dirks, and Clark Warner.
+ *
+ * Small changes to work under Linux -- davej@suse.de
+ *
+ * Sundry porting patches from Guy Harris 12/2001
+ *
+ * Checks for mmap last-page zero fill.
+ *
+ * Modified heavily by Charles Manning to exercise via the
+ * yaffs direct interface.
+ *
+ */
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _UWIN
+# include <sys/param.h>
+# include <limits.h>
+# include <time.h>
+# include <strings.h>
+#endif
+#include <fcntl.h>
+#include <sys/mman.h>
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <time.h>
+
+
+#define NUMPRINTCOLUMNS 32 /* # columns of data to print on each line */
+
+/*
+ * A log entry is an operation and a bunch of arguments.
+ */
+
+struct log_entry {
+ int operation;
+ int args[3];
+};
+
+#define LOGSIZE 1000
+
+struct log_entry oplog[LOGSIZE]; /* the log */
+int logptr = 0; /* current position in log */
+int logcount = 0; /* total ops */
+
+/*
+ * Define operations
+ */
+
+#define OP_READ 1
+#define OP_WRITE 2
+#define OP_TRUNCATE 3
+#define OP_CLOSEOPEN 4
+#define OP_MAPREAD 5
+#define OP_MAPWRITE 6
+#define OP_SKIPPED 7
+
+int page_size;
+int page_mask;
+
+char *original_buf; /* a pointer to the original data */
+char *good_buf; /* a pointer to the correct data */
+char *temp_buf; /* a pointer to the current data */
+
+char fname[200]; /* name of our test file */
+char mount_name[200];
+
+int fd; /* fd for our test file */
+
+off_t file_size = 0;
+off_t biggest = 0;
+char state[256];
+unsigned long testcalls = 0; /* calls to function "test" */
+
+unsigned long simulatedopcount = 0; /* -b flag */
+unsigned closeprob = 0; /* -c flag */
+int debug = 0; /* -d flag */
+unsigned long debugstart = 0; /* -D flag */
+unsigned long maxfilelen = 256 * 1024; /* -l flag */
+int sizechecks = 1; /* -n flag disables them */
+int maxoplen = 64 * 1024; /* -o flag */
+int quiet = 0; /* -q flag */
+unsigned long progressinterval = 0; /* -p flag */
+int readbdy = 1; /* -r flag */
+int style = 0; /* -s flag */
+int truncbdy = 1; /* -t flag */
+int writebdy = 1; /* -w flag */
+long monitorstart = -1; /* -m flag */
+long monitorend = -1; /* -m flag */
+int lite = 0; /* -L flag */
+int randomoplen = 1; /* -O flag disables it */
+int seed = 1; /* -S flag */
+
+int mapped_writes = 0; /* yaffs direct does not support mmapped files */
+int mapped_reads = 0;
+
+int fsxgoodfd = 0;
+FILE * fsxlogf = NULL;
+int badoff = -1;
+int closeopen = 0;
+
+
+
+void EXIT(int x)
+{
+ printf("fsx wanted to exit with %d\n",x);
+ while(x){}
+}
+
+char goodfile[1024];
+char logfile[1024];
+
+
+void
+vwarnc(code, fmt, ap)
+ int code;
+ const char *fmt;
+ va_list ap;
+{
+ fprintf(stderr, "fsx: ");
+ if (fmt != NULL) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, ": ");
+ }
+ fprintf(stderr, "%s\n", strerror(code));
+}
+
+
+void
+warn(const char * fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vwarnc(errno, fmt, ap);
+ va_end(ap);
+}
+
+
+void
+prt(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stdout, fmt, args);
+ if (fsxlogf)
+ vfprintf(fsxlogf, fmt, args);
+ va_end(args);
+}
+
+void
+prterr(char *prefix)
+{
+ prt("%s%s%s\n", prefix, prefix ? ": " : "", strerror(errno));
+}
+
+
+void
+log4(int operation, int arg0, int arg1, int arg2)
+{
+ struct log_entry *le;
+
+ le = &oplog[logptr];
+ le->operation = operation;
+ if (closeopen)
+ le->operation = ~ le->operation;
+ le->args[0] = arg0;
+ le->args[1] = arg1;
+ le->args[2] = arg2;
+ logptr++;
+ logcount++;
+ if (logptr >= LOGSIZE)
+ logptr = 0;
+}
+
+
+void
+logdump(void)
+{
+ int i, count, down;
+ struct log_entry *lp;
+
+ prt("LOG DUMP (%d total operations):\n", logcount);
+ if (logcount < LOGSIZE) {
+ i = 0;
+ count = logcount;
+ } else {
+ i = logptr;
+ count = LOGSIZE;
+ }
+ for ( ; count > 0; count--) {
+ int opnum;
+
+ opnum = i+1 + (logcount/LOGSIZE)*LOGSIZE;
+ prt("%d(%d mod 256): ", opnum, opnum%256);
+ lp = &oplog[i];
+ if ((closeopen = lp->operation < 0))
+ lp->operation = ~ lp->operation;
+
+ switch (lp->operation) {
+ case OP_MAPREAD:
+ prt("MAPREAD\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] && badoff <
+ lp->args[0] + lp->args[1])
+ prt("\t***RRRR***");
+ break;
+ case OP_MAPWRITE:
+ prt("MAPWRITE 0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] && badoff <
+ lp->args[0] + lp->args[1])
+ prt("\t******WWWW");
+ break;
+ case OP_READ:
+ prt("READ\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (badoff >= lp->args[0] &&
+ badoff < lp->args[0] + lp->args[1])
+ prt("\t***RRRR***");
+ break;
+ case OP_WRITE:
+ prt("WRITE\t0x%x thru 0x%x\t(0x%x bytes)",
+ lp->args[0], lp->args[0] + lp->args[1] - 1,
+ lp->args[1]);
+ if (lp->args[0] > lp->args[2])
+ prt(" HOLE");
+ else if (lp->args[0] + lp->args[1] > lp->args[2])
+ prt(" EXTEND");
+ if ((badoff >= lp->args[0] || badoff >=lp->args[2]) &&
+ badoff < lp->args[0] + lp->args[1])
+ prt("\t***WWWW");
+ break;
+ case OP_TRUNCATE:
+ down = lp->args[0] < lp->args[1];
+ prt("TRUNCATE %s\tfrom 0x%x to 0x%x",
+ down ? "DOWN" : "UP", lp->args[1], lp->args[0]);
+ if (badoff >= lp->args[!down] &&
+ badoff < lp->args[!!down])
+ prt("\t******WWWW");
+ break;
+ case OP_SKIPPED:
+ prt("SKIPPED (no operation)");
+ break;
+ default:
+ prt("BOGUS LOG ENTRY (operation code = %d)!",
+ lp->operation);
+ }
+ if (closeopen)
+ prt("\n\t\tCLOSE/OPEN");
+ prt("\n");
+ i++;
+ if (i == LOGSIZE)
+ i = 0;
+ }
+}
+
+
+void
+save_buffer(char *buffer, off_t bufferlength, int fd)
+{
+ off_t ret;
+ ssize_t byteswritten;
+
+ if (fd <= 0 || bufferlength == 0)
+ return;
+
+ if (bufferlength > SSIZE_MAX) {
+ prt("fsx flaw: overflow in save_buffer\n");
+ EXIT(67);
+ }
+ if (lite) {
+ off_t size_by_seek = lseek(fd, (off_t)0, SEEK_END);
+ if (size_by_seek == (off_t)-1)
+ prterr("save_buffer: lseek eof");
+ else if (bufferlength > size_by_seek) {
+ warn("save_buffer: .fsxgood file too short... will save 0x%llx bytes instead of 0x%llx\n", (unsigned long long)size_by_seek,
+ (unsigned long long)bufferlength);
+ bufferlength = size_by_seek;
+ }
+ }
+
+ ret = lseek(fd, (off_t)0, SEEK_SET);
+ if (ret == (off_t)-1)
+ prterr("save_buffer: lseek 0");
+
+ byteswritten = write(fd, buffer, (size_t)bufferlength);
+ if (byteswritten != bufferlength) {
+ if (byteswritten == -1)
+ prterr("save_buffer write");
+ else
+ warn("save_buffer: short write, 0x%x bytes instead of 0x%llx\n",
+ (unsigned)byteswritten,
+ (unsigned long long)bufferlength);
+ }
+}
+
+
+void
+report_failure(int status)
+{
+ logdump();
+
+ if (fsxgoodfd) {
+ if (good_buf) {
+ save_buffer(good_buf, file_size, fsxgoodfd);
+ prt("Correct content saved for comparison\n");
+ prt("(maybe hexdump \"%s\" vs \"%s.fsxgood\")\n",
+ fname, fname);
+ }
+ close(fsxgoodfd);
+ }
+ prt("Exiting with %d\n",status);
+ EXIT(status);
+}
+
+
+#define short_at(cp) ((unsigned short)((*((unsigned char *)(cp)) << 8) | \
+ *(((unsigned char *)(cp)) + 1)))
+
+void
+check_buffers(unsigned offset, unsigned size)
+{
+ unsigned char c, t;
+ unsigned i = 0;
+ unsigned n = 0;
+ unsigned op = 0;
+ unsigned bad = 0;
+
+ if (memcmp(good_buf + offset, temp_buf, size) != 0) {
+ prt("READ BAD DATA: offset = 0x%x, size = 0x%x\n",
+ offset, size);
+ prt("OFFSET\tGOOD\tBAD\tRANGE\n");
+ while (size > 0) {
+ c = good_buf[offset];
+ t = temp_buf[i];
+ if (c != t) {
+ if (n == 0) {
+ bad = short_at(&temp_buf[i]);
+ prt("0x%5x\t0x%04x\t0x%04x", offset,
+ short_at(&good_buf[offset]), bad);
+ op = temp_buf[offset & 1 ? i+1 : i];
+ }
+ n++;
+ badoff = offset;
+ }
+ offset++;
+ i++;
+ size--;
+ }
+ if (n) {
+ prt("\t0x%5x\n", n);
+ if (bad)
+ prt("operation# (mod 256) for the bad data may be %u\n", ((unsigned)op & 0xff));
+ else
+ prt("operation# (mod 256) for the bad data unknown, check HOLE and EXTEND ops\n");
+ } else
+ prt("????????????????\n");
+ report_failure(110);
+ }
+}
+
+
+void
+check_size(void)
+{
+ struct stat statbuf;
+ off_t size_by_seek;
+
+ if (fstat(fd, &statbuf)) {
+ prterr("check_size: fstat");
+ statbuf.st_size = -1;
+ }
+ size_by_seek = lseek(fd, (off_t)0, SEEK_END);
+ if (file_size != statbuf.st_size ||
+ file_size != size_by_seek) {
+ prt("Size error: expected 0x%llx stat 0x%llx seek 0x%llx\n",
+ (unsigned long long)file_size,
+ (unsigned long long)statbuf.st_size,
+ (unsigned long long)size_by_seek);
+ report_failure(120);
+ }
+}
+
+
+void
+check_trunc_hack(void)
+{
+ struct stat statbuf;
+
+ ftruncate(fd, (off_t)0);
+ ftruncate(fd, (off_t)100000);
+ fstat(fd, &statbuf);
+ if (statbuf.st_size != (off_t)100000) {
+ prt("no extend on truncate! not posix!\n");
+ EXIT(130);
+ }
+ ftruncate(fd, (off_t)0);
+}
+
+
+void
+doread(unsigned offset, unsigned size)
+{
+ off_t ret;
+ unsigned iret;
+
+ offset -= offset % readbdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size read\n");
+ log4(OP_SKIPPED, OP_READ, offset, size);
+ return;
+ }
+ if ((off_t)(size + offset) > file_size) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping seek/read past end of file\n");
+ log4(OP_SKIPPED, OP_READ, offset, size);
+ return;
+ }
+
+ log4(OP_READ, offset, size, 0);
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && ((progressinterval &&
+ testcalls % progressinterval == 0) ||
+ (debug &&
+ (monitorstart == -1 ||
+ (offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))))
+ prt("%lu read\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+ ret = lseek(fd, (off_t)offset, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr("doread: lseek");
+ report_failure(140);
+ }
+ iret = read(fd, temp_buf, size);
+ if (iret != size) {
+ if (iret == (unsigned)(-1))
+ prterr("doread: read");
+ else
+ prt("short read: 0x%x bytes instead of 0x%x\n",
+ iret, size);
+ report_failure(141);
+ }
+ check_buffers(offset, size);
+}
+
+
+
+
+
+void
+gendata(char *original_buf, char *good_buf, unsigned offset, unsigned size)
+{
+ while (size--) {
+ good_buf[offset] = testcalls % 256;
+ if (offset % 2)
+ good_buf[offset] += original_buf[offset];
+ offset++;
+ }
+}
+
+
+void
+dowrite(unsigned offset, unsigned size)
+{
+ off_t ret;
+ unsigned iret;
+
+ offset -= offset % writebdy;
+ if (size == 0) {
+ if (!quiet && testcalls > simulatedopcount)
+ prt("skipping zero size write\n");
+ log4(OP_SKIPPED, OP_WRITE, offset, size);
+ return;
+ }
+
+ log4(OP_WRITE, offset, size, file_size);
+
+ gendata(original_buf, good_buf, offset, size);
+ if (file_size < offset + size) {
+ if (file_size < offset)
+ memset(good_buf + file_size, '\0', offset - file_size);
+ file_size = offset + size;
+ if (lite) {
+ warn("Lite file size bug in fsx!");
+ report_failure(149);
+ }
+ }
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (!quiet && ((progressinterval &&
+ testcalls % progressinterval == 0) ||
+ (debug &&
+ (monitorstart == -1 ||
+ (offset + size > monitorstart &&
+ (monitorend == -1 || offset <= monitorend))))))
+ prt("%lu write\t0x%x thru\t0x%x\t(0x%x bytes)\n", testcalls,
+ offset, offset + size - 1, size);
+ ret = lseek(fd, (off_t)offset, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr("dowrite: lseek");
+ report_failure(150);
+ }
+ iret = write(fd, good_buf + offset, size);
+ if (iret != size) {
+ if (iret == (unsigned)(-1))
+ prterr("dowrite: write");
+ else
+ prt("short write: 0x%x bytes instead of 0x%x\n",
+ iret, size);
+ report_failure(151);
+ }
+}
+
+
+
+void
+dotruncate(unsigned size)
+{
+ int oldsize = file_size;
+
+ size -= size % truncbdy;
+ if (size > biggest) {
+ biggest = size;
+ if (!quiet && testcalls > simulatedopcount)
+ prt("truncating to largest ever: 0x%x\n", size);
+ }
+
+ log4(OP_TRUNCATE, size, (unsigned)file_size, 0);
+
+ if (size > file_size)
+ memset(good_buf + file_size, '\0', size - file_size);
+ file_size = size;
+
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if ((progressinterval && testcalls % progressinterval == 0) ||
+ (debug && (monitorstart == -1 || monitorend == -1 ||
+ size <= monitorend)))
+ prt("%lu trunc\tfrom 0x%x to 0x%x\n", testcalls, oldsize, size);
+ if (ftruncate(fd, (off_t)size) == -1) {
+ prt("ftruncate1: %x\n", size);
+ prterr("dotruncate: ftruncate");
+ report_failure(160);
+ }
+}
+
+
+void
+writefileimage()
+{
+ ssize_t iret;
+
+ if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
+ prterr("writefileimage: lseek");
+ report_failure(171);
+ }
+ iret = write(fd, good_buf, file_size);
+ if ((off_t)iret != file_size) {
+ if (iret == -1)
+ prterr("writefileimage: write");
+ else
+ prt("short write: 0x%x bytes instead of 0x%llx\n",
+ iret, (unsigned long long)file_size);
+ report_failure(172);
+ }
+ if (lite ? 0 : ftruncate(fd, file_size) == -1) {
+ prt("ftruncate2: %llx\n", (unsigned long long)file_size);
+ prterr("writefileimage: ftruncate");
+ report_failure(173);
+ }
+}
+
+
+void
+docloseopen(void)
+{
+ if (testcalls <= simulatedopcount)
+ return;
+
+ if (debug)
+ prt("%lu close/open\n", testcalls);
+ if (close(fd)) {
+ prterr("docloseopen: close");
+ report_failure(180);
+ }
+ fd = open(fname, O_RDWR, 0);
+ if (fd < 0) {
+ prterr("docloseopen: open");
+ report_failure(181);
+ }
+}
+
+
+void
+fsx_do_op(void)
+{
+ unsigned long offset;
+ unsigned long size = maxoplen;
+ unsigned long rv = random();
+ unsigned long op = rv % (3 + !lite + mapped_writes);
+
+ /* turn off the map read if necessary */
+
+ if (op == 2 && !mapped_reads)
+ op = 0;
+
+ if (simulatedopcount > 0 && testcalls == simulatedopcount)
+ writefileimage();
+
+ testcalls++;
+
+ if (closeprob)
+ closeopen = (rv >> 3) < (1U << 28) / closeprob;
+
+ if (debugstart > 0 && testcalls >= debugstart)
+ debug = 1;
+
+ if (!quiet && testcalls < simulatedopcount && testcalls % 100000 == 0)
+ prt("%lu...\n", testcalls);
+
+ /*
+ * READ: op = 0
+ * WRITE: op = 1
+ * MAPREAD: op = 2
+ * TRUNCATE: op = 3
+ * MAPWRITE: op = 3 or 4
+ */
+ if (lite ? 0 : op == 3 && (style & 1) == 0) /* vanilla truncate? */
+ dotruncate(random() % maxfilelen);
+ else {
+ if (randomoplen)
+ size = random() % (maxoplen+1);
+ if (lite ? 0 : op == 3)
+ dotruncate(size);
+ else {
+ offset = random();
+ if (op == 1 || op == (lite ? 3 : 4)) {
+ offset %= maxfilelen;
+ if (offset + size > maxfilelen)
+ size = maxfilelen - offset;
+ dowrite(offset, size);
+ } else {
+ if (file_size)
+ offset %= file_size;
+ else
+ offset = 0;
+ if ((ssize_t)(offset + size) > file_size)
+ size = file_size - offset;
+ doread(offset, size);
+ }
+ }
+ }
+ if (sizechecks && testcalls > simulatedopcount)
+ check_size();
+ if (closeopen)
+ docloseopen();
+}
+
+
+void
+cleanup(sig)
+ int sig;
+{
+ if (sig)
+ prt("signal %d\n", sig);
+ prt("testcalls = %lu\n", testcalls);
+ EXIT(sig);
+}
+
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s",
+ "fsx [-dnqLOW] [-b opnum] [-c Prob] [-l flen] [-m start:end] [-o oplen] [-p progressinterval] [-r readbdy] [-s style] [-t truncbdy] [-w writebdy] [-D startingop] [-N numops] [-P dirpath] [-S seed] fname\n\
+ -b opnum: beginning operation number (default 1)\n\
+ -c P: 1 in P chance of file close+open at each op (default infinity)\n\
+ -d: debug output for all operations\n\
+ -l flen: the upper bound on file size (default 262144)\n\
+ -m startop:endop: monitor (print debug output) specified byte range (default 0:infinity)\n\
+ -n: no verifications of file size\n\
+ -o oplen: the upper bound on operation size (default 65536)\n\
+ -p progressinterval: debug output at specified operation interval\n\
+ -q: quieter operation\n\
+ -r readbdy: 4096 would make reads page aligned (default 1)\n\
+ -s style: 1 gives smaller truncates (default 0)\n\
+ -t truncbdy: 4096 would make truncates page aligned (default 1)\n\
+ -w writebdy: 4096 would make writes page aligned (default 1)\n\
+ -D startingop: debug output starting at specified operation\n\
+ -L: fsxLite - no file creations & no file size changes\n\
+ -N numops: total # operations to do (default infinity)\n\
+ -O: use oplen (see -o flag) for every op (default random)\n\
+ -P dirpath: save .fsxlog and .fsxgood files in dirpath (default ./)\n\
+ -S seed: for random # generator (default 1) 0 gets timestamp\n\
+ fname: this filename is REQUIRED (no default)\n");
+ EXIT(90);
+}
+
+
+int
+getnum(char *s, char **e)
+{
+ int ret = -1;
+
+ *e = (char *) 0;
+ ret = strtol(s, e, 0);
+ if (*e)
+ switch (**e) {
+ case 'b':
+ case 'B':
+ ret *= 512;
+ *e = *e + 1;
+ break;
+ case 'k':
+ case 'K':
+ ret *= 1024;
+ *e = *e + 1;
+ break;
+ case 'm':
+ case 'M':
+ ret *= 1024*1024;
+ *e = *e + 1;
+ break;
+ case 'w':
+ case 'W':
+ ret *= 4;
+ *e = *e + 1;
+ break;
+ }
+ return (ret);
+}
+
+
+
+extern int random_seed;
+extern int simulate_power_failure;
+
+
+int mounted_by_fsx = 0;
+
+
+
+int
+fsx_init(const char *mount_pt)
+{
+ unsigned i;
+
+ goodfile[0] = 0;
+ logfile[0] = 0;
+
+ page_size = getpagesize();
+ page_mask = page_size - 1;
+
+ setvbuf(stdout, (char *)0, _IOLBF, 0); /* line buffered stdout */
+
+ strcpy(mount_name,mount_pt);
+ strcpy(fname,mount_name);
+ strcat(fname,"/fsxdata");
+
+#if 0
+ signal(SIGHUP, cleanup);
+ signal(SIGINT, cleanup);
+ signal(SIGPIPE, cleanup);
+ signal(SIGALRM, cleanup);
+ signal(SIGTERM, cleanup);
+ signal(SIGXCPU, cleanup);
+ signal(SIGXFSZ, cleanup);
+ signal(SIGVTALRM, cleanup);
+ signal(SIGUSR1, cleanup);
+ signal(SIGUSR2, cleanup);
+#endif
+
+#if 0
+ initstate(seed, state, 256);
+ setstate(state);
+#endif
+
+ fd = open(fname, O_RDWR|(lite ? 0 : O_CREAT|O_TRUNC), 0666);
+ if (fd < 0) {
+ prterr(fname);
+ EXIT(91);
+ }
+ strncat(goodfile, fname, 256);
+ strcat (goodfile, ".fsxgood");
+ fsxgoodfd = open(goodfile, O_RDWR|O_CREAT|O_TRUNC, 0666);
+ if (fsxgoodfd < 0) {
+ prterr(goodfile);
+ EXIT(92);
+ }
+ strncat(logfile, "fsx", 256);
+ strcat (logfile, ".fsxlog");
+ fsxlogf = fopen(logfile, "w");
+ if (fsxlogf == NULL) {
+ prterr(logfile);
+ EXIT(93);
+ }
+ if (lite) {
+ off_t ret;
+ file_size = maxfilelen = lseek(fd, (off_t)0, SEEK_END);
+ if (file_size == (off_t)-1) {
+ prterr(fname);
+ warn("main: lseek eof");
+ EXIT(94);
+ }
+ ret = lseek(fd, (off_t)0, SEEK_SET);
+ if (ret == (off_t)-1) {
+ prterr(fname);
+ warn("main: lseek 0");
+ EXIT(95);
+ }
+ }
+ original_buf = (char *) malloc(maxfilelen);
+ for (i = 0; i < maxfilelen; i++)
+ original_buf[i] = random() % 256;
+ good_buf = (char *) malloc(maxfilelen);
+ memset(good_buf, '\0', maxfilelen);
+ temp_buf = (char *) malloc(maxoplen);
+ memset(temp_buf, '\0', maxoplen);
+ if (lite) { /* zero entire existing file */
+ ssize_t written;
+
+ written = write(fd, good_buf, (size_t)maxfilelen);
+ if (written != (ssize_t)maxfilelen) {
+ if (written == -1) {
+ prterr(fname);
+ warn("main: error on write");
+ } else
+ warn("main: short write, 0x%x bytes instead of 0x%x\n",
+ (unsigned)written, maxfilelen);
+ EXIT(98);
+ }
+ } else
+ check_trunc_hack();
+
+ printf("fsx_init done\n");
+
+ return 0;
+}
+
+
+int fsx_complete(void)
+{
+ if (close(fd)) {
+ prterr("close");
+ report_failure(99);
+ }
+
+ close(fsxgoodfd);
+
+ prt("All operations completed A-OK!\n");
+
+ EXIT(0);
+ return 0;
+}
+
+int fsx_main(const char *mount_pt, int numops)
+{
+ fsx_init(mount_pt);
+ while (numops == -1 || numops--)
+ fsx_do_op();
+ fsx_complete();
+
+ return 0;
+}
+
+
+#define YPATH "/yaffs_mount_pt"
+
+#define FSX_TEST_DIR YPATH"/fsx_mount"
+
+int run_the_test(void)
+{
+ int ret;
+ ret = mkdir(FSX_TEST_DIR, 0777);
+ printf("mkdir returned %d\n", ret);
+
+ if (ret < 0)
+ perror("mkdir");
+
+ return fsx_main(FSX_TEST_DIR, 10000);
+}
--- /dev/null
+/*
+ * YAFFS port to RTEMS
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * As a special exception, linking other files with the object code from
+ * this one to produce an executable application does not by itself cause
+ * the resulting executable application to be covered by the GNU General
+ * Public License.
+ * This exception does not however invalidate any other reasons why the
+ * executable file might be covered by the GNU Public License. In particular,
+ * the other YAFFS files are not covered by this exception, and using them
+ * in a proprietary application requires a paid license from Aleph One.
+ */
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+#include <rtems/seterr.h>
+#include <rtems/userenv.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <dirent.h>
+
+#include "yportenv.h"
+
+#include "yaffs_guts.h"
+#include "yaffs_trace.h"
+#include "yaffs_packedtags2.h"
+
+#include "rtems_yaffs.h"
+
+/* RTEMS interface */
+
+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 */
+
+static void ylock(struct yaffs_dev *dev)
+{
+ rtems_yaffs_os_context *os_context = dev->os_context;
+ (*os_context->lock)(dev, os_context);
+}
+
+static void yunlock(struct yaffs_dev *dev)
+{
+ rtems_yaffs_os_context *os_context = dev->os_context;
+ (*os_context->unlock)(dev, os_context);
+}
+
+static void rtems_yaffs_os_unmount(struct yaffs_dev *dev)
+{
+ rtems_yaffs_os_context *os_context = dev->os_context;
+ (*os_context->unmount)(dev, os_context);
+}
+
+static struct yaffs_obj *ryfs_get_object_by_location(
+ const rtems_filesystem_location_info_t *loc
+)
+{
+ return loc->node_access;
+}
+
+static struct yaffs_obj *ryfs_get_object_by_iop(
+ const rtems_libio_t *iop
+)
+{
+ return iop->pathinfo.node_access;
+}
+
+static struct yaffs_dev *ryfs_get_device_by_mt_entry(
+ const rtems_filesystem_mount_table_entry_t *mt_entry
+)
+{
+ return mt_entry->fs_info;
+}
+
+static void ryfs_set_location(rtems_filesystem_location_info_t *loc, struct yaffs_obj *obj)
+{
+ loc->node_access = obj;
+
+ switch (obj->variant_type) {
+ case YAFFS_OBJECT_TYPE_FILE:
+ loc->handlers = &yaffs_file_handlers;
+ break;
+ 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;
+ };
+}
+
+static bool ryfs_eval_is_directory(
+ rtems_filesystem_eval_path_context_t *ctx,
+ void *arg
+)
+{
+ rtems_filesystem_location_info_t *currentloc =
+ rtems_filesystem_eval_path_get_currentloc(ctx);
+ struct yaffs_obj *obj = ryfs_get_object_by_location(currentloc);
+
+ obj = yaffs_get_equivalent_obj(obj);
+
+ return obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY;
+}
+
+static const char *ryfs_make_string(char *buf, const char *src, size_t len)
+{
+ buf [len] = '\0';
+
+ return memcpy(buf, src, len);
+}
+
+static struct yaffs_obj *ryfs_search_in_directory(
+ struct yaffs_obj *dir,
+ const char *token,
+ size_t tokenlen
+)
+{
+ if (rtems_filesystem_is_parent_directory(token, tokenlen)) {
+ dir = dir->parent;
+ } else if (!rtems_filesystem_is_current_directory(token, tokenlen)) {
+ if (tokenlen < YAFFS_MAX_NAME_LENGTH) {
+ char buf [YAFFS_MAX_NAME_LENGTH + 1];
+
+ dir = yaffs_find_by_name(
+ dir,
+ ryfs_make_string(buf, token, tokenlen)
+ );
+ } else {
+ dir = NULL;
+ }
+ }
+
+ return dir;
+}
+
+static rtems_filesystem_eval_path_generic_status ryfs_eval_token(
+ rtems_filesystem_eval_path_context_t *ctx,
+ void *arg,
+ const char *token,
+ size_t tokenlen
+)
+{
+ rtems_filesystem_eval_path_generic_status status =
+ RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE;
+ rtems_filesystem_location_info_t *currentloc =
+ rtems_filesystem_eval_path_get_currentloc(ctx);
+ struct yaffs_obj *dir = ryfs_get_object_by_location(currentloc);
+ bool access_ok = rtems_filesystem_eval_path_check_access(
+ ctx,
+ RTEMS_FS_PERMS_EXEC,
+ dir->yst_mode,
+ (uid_t) dir->yst_uid,
+ (gid_t) dir->yst_gid
+ );
+
+ if (access_ok) {
+ struct yaffs_obj *entry = ryfs_search_in_directory(dir, token, tokenlen);
+
+ if (entry != NULL) {
+ bool terminal = !rtems_filesystem_eval_path_has_path(ctx);
+ int eval_flags = rtems_filesystem_eval_path_get_flags(ctx);
+ bool follow_hard_link = (eval_flags & RTEMS_FS_FOLLOW_HARD_LINK) != 0;
+ bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0;
+ enum yaffs_obj_type type = entry->variant_type;
+
+ rtems_filesystem_eval_path_clear_token(ctx);
+
+ if (type == YAFFS_OBJECT_TYPE_HARDLINK && (follow_hard_link || !terminal)) {
+ entry = yaffs_get_equivalent_obj(entry);
+ }
+
+ if (type == YAFFS_OBJECT_TYPE_SYMLINK && (follow_sym_link || !terminal)) {
+ const char *target = entry->variant.symlink_variant.alias;
+
+ rtems_filesystem_eval_path_recursive(ctx, target, strlen(target));
+ } else {
+ ryfs_set_location(currentloc, entry);
+
+ if (!terminal) {
+ status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE;
+ }
+ }
+ } else {
+ status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY;
+ }
+ }
+
+ return status;
+}
+
+static const rtems_filesystem_eval_path_generic_config ryfs_eval_config = {
+ .is_directory = ryfs_eval_is_directory,
+ .eval_token = ryfs_eval_token
+};
+
+static void ryfs_eval_path(rtems_filesystem_eval_path_context_t *ctx)
+{
+ rtems_filesystem_eval_path_generic(ctx, NULL, &ryfs_eval_config);
+}
+
+/* Helper functions */
+
+static int ryfs_mknod(
+ const rtems_filesystem_location_info_t *parentloc,
+ const char *name,
+ size_t namelen,
+ mode_t mode,
+ dev_t dev
+)
+{
+ int rv = 0;
+ struct yaffs_obj *parent = ryfs_get_object_by_location(parentloc);
+ struct yaffs_obj *(*create)(
+ struct yaffs_obj *parent,
+ const YCHAR *name,
+ u32 mode,
+ u32 uid,
+ u32 gid
+ );
+
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ create = yaffs_create_file;
+ break;
+ case S_IFDIR:
+ create = yaffs_create_dir;
+ break;
+ default:
+ errno = EINVAL;
+ rv = -1;
+ break;
+ }
+
+ if (rv == 0) {
+ char buf [YAFFS_MAX_NAME_LENGTH + 1];
+ struct yaffs_obj *entry = (*create)(
+ parent,
+ ryfs_make_string(buf, name, namelen),
+ mode,
+ geteuid(),
+ getegid()
+ );
+
+ if (entry == NULL) {
+ errno = ENOSPC;
+ rv = -1;
+ }
+ }
+
+ return rv;
+}
+
+static int ryfs_utime(
+ const rtems_filesystem_location_info_t *loc,
+ time_t actime,
+ time_t modtime
+)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
+
+ 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);
+ } else {
+ errno = EIO;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static int ryfs_rename(
+ const rtems_filesystem_location_info_t *old_parent_loc,
+ const rtems_filesystem_location_info_t *old_loc,
+ const rtems_filesystem_location_info_t *new_parent_loc,
+ const char *name,
+ size_t namelen
+)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_location(old_loc);
+ char old_name_buf [YAFFS_MAX_NAME_LENGTH + 1];
+ char new_name_buf [YAFFS_MAX_NAME_LENGTH + 1];
+ int yc;
+
+ yaffs_get_obj_name(obj, old_name_buf, sizeof(old_name_buf));
+ yc = yaffs_rename_obj(
+ obj->parent,
+ old_name_buf,
+ ryfs_get_object_by_location(new_parent_loc),
+ ryfs_make_string(new_name_buf, name, namelen)
+ );
+ if (yc != YAFFS_OK) {
+ errno = EIO;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static ssize_t ryfs_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
+{
+ struct yaffs_obj *obj;
+ struct yaffs_dev *dev;
+ struct dirent *de = (struct dirent *)buffer;
+ size_t i;
+ size_t maxcount;
+ struct list_head *next;
+ ssize_t readlen;
+
+ obj = (struct yaffs_obj *)iop->pathinfo.node_access;
+ dev = obj->my_dev;
+ maxcount = count / sizeof(struct dirent);
+
+ ylock(dev);
+
+ if(iop->offset == 0) {
+ if(list_empty(&obj->variant.dir_variant.children))
+ iop->data1 = NULL;
+ else
+ iop->data1 = list_entry(obj->variant.dir_variant.children.next, struct yaffs_obj, siblings);
+ }
+
+ i = 0;
+ while((i < maxcount) && (iop->data1 != NULL)) {
+ de[i].d_ino = (long)yaffs_get_equivalent_obj((struct yaffs_obj *)iop->data1)->obj_id;
+ de[i].d_off = 0;
+ yaffs_get_obj_name((struct yaffs_obj *)iop->data1, de[i].d_name, NAME_MAX);
+ de[i].d_reclen = sizeof(struct dirent);
+ de[i].d_namlen = (unsigned short)strnlen(de[i].d_name, NAME_MAX);
+
+ i++;
+ next = ((struct yaffs_obj *)iop->data1)->siblings.next;
+ if(next == &obj->variant.dir_variant.children)
+ iop->data1 = NULL; /* end of list */
+ else
+ iop->data1 = list_entry(next, struct yaffs_obj, siblings);
+ }
+
+ readlen = (ssize_t)(i * sizeof(struct dirent));
+ iop->offset = iop->offset + readlen;
+
+ yunlock(dev);
+
+ return readlen;
+}
+
+static int ryfs_fstat(const rtems_filesystem_location_info_t *loc, struct stat *buf)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
+ struct yaffs_dev *dev = obj->my_dev;
+ rtems_yaffs_os_context *os_context = dev->os_context;
+
+ ylock(dev);
+
+ obj = yaffs_get_equivalent_obj(obj);
+ if (obj != NULL) {
+ buf->st_dev = os_context->dev;
+ buf->st_ino = obj->obj_id;
+ buf->st_mode = obj->yst_mode;
+ buf->st_nlink = (nlink_t) yaffs_get_obj_link_count(obj);
+ 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 = (blkcnt_t)
+ ((buf->st_size + buf->st_blksize - 1) / buf->st_blksize);
+ buf->st_uid = (uid_t) obj->yst_uid;
+ buf->st_gid = (gid_t) obj->yst_gid;
+ buf->st_atime = (time_t) obj->yst_atime;
+ buf->st_ctime = (time_t) obj->yst_ctime;
+ buf->st_mtime = (time_t) obj->yst_mtime;
+ } else {
+ errno = EIO;
+ rv = -1;
+ }
+
+ yunlock(dev);
+
+ return rv;
+}
+
+static int ryfs_fchmod(const rtems_filesystem_location_info_t *loc, mode_t mode)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
+ int yc;
+
+ obj = yaffs_get_equivalent_obj(obj);
+ if (obj != NULL) {
+ obj->yst_mode = mode;
+ obj->dirty = 1;
+ yc = yaffs_flush_file(obj, 0, 0, 0);
+ } else {
+ yc = YAFFS_FAIL;
+ }
+
+ if (yc != YAFFS_OK) {
+ errno = EIO;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static int ryfs_chown(
+ const rtems_filesystem_location_info_t *loc,
+ uid_t owner,
+ gid_t group
+)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
+ int yc;
+
+ obj = yaffs_get_equivalent_obj(obj);
+ if (obj != NULL) {
+ obj->yst_uid = owner;
+ obj->yst_gid = group;
+ obj->dirty = 1;
+ yc = yaffs_flush_file(obj, 0, 0, 0);
+ } else {
+ yc = YAFFS_FAIL;
+ }
+
+ if (yc != YAFFS_OK) {
+ errno = EIO;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static int ryfs_fsync_or_fdatasync(rtems_libio_t *iop)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
+ struct yaffs_dev *dev = obj->my_dev;
+ int yc;
+
+ ylock(dev);
+ yc = yaffs_flush_file(obj, 0, 1, 0);
+ if (rtems_filesystem_location_is_instance_root(&iop->pathinfo)) {
+ yaffs_flush_whole_cache(dev, 0);
+ }
+ yunlock(dev);
+
+ if (yc != YAFFS_OK) {
+ errno = EIO;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static int ryfs_rmnod(
+ const rtems_filesystem_location_info_t *parentloc,
+ const rtems_filesystem_location_info_t *loc
+)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_location(loc);
+ int yc = yaffs_del_obj(obj);
+
+ if (yc != YAFFS_OK) {
+ errno = ENOTEMPTY;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+static int ryfs_file_open(rtems_libio_t *iop, const char *pathname, int oflag, mode_t mode)
+{
+ struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
+ struct yaffs_dev *dev = obj->my_dev;
+ int length = 0;
+
+ ylock(dev);
+ length = yaffs_get_obj_length(obj);
+ if ((iop->flags & LIBIO_FLAGS_APPEND) != 0) {
+ iop->offset = length;
+ }
+ yunlock(dev);
+
+ return 0;
+}
+
+static int ryfs_file_close(rtems_libio_t *iop)
+{
+ struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
+ struct yaffs_dev *dev = obj->my_dev;
+
+ ylock(dev);
+ yaffs_flush_file(obj, 1, 0, 1);
+ yunlock(dev);
+
+ return 0;
+}
+
+static ssize_t ryfs_file_read(rtems_libio_t *iop, void *buffer, size_t count)
+{
+ struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
+ struct yaffs_dev *dev = obj->my_dev;
+ ssize_t nr;
+ int ol;
+ size_t maxread;
+
+ ylock(dev);
+
+ ol = yaffs_get_obj_length(obj);
+ if(iop->offset >= ol)
+ maxread = 0;
+ else
+ maxread = (size_t)(ol - (int)iop->offset);
+ if(count > maxread)
+ count = maxread;
+
+ nr = yaffs_file_rd(obj, buffer, iop->offset, (int)count);
+ if (nr >= 0) {
+ iop->offset += nr;
+ } else {
+ errno = EIO;
+ nr = -1;
+ }
+
+ yunlock(dev);
+
+ return nr;
+}
+
+static ssize_t ryfs_file_write(rtems_libio_t *iop, const void *buffer, size_t count)
+{
+ struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
+ struct yaffs_dev *dev = obj->my_dev;
+ ssize_t rv = -1;
+ int max_size = INT_MAX;
+ off_t offset;
+
+ if (count == 0) {
+ return 0;
+ }
+
+ ylock(dev);
+ offset = iop->offset;
+ if (offset < max_size) {
+ size_t max_count = max_size - (size_t) offset;
+
+ if (count > max_count) {
+ count = max_count;
+ }
+
+ rv = yaffs_wr_file(obj, buffer, offset, (int) count, 0);
+ if (rv > 0) {
+ iop->offset += rv;
+ } else {
+ errno = ENOSPC;
+ rv = -1;
+ }
+ } else {
+ errno = EFBIG;
+ }
+ yunlock(dev);
+
+ return rv;
+}
+
+static int ryfs_file_ftruncate(rtems_libio_t *iop, off_t length)
+{
+ int rv = 0;
+ struct yaffs_obj *obj = ryfs_get_object_by_iop(iop);
+ struct yaffs_dev *dev = obj->my_dev;
+ int yc;
+
+ ylock(dev);
+ yc = yaffs_resize_file(obj, length);
+ yunlock(dev);
+
+ if (yc != YAFFS_OK) {
+ errno = EIO;
+ rv = -1;
+ }
+
+ return rv;
+}
+
+int rtems_yaffs_mount_handler(rtems_filesystem_mount_table_entry_t *mt_entry, const void *data)
+{
+ const rtems_yaffs_mount_data *mount_data = data;
+ struct yaffs_dev *dev = mount_data->dev;
+
+ if (dev->read_only && mt_entry->writeable) {
+ errno = EACCES;
+ return -1;
+ }
+
+ ylock(dev);
+ if (yaffs_guts_initialise(dev) == YAFFS_FAIL) {
+ yunlock(dev);
+ errno = ENOMEM;
+ return -1;
+ }
+
+ mt_entry->fs_info = dev;
+ mt_entry->ops = &yaffs_ops;
+ 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, 0);
+ yunlock(dev);
+
+ return 0;
+}
+
+static void ryfs_fsunmount(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
+
+ ylock(dev);
+ yaffs_flush_whole_cache(dev, 1);
+ yaffs_checkpoint_save(dev);
+ yaffs_deinitialise(dev);
+ yunlock(dev);
+ rtems_yaffs_os_unmount(dev);
+}
+
+static void ryfs_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
+
+ ylock(dev);
+}
+
+static void ryfs_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ struct yaffs_dev *dev = ryfs_get_device_by_mt_entry(mt_entry);
+
+ 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,
+ .read_h = ryfs_dir_read,
+ .write_h = rtems_filesystem_default_write,
+ .ioctl_h = rtems_filesystem_default_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek_directory,
+ .fstat_h = ryfs_fstat,
+ .ftruncate_h = rtems_filesystem_default_ftruncate_directory,
+ .fsync_h = ryfs_fsync_or_fdatasync,
+ .fdatasync_h = ryfs_fsync_or_fdatasync,
+ .fcntl_h = rtems_filesystem_default_fcntl
+};
+
+static const rtems_filesystem_file_handlers_r yaffs_file_handlers = {
+ .open_h = ryfs_file_open,
+ .close_h = ryfs_file_close,
+ .read_h = ryfs_file_read,
+ .write_h = ryfs_file_write,
+ .ioctl_h = rtems_filesystem_default_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek_file,
+ .fstat_h = ryfs_fstat,
+ .ftruncate_h = ryfs_file_ftruncate,
+ .fsync_h = ryfs_fsync_or_fdatasync,
+ .fdatasync_h = ryfs_fsync_or_fdatasync,
+ .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,
+ .eval_path_h = ryfs_eval_path,
+ .link_h = rtems_filesystem_default_link,
+ .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
+ .mknod_h = ryfs_mknod,
+ .rmnod_h = ryfs_rmnod,
+ .fchmod_h = ryfs_fchmod,
+ .chown_h = ryfs_chown,
+ .clonenod_h = rtems_filesystem_default_clonenode,
+ .freenod_h = rtems_filesystem_default_freenode,
+ .mount_h = rtems_filesystem_default_mount,
+ .unmount_h = rtems_filesystem_default_unmount,
+ .fsunmount_me_h = ryfs_fsunmount,
+ .utime_h = ryfs_utime,
+ .symlink_h = ryfs_symlink,
+ .readlink_h = ryfs_readlink,
+ .rename_h = ryfs_rename,
+ .statvfs_h = rtems_filesystem_default_statvfs
+};
--- /dev/null
+/*
+ * YAFFS port to RTEMS
+ *
+ * Copyright (C) 2010 Sebastien Bourdeauducq
+ * Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de>
+ * Copyright (C) 2011 embedded brains GmbH <rtems@embedded-brains.de>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * As a special exception, including this header in a file does not by
+ * itself cause the resulting executable application to be covered by the
+ * GNU General Public License.
+ * This exception does not however invalidate any other reasons why the
+ * executable file might be covered by the GNU Public License. In particular,
+ * the other YAFFS files are not covered by this exception, and using them
+ * in a proprietary application requires a paid license from Aleph One.
+ */
+
+#ifndef __RTEMS_YAFFS_H
+#define __RTEMS_YAFFS_H
+
+#include <rtems.h>
+#include <rtems/fs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Must be inside the extern "C" */
+#include "yportenv.h"
+#include "yaffs_guts.h"
+
+/**
+ * @defgroup rtems_yaffs YAFFS Support for RTEMS
+ *
+ *
+ * @{
+ */
+
+#define RTEMS_FILESYSTEM_TYPE_YAFFS "yaffs"
+
+typedef void (*rtems_yaffs_os_handler)(
+ struct yaffs_dev *dev,
+ void *os_context
+);
+
+/**
+ * @brief Per YAFFS file system instance context.
+ */
+typedef struct {
+ rtems_yaffs_os_handler lock;
+ rtems_yaffs_os_handler unlock;
+ rtems_yaffs_os_handler unmount;
+
+ /**
+ * @brief The device containing the file system instance.
+ *
+ * This will be used for the st_dev field in stat().
+ */
+ dev_t dev;
+} rtems_yaffs_os_context;
+
+/**
+ * @brief Default per YAFFS file system instance context.
+ */
+typedef struct {
+ rtems_yaffs_os_context os_context;
+ rtems_id semaphore_id;
+} rtems_yaffs_default_os_context;
+
+/**
+ * @brief Data for YAFFS mount handler.
+ *
+ * @see rtems_yaffs_mount_handler()
+ */
+typedef struct {
+ /**
+ * @brief YAFFS device of the file system instance.
+ *
+ * The @a param field has to be completely set up. The
+ * @a driver_context can point to arbitrary driver specific
+ * information. The @a os_context must point to an initialized
+ * structure that begins with a rtems_yaffs_os_context structure.
+ */
+ struct yaffs_dev *dev;
+} rtems_yaffs_mount_data;
+
+/**
+ * @brief YAFFS mount handler.
+ *
+ * The @a data pointer must point to a completely initialized
+ * rtems_yaffs_mount_data structure. The ownership of the YAFFS device
+ * structure changes. This structure is now owned by the file system layer.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred. The @c errno indicates the error.
+ */
+int rtems_yaffs_mount_handler(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ const void *data
+);
+
+/**
+ * @brief Initializes the default per file system context @a os_context.
+ *
+ * A binary semaphore with priority inheritance will be used to ensure mutual
+ * exclusion.
+ *
+ * The umount handler will release all resources of the default context.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred. The @c errno indicates the error.
+ */
+int rtems_yaffs_initialize_default_os_context(
+ rtems_yaffs_default_os_context *os_context
+);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __RTEMS_YAFFS_H */
--- /dev/null
+/*
+ * YAFFS port to RTEMS
+ *
+ * Copyright (c) 2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * As a special exception, linking other files with the object code from
+ * this one to produce an executable application does not by itself cause
+ * the resulting executable application to be covered by the GNU General
+ * Public License.
+ * This exception does not however invalidate any other reasons why the
+ * executable file might be covered by the GNU Public License. In particular,
+ * the other YAFFS files are not covered by this exception, and using them
+ * in a proprietary application requires a paid license from Aleph One.
+ */
+
+#include "rtems_yaffs.h"
+
+#include <assert.h>
+#include <errno.h>
+
+static void rtems_yaffs_default_lock(struct yaffs_dev *dev, void *arg)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_yaffs_default_os_context *os_context = arg;
+
+ sc = rtems_semaphore_obtain(
+ os_context->semaphore_id,
+ RTEMS_WAIT,
+ RTEMS_NO_TIMEOUT
+ );
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void rtems_yaffs_default_unlock(struct yaffs_dev *dev, void *arg)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_yaffs_default_os_context *os_context = arg;
+
+ sc = rtems_semaphore_release(os_context->semaphore_id);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+static void rtems_yaffs_default_unmount(struct yaffs_dev *dev, void *arg)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ rtems_yaffs_default_os_context *os_context = arg;
+
+ sc = rtems_semaphore_delete(os_context->semaphore_id);
+ assert(sc == RTEMS_SUCCESSFUL);
+}
+
+int rtems_yaffs_initialize_default_os_context(
+ rtems_yaffs_default_os_context *os_context
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+ os_context->os_context.lock = rtems_yaffs_default_lock;
+ os_context->os_context.unlock = rtems_yaffs_default_unlock;
+ os_context->os_context.unmount = rtems_yaffs_default_unmount;
+
+ sc = rtems_semaphore_create(
+ rtems_build_name('Y', 'A', 'F', 'S'),
+ 1,
+ RTEMS_LOCAL
+ | RTEMS_BINARY_SEMAPHORE
+ | RTEMS_INHERIT_PRIORITY
+ | RTEMS_PRIORITY,
+ 0,
+ &os_context->semaphore_id
+ );
+ if (sc == RTEMS_SUCCESSFUL) {
+ return 0;
+ } else {
+ errno = ENOMEM;
+
+ return -1;
+ }
+}
--- /dev/null
+/*
+ * YAFFS port to RTEMS
+ *
+ * Copyright (C) 2010, 2011 Sebastien Bourdeauducq
+ * Copyright (C) 2011 Stephan Hoffmann <sho@reLinux.de>
+ * Copyright (C) 2011 embedded brains GmbH <rtems@embedded-brains.de>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * As a special exception, linking other files with the object code from
+ * this one to produce an executable application does not by itself cause
+ * the resulting executable application to be covered by the GNU General
+ * Public License.
+ * This exception does not however invalidate any other reasons why the
+ * executable file might be covered by the GNU Public License. In particular,
+ * the other YAFFS files are not covered by this exception, and using them
+ * in a proprietary application requires a paid license from Aleph One.
+ */
+
+#include <stdlib.h>
+#include <time.h>
+
+#include "yaffs_trace.h"
+#include "yaffs_osglue.h"
+
+unsigned int yaffs_trace_mask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
+
+unsigned int yaffs_wr_attempts;
+
+void *yaffsfs_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+void yaffsfs_free(void *ptr)
+{
+ free(ptr);
+}
+
+u32 yaffsfs_CurrentTime(void)
+{
+ return time(NULL);
+}
* tags storage.
*/
-#include "yaffs_guts.h"
+#include "yaffs_tagsmarshall.h"
#include "yaffs_trace.h"
#include "yaffs_packedtags2.h"