Re: [Yaffs] yaffs in CVS broken?

Top Page
Attachments:
Message as email
+ (text/plain)
+ fileio1.c (text/x-csrc)
Delete this message
Reply to this message
Author: Rutger Hofman
Date:  
To: Charles Manning
CC: yaffs@lists.aleph1.co.uk
Subject: Re: [Yaffs] yaffs in CVS broken?
Charles Manning wrote:
> On Wednesday 19 November 2008 05:34:48 Rutger Hofman wrote:
>> I updated my checkout, and since that, after a while of running my basic
>> test program spews:
>>
>> Writing -48 bytes to chunk!!!!!!!!!
>>
>> And it seems there are lots of blocks that are marked bad afterwards.
>
> Please email me your test (off list).
>
> Are you using yaffs1 or yaffs2 mode of operation?
>
> Bad blocks are usually a result of some lower level issue with the device
> driver hosing the spare bytes.


To make sure about the spare bytes, I check in 2 places whether a
written data+spare are read back correctly by immediately reading them:
in yaffs-fs.c, i.e. my eCos/YAFFS filesystem wrapper; and in my eCos
NAND controller code. They compare identical in all cases. (This took
some brain massage: memcmp() started reporting differences in the
packedTag2 ecc field. But the only place where they turned out to differ
is in the unused bytes for alignment between the starting unsigned char
colParity and following unsigned lineParity).

I am using the yaffs2 direct/ code. Depending on the history, sometimes
my test completes correctly, and sometimes (e.g. after an erase of the
nand chip) it gives this -48 bytes error after a while of testing.

The test program just uses posix calls, it is my hacked-around version
of a legacy eCos test program fileio1.c. Attached. I hope you can do
something with some direct wrapper of your own... and that might be
sufficiently different to make the problem go away of course. My nand
chip is 2048Byte pages, a block is 64 pages, and I configure a YAFFS2
file system on blocks 10 .. 26.

Rutger
//==========================================================================
//
//      fileio1.c
//
//      Test fileio system
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, 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.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 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.
//
// 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 <cyg/kernel/ktypes.h>         // base kernel types
#include <cyg/infra/cyg_trac.h>        // tracing macros
#include <cyg/infra/cyg_ass.h>         // assertion macros
#include <cyg/io/flash_nand.h>


#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>

#include <stdlib.h>
#include <stdio.h>                      /* rename() */


#include <cyg/fileio/fileio.h>

#include <cyg/infra/testcase.h>
#include <cyg/infra/diag.h>            // HAL polled output


#include <pkgconf/fs_yaffs.h>            // Address of YAFFS


//==========================================================================

#if 0
MTAB_ENTRY( yaffs_mte1,
                   "/",
                   "yaffs",
                   CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1,
                   0);
#endif


//==========================================================================

