changeset 336:38a956139d12

Import tests from eCosPro
author Ross Younger <wry@ecoscentric.com>
date Tue, 03 Nov 2009 18:00:39 +0000
parents 201205efa9e1
children b254764fbeac
files packages/fs/yaffs/current/ChangeLog packages/fs/yaffs/current/cdl/yaffs.cdl packages/fs/yaffs/current/tests/mounttime.c packages/fs/yaffs/current/tests/yaffs1.c packages/fs/yaffs/current/tests/yaffs2.c packages/fs/yaffs/current/tests/yaffs4.c packages/fs/yaffs/current/tests/yaffs5.c packages/fs/yaffs/current/tests/yaffs6.c
diffstat 8 files changed, 4846 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/packages/fs/yaffs/current/ChangeLog
+++ b/packages/fs/yaffs/current/ChangeLog
@@ -1,3 +1,8 @@
+2009-11-03  Ross Younger  <wry@ecoscentric.com>
+
+	* tests: Import from eCosPro: mounttime, yaffs1, yaffs2,
+	yaffs4, yaffs5, yaffs6.
+
 2009-11-02  Ross Younger  <wry@ecoscentric.com>
 
 	* Update to latest snapshot from Aleph One CVS (mostly
--- a/packages/fs/yaffs/current/cdl/yaffs.cdl
+++ b/packages/fs/yaffs/current/cdl/yaffs.cdl
@@ -228,10 +228,62 @@ cdl_package CYGPKG_FS_YAFFS {
 		display "YAFFS filesystem tests"
 		flavor data
 		no_define
-		calculated { "tests/fops" }
+		calculated { "tests/fops tests/mounttime" 
+                   . " tests/yaffs1 tests/yaffs2 tests/yaffs4"
+                   . " tests/yaffs5 tests/yaffs6"
+        }
 		description "
 		This special option specifies the set of tests to build for YAFFS."
 	}
 
+    cdl_component CYGPKG_FS_YAFFS_TESTING {
+        display          "Testing configuration"
+        default_value    1
+
+        define_proc {
+            puts $::cdl_system_header "/***** Synthdisk driver proc output start *****/"
+            puts $::cdl_system_header "#define CYGDAT_DEVS_DISK_CFG <pkgconf/fs_yaffs.h>"
+            puts $::cdl_system_header "/***** Synthdisk driver proc output end  *****/"        
+        }
+
+        
+        cdl_option CYGDAT_DEVS_DISK_TEST_DEVICE {
+            display      "Test device driver"
+            flavor       data
+            default_value { CYGPKG_DEVS_NAND_SYNTH?"\"synth/0\"":"\"onboard/0\"" }
+        }
+
+        cdl_option CYGDAT_DEVS_DISK_TEST_MOUNTPOINT {
+            display      "Test filesystem mountpoint"
+            flavor       data
+            default_value {"\"/nand\"" }
+        }
+
+        cdl_option CYGDAT_DEVS_DISK_TEST_DIRECTORY {
+            display      "Test directory on test device"
+            flavor       data
+            default_value {"\"/test\"" }
+        }
+
+        
+        cdl_option CYGDAT_DEVS_DISK_TEST_DEVICE2 {
+            display      "Second Test device driver"
+            flavor       data
+            default_value { CYGPKG_DEVS_NAND_SYNTH?"\"synth/1\"":"\"onboard/1\"" }
+        }
+
+        cdl_option CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2 {
+            display      "Second Test filesystem mountpoint"
+            flavor       data
+            default_value {"\"/nand2\"" }
+        }
+
+        cdl_option CYGDAT_DEVS_DISK_TEST_DIRECTORY2 {
+            display      "Test directory on second test device"
+            flavor       data
+            default_value {"\"/test\"" }
+        }
+
+    }
 
 }
new file mode 100644
--- /dev/null
+++ b/packages/fs/yaffs/current/tests/mounttime.c
@@ -0,0 +1,303 @@
+//=============================================================================
+//
+//      mounttime.c
+//
+//      Mount timings exerciser, use on a filesystem filled by `makefiles'
+//      THIS DOES NOT CURRENTLY WORK ON non-PRO eCos!
+//
+//=============================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 2009 Free Software Foundation, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):   wry
+// Date:        2009-06-29
+// Description: File system mount and unmount timing benchmark.
+//              Intended to be used on a complicated filesystem, e.g.
+//              one filled up by `makefiles'.
+//              Some timing code borrowed from mmfs tests.
+//
+//####DESCRIPTIONEND####
+//=============================================================================
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>
+#include <cyg/infra/cyg_ass.h>
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <cyg/hal/hal_intr.h>
+
+#ifndef HAL_CLOCK_READ
+# error "HAL_CLOCK_READ not defined!"
+#endif
+
+#if !defined(CYGPKG_LIBC_TIME) || !defined(CYGPKG_ERROR) || !defined(CYGPKG_LIBC_STDIO) || !defined(CYGPKG_KERNEL)
+
+void cyg_user_start(void)
+{
+    CYG_TEST_NA("Needs CYGPKG_KERNEL, CYGPKG_LIBC_TIME, CYGPKG_ERROR and CYGPKG_LIBC_STDIO");
+}
+
+#else
+
+#include <cyg/fileio/fileio.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+#include <cyg/kernel/kapi.h>
+
+#ifdef CYGPKG_DEVS_NAND_SYNTH
+#define DEVICE "synth/0"
+#else
+#define DEVICE "onboard/0"
+#endif
+
+#define MOUNTPOINT "/n"
+#define FSTYPE "yaffs"
+#define _NOCACHE "skip-checkpoint-read"
+
+#define FS_NOCACHE FSTYPE":"_NOCACHE
+
+//#define MUST(what) do { CYG_TEST_CHECK((what), #what); } while(0)
+
+#define MUST(what) do { \
+        if (0 != what) { \
+                perror(#what);          \
+                CYG_TEST_FAIL(#what);   \
+                cyg_test_exit();        \
+        }                           \
+} while(0)
+
+#define min(a,b) ( (a) > (b) ? (b) : (a) )
+
+// --------------------------------------------------------------
+
+void RM_RF_work(const char *f, int recurse)
+{
+    MUST(chdir(f));
+    DIR *d = opendir(".");
+    if (!d) {
+        diag_printf("opendir %s: %s\n", f, strerror(errno));
+        return;
+    }
+    struct dirent de_stack;
+    struct dirent *de_res;
+    while (0==readdir_r(d, &de_stack, &de_res) && de_res) {
+        struct stat st;
+        if (0==strcmp(de_res->d_name,".")) continue;
+        if (0==strcmp(de_res->d_name,"..")) continue;
+        MUST(stat(de_res->d_name,&st));
+        if (S_ISDIR(st.st_mode)) {
+            RM_RF_work(de_res->d_name, recurse+1);
+            if (rmdir(de_res->d_name))
+                perror("rmdir");
+        } else {
+            MUST(unlink(de_res->d_name));
+        }
+    }
+    closedir(d);
+    MUST(chdir(".."));
+}
+
+void RM_RF(const char *p)
+{
+    diag_printf("rm -rf %s\n",p);
+    RM_RF_work(p,0);
+    MUST(rmdir(p));
+}
+
+// --------------------------------------------------------------
+// Timing code cribbed from pvr5.c
+
+typedef struct
+{
+    cyg_int64           ticks;
+    cyg_uint32           halticks;
+} timestamp;
+
+typedef struct
+{
+    timestamp           start;
+    timestamp           end;
+    cyg_int64           interval;       // In HAL ticks
+    cyg_int64           us_interval;    // Interval in microseconds
+} timing;
+
+static cyg_int64        ticks_overhead = 0;
+static cyg_int32        us_per_haltick = 0;
+static cyg_int32        halticks_per_us = 0;
+
+static cyg_int64        rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
+static cyg_int64        rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+
+static void wait_for_tick( void )
+{
+    cyg_tick_count_t now = cyg_current_time();
+
+    while( cyg_current_time() == now )
+        continue;
+}
+
+static void get_timestamp( timestamp *ts )
+{
+    ts->ticks = cyg_current_time();
+    HAL_CLOCK_READ( &ts->halticks );
+}
+
+static cyg_int64 ticks_to_us( cyg_int64 ticks )
+{
+    cyg_int64 us;
+
+    if( us_per_haltick != 0 )
+        us = ticks * us_per_haltick;
+    else
+        us = ticks / halticks_per_us;
+
+    return us;
+}
+
+static void calculate_interval( timing *t )
+{
+    t->interval = t->end.halticks - t->start.halticks;
+
+    t->interval += (t->end.ticks - t->start.ticks) * rtc_period;
+
+    t->interval -= ticks_overhead;
+
+    t->us_interval = ticks_to_us( t->interval );
+}
+
+static void init_timing( void )
+{
+    timing t;
+    cyg_thread_delay(2); // ensure clock running - asserts if not
+
+    us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]);
+    halticks_per_us = (rtc_period * rtc_resolution[1])/1000000;
+
+    wait_for_tick();
+
+    get_timestamp( &t.start );
+    get_timestamp( &t.end );
+
+    calculate_interval( &t );
+
+    ticks_overhead = t.interval;
+
+    diag_printf("Timing overhead %lld ticks (%lluus), this will be factored out of all other measurements\n", ticks_overhead, t.us_interval );
+}
+
+static timing tm;
+
+#define START() do {            \
+    wait_for_tick();            \
+    get_timestamp(&tm.start);   \
+} while(0)
+
+static void report(const char *what, timing tm)
+{
+    if (tm.us_interval > 1100000) 
+        diag_printf("%30s: %2d.%03d s\n", what, (int)(tm.us_interval/1000000), (int)(tm.us_interval/1000)%1000);
+    else
+        diag_printf("%30s: %2d.%03d ms\n", what, (int)(tm.us_interval/1000), (int)(tm.us_interval%1000));
+
+}
+
+#define STOP(what) do {         \
+    get_timestamp(&tm.end);     \
+    calculate_interval(&tm);    \
+    report(what, tm);           \
+} while(0)
+
+// --------------------------------------------------------------
+
+void dumpmallinfo(void)
+{
+    struct mallinfo mi = mallinfo();
+    int total_ord = mi.uordblks + mi.fordblks;
+    double pct = (double)mi.uordblks / (double)total_ord;
+    diag_printf("! Arena: size 0x%x, small blks %u/%u, ord blks used %u/%u (%u%%)\n", 
+            mi.arena,
+            mi.usmblks, mi.fsmblks,
+            mi.uordblks, total_ord, (int)(100.0*pct));
+}
+
+// --------------------------------------------------------------
+
+#define WORKDIR MOUNTPOINT "/" "test"
+
+void mounttime_main(void)
+{
+#define NTIMES 3
+    int i;
+    for (i=0; i<NTIMES; i++) {
+        START();
+        MUST(mount(DEVICE, MOUNTPOINT, FSTYPE));
+        STOP("remount");
+        //if (i==0) dumpmallinfo();
+        START();
+        MUST(umount(MOUNTPOINT));
+        STOP("unmount");
+
+        START();
+        MUST(mount(DEVICE, MOUNTPOINT, FS_NOCACHE));
+        // plain eCos does not support mount options, this test won't work there.
+        STOP("remount without checkpoint");
+        //if (i==0) dumpmallinfo();
+        START();
+        MUST(umount(MOUNTPOINT));
+        STOP("unmount");
+        //if (i==0) dumpmallinfo();
+    }
+    //dumpmallinfo();
+
+    // then consider repeats..
+
+    CYG_TEST_EXIT("Run complete");
+}
+
+int main(void)
+{
+    CYG_TEST_INIT();
+    init_timing();
+
+    mounttime_main();
+    return 0;
+}
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/packages/fs/yaffs/current/tests/yaffs1.c
@@ -0,0 +1,959 @@
+//==========================================================================
+//
+//      yaffs1.c
+//
+//      Test fileio system
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2006, 2007 eCosCentric Limited                       
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2000-05-25
+// Purpose:             Test fileio system
+// Description:         This test uses the testfs to check out the initialization
+//                      and basic operation of the fileio system
+//                      
+//                      
+//                      
+//                      
+//                      
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+
+#include CYGDAT_DEVS_DISK_CFG           // testing config defines
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>            // HAL polled output
+
+//==========================================================================
+// Config options
+
+#define TEST_DEVICE     CYGDAT_DEVS_DISK_TEST_DEVICE
+
+#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT
+
+#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY
+
+#define TEST_FSTYPE     "yaffs"
+
+#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DEVICE2     CYGDAT_DEVS_DISK_TEST_DEVICE2
+
+#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2
+
+#define TEST_FSTYPE2    "yaffs"
+
+#endif
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res )                                                                \
+{                                                                                               \
+    diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):"");        \
+}
+
+//==========================================================================
+
+#define IOSIZE  100
+
+#define LONGNAME1       "long_file_name_that_should_take_up_more_than_one_directory_entry_1"
+#define LONGNAME2       "long_file_name_that_should_take_up_more_than_one_directory_entry_2"
+
+
+//==========================================================================
+
+#ifndef CYGPKG_LIBC_STRING
+
+char *strcat( char *s1, const char *s2 )
+{
+    char *s = s1;
+    while( *s1 ) s1++;
+    while( (*s1++ = *s2++) != 0);
+    return s;
+}
+
+#endif
+
+__externC int
+rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW;
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot )
+{
+    int err;
+    DIR *dirp;
+    int num=0;
+    
+    diag_printf("<INFO>: reading directory %s\n",name);
+    
+//    diag_printf("<INFO>: opendir(%s)\n",name);
+    dirp = opendir( name );
+    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+    for(;;)
+    {
+        struct dirent *entry = readdir( dirp );
+        
+        if( entry == NULL )
+            break;
+        num++;
+        diag_printf("<INFO>: entry %14s",entry->d_name);
+#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE
+        diag_printf(" d_type %2x", entry->d_type);
+#endif
+        if( statp )
+        {
+            char fullname[PATH_MAX];
+            struct stat sbuf;
+
+            if( name[0] )
+            {
+                strcpy(fullname, name );
+                if( !(name[0] == '/' && name[1] == 0 ) )
+                    strcat(fullname, "/" );
+            }
+            else fullname[0] = 0;
+            
+            strcat(fullname, entry->d_name );
+            
+            err = stat( fullname, &sbuf );
+            if( err < 0 )
+            {
+                if( errno == ENOSYS )
+                    diag_printf(" <no status available>");
+                else SHOW_RESULT( stat, err );
+            }
+            else
+            {
+                diag_printf(" [mode %08x ino %08x nlink %d size %ld]",
+                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
+            }
+#ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE
+            if ((entry->d_type & S_IFMT) != (sbuf.st_mode & S_IFMT))
+              CYG_TEST_FAIL("File mode's don't match between dirent and stat");
+#endif
+        }
+
+        diag_printf("\n");
+    }
+
+//    diag_printf("<INFO>: closedir(%s)\n",name);    
+    err = closedir( dirp );
+    if( err < 0 ) SHOW_RESULT( stat, err );
+    if (numexpected >= 0 && num != numexpected)
+        CYG_TEST_FAIL("Wrong number of dir entries\n");
+    if ( numgot != NULL )
+        *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t size )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+
+    diag_printf("<INFO>: create file %s size %zd\n",name,size);
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    while( size > 0 )
+    {
+        ssize_t len = size;
+        if ( len > IOSIZE ) len = IOSIZE;
+        
+        wrote = write( fd, buf, len );
+        if( wrote != len ) SHOW_RESULT( write, wrote );        
+
+        size -= wrote;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+#if 0
+static void maxfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+    size_t size = 0;
+    size_t prevsize = 0;
+    
+    diag_printf("<INFO>: create maximal file %s\n",name);
+    diag_printf("<INFO>: This may take a few minutes\n");
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    do
+    {
+        wrote = write( fd, buf, IOSIZE );
+        //if( wrote < 0 ) SHOW_RESULT( write, wrote );        
+
+        if( wrote >= 0 )
+            size += wrote;
+
+        if( (size-prevsize) > 100000 )
+        {
+            diag_printf("<INFO>: size = %zd\n", size);
+            prevsize = size;
+        }
+        
+    } while( wrote == IOSIZE );
+
+    diag_printf("<INFO>: file size == %zd\n",size);
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+#endif
+
+//==========================================================================
+
+static void checkfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t done;
+    int i;
+    int err;
+    off_t pos = 0;
+
+    diag_printf("<INFO>: check file %s\n",name);
+    
+    err = access( name, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd = open( name, O_RDONLY );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    for(;;)
+    {
+        done = read( fd, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        for( i = 0; i < done; i++ )
+            if( buf[i] != i%256 )
+            {
+                diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256);
+                CYG_TEST_FAIL("Data read not equal to data written\n");
+                for(;;);
+            }
+        
+        pos += done;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void copyfile( char *name2, char *name1 )
+{
+
+    int err;
+    char buf[IOSIZE];
+    int fd1, fd2;
+    ssize_t done, wrote;
+
+    diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    err = access( name2, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_WRONLY|O_CREAT );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done = read( fd2, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        wrote = write( fd1, buf, done );
+        if( wrote != done ) SHOW_RESULT( write, wrote );
+
+        if( wrote != done ) break;
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1 )
+{
+    int err;
+    char buf1[IOSIZE];
+    char buf2[IOSIZE];
+    int fd1, fd2;
+    ssize_t done1, done2;
+    int i;
+
+    diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_RDONLY );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done1 = read( fd1, buf1, IOSIZE );
+        if( done1 < 0 ) SHOW_RESULT( read, done1 );
+
+        done2 = read( fd2, buf2, IOSIZE );
+        if( done2 < 0 ) SHOW_RESULT( read, done2 );
+
+        if( done1 != done2 )
+            diag_printf("Files different sizes\n");
+        
+        if( done1 == 0 ) break;
+
+        for( i = 0; i < done1; i++ )
+            if( buf1[i] != buf2[i] )
+            {
+                diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+                CYG_TEST_FAIL("Data in files not equal\n");
+            }
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+void checkcwd( const char *cwd )
+{
+    static char cwdbuf[PATH_MAX];
+    char *ret;
+
+    ret = getcwd( cwdbuf, sizeof(cwdbuf));
+    if( ret == NULL ) SHOW_RESULT( getcwd, ret );    
+
+    if( strcmp( cwdbuf, cwd ) != 0 )
+    {
+        diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+        CYG_TEST_FAIL( "Current directory mismatch");
+    }
+}
+
+//==========================================================================
+// main
+
+void fileio1_main( CYG_ADDRESS id )
+{
+    int err;
+    int existingdirents=-1;
+    cyg_bool mp2 = false;
+    int fd;
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    struct cyg_fs_block_usage usage;
+#endif
+    
+    char dirname[64];
+    char filename1[64];
+    char filename2[64];
+
+#define NEW_FILENAME( fn, f )                           \
+{                                                       \
+    fn[0]=0;                                            \
+    strcat(fn, dirname);                                \
+    strcat(fn, "/");                                    \
+    strcat(fn,f);                                       \
+}
+
+#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f )
+#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f )
+
+    CYG_TEST_INIT();
+    
+    // --------------------------------------------------------------
+
+    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );    
+    if( err < 0 ) {
+        SHOW_RESULT( mount, err );
+        CYG_TEST_FAIL_FINISH("yaffs1");
+    }
+
+    err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    if( err < 0 && errno == EACCES )
+    {
+        diag_printf("<INFO>: create %s\n",
+                    TEST_MOUNTPOINT TEST_DIRECTORY);
+        err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 );
+        if( err < 0 ) SHOW_RESULT( mkdir, err );
+    }
+
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY );    
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents );
+
+    // --------------------------------------------------------------
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE,
+                         &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+               usage.total_blocks, usage.total_blocks * usage.block_size);
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+               usage.free_blocks, usage.free_blocks * usage.block_size);
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
+    // --------------------------------------------------------------
+    
+    dirname[0] = 0;
+    strcat(dirname, TEST_MOUNTPOINT );
+    strcat(dirname, TEST_DIRECTORY );
+    
+    // --------------------------------------------------------------
+
+    createfile( "foo", 20257 );
+    checkfile( "foo" );
+    copyfile( "foo", "fee");
+    checkfile( "fee" );
+    comparefiles( "foo", "fee" );
+    diag_printf("<INFO>: mkdir bar\n");
+    err = mkdir( "bar", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL );
+
+    copyfile( "fee", "bar/fum" );
+    checkfile( "bar/fum" );
+    comparefiles( "fee", "bar/fum" );
+    diag_printf("<INFO>: cd bar\n");
+    err = chdir( "bar" );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    // Create a further subdirectory and immediately remove it
+    // This should make no overall change, but may expose later
+    // node cache reference counting issues.
+    diag_printf("<INFO>: mkdir delme\n");                
+    err = mkdir( "delme", 0);
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+    diag_printf("<INFO>: cd delme\n");                
+    err = chdir( "delme");
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    diag_printf("<INFO>: cd ..\n");                
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    diag_printf("<INFO>: rmdir delme\n");                
+    err = rmdir( "delme" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    NEW_FILENAME1( "bar/delme1" );
+    diag_printf("<INFO>: mkdir %s\n",filename1);            
+    err = mkdir( filename1, 0);
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+    diag_printf("<INFO>: rmdir %s\n",filename1);                
+    err = rmdir( filename1 );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    
+    NEW_FILENAME1( "bar" );
+    checkcwd( filename1 );
+    
+    diag_printf("<INFO>: rename ../foo bundy\n");    
+    err = rename( "../foo", "bundy" );
+    if( err < 0 ) SHOW_RESULT( rename, err );
+    
+    listdir( dirname, true, existingdirents+2, NULL );
+    listdir( "." , true, 4, NULL );
+
+    checkfile( "../bar/bundy" );
+    comparefiles("../fee", "bundy" );
+
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE,
+                         &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+               usage.total_blocks, usage.total_blocks * usage.block_size);
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+               usage.free_blocks, usage.free_blocks * usage.block_size);
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
+    // --------------------------------------------------------------
+    // Check for some common error cases
+
+
+    // First make some directories
+    diag_printf("<INFO>: mkdir doo\n");    
+    err = mkdir( "doo", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    diag_printf("<INFO>: mkdir fie\n");    
+    err = mkdir( "fie", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    diag_printf("<INFO>: mkdir fie/foe\n");    
+    err = mkdir( "fie/foe", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    
+    diag_printf("<INFO>: rename fum doo -- should fail\n");    
+    err = rename( "fum", "doo" );
+    if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename doo fum -- should fail\n");    
+    err = rename( "doo", "fum" );
+    if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename doo fie -- should fail\n");    
+    err = rename( "doo", "fie" );
+    // FATFS returns ENOTEMPTY, since fie has foe within it
+    if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err );
+    
+    diag_printf("<INFO>: open floop for reading -- should fail\n");    
+    err = open( "floop", O_RDONLY );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( open, err );
+
+    NEW_FILENAME1( "x/y" )
+    diag_printf("<INFO>: rename fum %s -- should fail\n",filename1);    
+    err = rename( "fum", filename1 );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename fum fum -- should succeed\n");    
+    err = rename( "fum", "fum" );
+    if( err < 0 ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: unlink fee -- should fail\n");        
+    err = unlink( "fee" );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "bar" );
+    diag_printf("<INFO>: rmdir %s -- should fail\n",filename1);        
+    err = rmdir( filename1 );
+    // FATFS gives EBUSY here, since bar is the current dir
+    if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: unlink %s -- should fail\n",filename1);        
+    err = unlink( filename1 );
+    // FATFS returns EBUSY here, also because bar is current dir
+    if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "bar/fum" );
+    diag_printf("<INFO>: rmdir %s -- should fail\n",filename1);        
+    err = rmdir( filename1 );
+    if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: mkdir %s -- should fail\n",filename1);        
+    err = mkdir( filename1, 0 );
+    if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err );
+    
+    diag_printf("<INFO>: open bundy exclusive -- should fail\n");        
+    fd = open( "bundy", O_WRONLY|O_CREAT|O_EXCL );
+    if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd );
+
+    diag_printf("<INFO>: open %s -- should fail\n",dirname);        
+    fd = open( dirname, O_WRONLY );
+    if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd );
+    
+    
+    listdir( dirname, true, existingdirents+2, NULL );
+    listdir( "." , true, 6, NULL );
+    
+    // --------------------------------------------------------------    
+
+    diag_printf("<INFO>: rename fie doo\n");
+    err = rename( "fie", "doo" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: rmdir doo/foe\n");
+    err = rmdir("doo/foe");
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+
+    diag_printf("<INFO>: rmdir doo\n");
+    err = rmdir("doo");
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+    
+    diag_printf("<INFO>: unlink ../fee\n");    
+    err = unlink( "../fee" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink fum\n");
+    err = unlink( "fum" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink ../bar/bundy\n");        
+    err = unlink( "../bar/bundy" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: cd ..\n");        
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( dirname );
+    
+    diag_printf("<INFO>: rmdir bar\n");        
+    err = rmdir( "bar" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+    listdir( dirname, false, existingdirents, NULL );
+
+    // --------------------------------------------------------------
+
+#ifdef TEST_MOUNTPOINT2
+    diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2);    
+    err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 );
+
+    if( err == 0 )
+    {
+        mp2 = true;
+        diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2);    
+        err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK );
+        if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+        if( err < 0 && errno == EACCES )
+        {
+            diag_printf("<INFO>: create %s\n",
+                        TEST_MOUNTPOINT2 TEST_DIRECTORY2);
+            err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 );
+            if( err < 0 ) SHOW_RESULT( mkdir, err );
+        }
+
+        err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 );    
+        if( err < 0 ) SHOW_RESULT( chdir, err );
+
+        checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 );
+
+        dirname[0] = 0;
+        strcat(dirname, TEST_MOUNTPOINT2 );
+        strcat(dirname, TEST_DIRECTORY2 );
+
+    }
+    else
+    {
+        mp2 = false;
+        diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2);
+        diag_printf("using %s instead\n", dirname );
+    }
+
+#endif
+    
+    listdir( dirname , true, -1, &existingdirents);
+
+    NEW_FILENAME1( "tinky" );
+    NEW_FILENAME2( "laalaa" );
+    
+    createfile( filename1, 4567 );
+    copyfile( filename1, filename2 );
+    checkfile( filename1);
+    checkfile( filename2);
+    comparefiles( filename1, filename2 );
+
+    diag_printf("<INFO>: cd %s\n",dirname);    
+    err = chdir( dirname );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( dirname );
+        
+    diag_printf("<INFO>: mkdir noonoo\n");    
+    err = mkdir( "noonoo", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL);
+
+    diag_printf("<INFO>: cd noonoo\n");
+    err = chdir( "noonoo" );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    NEW_FILENAME1( "noonoo" );
+    checkcwd( filename1 );
+    
+    createfile( "tinky", 6789 );
+    checkfile( "tinky" );
+
+    createfile( "dipsy", 34567 );
+    checkfile( "dipsy" );
+    copyfile( "dipsy", "po" );
+    checkfile( "po" );
+    comparefiles( "dipsy", "po" );
+
+    listdir( ".", true, 5, NULL );
+    listdir( "..", true, existingdirents+3, NULL );
+
+    // --------------------------------------------------------------
+
+    diag_printf("<INFO>: unlink tinky\n");    
+    err = unlink( "tinky" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink dipsy\n");    
+    err = unlink( "dipsy" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink po\n");    
+    err = unlink( "po" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: cd ..\n"); 
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( dirname );
+    
+    diag_printf("<INFO>: rmdir noonoo\n"); 
+    err = rmdir( "noonoo" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    // --------------------------------------------------------------
+
+    diag_printf("<INFO>: mkdir x\n");    
+    err = mkdir( "x", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+    
+    diag_printf("<INFO>: mkdir x/y\n");    
+    err = mkdir( "x/y", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+    
+    diag_printf("<INFO>: mkdir x/y/z\n");    
+    err = mkdir( "x/y/z", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    diag_printf("<INFO>: mkdir x/y/z/w\n");    
+    err = mkdir( "x/y/z/w", 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    NEW_FILENAME1( "x/y/z/w" );
+    diag_printf("<INFO>: cd %s\n",filename1);
+    err = chdir( filename1 );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( "x/y/z" );    
+    diag_printf("<INFO>: cd ..\n");
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( "x/y/z" );
+    diag_printf("<INFO>: cd .\n");
+    err = chdir( "." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( "x/y" );    
+    diag_printf("<INFO>: cd ../../y\n");
+    err = chdir( "../../y" );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    diag_printf("<INFO>: cd ../..\n");
+    err = chdir( "../.." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( dirname );
+
+    diag_printf("<INFO>: rmdir x/y/z/w\n"); 
+    err = rmdir( "x/y/z/w" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir x/y/z\n"); 
+    err = rmdir( "x/y/z" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir x/y\n"); 
+    err = rmdir( "x/y" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir x\n"); 
+    err = rmdir( "x" );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+    // --------------------------------------------------------------
+
+    checkcwd( dirname );
+    
+    diag_printf("<INFO>: unlink tinky\n");    
+    err = unlink( "tinky" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink laalaa\n");    
+    err = unlink( "laalaa" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    // --------------------------------------------------------------
+    
+    diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY);
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY);
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( ".", true, -1, NULL );
+
+#ifdef TEST_MOUNTPOINT2
+    if( mp2 )
+    {
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2);    
+        err = umount( TEST_MOUNTPOINT2 );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+    }
+#endif
+
+    // --------------------------------------------------------------
+
+#if 0
+    maxfile("file.max");
+
+    listdir( "/", true, -1, NULL );    
+        
+    diag_printf("<INFO>: unlink file.max\n");    
+    err = unlink( "file.max" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+#endif
+
+    // --------------------------------------------------------------
+
+    diag_printf("<INFO>: cd /\n");    
+    err = chdir( "/" );
+    if( err == 0 )
+    {
+        checkcwd( "/" );
+    
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT);    
+        err = umount( TEST_MOUNTPOINT );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+    }
+
+    diag_printf("<INFO>: syncing\n");    
+    sync();
+    
+    CYG_TEST_PASS_FINISH("yaffs1");
+}
+
+// -------------------------------------------------------------------------
+
+#include <cyg/kernel/kapi.h>
+
+static cyg_handle_t thread_handle;
+static cyg_thread thread;
+static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024];
+
+externC void
+cyg_start( void )
+{
+    cyg_thread_create(3,                // Priority - just a number
+                      fileio1_main,     // entry
+                      0,                // index
+                      0,                // no name
+                      &stack[0],        // Stack
+                      sizeof(stack),    // Size
+                      &thread_handle,   // Handle
+                      &thread           // Thread data structure
+        );
+    cyg_thread_resume(thread_handle);
+
+    cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+// EOF yaffs1.c
new file mode 100644
--- /dev/null
+++ b/packages/fs/yaffs/current/tests/yaffs2.c
@@ -0,0 +1,809 @@
+//==========================================================================
+//
+//      yaffs2.c
+//
+//      Test fileio system
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2006, 2007 eCosCentric Limited                       
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2000-05-25
+// Purpose:             Test fileio system
+// Description:         This test uses the testfs to check out the initialization
+//                      and basic operation of the fileio system
+//                      
+//                      
+//                      
+//                      
+//                      
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+#include <pkgconf/io_fileio.h>
+
+#include CYGDAT_DEVS_DISK_CFG           // testing config defines
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>            // HAL polled output
+
+#include <cyg/kernel/instrmnt.h>
+
+//==========================================================================
+// Config options
+
+#define TEST_DEVICE     CYGDAT_DEVS_DISK_TEST_DEVICE
+
+#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT
+
+#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY
+
+#define TEST_FSTYPE     "yaffs"
+
+#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DEVICE2     CYGDAT_DEVS_DISK_TEST_DEVICE2
+
+#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2
+
+#define TEST_FSTYPE2    "yaffs"
+
+#endif
+
+//==========================================================================
+
+#if 0
+# define X(_args_)                              \
+{                                               \
+    cyg_drv_isr_lock();                         \
+    diag_printf("%08x: ",cyg_thread_self());    \
+    diag_printf _args_;                         \
+    cyg_drv_isr_unlock();                       \
+                                                \
+}
+#else
+# define X(_args_) CYG_EMPTY_STATEMENT
+#endif
+
+#ifdef JNGPKG_USB_STACK
+extern int usb_stack_init(void);
+#endif
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res ) \
+diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):"");
+
+//==========================================================================
+
+#define IOSIZE  100
+
+#define NTHREAD 6
+
+
+//==========================================================================
+
+#ifndef CYGPKG_LIBC_STRING
+
+char *strcat( char *s1, const char *s2 )
+{
+    char *s = s1;
+    while( *s1 ) s1++;
+    while( (*s1++ = *s2++) != 0);
+    return s;
+}
+
+#endif
+
+__externC int
+rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW;
+
+//==========================================================================
+
+
+static cyg_mutex_t db_lock;
+
+#define db_printf( args... )                    \
+{                                               \
+    cyg_mutex_lock( &db_lock );                 \
+    diag_printf("%d: ",id);                     \
+    diag_printf( args );                        \
+    cyg_mutex_unlock( &db_lock );               \
+}
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot, int id )
+{
+    int err;
+    DIR *dirp;
+    int num=0;
+    
+    db_printf("<INFO>: reading directory %s\n",name);
+
+    dirp = opendir( name );
+    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+    for(;;)
+    {
+        struct dirent entry_data;
+        struct dirent *entry;
+        
+        err = readdir_r( dirp, &entry_data, &entry );
+        
+        if( err < 0 || entry == NULL )
+            break;
+        num++;
+        
+        cyg_mutex_lock( &db_lock );
+        diag_printf("%d: <INFO>: entry %14s",id, entry->d_name);
+        
+        if( statp )
+        {
+            char fullname[PATH_MAX];
+            struct stat sbuf;
+
+            if( name[0] )
+            {
+                strcpy(fullname, name );
+                if( !(name[0] == '/' && name[1] == 0 ) )
+                    strcat(fullname, "/" );
+            }
+            else fullname[0] = 0;
+            
+            strcat(fullname, entry->d_name );
+            
+            err = stat( fullname, &sbuf );
+            if( err < 0 )
+            {
+                if( errno == ENOSYS )
+                    diag_printf(" <no status available>");
+                else
+                {
+                    SHOW_RESULT( stat, err );
+                    cyg_scheduler_lock();
+                    CYG_INSTRUMENT_USER(0xff,err,errno);
+                    for(;;);
+                }
+            }
+            else
+            {
+                diag_printf(" [mode %08x ino %08x nlink %d size %ld]",
+                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
+            }
+        }
+
+        diag_printf("\n");
+        cyg_mutex_unlock( &db_lock );
+    }
+
+    err = closedir( dirp );
+    if( err < 0 ) SHOW_RESULT( stat, err );
+    if (numexpected >= 0 && num != numexpected)
+        CYG_TEST_FAIL("Wrong number of dir entries\n");
+    if ( numgot != NULL )
+        *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t size, int id  )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+
+    db_printf("<INFO>: create file %s size %ld\n",name, (long)size);
+
+    err = access( name, F_OK );
+    if( err < 0 && errno == EEXIST )
+    {
+        err = unlink( name );
+        if( err < 0 ) SHOW_RESULT( unlink, err );
+    }
+    else
+        if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    while( size > 0 )
+    {
+        ssize_t len = size;
+        if ( len > IOSIZE ) len = IOSIZE;
+        
+        wrote = write( fd, buf, len );
+        if( wrote != len ) SHOW_RESULT( write, wrote );        
+
+        size -= wrote;
+
+        cyg_thread_yield();
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+#if 0
+static void maxfile( char *name, int id  )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+    size_t size = 0;
+    size_t prevsize = 0;
+    
+    db_printf("<INFO>: create maximal file %s\n",name);
+    db_printf("<INFO>: This may take a few minutes\n");
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    do
+    {
+        wrote = write( fd, buf, IOSIZE );
+        //if( wrote < 0 ) SHOW_RESULT( write, wrote );        
+
+        if( wrote >= 0 )
+            size += wrote;
+
+        if( (size-prevsize) > 100000 )
+        {
+            db_printf("<INFO>: size = %ld \n", size);
+            prevsize = size;
+        }
+        
+    } while( wrote == IOSIZE );
+
+    db_printf("<INFO>: file size == %ld\n",size);
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+#endif
+
+//==========================================================================
+
+static void checkfile( char *name, int id  )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t done;
+    int i;
+    int err;
+    off_t pos = 0;
+
+    db_printf("<INFO>: check file %s\n",name);
+    
+    err = access( name, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd = open( name, O_RDONLY );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    for(;;)
+    {
+        done = read( fd, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        for( i = 0; i < done; i++ )
+            if( buf[i] != i%256 )
+            {
+//                db_printf("buf[%d+%d](%02x) != %02x\n",pos,i,buf[i],i%256);
+//                CYG_TEST_FAIL("Data read not equal to data written\n");
+                X(("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256));
+                cyg_scheduler_lock();
+                CYG_INSTRUMENT_USER(0xf0,err,errno);
+                for(;;);
+            }
+        
+        pos += done;
+
+        cyg_thread_yield();
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void copyfile( char *name2, char *name1, int id  )
+{
+
+    int err;
+    char buf[IOSIZE];
+    int fd1, fd2;
+    ssize_t done, wrote;
+
+    db_printf("<INFO>: copy file %s -> %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    err = access( name2, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_WRONLY|O_CREAT );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done = read( fd2, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        wrote = write( fd1, buf, done );
+        if( wrote != done ) SHOW_RESULT( write, wrote );
+
+        if( wrote != done ) break;
+
+        cyg_thread_yield();
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1, int id  )
+{
+    int err;
+    char buf1[IOSIZE];
+    char buf2[IOSIZE];
+    int fd1, fd2;
+    ssize_t done1, done2;
+    int i;
+
+    db_printf("<INFO>: compare files %s == %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_RDONLY );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done1 = read( fd1, buf1, IOSIZE );
+        if( done1 < 0 ) SHOW_RESULT( read, done1 );
+
+        done2 = read( fd2, buf2, IOSIZE );
+        if( done2 < 0 ) SHOW_RESULT( read, done2 );
+
+        if( done1 != done2 )
+            db_printf("Files different sizes\n");
+        
+        if( done1 == 0 ) break;
+
+        for( i = 0; i < done1; i++ )
+            if( buf1[i] != buf2[i] )
+            {
+//                db_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+//                CYG_TEST_FAIL("Data in files not equal\n");
+                X(("%s[%d](%02x) != %s[%d](%02x)\n",name1,i,buf1[i],name2,i,buf2[i]));
+                cyg_scheduler_lock();
+                CYG_INSTRUMENT_USER(0xf1,err,errno);
+                for(;;);
+            }
+
+        cyg_thread_yield();
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+void checkcwd( const char *cwd, int id  )
+{
+    static char cwdbuf[PATH_MAX];
+    char *ret;
+
+    ret = getcwd( cwdbuf, sizeof(cwdbuf));
+    if( ret == NULL ) SHOW_RESULT( getcwd, ret );    
+
+    if( strcmp( cwdbuf, cwd ) != 0 )
+    {
+        db_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+        CYG_TEST_FAIL( "Current directory mismatch");
+    }
+}
+
+//==========================================================================
+// main
+
+static cyg_sem_t sem;
+
+void fileio2_main( CYG_ADDRESS id )
+{
+    int err;
+    int existingdirents=-1;
+
+    char dirname[64];
+    char filename1[64];
+    char filename2[64];
+
+#define NEW_FILENAME( fn, f )                           \
+{                                                       \
+    fn[0]=0;                                            \
+    strcat(fn, dirname);                                \
+    strcat(fn, "/");                                    \
+    strcat(fn,f);                                       \
+}
+
+#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f )
+#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f )
+    
+    // --------------------------------------------------------------
+
+    if( id == 0 )
+    {
+        int i;
+
+#ifdef JNGPKG_USB_STACK
+        err = usb_stack_init();
+        cyg_thread_delay( 1000 );
+#endif
+    
+        CYG_TEST_INIT();
+        
+        err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );
+        if( err < 0 ) {
+            SHOW_RESULT( mount, err );
+            CYG_TEST_FAIL_FINISH("yaffs2");
+        }
+
+        err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK );
+        if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+        if( err < 0 && errno == EACCES )
+        {
+            db_printf("<INFO>: create %s\n",
+                      TEST_MOUNTPOINT TEST_DIRECTORY);
+            err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 );
+            if( err < 0 ) SHOW_RESULT( mkdir, err );
+        }
+        
+        err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY );
+        if( err < 0 ) SHOW_RESULT( chdir, err );
+
+        checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY, id );
+    
+        for( i = 0; i < NTHREAD-1; i++ )
+            cyg_semaphore_post( &sem );
+    }
+    else
+    {
+        cyg_semaphore_wait( &sem );
+    }
+
+    // --------------------------------------------------------------
+
+    dirname[0] = 0;
+    strcat(dirname, TEST_MOUNTPOINT );
+    strcat(dirname, TEST_DIRECTORY );
+    strcat(dirname, "/dirX");
+    dirname[sizeof(TEST_MOUNTPOINT) +
+            sizeof(TEST_DIRECTORY) - 2 +
+            4] = '0' + id;
+//    dirname[5] = 0;
+
+    
+    db_printf("<INFO>: create %s\n",dirname);        
+    err = mkdir( dirname, 0 );
+    if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname, true, -1, &existingdirents, id );
+
+    db_printf("<INFO>: existingdirents %d\n",existingdirents);
+    
+    // --------------------------------------------------------------
+
+    NEW_FILENAME1( "foo" );
+    createfile( filename1, 20257, id );
+    checkfile( filename1, id );
+
+    NEW_FILENAME1( "foo" );
+    NEW_FILENAME2( "fee" );
+    
+    copyfile( filename1, filename2, id);
+    checkfile( filename2, id );
+    comparefiles( filename1, filename2, id );
+
+    NEW_FILENAME1( "bar" );
+    db_printf("<INFO>: mkdir bar\n");
+    err = mkdir( filename1, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL, id );
+
+    NEW_FILENAME1( "bar/fum" );
+    copyfile( filename2, filename1, id );
+    checkfile( filename1, id );
+    comparefiles( filename2, filename1, id );
+
+    NEW_FILENAME1( "foo" );    
+    NEW_FILENAME2( "bar/bundy" );    
+    db_printf("<INFO>: rename %s -> %s\n",filename1,filename2);    
+    err = rename( filename1, filename2 );
+    if( err < 0 ) SHOW_RESULT( rename, err );
+
+    NEW_FILENAME1( "bar" );
+    
+    listdir( dirname, true, existingdirents+2, NULL, id );
+    listdir( filename1 , true, 4, NULL, id );
+
+    NEW_FILENAME1( "fee" );        
+    checkfile( filename2, id );
+    comparefiles( filename1, filename2, id );
+
+//    db_printf("spinning\n"); for(;;) cyg_thread_delay(10);
+    
+    
+    // --------------------------------------------------------------
+
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "bar/fum" );    
+    db_printf("<INFO>: unlink %s\n",filename1);        
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "bar/bundy" );        
+    db_printf("<INFO>: unlink %s\n",filename1);        
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "bar" );            
+    db_printf("<INFO>: rmdir %s\n",filename1);        
+    err = rmdir( filename1 );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+//    listdir( dirname, false, existingdirents, NULL, id );
+
+        listdir( dirname, true, existingdirents, NULL, id );
+
+    // --------------------------------------------------------------
+
+    
+    listdir( dirname , true, -1, &existingdirents, id);
+
+    NEW_FILENAME1( "tinky" );            
+    NEW_FILENAME2( "laalaa" );            
+    createfile( filename1, 4567, id );
+    copyfile( filename1, filename2, id );
+    checkfile( filename1, id);
+    checkfile( filename2, id);
+    comparefiles( filename1, filename2, id );
+
+    NEW_FILENAME1( "noonoo" );                
+    db_printf("<INFO>: mkdir %s\n",filename1);    
+    err = mkdir( filename1, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL, id);
+
+    NEW_FILENAME1( "noonoo/tinky" );            
+    createfile( filename1, 6789, id );
+    checkfile( filename1, id );
+
+    NEW_FILENAME1( "noonoo/dipsy" );            
+    NEW_FILENAME2( "noonoo/po" );            
+    createfile( filename1, 34567, id );
+    checkfile( filename1, id );
+    copyfile( filename1, filename2, id );
+    checkfile( filename2, id );
+    comparefiles( filename1, filename2, id );
+
+    NEW_FILENAME1( "noonoo" );                    
+    listdir( filename1, true, 5, NULL, id );
+    listdir( dirname, true, existingdirents+3, NULL, id );
+
+    // --------------------------------------------------------------
+
+    NEW_FILENAME1( "noonoo/tinky" );                
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "noonoo/dipsy" );                
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "noonoo/po" );
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "noonoo" );                        
+    db_printf("<INFO>: rmdir %s\n",filename1); 
+    err = rmdir( filename1 );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    listdir( dirname, true, existingdirents+2, NULL, id );
+    
+    // --------------------------------------------------------------
+
+    
+    NEW_FILENAME1( "tinky" );
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( "laalaa" );
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    listdir( dirname, true, -1, NULL, id );
+
+#if 0
+    NEW_FILENAME1( "file.max" );
+    maxfile( filename1, id );
+
+    listdir( dirname, true, -1, NULL, id );    
+        
+    db_printf("<INFO>: unlink %s\n",filename1);    
+    err = unlink( filename1 );
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+#endif
+
+    db_printf("<INFO>: rmdir %s\n",dirname);    
+    err = rmdir( dirname );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    db_printf("<INFO>: syncing\n");
+    sync();
+    
+    if( id == 0 )
+    {
+        int i;
+        db_printf("<INFO>: waiting for other threads to finish\n");        
+        for( i = 0; i < NTHREAD-1; i++ )
+            cyg_semaphore_wait( &sem );
+
+        CYG_TEST_PASS_FINISH("yaffs2");
+    }
+    else
+    {
+        db_printf("<INFO>: thread finished\n");
+        cyg_semaphore_post( &sem );
+    }
+    
+    cyg_thread_exit();
+}
+
+// -------------------------------------------------------------------------
+
+#include <cyg/kernel/kapi.h>
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL*2)
+
+static char stack[NTHREAD][STACK_SIZE];
+static cyg_handle_t thread_handle[NTHREAD];
+static cyg_thread thread[NTHREAD];
+
+externC void
+cyg_start( void )
+{
+    int i;
+
+    CYG_INSTRUMENT_USER(0x01,0,0);
+                    
+    cyg_mutex_init( &db_lock );
+    
+    cyg_semaphore_init( &sem, 0 );
+    
+    for( i = 0; i < NTHREAD; i++ )
+    {
+        cyg_thread_create(3,                    // Priority - just a number
+                          fileio2_main,         // entry
+                          i,                    // index
+                          0,                    // no name
+                          &stack[i][0],         // Stack
+                          STACK_SIZE,           // Size
+                          &thread_handle[i],    // Handle
+                          &thread[i]            // Thread data structure
+            );
+        cyg_thread_resume(thread_handle[i]);
+    }
+
+    cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+// EOF yaffs2.c
new file mode 100644
--- /dev/null
+++ b/packages/fs/yaffs/current/tests/yaffs4.c
@@ -0,0 +1,934 @@
+//==========================================================================
+//
+//      yaffs4.c
+//
+//      Test fileio system
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited                 
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2005-07-25
+// Purpose:             Test fileio system
+// Description:         This test uses the testfs to check out the initialization
+//                      and basic operation of the fileio system.
+//                      This is essentially a copy of yaffs1 but using long
+//                      file names.
+//                      
+//                       
+//                      
+//                      
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+
+#include CYGDAT_DEVS_DISK_CFG           // testing config defines
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>            // HAL polled output
+
+//==========================================================================
+// Config options
+
+#define TEST_DEVICE     CYGDAT_DEVS_DISK_TEST_DEVICE
+
+#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT
+
+#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY
+
+#define TEST_FSTYPE     "yaffs"
+
+#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DEVICE2     CYGDAT_DEVS_DISK_TEST_DEVICE2
+
+#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2
+
+#define TEST_FSTYPE2    "yaffs"
+
+#endif
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res )                                                                \
+{                                                                                               \
+    diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \
+}
+
+//==========================================================================
+
+#define IOSIZE  100
+
+#define CLEANUP
+
+#define LONGNAME1       "long_file_name_that_should_take_up_more_than_one_directory_entry_1"
+#define LONGNAME2       "long_file_name_that_should_take_up_more_than_one_directory_entry_2"
+
+//                       123456789012345678901234567890
+#define FOO             "foo_longer_file_x.filename"
+//#define FEE             "fee_.filename"
+//#define BAR             "bar_long_directory_name.dirname"
+#define FEE             "a234567890123"
+#define BAR             "a2345678901234"
+#define BUNDY           "bundy_long_file_name_ccccccccccccccccccccccccccccccc.filename"
+#define FUM             "bundy_long_file_name_fum.filename"
+#define DOO             "doo_aaaaaaaaaabbbbbbbbbbbccccccccccccc"
+#define FIE             "fie.rrrrrrrrrrrrllllllllllllvvvvvvvvvvvvv"
+#define FOE             "foe_xxxxxxxxxxllllll.xxxxxxeeeeeeeeee"
+
+#define TINKY           "tinky_long_file_name.filename"
+#define LAALAA          "laalaa_long_file_name.filename"
+#define NOONOO          "noonoo_long_directory_name.dirname"
+#define DIPSY           "dipsy_long_file_name.filename"
+#define PO              "po_long_file_name.filename"
+
+#define XXXX            "xxxx_long_directory_name.dirname"
+#define YYYY            "yyyy_long_directory_name.dirname"
+#define ZZZZ            "zzzz_long_directory_name.dirname"
+#define WWWW            "wwww_long_directory_name.dirname"
+
+
+//==========================================================================
+
+#ifndef CYGPKG_LIBC_STRING
+
+char *strcat( char *s1, const char *s2 )
+{
+    char *s = s1;
+    while( *s1 ) s1++;
+    while( (*s1++ = *s2++) != 0);
+    return s;
+}
+
+#endif
+
+__externC int
+rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW;
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot )
+{
+    int err;
+    DIR *dirp;
+    int num=0;
+    
+    diag_printf("<INFO>: reading directory %s\n",name);
+    
+//    diag_printf("<INFO>: opendir(%s)\n",name);
+    dirp = opendir( name );
+    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+    for(;;)
+    {
+        struct dirent *entry = readdir( dirp );
+        
+        if( entry == NULL )
+            break;
+        num++;
+        diag_printf("<INFO>: entry");
+        if( statp )
+        {
+            char fullname[PATH_MAX];
+            struct stat sbuf;
+
+            if( name[0] )
+            {
+                strcpy(fullname, name );
+                if( !(name[0] == '/' && name[1] == 0 ) )
+                    strcat(fullname, "/" );
+            }
+            else fullname[0] = 0;
+            
+            strcat(fullname, entry->d_name );
+            
+            err = stat( fullname, &sbuf );
+            if( err < 0 )
+            {
+                if( errno == ENOSYS )
+                    diag_printf(" <no status available>");
+                else SHOW_RESULT( stat, err );
+            }
+            else
+            {
+                diag_printf(" [mode %08x ino %08x nlink %d size %6ld]",
+                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
+            }
+        }
+
+        diag_printf(" %s\n",entry->d_name);        
+    }
+
+//    diag_printf("<INFO>: closedir(%s)\n",name);    
+    err = closedir( dirp );
+    if( err < 0 ) SHOW_RESULT( stat, err );
+    if (numexpected >= 0 && num != numexpected)
+        CYG_TEST_FAIL("Wrong number of dir entries");
+    if ( numgot != NULL )
+        *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t size )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+
+    diag_printf("<INFO>: create file %s size %ld\n",name, (long)size);
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    while( size > 0 )
+    {
+        ssize_t len = size;
+        if ( len > IOSIZE ) len = IOSIZE;
+        
+        wrote = write( fd, buf, len );
+        if( wrote != len ) SHOW_RESULT( write, wrote );        
+
+        size -= wrote;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+#if 0
+static void maxfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+    size_t size = 0;
+    size_t prevsize = 0;
+    
+    diag_printf("<INFO>: create maximal file %s\n",name);
+    diag_printf("<INFO>: This may take a few minutes\n");
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    do
+    {
+        wrote = write( fd, buf, IOSIZE );
+        //if( wrote < 0 ) SHOW_RESULT( write, wrote );        
+
+        if( wrote >= 0 )
+            size += wrote;
+
+        if( (size-prevsize) > 100000 )
+        {
+            diag_printf("<INFO>: size = %ld \n", size);
+            prevsize = size;
+        }
+        
+    } while( wrote == IOSIZE );
+
+    diag_printf("<INFO>: file size == %ld\n",size);
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+#endif
+
+//==========================================================================
+
+static void checkfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t done;
+    int i;
+    int err;
+    off_t pos = 0;
+
+    diag_printf("<INFO>: check file %s\n",name);
+    
+    err = access( name, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd = open( name, O_RDONLY );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    for(;;)
+    {
+        done = read( fd, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        for( i = 0; i < done; i++ )
+            if( buf[i] != i%256 )
+            {
+                diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256);
+                CYG_TEST_FAIL("Data read not equal to data written\n");
+                for(;;);
+            }
+        
+        pos += done;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void copyfile( char *name2, char *name1 )
+{
+
+    int err;
+    char buf[IOSIZE];
+    int fd1, fd2;
+    ssize_t done, wrote;
+
+    diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    err = access( name2, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_WRONLY|O_CREAT );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done = read( fd2, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        wrote = write( fd1, buf, done );
+        if( wrote != done ) SHOW_RESULT( write, wrote );
+
+        if( wrote != done ) break;
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1 )
+{
+    int err;
+    char buf1[IOSIZE];
+    char buf2[IOSIZE];
+    int fd1, fd2;
+    ssize_t done1, done2;
+    int i;
+
+    diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_RDONLY );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done1 = read( fd1, buf1, IOSIZE );
+        if( done1 < 0 ) SHOW_RESULT( read, done1 );
+
+        done2 = read( fd2, buf2, IOSIZE );
+        if( done2 < 0 ) SHOW_RESULT( read, done2 );
+
+        if( done1 != done2 )
+            diag_printf("Files different sizes\n");
+        
+        if( done1 == 0 ) break;
+
+        for( i = 0; i < done1; i++ )
+            if( buf1[i] != buf2[i] )
+            {
+                diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+                CYG_TEST_FAIL("Data in files not equal\n");
+            }
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+void checkcwd( const char *cwd )
+{
+    static char cwdbuf[PATH_MAX];
+    char *ret;
+
+    ret = getcwd( cwdbuf, sizeof(cwdbuf));
+    if( ret == NULL ) SHOW_RESULT( getcwd, ret );    
+
+    if( strcmp( cwdbuf, cwd ) != 0 )
+    {
+        diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+        CYG_TEST_FAIL( "Current directory mismatch");
+    }
+}
+
+//==========================================================================
+// main
+
+void fileio4_main( CYG_ADDRESS id )
+{
+    int err;
+    int existingdirents=-1;
+    cyg_bool mp2 = false;
+    int fd;
+    
+    char dirname[256];
+    char filename1[256];
+    char filename2[256];
+
+#define NEW_FILENAME( fn, f )                           \
+{                                                       \
+    fn[0]=0;                                            \
+    strcat(fn, dirname);                                \
+    strcat(fn, "/");                                    \
+    strcat(fn,f);                                       \
+}
+
+#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f )
+#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f )
+
+    CYG_TEST_INIT();
+    
+    // --------------------------------------------------------------
+
+    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );    
+    if( err < 0 ) {
+        SHOW_RESULT( mount, err );
+        CYG_TEST_FAIL_FINISH("yaffs4");
+    }
+
+    err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    if( err < 0 && errno == EACCES )
+    {
+        diag_printf("<INFO>: create %s\n",
+                    TEST_MOUNTPOINT TEST_DIRECTORY);
+        err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 );
+        if( err < 0 ) SHOW_RESULT( mkdir, err );
+    }
+
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY );    
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents );
+
+    // --------------------------------------------------------------
+    
+    dirname[0] = 0;
+    strcat(dirname, TEST_MOUNTPOINT );
+    strcat(dirname, TEST_DIRECTORY );
+    
+    // --------------------------------------------------------------
+
+    createfile( FOO, 20257 );    
+    checkfile( FOO );
+    copyfile( FOO, FEE);
+    checkfile( FEE );
+    comparefiles( FOO, FEE );
+    diag_printf("<INFO>: mkdir " BAR "\n");
+    err = mkdir( BAR, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL );
+    
+    copyfile( FEE, BAR "/" FUM );
+    checkfile( BAR "/" FUM );
+    comparefiles( FEE, BAR "/" FUM );
+
+    diag_printf("<INFO>: cd " BAR "\n");
+    err = chdir( BAR );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    NEW_FILENAME1( BAR );
+    checkcwd( filename1 );
+    
+    diag_printf("<INFO>: rename ../" FOO " " BUNDY "\n");    
+    err = rename( "../" FOO, BUNDY );
+    if( err < 0 ) SHOW_RESULT( rename, err );
+    
+    listdir( dirname, true, existingdirents+2, NULL );
+    listdir( "." , true, 4, NULL );
+
+    checkfile( "../" BAR "/" BUNDY );
+    comparefiles("../" FEE, BUNDY );
+
+    // --------------------------------------------------------------
+    // Check for some common error cases
+
+    // First make some directories
+    diag_printf("<INFO>: mkdir " DOO "\n");    
+    err = mkdir( DOO, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    diag_printf("<INFO>: mkdir " FIE" \n");    
+    err = mkdir( FIE, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    diag_printf("<INFO>: mkdir " FIE "/" FOE "\n");    
+    err = mkdir( FIE "/" FOE, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    
+    diag_printf("<INFO>: rename " FUM " " DOO " -- should fail\n");    
+    err = rename( FUM, DOO );
+    if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename " DOO " " FUM " -- should fail\n");    
+    err = rename( DOO, FUM );
+    if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename " DOO " " FIE " -- should fail\n");    
+    err = rename( DOO, FIE );
+    if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err );
+    
+    NEW_FILENAME1( XXXX "/" YYYY )
+    diag_printf("<INFO>: rename " FUM " %s -- should fail\n",filename1);    
+    err = rename( FUM, filename1 );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err );
+    
+    diag_printf("<INFO>: rename " FUM " " FUM " -- should fail\n");    
+    err = rename( FUM, FUM );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: unlink " FEE " -- should fail\n");        
+    err = unlink( FEE );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( BAR );
+    diag_printf("<INFO>: rmdir %s -- should fail\n",filename1);        
+    err = rmdir( filename1 );
+    if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: unlink %s -- should fail\n",filename1);        
+    err = unlink( filename1 );
+    if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( BAR "/" FUM );
+    diag_printf("<INFO>: rmdir %s -- should fail\n",filename1);        
+    err = rmdir( filename1 );
+    if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: mkdir %s -- should fail\n",filename1);        
+    err = mkdir( filename1, 0 );
+    if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err );
+    
+    diag_printf("<INFO>: open " BUNDY "  exclusive -- should fail\n");        
+    fd = open( BUNDY, O_WRONLY|O_CREAT|O_EXCL );
+    if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd );
+
+    diag_printf("<INFO>: open %s -- should fail\n",dirname);        
+    fd = open( dirname, O_WRONLY );
+    if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd );
+    
+    
+    listdir( dirname, true, existingdirents+2, NULL );
+    listdir( "." , true, 6, NULL );
+    
+    // --------------------------------------------------------------    
+
+#ifdef CLEANUP
+
+    diag_printf("<INFO>: rename " FIE " " DOO "\n");
+    err = rename( FIE, DOO );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: rmdir " DOO "/" FOE "\n");
+    err = rmdir(DOO "/" FOE);
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+
+    diag_printf("<INFO>: rmdir " DOO "\n");
+    err = rmdir(DOO);
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+        
+    diag_printf("<INFO>: unlink ../" FEE "\n");    
+    err = unlink( "../" FEE );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " FUM "\n");        
+    err = unlink( FUM );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink ../" BAR "/" BUNDY "\n");        
+    err = unlink( "../" BAR "/" BUNDY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    diag_printf("<INFO>: cd ..\n");        
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( dirname );
+
+#ifdef CLEANUP    
+    diag_printf("<INFO>: rmdir " BAR "\n");        
+    err = rmdir( BAR );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+    listdir( dirname, false, existingdirents, NULL );
+#endif
+    
+    // --------------------------------------------------------------
+
+#ifdef TEST_MOUNTPOINT2
+    diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2);    
+    err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 );
+
+    if( err == 0 )
+    {
+        mp2 = true;
+        diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2);    
+        err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK );
+        if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+        if( err < 0 && errno == EACCES )
+        {
+            diag_printf("<INFO>: create %s\n",
+                        TEST_MOUNTPOINT2 TEST_DIRECTORY2);
+            err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 );
+            if( err < 0 ) SHOW_RESULT( mkdir, err );
+        }
+
+        err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 );    
+        if( err < 0 ) SHOW_RESULT( chdir, err );
+
+        checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 );
+
+        dirname[0] = 0;
+        strcat(dirname, TEST_MOUNTPOINT2 );
+        strcat(dirname, TEST_DIRECTORY2 );
+
+    }
+    else
+    {
+        mp2 = false;
+        diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2);
+        diag_printf("using %s instead\n", dirname );
+    }
+
+#endif
+    
+    listdir( dirname , true, -1, &existingdirents);
+
+    NEW_FILENAME1( TINKY );
+    NEW_FILENAME2( LAALAA );
+    
+    createfile( filename1, 4567 );
+    copyfile( filename1, filename2 );
+    checkfile( filename1);
+    checkfile( filename2);
+    comparefiles( filename1, filename2 );
+
+    diag_printf("<INFO>: cd %s\n",dirname);    
+    err = chdir( dirname );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( dirname );
+        
+    diag_printf("<INFO>: mkdir " NOONOO "\n");    
+    err = mkdir( NOONOO, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL);
+
+    diag_printf("<INFO>: cd " NOONOO "\n");
+    err = chdir( NOONOO );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    NEW_FILENAME1( NOONOO );
+    checkcwd( filename1 );
+    
+    createfile( TINKY, 6789 );
+    checkfile( TINKY );
+
+    createfile( DIPSY, 34567 );
+    checkfile( DIPSY );
+    copyfile( DIPSY, PO );
+    checkfile( PO );
+    comparefiles( DIPSY, PO );
+
+    listdir( ".", true, 5, NULL );
+    listdir( "..", true, existingdirents+3, NULL );
+
+    // --------------------------------------------------------------
+
+#ifdef CLEANUP    
+    diag_printf("<INFO>: unlink " TINKY "\n");    
+    err = unlink( TINKY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " DIPSY "\n");    
+    err = unlink( DIPSY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " PO "\n");    
+    err = unlink( PO );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    diag_printf("<INFO>: cd ..\n"); 
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( dirname );
+
+#ifdef CLEANUP    
+    diag_printf("<INFO>: rmdir " NOONOO "\n"); 
+    err = rmdir( NOONOO );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+#endif
+    
+    // --------------------------------------------------------------
+
+    diag_printf("<INFO>: mkdir " XXXX "\n");    
+    err = mkdir( XXXX, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    diag_printf("<INFO>: mkdir " XXXX "/" YYYY "\n");        
+    err = mkdir( XXXX "/" YYYY, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    diag_printf("<INFO>: mkdir " XXXX "/" YYYY "/" ZZZZ "\n");        
+    err = mkdir( XXXX "/" YYYY "/" ZZZZ, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    diag_printf("<INFO>: mkdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n");    
+    err = mkdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ "/" WWWW );
+    diag_printf("<INFO>: cd %s\n",filename1);
+    err = chdir( filename1 );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ );    
+    diag_printf("<INFO>: cd ..\n");
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ );
+    diag_printf("<INFO>: cd .\n");
+    err = chdir( "." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( XXXX "/" YYYY );    
+    diag_printf("<INFO>: cd ../../" YYYY "\n");
+    err = chdir( "../../" YYYY );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    diag_printf("<INFO>: cd ../..\n");
+    err = chdir( "../.." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( dirname );
+
+    diag_printf("<INFO>: rmdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); 
+    err = rmdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir "XXXX "/" YYYY "/" ZZZZ "\n"); 
+    err = rmdir( XXXX "/" YYYY "/" ZZZZ );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir " XXXX "/" YYYY "\n"); 
+    err = rmdir( XXXX "/" YYYY );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir "XXXX "\n"); 
+    err = rmdir( XXXX );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+    // --------------------------------------------------------------
+
+    checkcwd( dirname );
+
+#ifdef CLEANUP    
+    diag_printf("<INFO>: unlink "TINKY "\n");    
+    err = unlink( TINKY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " LAALAA" \n");    
+    err = unlink( LAALAA );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    // --------------------------------------------------------------
+    
+    diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY);
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY);
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( ".", true, -1, NULL );
+
+#ifdef TEST_MOUNTPOINT2
+    if( mp2 )
+    {
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2);    
+        err = umount( TEST_MOUNTPOINT2 );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+    }
+#endif
+
+    // --------------------------------------------------------------
+
+#if 0
+    maxfile("file.max");
+
+    listdir( "/", true, -1, NULL );    
+        
+    diag_printf("<INFO>: unlink file.max\n");    
+    err = unlink( "file.max" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+#endif
+
+    // --------------------------------------------------------------
+
+    diag_printf("<INFO>: cd /\n");    
+    err = chdir( "/" );
+    if( err == 0 )
+    {
+        checkcwd( "/" );
+    
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT);    
+        err = umount( TEST_MOUNTPOINT );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+    }
+
+    diag_printf("<INFO>: syncing\n");    
+    sync();
+    
+    CYG_TEST_PASS_FINISH("yaffs4");
+}
+
+// -------------------------------------------------------------------------
+
+#include <cyg/kernel/kapi.h>
+
+static cyg_handle_t thread_handle;
+static cyg_thread thread;
+static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024*4];
+
+externC void
+cyg_start( void )
+{
+    cyg_thread_create(3,                // Priority - just a number
+                      fileio4_main,     // entry
+                      0,                // index
+                      0,                // no name
+                      &stack[0],        // Stack
+                      sizeof(stack),    // Size
+                      &thread_handle,   // Handle
+                      &thread           // Thread data structure
+        );
+    cyg_thread_resume(thread_handle);
+
+    cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+// EOF yaffs4.c
new file mode 100644
--- /dev/null
+++ b/packages/fs/yaffs/current/tests/yaffs5.c
@@ -0,0 +1,815 @@
+//==========================================================================
+//
+//      yaffs5.c
+//
+//      Test FAT filesystem
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2006, 2007 eCosCentric Limited                       
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2007-03-28
+// Purpose:             Test FAT system
+// Description:         This test gets some performance figures from the
+//                      FAT filesystem.
+//                      
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+
+#include CYGDAT_DEVS_DISK_CFG           // testing config defines
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>            // HAL polled output
+
+//==========================================================================
+// Config options
+
+#define TEST_DEVICE     CYGDAT_DEVS_DISK_TEST_DEVICE
+
+#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT
+
+#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY
+
+#define TEST_FSTYPE     "yaffs"
+
+#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DEVICE2     CYGDAT_DEVS_DISK_TEST_DEVICE2
+
+#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2
+
+#define TEST_FSTYPE2    "yaffs"
+
+#endif
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res )                                                                \
+{                                                                                               \
+    diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):"");        \
+}
+
+//==========================================================================
+
+typedef struct
+{
+    cyg_int64           ticks;
+    cyg_int32           halticks;
+} timestamp;
+
+typedef struct
+{
+    timestamp           start;
+    timestamp           end;
+    cyg_int64           interval;       // In HAL ticks
+    cyg_int64           us_interval;    // Interval in microseconds
+} timing;
+
+static cyg_int64        ticks_overhead = 0;
+static cyg_int32        us_per_haltick = 0;
+static cyg_int32        halticks_per_us = 0;
+
+static cyg_int64        rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION;
+static cyg_int64        rtc_period = CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+static cyg_int32        ticks_per_second;
+
+//==========================================================================
+
+static char date_string[] = __DATE__;
+static char time_string[] = __TIME__;
+
+cyg_uint32 timehash;
+
+//==========================================================================
+
+static void wait_for_tick( void )
+{
+    cyg_tick_count_t now = cyg_current_time();
+
+    while( cyg_current_time() == now )
+        continue;
+}
+
+static void get_timestamp( timestamp *ts )
+{
+    ts->ticks = cyg_current_time();
+    HAL_CLOCK_READ( (cyg_uint32 *)&ts->halticks );
+}
+
+static cyg_int64 ticks_to_us( cyg_int64 ticks )
+{
+    cyg_int64 us;
+    
+    if( us_per_haltick != 0 )
+        us = ticks * us_per_haltick;
+    else
+        us = ticks / halticks_per_us;
+
+    return us;
+}
+
+static void calculate_interval( timing *t )
+{
+    t->interval = t->end.halticks - t->start.halticks;
+
+    t->interval += (t->end.ticks - t->start.ticks) * rtc_period;
+
+    t->interval -= ticks_overhead;
+    
+    t->us_interval = ticks_to_us( t->interval );
+}
+
+static void init_timing( void )
+{
+    timing t;
+
+    ticks_per_second = (1000000000ULL*rtc_resolution[1])/rtc_resolution[0];
+    us_per_haltick = 1000000/(rtc_period * rtc_resolution[1]);
+    halticks_per_us = (rtc_period * rtc_resolution[1])/1000000; 
+    
+    wait_for_tick();
+
+    get_timestamp( &t.start );
+    get_timestamp( &t.end );
+
+    calculate_interval( &t );
+
+    ticks_overhead = t.interval;
+
+    diag_printf("Timing overhead %lld ticks\n", ticks_overhead );
+    
+}
+
+//==========================================================================
+
+#ifndef CYGPKG_LIBC_STRING
+
+char *strcat( char *s1, const char *s2 )
+{
+    char *s = s1;
+    while( *s1 ) s1++;
+    while( (*s1++ = *s2++) != 0);
+    return s;
+}
+
+#endif
+
+__externC int
+rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW;
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot )
+{
+    int err;
+    DIR *dirp;
+    int num=0;
+    
+    diag_printf("<INFO>: reading directory %s\n",name);
+    
+//    diag_printf("<INFO>: opendir(%s)\n",name);
+    dirp = opendir( name );
+    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+    for(;;)
+    {
+        struct dirent *entry = readdir( dirp );
+        
+        if( entry == NULL )
+            break;
+        num++;
+        diag_printf("<INFO>: entry %14s",entry->d_name);
+        if( statp )
+        {
+            char fullname[PATH_MAX];
+            struct stat sbuf;
+
+            if( name[0] )
+            {
+                strcpy(fullname, name );
+                if( !(name[0] == '/' && name[1] == 0 ) )
+                    strcat(fullname, "/" );
+            }
+            else fullname[0] = 0;
+            
+            strcat(fullname, entry->d_name );
+
+            err = stat( fullname, &sbuf );
+            if( err < 0 )
+            {
+                if( errno == ENOSYS )
+                    diag_printf(" <no status available>");
+                else SHOW_RESULT( stat, err );
+            }
+            else
+            {
+                diag_printf(" [mode %08x ino %08x nlink %d size %ld]",
+                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
+            }
+        }
+
+        diag_printf("\n");
+    }
+
+//    diag_printf("<INFO>: closedir(%s)\n",name);    
+    err = closedir( dirp );
+    if( err < 0 ) SHOW_RESULT( stat, err );
+    if (numexpected >= 0 && num != numexpected)
+        CYG_TEST_FAIL("Wrong number of dir entries\n");
+    if ( numgot != NULL )
+        *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t asize, size_t block_size )
+{
+    size_t size = asize;
+    cyg_uint8 *buf;
+    cyg_uint32 *b;
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+    timing opent, writet;
+        
+    diag_printf("\n--------------------------------------------------------------------\n");
+    diag_printf("<INFO>: create file %s size %ld block_size %ld\n",name, (long)size, (long)block_size);
+
+    buf = malloc( block_size );
+    if( buf == NULL )
+    {
+        SHOW_RESULT( malloc, -1 );
+        return;
+    }
+    b = (cyg_uint32 *)buf;
+    
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    i = 0;
+    while( i < block_size/sizeof(cyg_uint32) )
+    {
+        b[i] = i;
+        i++;
+        b[i++] = 0;
+        b[i++] = timehash;
+        b[i++] = 0x12345678;
+    }
+
+    
+    get_timestamp( &opent.start );        
+    fd = open( name, O_WRONLY|O_CREAT );
+    get_timestamp( &opent.end );        
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    get_timestamp( &writet.start );    
+    while( size > 0 )
+    {
+        ssize_t len = size;
+        if ( len > block_size ) len = block_size;
+
+        b[1] = asize-size;
+        b[block_size/sizeof(cyg_uint32)-3] = asize-size;
+        wrote = write( fd, buf, len );
+        if( wrote != len ) SHOW_RESULT( write, wrote );        
+
+        size -= wrote;
+    }
+    get_timestamp( &writet.end );        
+
+    free( buf );
+    
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    calculate_interval( &opent );
+    calculate_interval( &writet );
+
+    diag_printf("CreateFile Results: %s size %ld\n", name, (long)asize);
+    diag_printf("         Open        %8d.%03d ms\n", (int)(opent.us_interval/1000), (int)(opent.us_interval%1000) );
+    diag_printf("        Write        %8d.%03d ms\n", (int)(writet.us_interval/1000), (int)(writet.us_interval%1000) );
+    diag_printf("    Data Rate          %10lld KiB/s\n", (1000000LL*asize)/1024/writet.us_interval);
+}
+
+//==========================================================================
+
+static void checkfile( char *name, size_t block_size )
+{
+    cyg_uint8 *buf;
+    cyg_uint32 *b;
+    int fd;
+    ssize_t done;
+    int err;
+    off_t pos = 0;
+    timing opent, readt;
+    
+    diag_printf("\n--------------------------------------------------------------------\n");
+    diag_printf("<INFO>: check file %s\n",name);
+    
+    buf = malloc( block_size );
+    if( buf == NULL )
+    {
+        SHOW_RESULT( malloc, -1 );
+        return;
+    }
+    b = (cyg_uint32 *)buf;
+    
+    err = access( name, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    get_timestamp( &opent.start );
+    fd = open( name, O_RDONLY );
+    get_timestamp( &opent.end );            
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    get_timestamp( &readt.start );            
+    for(;;)
+    {
+        done = read( fd, buf, block_size );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        // Check that this is the block we wrote
+        if( b[0] != 0 )
+            diag_printf("b[%d] != %08x\n", 0, 0 );
+
+        if( b[1] != pos )
+            diag_printf("b[%d] != %08x\n", 1, (unsigned)pos );
+
+        if( b[2] != timehash )
+            diag_printf("b[%d] != %08x\n", 2, timehash );
+
+        if( b[3] != 0x12345678 )
+            diag_printf("b[%d] != %08x\n", 3, 0x12345678 );
+
+        if( b[(block_size/sizeof(cyg_uint32))-4] != (block_size/sizeof(cyg_uint32)-4) )
+            diag_printf("b[%lu](%08x) != %08x\n", (long)block_size/sizeof(cyg_uint32)-4,
+                                                  b[(block_size/sizeof(cyg_uint32))-4],
+                                                  (unsigned)(block_size/sizeof(cyg_uint32)-4) );
+
+        if( b[block_size/sizeof(cyg_uint32)-3] != pos )
+            diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-3, (unsigned)pos );
+
+        if( b[block_size/sizeof(cyg_uint32)-2] != timehash )
+            diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-2, timehash );
+
+        if( b[block_size/sizeof(cyg_uint32)-1] != 0x12345678 )
+            diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-1, 0x12345678 );
+        
+        pos += done;
+    }
+    get_timestamp( &readt.end );            
+
+    free( buf );
+    
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    calculate_interval( &opent );
+    calculate_interval( &readt );
+
+    diag_printf("CheckFile Results: %s size %ld\n", name, pos);
+    diag_printf("         Open        %8d.%03d ms\n", (int)(opent.us_interval/1000), (int)(opent.us_interval%1000) );
+    diag_printf("         Read        %8d.%03d ms\n", (int)(readt.us_interval/1000), (int)(readt.us_interval%1000) );
+    diag_printf("    Data Rate          %10lld KiB/s\n", (1000000LL*pos)/1024/readt.us_interval);
+}
+
+//==========================================================================
+
+#define TIME_DATA_MAX 20
+
+static void checkfile1( char *name, size_t block_size )
+{
+    cyg_uint8 *buf;
+    cyg_uint32 *b;
+    int fd;
+    ssize_t done;
+    int err;
+    off_t pos = 0;
+    timing totalt;
+    
+    struct
+    {
+        int     valid;
+        timing  mountt;
+        timing  opent;
+        timing  seekt;
+        timing  readt;
+        timing  closet;
+        timing  umountt;
+    } time_data[TIME_DATA_MAX];
+    int td;
+
+    for( td = 0; td < TIME_DATA_MAX; td++ )
+        time_data[td].valid = 0;
+    td = 0;
+    
+    diag_printf("\n--------------------------------------------------------------------\n");
+    diag_printf("<INFO>: check file1 %s\n",name);
+    
+    buf = malloc( block_size );
+    if( buf == NULL )
+    {
+        SHOW_RESULT( malloc, -1 );
+        return;
+    }
+    b = (cyg_uint32 *)buf;
+
+    get_timestamp( &totalt.start );
+    for(;;)
+    {
+        get_timestamp( &time_data[td].mountt.start );
+        err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );
+        get_timestamp( &time_data[td].mountt.end );
+        if( err < 0 ) SHOW_RESULT( mount, err );
+        
+        get_timestamp( &time_data[td].opent.start );
+        fd = open( name, O_RDONLY );        
+        get_timestamp( &time_data[td].opent.end );
+        if( fd < 0 ) SHOW_RESULT( open, fd );
+    
+        get_timestamp( &time_data[td].seekt.start );
+        err = lseek( fd, pos, SEEK_SET );
+        get_timestamp( &time_data[td].seekt.end );
+        if( err < 0 ) SHOW_RESULT( lseek, err );
+        
+        get_timestamp( &time_data[td].readt.start );        
+        done = read( fd, buf, block_size );
+        get_timestamp( &time_data[td].readt.end );                
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        get_timestamp( &time_data[td].closet.start );        
+        err = close( fd );
+        get_timestamp( &time_data[td].closet.end );        
+        if( err < 0 ) SHOW_RESULT( close, err );
+        
+        get_timestamp( &time_data[td].umountt.start );
+        err = umount( TEST_MOUNTPOINT );
+        get_timestamp( &time_data[td].umountt.end );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+        
+        if( done == 0 ) break;
+
+        // Check that this is the block we wrote
+        if( b[0] != 0 )
+            diag_printf("b[%d] != %08x\n", 0, 0 );
+
+        if( b[1] != pos )
+            diag_printf("b[%d] != %08x\n", 1, (unsigned)pos );
+
+//        if( b[2] != timehash )
+//            diag_printf("b[%d] != %08x\n", 2, timehash );
+
+        if( b[3] != 0x12345678 )
+            diag_printf("b[%d] != %08x\n", 3, 0x12345678 );
+
+        if( b[(block_size/sizeof(cyg_uint32))-4] != (block_size/sizeof(cyg_uint32)-4) )
+            diag_printf("b[%lu](%08x) != %08x\n", (long)block_size/sizeof(cyg_uint32)-4,
+                                                  b[(block_size/sizeof(cyg_uint32))-4],
+                                                  (unsigned)(block_size/sizeof(cyg_uint32)-4) );
+
+        if( b[block_size/sizeof(cyg_uint32)-3] != pos )
+            diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-3, (unsigned)pos );
+
+//        if( b[block_size/sizeof(cyg_uint32)-2] != timehash )
+//            diag_printf("b[%d] != %08x\n", block_size/sizeof(cyg_uint32)-2, timehash );
+
+        if( b[block_size/sizeof(cyg_uint32)-1] != 0x12345678 )
+            diag_printf("b[%lu] != %08x\n", (long)block_size/sizeof(cyg_uint32)-1, 0x12345678 );
+        
+        pos += done;
+
+        time_data[td].valid = 1;
+        if( td < (TIME_DATA_MAX-1) )
+            td++;
+    }
+    get_timestamp( &totalt.end );
+
+    free( buf );
+
+    diag_printf("Block      Mount        Open         Seek         Read         Close        Umount\n");
+
+    for( td = 0; td < TIME_DATA_MAX; td++ )
+    {
+        if( !time_data[td].valid )
+            continue;
+        
+        calculate_interval( &time_data[td].mountt );
+        calculate_interval( &time_data[td].opent );
+        calculate_interval( &time_data[td].seekt );
+        calculate_interval( &time_data[td].readt );
+        calculate_interval( &time_data[td].closet );
+        calculate_interval( &time_data[td].umountt );
+
+        diag_printf("%2d:", td);
+        diag_printf(" %8d.%03d", (int)(time_data[td].mountt.us_interval/1000), (int)(time_data[td].mountt.us_interval%1000) );
+        diag_printf(" %8d.%03d", (int)(time_data[td].opent.us_interval/1000), (int)(time_data[td].opent.us_interval%1000) );
+        diag_printf(" %8d.%03d", (int)(time_data[td].seekt.us_interval/1000), (int)(time_data[td].seekt.us_interval%1000) );
+        diag_printf(" %8d.%03d", (int)(time_data[td].readt.us_interval/1000), (int)(time_data[td].readt.us_interval%1000) );
+        diag_printf(" %8d.%03d", (int)(time_data[td].closet.us_interval/1000), (int)(time_data[td].closet.us_interval%1000) );
+        diag_printf(" %8d.%03d", (int)(time_data[td].umountt.us_interval/1000), (int)(time_data[td].umountt.us_interval%1000) );
+        diag_printf("\n");
+    }
+
+    calculate_interval( &totalt );
+    diag_printf("CheckFile1 Results: %s size %ld\n", name, pos);
+    diag_printf("        Total        %8d.%03d ms\n", (int)(totalt.us_interval/1000), (int)(totalt.us_interval%1000) );
+    diag_printf("    Data Rate          %10lld KiB/s\n", (1000000LL*pos)/1024/totalt.us_interval);
+    
+}
+
+//==========================================================================
+
+void checkcwd( const char *cwd )
+{
+    static char cwdbuf[PATH_MAX];
+    char *ret;
+
+    ret = getcwd( cwdbuf, sizeof(cwdbuf));
+    if( ret == NULL ) SHOW_RESULT( getcwd, ret );    
+
+    if( strcmp( cwdbuf, cwd ) != 0 )
+    {
+        diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+        CYG_TEST_FAIL( "Current directory mismatch");
+    }
+}
+
+//==========================================================================
+
+void fs_callback( cyg_int32 event, CYG_ADDRWORD data )
+{
+#if 1
+    diag_printf("Filesystem %sSAFE\n",
+                event==CYG_FS_CALLBACK_UNSAFE?"UN":"");
+#endif
+}
+
+
+//==========================================================================
+// main
+
+void yaffs5_main( CYG_ADDRESS id )
+{
+    int err;
+    int existingdirents=-1;
+    int i;
+    timing mountt, umountt;
+    
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    struct cyg_fs_block_usage usage;
+#endif
+//    struct cyg_fs_callback_info callback;
+    
+    CYG_TEST_INIT();
+
+    init_timing();
+
+    for( i = 0 ; date_string[i] != 0 ; i++ )
+        timehash = (timehash<<1) ^ date_string[i];
+    for( i = 0 ; time_string[i] != 0 ; i++ )
+        timehash = (timehash<<1) ^ time_string[i];
+    
+    // --------------------------------------------------------------
+
+#if 1
+#define DO_UMOUNT
+    get_timestamp( &mountt.start );
+    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );    
+//    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=write" );    
+//    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=close" );    
+//    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, "yaffs:sync=data" );    
+    get_timestamp( &mountt.end );
+    if( err < 0 ) {
+        SHOW_RESULT( mount, err );
+        CYG_TEST_FAIL_FINISH("yaffs5");
+    }
+
+#if 0
+    callback.callback = fs_callback;
+    callback.data = 0;
+    err = cyg_fs_setinfo(TEST_MOUNTPOINT, FS_INFO_CALLBACK,
+                         &callback, sizeof(callback));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_setinfo, err );
+#endif
+    
+    calculate_interval( &mountt );
+    diag_printf("        Mount        %8d.%03d ms\n", (int)(mountt.us_interval/1000), (int)(mountt.us_interval%1000) );
+    
+    err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    if( err < 0 && errno == EACCES )
+    {
+        diag_printf("<INFO>: create %s\n",
+                    TEST_MOUNTPOINT TEST_DIRECTORY);
+        err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 );
+        if( err < 0 ) SHOW_RESULT( mkdir, err );
+    }
+
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY );    
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents );
+
+    // --------------------------------------------------------------
+#if defined(CYGSEM_FILEIO_BLOCK_USAGE)
+    err = cyg_fs_getinfo(TEST_MOUNTPOINT, FS_INFO_BLOCK_USAGE,
+                         &usage, sizeof(usage));
+    if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err );
+    diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n",
+               usage.total_blocks, usage.total_blocks * usage.block_size);
+    diag_printf("<INFO>: free size:  %6lld blocks, %10lld bytes\n",
+               usage.free_blocks, usage.free_blocks * usage.block_size);
+    diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size);
+#endif
+    // --------------------------------------------------------------
+    
+#endif
+    
+#if 1
+    createfile( "yaffs5.0", 1024*1024, 16*1024 );
+    checkfile( "yaffs5.0",16*1024 );    
+    err = unlink( "yaffs5.0" );
+    sync();    
+#endif
+
+#if 1
+    createfile( "yaffs5.0", 200*1024, 1024 );
+    checkfile( "yaffs5.0", 1024 );    
+    err = unlink( "yaffs5.0" );
+#endif
+    
+#if 1
+    createfile( "yaffs5.1", 1024*1024, 1024 );
+    createfile( "yaffs5.2", 1024*1024, 4*1024 );
+    sync();
+    createfile( "yaffs5.3", 8*1024*1024, 32*1024 );
+
+    checkfile( "yaffs5.1", 1024 );
+    checkfile( "yaffs5.2", 4*1024 );
+    checkfile( "yaffs5.3", 32*1024 );
+
+    diag_printf("\n--------------------------------------------------------------------\n");
+    
+    listdir( "." , true, existingdirents+3, NULL );
+
+    // --------------------------------------------------------------
+
+    diag_printf("<INFO>: unlink yaffs5.1\n");    
+    err = unlink( "yaffs5.1" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink yaffs5.2\n");    
+    err = unlink( "yaffs5.2" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink yaffs5.3\n");    
+    err = unlink( "yaffs5.3" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    // --------------------------------------------------------------
+
+#if 1 && defined(DO_UMOUNT)
+
+    diag_printf("<INFO>: unlink yaffs5.4\n");    
+    err = unlink( "yaffs5.4" );
+    
+    createfile( "yaffs5.4", 5*1024*1024, 32*1024 );
+#endif
+    
+    // --------------------------------------------------------------
+
+#ifdef DO_UMOUNT
+    diag_printf("<INFO>: cd /\n");    
+    err = chdir( "/" );
+    if( err == 0 )
+    {
+        checkcwd( "/" );
+    
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT);
+        get_timestamp( &umountt.start );        
+        err = umount( TEST_MOUNTPOINT );
+        get_timestamp( &umountt.end );        
+        if( err < 0 ) SHOW_RESULT( umount, err );
+
+        calculate_interval( &umountt );
+        diag_printf("      Umount        %8d.%03d ms\n", (int)(umountt.us_interval/1000), (int)(umountt.us_interval%1000) );
+        
+    }
+#endif
+    
+#if 1
+
+    diag_printf("<INFO>: syncing\n");    
+    sync();
+        
+    checkfile1(TEST_MOUNTPOINT TEST_DIRECTORY "/yaffs5.4", 32*1024 );
+
+    // Remount just to remove yaffs5.4
+    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );    
+    if( err < 0 ) {
+        SHOW_RESULT( mount, err );
+        CYG_TEST_FAIL_FINISH("yaffs5");
+    }
+    err = unlink( TEST_MOUNTPOINT TEST_DIRECTORY "/yaffs5.4" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+    err = umount( TEST_MOUNTPOINT );
+    if( err < 0 ) SHOW_RESULT( umount, err );
+
+#endif
+
+    diag_printf("<INFO>: syncing\n");    
+    sync();
+    
+    CYG_TEST_PASS_FINISH("yaffs5");
+}
+
+// -------------------------------------------------------------------------
+
+#include <cyg/kernel/kapi.h>
+
+static cyg_handle_t thread_handle;
+static cyg_thread thread;
+static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+8*1024];
+//static char stack[64*1024];
+
+externC void
+cyg_start( void )
+{
+    cyg_thread_create(3,                // Priority - just a number
+                      yaffs5_main,      // entry
+                      0,                // index
+                      0,                // no name
+                      &stack[0],        // Stack
+                      sizeof(stack),    // Size
+                      &thread_handle,   // Handle
+                      &thread           // Thread data structure
+        );
+    cyg_thread_resume(thread_handle);
+
+    cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+// EOF yaffs5.c
new file mode 100644
--- /dev/null
+++ b/packages/fs/yaffs/current/tests/yaffs6.c
@@ -0,0 +1,968 @@
+//==========================================================================
+//
+//      yaffs6.c
+//
+//      Test FAT UTF-8 support
+//
+//==========================================================================
+// ####ECOSGPLCOPYRIGHTBEGIN####                                            
+// -------------------------------------------                              
+// This file is part of eCos, the Embedded Configurable Operating System.   
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+// Copyright (C) 2004, 2005, 2006, 2007 eCosCentric Limited                 
+//
+// eCos is free software; you can redistribute it and/or modify it under    
+// the terms of the GNU General Public License as published by the Free     
+// Software Foundation; either version 2 or (at your option) any later      
+// version.                                                                 
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT      
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
+// for more details.                                                        
+//
+// You should have received a copy of the GNU General Public License        
+// along with eCos; if not, write to the Free Software Foundation, Inc.,    
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
+//
+// As a special exception, if other files instantiate templates or use      
+// macros or inline functions from this file, or you compile this file      
+// and link it with other works to produce a work based on this file,       
+// this file does not by itself cause the resulting work to be covered by   
+// the GNU General Public License. However the source code for this file    
+// must still be made available in accordance with section (3) of the GNU   
+// General Public License v2.                                               
+//
+// This exception does not invalidate any other reasons why a work based    
+// on this file might be covered by the GNU General Public License.         
+// -------------------------------------------                              
+// ####ECOSGPLCOPYRIGHTEND####                                              
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2007-06-20
+// Purpose:             Test fileio system
+// Description:         This test uses the testfs to check out the initialization
+//                      and basic operation of the fileio system.
+//                      This is essentially a copy of yaffs4 with UTF8 encoded
+//                      file names.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+
+#include CYGDAT_DEVS_DISK_CFG           // testing config defines
+
+#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_trac.h>        // tracing macros
+#include <cyg/infra/cyg_ass.h>         // assertion macros
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h>            // HAL polled output
+
+//==========================================================================
+// Config options
+
+#define TEST_DEVICE     CYGDAT_DEVS_DISK_TEST_DEVICE
+
+#define TEST_MOUNTPOINT CYGDAT_DEVS_DISK_TEST_MOUNTPOINT
+
+#define TEST_DIRECTORY CYGDAT_DEVS_DISK_TEST_DIRECTORY
+
+#define TEST_FSTYPE     "yaffs"
+
+#ifdef CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DEVICE2     CYGDAT_DEVS_DISK_TEST_DEVICE2
+
+#define TEST_MOUNTPOINT2 CYGDAT_DEVS_DISK_TEST_MOUNTPOINT2
+
+#define TEST_DIRECTORY2 CYGDAT_DEVS_DISK_TEST_DIRECTORY2
+
+#define TEST_FSTYPE2    "yaffs"
+
+#endif
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res )                                                                \
+{                                                                                               \
+    diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):""); \
+}
+
+//==========================================================================
+
+#define IOSIZE  100
+
+#define CLEANUP
+
+//==========================================================================
+// The following filenames are in Cyrillic and are UTF-8 encoded. 
+//
+// WARNING: Only edit this file with an editor that is UTF-8 aware (I
+// use EMACS on Linux, but Notepad on Windows also works). Saving this
+// file from an unaware editor could cause these strings to be
+// corrupted and make this test fail. If the strings below do not
+// appear as clean Cyrillic characters then exit now without saving
+// and look for a better editor.
+
+#if 1
+
+#define FOO             "Фоо"
+#define FEE             "Спутник"
+#define BAR             "Байконур"
+#define BUNDY           "СергеЬй ПаЬвлович Королёв"
+#define FUM             "Юрий Гагаринский"
+#define DOO             "Константин Эдуардович Циолковский"
+//#define FIE             "Федеральное космическое агентство России"
+#define FIE             "Федеральное космическое"
+#define FOE             "Валентин Петрович Глушко"
+
+#define TINKY           "Восток"
+#define LAALAA          "Восход"
+#define NOONOO          "Салют"
+#define DIPSY           "Космодром"
+#define PO              "Лайка"
+
+#define XXXX            "Гласность"
+#define YYYY            "перестройка"
+#define ZZZZ            "Калашникова"
+#define WWWW            "матрёшка"
+
+#else
+
+#define FOO             "foo"
+#define FEE             "fee"
+#define BAR             "bar"
+#define BUNDY           "bundy"
+#define FUM             "fum"
+#define DOO             "doo"
+#define FIE             "fie"
+#define FOE             "foe"
+
+#define TINKY           "tinky"
+#define LAALAA          "laalaa"
+#define NOONOO          "noonoo"
+#define DIPSY           "dipsy"
+#define PO              "po"
+
+#define XXXX            "xxxx"
+#define YYYY            "yyyy"
+#define ZZZZ            "zzzz"
+#define WWWW            "wwww"
+
+#endif
+
+
+//==========================================================================
+
+#ifndef CYGPKG_LIBC_STRING
+
+char *strcat( char *s1, const char *s2 )
+{
+    char *s = s1;
+    while( *s1 ) s1++;
+    while( (*s1++ = *s2++) != 0);
+    return s;
+}
+
+#endif
+
+__externC int
+rename( const char * /* oldpath */, const char * /* newpath */ ) __THROW;
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot )
+{
+    int err;
+    DIR *dirp;
+    int num=0;
+    
+    diag_printf("<INFO>: reading directory %s\n",name);
+    
+//    diag_printf("<INFO>: opendir(%s)\n",name);
+    dirp = opendir( name );
+    if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+    for(;;)
+    {
+        struct dirent *entry = readdir( dirp );
+        
+        if( entry == NULL )
+            break;
+        num++;
+
+       diag_printf("<INFO>: entry ");
+        
+        if( statp )
+        {
+            char fullname[PATH_MAX];
+            struct stat sbuf;
+
+            if( name[0] )
+            {
+                strcpy(fullname, name );
+                if( !(name[0] == '/' && name[1] == 0 ) )
+                    strcat(fullname, "/" );
+            }
+            else fullname[0] = 0;
+            
+            strcat(fullname, entry->d_name );
+            
+            err = stat( fullname, &sbuf );
+            if( err < 0 )
+            {
+                if( errno == ENOSYS )
+                    diag_printf(" <no status available>");
+                else SHOW_RESULT( stat, err );
+            }
+            else
+            {
+                diag_printf(" [mode %08x ino %08x nlink %d size %6ld]",
+                            sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
+            }
+        }
+
+        diag_printf(" %s\n",entry->d_name);
+    }
+
+//    diag_printf("<INFO>: closedir(%s)\n",name);    
+    err = closedir( dirp );
+    if( err < 0 ) SHOW_RESULT( stat, err );
+    if (numexpected >= 0 && num != numexpected)
+        CYG_TEST_FAIL("Wrong number of dir entries");
+    if ( numgot != NULL )
+        *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t size )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+
+    diag_printf("<INFO>: create file %s size %ld\n",name, (long)size);
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    while( size > 0 )
+    {
+        ssize_t len = size;
+        if ( len > IOSIZE ) len = IOSIZE;
+        
+        wrote = write( fd, buf, len );
+        if( wrote != len ) SHOW_RESULT( write, wrote );        
+
+        size -= wrote;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+#if 0
+static void maxfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t wrote;
+    int i;
+    int err;
+    size_t size = 0;
+    size_t prevsize = 0;
+    
+    diag_printf("<INFO>: create maximal file %s\n",name);
+    diag_printf("<INFO>: This may take a few minutes\n");
+
+    err = access( name, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+    
+    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+ 
+    fd = open( name, O_WRONLY|O_CREAT );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    do
+    {
+        wrote = write( fd, buf, IOSIZE );
+        //if( wrote < 0 ) SHOW_RESULT( write, wrote );        
+
+        if( wrote >= 0 )
+            size += wrote;
+
+        if( (size-prevsize) > 100000 )
+        {
+            diag_printf("<INFO>: size = %ld \n", size);
+            prevsize = size;
+        }
+        
+    } while( wrote == IOSIZE );
+
+    diag_printf("<INFO>: file size == %ld\n",size);
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+#endif
+
+//==========================================================================
+
+static void checkfile( char *name )
+{
+    char buf[IOSIZE];
+    int fd;
+    ssize_t done;
+    int i;
+    int err;
+    off_t pos = 0;
+
+    diag_printf("<INFO>: check file %s\n",name);
+    
+    err = access( name, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    fd = open( name, O_RDONLY );
+    if( fd < 0 ) SHOW_RESULT( open, fd );
+
+    for(;;)
+    {
+        done = read( fd, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        for( i = 0; i < done; i++ )
+            if( buf[i] != i%256 )
+            {
+                diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256);
+                CYG_TEST_FAIL("Data read not equal to data written\n");
+                for(;;);
+            }
+        
+        pos += done;
+    }
+
+    err = close( fd );
+    if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void copyfile( char *name2, char *name1 )
+{
+
+    int err;
+    char buf[IOSIZE];
+    int fd1, fd2;
+    ssize_t done, wrote;
+
+    diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    err = access( name2, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_WRONLY|O_CREAT );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done = read( fd2, buf, IOSIZE );
+        if( done < 0 ) SHOW_RESULT( read, done );
+
+        if( done == 0 ) break;
+
+        wrote = write( fd1, buf, done );
+        if( wrote != done ) SHOW_RESULT( write, wrote );
+
+        if( wrote != done ) break;
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1 )
+{
+    int err;
+    char buf1[IOSIZE];
+    char buf2[IOSIZE];
+    int fd1, fd2;
+    ssize_t done1, done2;
+    int i;
+
+    diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+
+    err = access( name1, F_OK );
+    if( err != 0 ) SHOW_RESULT( access, err );
+    
+    fd1 = open( name1, O_RDONLY );
+    if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+    fd2 = open( name2, O_RDONLY );
+    if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+    
+    for(;;)
+    {
+        done1 = read( fd1, buf1, IOSIZE );
+        if( done1 < 0 ) SHOW_RESULT( read, done1 );
+
+        done2 = read( fd2, buf2, IOSIZE );
+        if( done2 < 0 ) SHOW_RESULT( read, done2 );
+
+        if( done1 != done2 )
+            diag_printf("Files different sizes\n");
+        
+        if( done1 == 0 ) break;
+
+        for( i = 0; i < done1; i++ )
+            if( buf1[i] != buf2[i] )
+            {
+                diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+                CYG_TEST_FAIL("Data in files not equal\n");
+            }
+    }
+
+    err = close( fd1 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+
+    err = close( fd2 );
+    if( err < 0 ) SHOW_RESULT( close, err );
+    
+}
+
+//==========================================================================
+
+void checkcwd( const char *cwd )
+{
+    static char cwdbuf[PATH_MAX];
+    char *ret;
+
+    ret = getcwd( cwdbuf, sizeof(cwdbuf));
+    if( ret == NULL ) SHOW_RESULT( getcwd, ret );    
+
+    if( strcmp( cwdbuf, cwd ) != 0 )
+    {
+        diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+        CYG_TEST_FAIL( "Current directory mismatch");
+    }
+}
+
+//==========================================================================
+// main
+
+void yaffs6_main( CYG_ADDRESS id )
+{
+    int err;
+    int existingdirents=-1;
+    cyg_bool mp2 = false;
+    int fd;
+    
+    char dirname[256];
+    char filename1[256];
+    char filename2[256];
+
+#define NEW_FILENAME( fn, f )                           \
+{                                                       \
+    fn[0]=0;                                            \
+    strcat(fn, dirname);                                \
+    strcat(fn, "/");                                    \
+    strcat(fn,f);                                       \
+}
+
+#define NEW_FILENAME1( f ) NEW_FILENAME( filename1, f )
+#define NEW_FILENAME2( f ) NEW_FILENAME( filename2, f )
+
+    CYG_TEST_INIT();
+    
+#ifdef CYGDBG_INFRA_DIAG_CHECK_STRINGS
+    diag_printf("WARNING: CYGDBG_INFRA_DIAG_CHECK_STRINGS is defined, Cyrillic file names will not be printed.\n");
+#else
+    diag_printf("WARNING: Cyrillic file names printed in UTF-8 may not be readable in some environments.\n");
+#endif
+    
+    // --------------------------------------------------------------
+
+    err = mount( TEST_DEVICE, TEST_MOUNTPOINT, TEST_FSTYPE );    
+    if( err < 0 ) {
+        SHOW_RESULT( mount, err );
+        CYG_TEST_FAIL_FINISH("yaffs6");
+    }
+
+    err = access( TEST_MOUNTPOINT TEST_DIRECTORY, F_OK );
+    if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+    if( err < 0 && errno == EACCES )
+    {
+        diag_printf("<INFO>: create %s\n",
+                    TEST_MOUNTPOINT TEST_DIRECTORY);
+        err = mkdir( TEST_MOUNTPOINT TEST_DIRECTORY, 0 );
+        if( err < 0 ) SHOW_RESULT( mkdir, err );
+    }
+
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY );    
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( TEST_MOUNTPOINT TEST_DIRECTORY, true, -1, &existingdirents );
+
+    // --------------------------------------------------------------
+    
+    dirname[0] = 0;
+    strcat(dirname, TEST_MOUNTPOINT );
+    strcat(dirname, TEST_DIRECTORY );
+    
+    // --------------------------------------------------------------
+
+    createfile( FOO, 20257 );
+    checkfile( FOO );
+    copyfile( FOO, FEE);
+    checkfile( FEE );
+    comparefiles( FOO, FEE );
+
+    diag_printf("<INFO>: mkdir " BAR "\n");
+    err = mkdir( BAR, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL );
+    
+    copyfile( FEE, BAR "/" FUM );
+    checkfile( BAR "/" FUM );
+    comparefiles( FEE, BAR "/" FUM );
+
+    diag_printf("<INFO>: cd " BAR "\n");
+    err = chdir( BAR );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    NEW_FILENAME1( BAR );
+    checkcwd( filename1 );
+    
+    diag_printf("<INFO>: rename ../" FOO " " BUNDY "\n");    
+    err = rename( "../" FOO, BUNDY );
+    if( err < 0 ) SHOW_RESULT( rename, err );
+    
+    listdir( dirname, true, existingdirents+2, NULL );
+    listdir( "." , true, 4, NULL );
+
+    checkfile( "../" BAR "/" BUNDY );
+    comparefiles("../" FEE, BUNDY );
+
+#if 1
+
+    // --------------------------------------------------------------
+    // Check for some common error cases
+
+    // First make some directories
+    diag_printf("<INFO>: mkdir " DOO "\n");    
+    err = mkdir( DOO, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    diag_printf("<INFO>: mkdir " FIE" \n");    
+    err = mkdir( FIE, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+    diag_printf("<INFO>: mkdir " FIE "/" FOE "\n");    
+    err = mkdir( FIE "/" FOE, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );    
+
+
+    diag_printf("<INFO>: rename " FUM " " DOO " -- should fail\n");    
+    err = rename( FUM, DOO );
+    if( err < 0 && errno != EISDIR ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename " DOO " " FUM " -- should fail\n");    
+    err = rename( DOO, FUM );
+    if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: rename " DOO " " FIE " -- should fail\n");    
+    err = rename( DOO, FIE );
+    if( err < 0 && errno != EIO ) SHOW_RESULT( rename, err );
+    
+    NEW_FILENAME1( XXXX "/" YYYY )
+    diag_printf("<INFO>: rename " FUM " %s -- should fail\n",filename1);    
+    err = rename( FUM, filename1 );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( rename, err );
+    
+    diag_printf("<INFO>: rename " FUM " " FUM " -- should fail\n");    
+    err = rename( FUM, FUM );
+    if( err < 0 ) SHOW_RESULT( rename, err );
+
+    diag_printf("<INFO>: unlink " FEE " -- should fail\n");        
+    err = unlink( FEE );
+    if( err < 0 && errno != ENOENT ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( BAR );
+    diag_printf("<INFO>: rmdir %s -- should fail\n",filename1);        
+    err = rmdir( filename1 );
+    if( err < 0 && errno != ENOTEMPTY ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: unlink %s -- should fail\n",filename1);        
+    err = unlink( filename1 );
+    if( err < 0 && errno != EISDIR ) SHOW_RESULT( unlink, err );
+
+    NEW_FILENAME1( BAR "/" FUM );
+    diag_printf("<INFO>: rmdir %s -- should fail\n",filename1);        
+    err = rmdir( filename1 );
+    if( err < 0 && errno != ENOTDIR ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: mkdir %s -- should fail\n",filename1);        
+    err = mkdir( filename1, 0 );
+    if( err < 0 && errno != EEXIST ) SHOW_RESULT( mkdir, err );
+    
+    diag_printf("<INFO>: open " BUNDY "  exclusive -- should fail\n");        
+    fd = open( BUNDY, O_WRONLY|O_CREAT|O_EXCL );
+    if( fd < 0 && errno != EEXIST ) SHOW_RESULT( open, fd );
+
+    diag_printf("<INFO>: open %s -- should fail\n",dirname);        
+    fd = open( dirname, O_WRONLY );
+    if( fd < 0 && errno != EISDIR ) SHOW_RESULT( open, fd );
+    
+    
+    listdir( dirname, true, existingdirents+2, NULL );
+    listdir( "." , true, 6, NULL );
+    
+    // --------------------------------------------------------------    
+
+#ifdef CLEANUP
+
+    diag_printf("<INFO>: rename " FIE " " DOO "\n");
+    err = rename( FIE, DOO );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: rmdir " DOO "/" FOE "\n");
+    err = rmdir(DOO "/" FOE);
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+
+    diag_printf("<INFO>: rmdir " DOO "\n");
+    err = rmdir(DOO);
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+    
+    diag_printf("<INFO>: unlink ../" FEE "\n");    
+    err = unlink( "../" FEE );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " FUM "\n");        
+    err = unlink( FUM );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink ../" BAR "/" BUNDY "\n");        
+    err = unlink( "../" BAR "/" BUNDY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    diag_printf("<INFO>: cd ..\n");        
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( dirname );
+
+#ifdef CLEANUP    
+    diag_printf("<INFO>: rmdir " BAR "\n");        
+    err = rmdir( BAR );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+    listdir( dirname, false, existingdirents, NULL );
+#endif
+
+    // --------------------------------------------------------------
+
+#ifdef TEST_MOUNTPOINT2
+    diag_printf("<INFO>: mount %s\n", TEST_MOUNTPOINT2);    
+    err = mount( TEST_DEVICE2, TEST_MOUNTPOINT2, TEST_FSTYPE2 );
+
+    if( err == 0 )
+    {
+        mp2 = true;
+        diag_printf("<INFO>: mount %s succeeded\n", TEST_MOUNTPOINT2);    
+        err = access( TEST_MOUNTPOINT2 TEST_DIRECTORY2, F_OK );
+        if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+        if( err < 0 && errno == EACCES )
+        {
+            diag_printf("<INFO>: create %s\n",
+                        TEST_MOUNTPOINT2 TEST_DIRECTORY2);
+            err = mkdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2, 0 );
+            if( err < 0 ) SHOW_RESULT( mkdir, err );
+        }
+
+        err = chdir( TEST_MOUNTPOINT2 TEST_DIRECTORY2 );    
+        if( err < 0 ) SHOW_RESULT( chdir, err );
+
+        checkcwd( TEST_MOUNTPOINT2 TEST_DIRECTORY2 );
+
+        dirname[0] = 0;
+        strcat(dirname, TEST_MOUNTPOINT2 );
+        strcat(dirname, TEST_DIRECTORY2 );
+
+    }
+    else
+    {
+        mp2 = false;
+        diag_printf("<INFO>: mount %s failed, ", TEST_MOUNTPOINT2);
+        diag_printf("using %s instead\n", dirname );
+    }
+
+#endif
+    
+    listdir( dirname , true, -1, &existingdirents);
+
+    NEW_FILENAME1( TINKY );
+    NEW_FILENAME2( LAALAA );
+    
+    createfile( filename1, 4567 );
+    copyfile( filename1, filename2 );
+    checkfile( filename1);
+    checkfile( filename2);
+    comparefiles( filename1, filename2 );
+
+    diag_printf("<INFO>: cd %s\n",dirname);    
+    err = chdir( dirname );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    checkcwd( dirname );
+        
+    diag_printf("<INFO>: mkdir " NOONOO "\n");    
+    err = mkdir( NOONOO, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    listdir( dirname , true, existingdirents+3, NULL);
+
+    diag_printf("<INFO>: cd " NOONOO "\n");
+    err = chdir( NOONOO );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+
+    NEW_FILENAME1( NOONOO );
+    checkcwd( filename1 );
+    
+    createfile( TINKY, 6789 );
+    checkfile( TINKY );
+
+    createfile( DIPSY, 34567 );
+    checkfile( DIPSY );
+    copyfile( DIPSY, PO );
+    checkfile( PO );
+    comparefiles( DIPSY, PO );
+
+    listdir( ".", true, 5, NULL );
+    listdir( "..", true, existingdirents+3, NULL );
+
+    // --------------------------------------------------------------
+
+#ifdef CLEANUP
+    diag_printf("<INFO>: unlink " TINKY "\n");    
+    err = unlink( TINKY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " DIPSY "\n");    
+    err = unlink( DIPSY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " PO "\n");    
+    err = unlink( PO );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    diag_printf("<INFO>: cd ..\n"); 
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( dirname );
+
+#ifdef CLEANUP
+    diag_printf("<INFO>: rmdir " NOONOO "\n"); 
+    err = rmdir( NOONOO );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+#endif
+    
+    // --------------------------------------------------------------
+
+    err = mkdir( XXXX, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+    
+    err = mkdir( XXXX "/" YYYY, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+    
+    err = mkdir( XXXX "/" YYYY "/" ZZZZ, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    err = mkdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW, 0 );
+    if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+    NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ "/" WWWW );
+    diag_printf("<INFO>: cd %s\n",filename1);
+    err = chdir( filename1 );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ );    
+    diag_printf("<INFO>: cd ..\n");
+    err = chdir( ".." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( XXXX "/" YYYY "/" ZZZZ );
+    diag_printf("<INFO>: cd .\n");
+    err = chdir( "." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    NEW_FILENAME1( XXXX "/" YYYY );    
+    diag_printf("<INFO>: cd ../../" YYYY "\n");
+    err = chdir( "../../" YYYY );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( filename1 );
+
+    diag_printf("<INFO>: cd ../..\n");
+    err = chdir( "../.." );
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( dirname );
+
+    diag_printf("<INFO>: rmdir " XXXX "/" YYYY "/" ZZZZ "/" WWWW "\n"); 
+    err = rmdir( XXXX "/" YYYY "/" ZZZZ "/" WWWW );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir "XXXX "/" YYYY "/" ZZZZ "\n"); 
+    err = rmdir( XXXX "/" YYYY "/" ZZZZ );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir " XXXX "/" YYYY "\n"); 
+    err = rmdir( XXXX "/" YYYY );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+    diag_printf("<INFO>: rmdir "XXXX "\n"); 
+    err = rmdir( XXXX );
+    if( err < 0 ) SHOW_RESULT( rmdir, err );
+    
+    // --------------------------------------------------------------
+
+    checkcwd( dirname );
+
+#ifdef CLEANUP
+    diag_printf("<INFO>: unlink "TINKY "\n");    
+    err = unlink( TINKY );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+
+    diag_printf("<INFO>: unlink " LAALAA" \n");    
+    err = unlink( LAALAA );
+    if( err < 0 ) SHOW_RESULT( unlink, err );
+#endif
+    
+    // --------------------------------------------------------------
+    
+    diag_printf("<INFO>: cd %s\n", TEST_MOUNTPOINT TEST_DIRECTORY);
+    err = chdir( TEST_MOUNTPOINT TEST_DIRECTORY);
+    if( err < 0 ) SHOW_RESULT( chdir, err );
+    checkcwd( TEST_MOUNTPOINT TEST_DIRECTORY );
+    
+    listdir( ".", true, -1, NULL );
+
+#ifdef TEST_MOUNTPOINT2
+    if( mp2 )
+    {
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT2);    
+        err = umount( TEST_MOUNTPOINT2 );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+    }
+#endif
+
+    // --------------------------------------------------------------
+
+#if 0
+    maxfile("file.max");
+
+    listdir( "/", true, -1, NULL );    
+        
+    diag_printf("<INFO>: unlink file.max\n");    
+    err = unlink( "file.max" );
+    if( err < 0 ) SHOW_RESULT( unlink, err );    
+#endif
+
+    // --------------------------------------------------------------
+
+#endif
+    diag_printf("<INFO>: cd /\n");    
+    err = chdir( "/" );
+    if( err == 0 )
+    {
+        checkcwd( "/" );
+    
+        diag_printf("<INFO>: umount %s\n",TEST_MOUNTPOINT);    
+        err = umount( TEST_MOUNTPOINT );
+        if( err < 0 ) SHOW_RESULT( umount, err );
+    }
+
+    diag_printf("<INFO>: syncing\n");    
+    sync();
+    
+    CYG_TEST_PASS_FINISH("yaffs6");
+}
+
+// -------------------------------------------------------------------------
+
+#include <cyg/kernel/kapi.h>
+
+static cyg_handle_t thread_handle;
+static cyg_thread thread;
+static char stack[CYGNUM_HAL_STACK_SIZE_TYPICAL+1024*4];
+
+externC void
+cyg_start( void )
+{
+    cyg_thread_create(3,                // Priority - just a number
+                      yaffs6_main,      // entry
+                      0,                // index
+                      0,                // no name
+                      &stack[0],        // Stack
+                      sizeof(stack),    // Size
+                      &thread_handle,   // Handle
+                      &thread           // Thread data structure
+        );
+    cyg_thread_resume(thread_handle);
+
+    cyg_scheduler_start();
+}
+
+// -------------------------------------------------------------------------
+// EOF yaffs6.c