#define SHOW_RESULT( do_abort, _fn, _res ) \
    do { \
        if (do_abort) { \
            diag_printf("<FAIL>: "); \
        } \
        diag_printf("%s.%d " #_fn "() returned %d %s\n", __FILE__, __LINE__, (int)_res, _res<0?strerror(errno):""); \
        if (do_abort) { \
            CYG_TEST_FAIL("from SHOW_RESULT\n"); \
            exit(121); \
        } \
    } while (0)


#define CYG_TEST_WARN(str) \
    diag_printf("<WARN>: %s.%d %s Unexpected result: %s\n", __FILE__, __LINE__, __FUNCTION__, str)



//==========================================================================

#define IOSIZE 1000

#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


//==========================================================================

static char
file_type(mode_t m)
{
    if (0) {
    } else if (S_ISREG(m)) {
        return '-';
    } else if (S_ISDIR(m)) {
        return 'd';
    } else if (S_ISCHR(m)) {
        return 'c';
    } else if (S_ISBLK(m)) {
        return 'b';
    } else if (S_ISFIFO(m)) {
        return 'f';
    } else if (S_ISLNK(m)) {
        return 'l';
#ifndef __STDC__
    } else if (S_ISSOCK(m)) {
        return 's';
#endif
    }


    return '?';
}




static void
report_mode(mode_t mode)
{
    if (mode & S_IRUSR) {
        diag_printf("r");
    } else {
        diag_printf("-");
    }
    if (mode & S_IWUSR) {
        diag_printf("w");
    } else {
        diag_printf("-");
    }
    if (mode & S_IXUSR) {
        diag_printf("x");
    } else {
        diag_printf("-");
    }
}



static void
report_stat(const char *file, const struct stat *stat_buf)
{
    mode_t      mode = stat_buf->st_mode;


    diag_printf("%c", file_type(mode));


    report_mode(mode & S_IRWXU);
    report_mode((mode & S_IRWXG) << 3);
    report_mode((mode & S_IRWXO) << 6);


    diag_printf(" %8lu", (long unsigned)stat_buf->st_size);
    diag_printf(" <date> %s\n", file);
}



//==========================================================================

static void listdir( char *name, int statp, int numexpected, int *numgot )
{
    int err;
    DIR *dirp;
    int num=0;


    diag_printf("<INFO>: list directory '%s'\n",name);


    dirp = opendir( name );
    if( dirp == NULL ) SHOW_RESULT( 1, opendir, -1 );


    for(;;)
    {
        struct dirent *entry = readdir( dirp );


        if( entry == NULL )
            break;
        num++;
        if( statp )
        {
            char fullname[PATH_MAX];
            struct stat sbuf;


            if( name[0] )
            {
                strcpy(fullname, name );
                if( fullname[strlen(fullname) - 1] != '/' &&
                        !(name[0] == '/' && name[1] == 0 ) )
                    strcat(fullname, "/" );
            }
            else fullname[0] = 0;


            strcat(fullname, entry->d_name );


            if (0) {
                diag_printf("Under dir '%s': stat entry '%s'\n", name, fullname);
            }
            err = stat( fullname, &sbuf );
            if( err < 0 )
            {
                if( errno == ENOSYS )
                    diag_printf(" <no status available>");
                else SHOW_RESULT( 1, stat, err );
            }
            else
            {
                diag_printf(" [mode %08x ino %08x nlink %d size %d]",
                            sbuf.st_mode, (int)sbuf.st_ino, (int)sbuf.st_nlink,
                            (int)sbuf.st_size);
                diag_printf("\n");
                report_stat(fullname, &sbuf);
            }
        } else {
            diag_printf("<INFO>: entry '%14s'\n",entry->d_name);
        }
    }


    err = closedir( dirp );
    if( err < 0 ) SHOW_RESULT( 1, closedir, err );
    if (numexpected >= 0 && num != numexpected)
        CYG_TEST_WARN("Wrong number of dir entries\n");
    if ( numgot != NULL )
        *numgot = num;
}


//==========================================================================

static void createfile( char *name, size_t size )
{
    unsigned char buf[IOSIZE];
    int fd;
    ssize_t wrote;
    int i;
    int err;


    diag_printf("<INFO>: create file %s size %d\n",name, (int)size);


    err = access( name, F_OK );
    if (err < 0) {
        SHOW_RESULT( 0, access, err );
        diag_printf("access('%s') gives error %d %s\n", name, errno, strerror(errno));
        errno = 0;
    } else {
        struct stat statbuf;


        err = stat(name, &statbuf);
        if (err < 0) {
            diag_printf("create file '%s': stat gives error %d %s\n", name, errno, strerror(errno));
        } else {
            diag_printf("create file '%s': can already stat it\n", name);
        }
    }


    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;


    fd = open( name, O_WRONLY | O_CREAT | O_EXCL );
    if( fd < 0 ) {
        if (errno == EEXIST) {
            diag_printf("cannot creat('%s') : already exists\n", name);
            errno = 0;


            return;
        }
        SHOW_RESULT( 1, open, fd );
    } else {
        diag_printf("open('%s') OK\n", name);
    }


    while( size > 0 )
    {
        ssize_t len = size;
        if ( len > IOSIZE ) len = IOSIZE;


        wrote = write( fd, buf, len );
        if( wrote != len ) SHOW_RESULT( 1, write, wrote );


        size -= wrote;
    }


    err = close( fd );
    if( err < 0 ) SHOW_RESULT( 1, 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;


    diag_printf("<INFO>: create maximal file %s\n",name);


    err = access( name, F_OK );
    if( err < 0 && errno != EACCES ) SHOW_RESULT( 1, access, err );


    for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;


    fd = open( name, O_WRONLY|O_CREAT );
    if( fd < 0 ) SHOW_RESULT( 1, open, fd );


    do
    {
        wrote = write( fd, buf, IOSIZE );
        if( wrote < 0 ) SHOW_RESULT( 1, write, wrote );


        size += wrote;


    } while( wrote == IOSIZE );


    diag_printf("<INFO>: file size == %d\n",size);


    err = close( fd );
    if( err < 0 ) SHOW_RESULT( 1, close, err );
}
#endif


//==========================================================================

static void checkfile( char *name )
{
    unsigned 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( 1, access, err );


    fd = open( name, O_RDONLY );
    if( fd < 0 ) SHOW_RESULT(1, open, fd );


    for(;;)
    {
        done = read( fd, buf, IOSIZE );
        if( done < 0 ) SHOW_RESULT( 1, read, done );


        if( done == 0 ) break;


        for( i = 0; i < done; i++ )
            if( buf[i] != i%256 )
            {
                diag_printf("buf[%d+%d](%02x) != %02x\n",(int)pos,i,buf[i],i%256);
                CYG_TEST_WARN("Data read not equal to data written\n");
            }


        pos += done;
    }


    err = close( fd );
    if( err < 0 ) SHOW_RESULT( 1, 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 ) SHOW_RESULT( errno != EACCES, access, err );


    err = access( name2, F_OK );
    if( err != 0 ) SHOW_RESULT( 1, access, err );


    fd1 = open( name1, O_WRONLY|O_CREAT );
    if( fd1 < 0 ) SHOW_RESULT( 1, open, fd1 );


    fd2 = open( name2, O_RDONLY );
    if( fd2 < 0 ) SHOW_RESULT( 1, open, fd2 );


    for(;;)
    {
        done = read( fd2, buf, IOSIZE );
        if( done < 0 ) SHOW_RESULT( 1, read, done );


        if( done == 0 ) break;


        wrote = write( fd1, buf, done );
        if( wrote != done ) SHOW_RESULT( 1, write, wrote );


        if( wrote != done ) break;
    }


    err = close( fd1 );
    if( err < 0 ) SHOW_RESULT( 1, close, err );


    err = close( fd2 );
    if( err < 0 ) SHOW_RESULT( 1, 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( 1, access, err );


    err = access( name1, F_OK );
    if( err != 0 ) SHOW_RESULT( 1, access, err );


    fd1 = open( name1, O_RDONLY );
    if( fd1 < 0 ) SHOW_RESULT( 1, open, fd1 );


    fd2 = open( name2, O_RDONLY );
    if( fd2 < 0 ) SHOW_RESULT( 1, open, fd2 );


    for(;;)
    {
        done1 = read( fd1, buf1, IOSIZE );
        if( done1 < 0 ) SHOW_RESULT( 1, read, done1 );


        done2 = read( fd2, buf2, IOSIZE );
        if( done2 < 0 ) SHOW_RESULT( 1, 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_WARN("Data in files not equal\n");
            }
    }


    err = close( fd1 );
    if( err < 0 ) SHOW_RESULT( 1, close, err );


    err = close( fd2 );
    if( err < 0 ) SHOW_RESULT( 1, close, err );


}

//==========================================================================

static
void checkcwd( const char *cwd )
{
    static char cwdbuf[PATH_MAX];
    char *ret;


    ret = getcwd( cwdbuf, sizeof(cwdbuf));
    if( ret == NULL ) SHOW_RESULT( 1, getcwd, ret );


    if( strcmp( cwdbuf, cwd ) != 0 )
    {
        diag_printf( "cwdbuf '%s' cwd '%s'\n",cwdbuf, cwd );
        CYG_TEST_FAIL( "Current directory mismatch");
    }
}



//==========================================================================
// main

/* Needs a trailing slash */
#define ROOT_DIR        "/"
// #define ROOT_DIR        "/dev/yaffs0"
// #define ROOT_DIR        "/yaffs0"


#define PERSISTENT_FILE "this-file-persists"

int main( int argc, char **argv )
{
    int err;
    //int i;
    int existingdirents=-1;
    struct stat stat_buf;


    struct mallinfo info;


    info =  mallinfo();
    diag_printf("arenasize %d, freeblocks %d, totalallocated %d, totalfree %d, maxfree %d\n",
                info.arena, info.ordblks, info.uordblks, info.fordblks, info.maxfree);




    CYG_TEST_INIT();


    // --------------------------------------------------------------


    diag_printf("mount '%s' as '%s'\n", CYGDAT_FS_YAFFS_DEVICE_NAME_0, ROOT_DIR);
    err = mount( CYGDAT_FS_YAFFS_DEVICE_NAME_0, ROOT_DIR, "yaffs" );
    if( err < 0 ) SHOW_RESULT( 1, mount, err );


    diag_printf("%s.%d %s HERE\n", __FILE__, __LINE__, __FUNCTION__);


    diag_printf("<INFO>: stat '%s'\n", ROOT_DIR);
    err = stat(ROOT_DIR, &stat_buf);
    SHOW_RESULT(0, stat, err);
    report_stat(ROOT_DIR, &stat_buf);


    err = chdir( ROOT_DIR );
    if( err < 0 ) SHOW_RESULT(1, chdir, err );


    diag_printf("%s.%d %s HERE\n", __FILE__, __LINE__, __FUNCTION__);


    checkcwd( ROOT_DIR );


#ifdef CHMOD_IS_SUPPORTED
    err = chmod(ROOT_DIR, 0775);
    if (err < 0) {
        SHOW_RESULT(1, chmod, err);
    }


    diag_printf("<INFO>: stat '%s'\n", ROOT_DIR);
    err = stat(ROOT_DIR, &stat_buf);
    if (err < 0) {
        SHOW_RESULT(1, stat, err);
    } else {
        report_stat(ROOT_DIR, &stat_buf);
    }
#endif


    diag_printf("%s.%d %s HERE\n", __FILE__, __LINE__, __FUNCTION__);


    listdir( ROOT_DIR, true, -1, &existingdirents );
    if ( existingdirents < 2 )
        CYG_TEST_WARN("Not enough dir entries\n");


    err = stat(".", &stat_buf);
    if (err < 0) {
        SHOW_RESULT(1, stat, err);
    } else {
        diag_printf("<INFO>: stat '%s'\n", ".");
        report_stat(PERSISTENT_FILE, &stat_buf);
    }


    err = stat(PERSISTENT_FILE, &stat_buf);
    if (err < 0) {
        SHOW_RESULT(0, stat, err);
    } else {
        diag_printf("<INFO>: stat '%s'\n", PERSISTENT_FILE);
        report_stat(PERSISTENT_FILE, &stat_buf);
    }


    diag_printf("<INFO>: creat('%s')\n", PERSISTENT_FILE);
    createfile( PERSISTENT_FILE, 202 );


    listdir( ROOT_DIR, true, -1, &existingdirents );
    if ( existingdirents < 2 )
        CYG_TEST_WARN("Not enough dir entries\n");


    if (0) {
        listdir( ROOT_DIR, true, -1, &existingdirents );
        if ( existingdirents < 2 )
            CYG_TEST_WARN("Not enough dir entries\n");
    }


    if (0) {
        diag_printf("That's all for now, folks. Quit!\n");
        exit(0);
    }


    // --------------------------------------------------------------


    diag_printf("%s.%d %s HERE\n", __FILE__, __LINE__, __FUNCTION__);


    createfile( "foo", 202 );
    checkfile( "foo" );
    copyfile( "foo", "fee");
    checkfile( "fee" );
    comparefiles( "foo", ROOT_DIR "/fee" );
    diag_printf("<INFO>: mkdir bar ");
    err = mkdir( ROOT_DIR "/bar", 0 );
    if( err < 0 ) {
        if (errno == EEXIST) {
            diag_printf("directory 'bar' already exists. Continue...\n");
            errno = 0;
        } else {
            SHOW_RESULT(1,  mkdir, err );
        }
    } else {
        diag_printf("   .... OK\n");
    }


    listdir( ROOT_DIR "/" , true, existingdirents+3, NULL );


    copyfile( "fee", ROOT_DIR "/bar/fum" );
    checkfile( "bar/fum" );
    comparefiles( ROOT_DIR "/fee", ROOT_DIR "/bar/fum" );


    diag_printf("<INFO>: cd bar ");
    err = chdir( "bar" );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    checkcwd( ROOT_DIR "/bar" );


    diag_printf("<INFO>: rename %s/foo bundy ", ROOT_DIR);
    err = rename( ROOT_DIR "/foo", "bundy" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rename, err );
    } else {
        diag_printf("   .... OK\n");
    }


    listdir( ROOT_DIR, true, existingdirents+2, NULL );
    listdir( "" , true, 4, NULL );
    listdir( "." , true, 2+2, NULL );
    listdir( "/bar", true, 2+2, NULL );


    diag_printf("Now check file '/bar/bundy', its stat:\n");
    err = stat("/bar/bundy", &stat_buf);
    if (err < 0) {
        SHOW_RESULT(1, stat, err);
    } else {
        diag_printf("%s.%d %s result for stat:\n", __FILE__, __LINE__, __FUNCTION__);
        report_stat(ROOT_DIR, &stat_buf);
    }
    checkfile( ROOT_DIR "/bar/bundy" );
    comparefiles(ROOT_DIR "/fee", "bundy" );


    // --------------------------------------------------------------


#if NAME_MAX > 64
    if (strlen(LONGNAME1) + 1 >= PATH_MAX) {
        CYG_TEST_FAIL("File name length exceeds PATH_MAX");
        return 1;
    }
    if (strlen(LONGNAME2) + 1 >= PATH_MAX) {
        CYG_TEST_FAIL("File name length exceeds PATH_MAX");
        return 1;
    }


    if (0) {
        if (strlen(LONGNAME1) >= NAME_MAX) {
            CYG_TEST_FAIL("File name length exceeds sizeof dirent->d_name");
            return 1;
        }
        if (strlen(LONGNAME2) >= NAME_MAX) {
            CYG_TEST_FAIL("File name length exceeds sizeof dirent->d_name");
            return 1;
        }
    }


    createfile( LONGNAME1, 123 );
    checkfile( LONGNAME1 );
    copyfile( LONGNAME1, LONGNAME2 );


    listdir( "", false, 6, NULL );


    diag_printf("<INFO>: unlink %s ", LONGNAME1);
    err = unlink( LONGNAME1 );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: unlink %s ", LONGNAME2);
    err = unlink( LONGNAME2 );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }
#else
    diag_printf("<INFO>: Skip the test with long filenames since they generate an error ENAMETOOLONG\n");
#endif



    // --------------------------------------------------------------


    diag_printf("<INFO>: unlink fee ");
    err = unlink( ROOT_DIR "/fee" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: unlink fum ");
    err = unlink( "fum" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: unlink %s/bar/bundy ", ROOT_DIR);
    err = unlink( ROOT_DIR "/bar/bundy" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: cd %s ", ROOT_DIR);
    err = chdir( ROOT_DIR );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    checkcwd( ROOT_DIR );


    diag_printf("<INFO>: rmdir %s/bar ", ROOT_DIR);
    err = rmdir( ROOT_DIR "/bar" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rmdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    listdir( ROOT_DIR, false, existingdirents, NULL );


    // --------------------------------------------------------------


    diag_printf("<INFO>: mount /yaffs2 ");
    err = mount( CYGDAT_FS_YAFFS_DEVICE_NAME_0, "/yaffs2", "yaffs" );
    if( err < 0 ) {
        SHOW_RESULT(1,  mount, err );
    } else {
        diag_printf("   .... OK\n");
    }


    createfile( "/yaffs2/tinky", 456 );
    copyfile( "/yaffs2/tinky", "/yaffs2/laalaa" );
    checkfile( "/yaffs2/tinky");
    checkfile( "/yaffs2/laalaa");
    comparefiles( "/yaffs2/tinky", "/yaffs2/laalaa" );


    diag_printf("<INFO>: cd /yaffs2 ");
    err = chdir( "/yaffs2" );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    checkcwd( "/yaffs2" );


    diag_printf("<INFO>: mkdir noonoo ");
    err = mkdir( "noonoo", 0 );
    if( err < 0 ) {
        SHOW_RESULT(0,  mkdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    listdir( "." , true, existingdirents+3, NULL);


    diag_printf("<INFO>: cd noonoo ");
    err = chdir( "noonoo" );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    if (0) {
        diag_printf("For now, quits....\n");
        exit(0);
    }


    checkcwd( "/yaffs2/noonoo" );


    createfile( "tinky", 678 );
    checkfile( "tinky" );


    createfile( "dipsy", 3456 );
    checkfile( "dipsy" );
    copyfile( "dipsy", "po" );
    checkfile( "po" );
    comparefiles( "dipsy", "po" );



    /*for(i=0;i<2048;i++) {
        diag_printf("<INFO>: churningchurningchurning................................ITERATION = %d\n", i);
        createfile( "churningchurningchurning", 4096 );
        diag_printf("<INFO>: unlink churningchurningchurning\n");
        err = unlink( "churningchurningchurning" );
        if( err < 0 ) SHOW_RESULT(1,  unlink, err );
    }*/



    listdir( ".", true, 5, NULL );
    listdir( "", true, 5, NULL );
    listdir( "..", true, existingdirents+3, NULL );


    // --------------------------------------------------------------


    diag_printf("<INFO>: unlink tinky ");
    err = unlink( "tinky" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: unlink dipsy ");
    err = unlink( "dipsy" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: unlink po ");
    err = unlink( "po" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: cd .. ");
    err = chdir( ".." );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    checkcwd( "/yaffs2" );


    diag_printf("<INFO>: rmdir noonoo ");
    err = rmdir( "noonoo" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rmdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    // --------------------------------------------------------------


    err = mkdir( "x", 0 );
    if( err < 0 ) SHOW_RESULT(1,  mkdir, err );


    err = mkdir( "x/y", 0 );
    if( err < 0 ) SHOW_RESULT(1,  mkdir, err );


    err = mkdir( "x/y/z", 0 );
    if( err < 0 ) SHOW_RESULT(1,  mkdir, err );


    err = mkdir( "x/y/z/w", 0 );
    if( err < 0 ) SHOW_RESULT(1,  mkdir, err );


    diag_printf("<INFO>: cd /yaffs2/x/y/z/w ");
    err = chdir( "/yaffs2/x/y/z/w" );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }
    checkcwd( "/yaffs2/x/y/z/w" );


    diag_printf("<INFO>: cd .. ");
    err = chdir( ".." );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }
    checkcwd( "/yaffs2/x/y/z" );


    diag_printf("<INFO>: cd . ");
    err = chdir( "." );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }
    checkcwd( "/yaffs2/x/y/z" );


    diag_printf("<INFO>: cd ../../y ");
    err = chdir( "../../y" );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }
    checkcwd( "/yaffs2/x/y" );


    diag_printf("<INFO>: cd ../.. ");
    err = chdir( "../.." );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }
    checkcwd( "/yaffs2" );


    diag_printf("<INFO>: rmdir x/y/z/w ");
    err = rmdir( "x/y/z/w" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rmdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: rmdir x/y/z ");
    err = rmdir( "x/y/z" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rmdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: rmdir x/y ");
    err = rmdir( "x/y" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rmdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: rmdir x ");
    err = rmdir( "x" );
    if( err < 0 ) {
        SHOW_RESULT(1,  rmdir, err );
    } else {
        diag_printf("   .... OK\n");
    }


    // --------------------------------------------------------------


    diag_printf("<INFO>: unlink tinky ");
    err = unlink( "tinky" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: unlink laalaa ");
    err = unlink( "laalaa" );
    if( err < 0 ) {
        SHOW_RESULT(1,  unlink, err );
    } else {
        diag_printf("   .... OK\n");
    }


    diag_printf("<INFO>: cd %s ", ROOT_DIR);
    err = chdir( ROOT_DIR );
    if( err < 0 ) {
        SHOW_RESULT(1,  chdir, err );
    } else {
        diag_printf("   .... OK\n");
    }
    checkcwd( ROOT_DIR );


    diag_printf("<INFO>: umount /yaffs2 ");
    err = umount( "/yaffs2" );
    if( err < 0 ) {
        SHOW_RESULT(1,  umount, err );
    } else {
        diag_printf("   .... OK\n");
    }


#ifdef CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_2
    diag_printf("<INFO>: mounting second JFFS2 filesystem on /mnt\n");


    err = mount( CYGDAT_IO_FLASH_BLOCK_DEVICE_NAME_1, "/mnt", "yaffs" );
    if( err < 0 ) SHOW_RESULT(1,  mount, err );


    err = chdir( "/" );
    if( err < 0 ) SHOW_RESULT(1,  chdir, err );


    checkcwd( "/" );


    listdir( "/", true, -1, &existingdirents );
    if ( existingdirents < 2 )
        CYG_TEST_WARN("Not enough dir entries\n");


    listdir( "/mnt", true, -1, &existingdirents );
    if ( existingdirents < 2 )
        CYG_TEST_WARN("Not enough dir entries\n");


    diag_printf("<INFO>: umount /mnt\n");
    err = umount( "/mnt" );
#endif


    diag_printf("<INFO>: umount %s ", ROOT_DIR);
    err = umount( ROOT_DIR );
    if( err < 0 ) {
        SHOW_RESULT(1,  umount, err );
    } else {
        diag_printf("   .... OK\n");
    }



    CYG_TEST_PASS_FINISH("fileio1");
}


// -------------------------------------------------------------------------
// EOF fileio1.c