diff src/cs/drivers/drv_app/ffs/board/tcases.c @ 0:b6a5e36de839

src/cs: initial import from Magnetite
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 15 Jul 2018 04:39:26 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/drivers/drv_app/ffs/board/tcases.c	Sun Jul 15 04:39:26 2018 +0000
@@ -0,0 +1,6488 @@
+/******************************************************************************
+ * Flash File System (ffs)
+ * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
+ *
+ * ffs test cases
+ *
+ * $Id: tcases.c 1.13.1.1.1.66 Thu, 08 Jan 2004 15:05:23 +0100 tsj $
+ *
+ ******************************************************************************/
+
+#ifndef TARGET
+#include "ffs.cfg"
+#endif
+
+#include "ffs/ffs_api.h"  // Temp 
+#include "ffs/ffs.h"
+
+#include "ffs/board/tffs.h"
+#include "ffs/board/core.h" // only for block/object recovery test flags
+#include "ffs/board/tdata.h"
+#include "ffs/board/ffstrace.h"
+#include "ffs/board/drv.h"
+#include "ffs/pcm.h"
+
+#if((TARGET == 1) || (RIV_ENV==1))
+#include "rvf/rvf_api.h"  // this include rv_general.h and rvf_target.h
+#include "rvm/rvm_use_id_list.h"
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+
+#define LUDIR  "/europe/sweden"
+#define MFDIR "/pcm"
+
+// TODO: reimplement test case bfull (not valid any more).
+
+// TODO: Cleanup in beginning of each test case for as many cases as
+// possible, so they can be re-run.
+
+// TODO: Make as many cases as possible fully independent of number of
+// blocks and size of blocks in ffs.
+
+// TODO: Every testcase should test if it is applicable to the current
+// environment, e.g. some tests are impossible if e have a 2 or 3 block
+// file system.
+
+// TODO: test case for testing age functionality
+// TODO: Implement case_ren
+// TODO: Implement case_rm
+
+// NOTEME: DO something with test case flags (PC, IT, RND)?
+
+// Should we make a test case where we use case_lsr to make map of objects (
+// ensuring mapsize is prime). In a loop, we select a random object (object
+// index[rnd%size]) and perform a random operation on that object?
+
+// Should test data (tdata[]) be of sizes 2^n+n or Xn+n where n = 0..15
+
+// Should all test files have suffix ".<tdata-index>"? This would make very
+// easy data checking!
+
+// Add compiler define: WITH_PCM
+
+//unsigned char ffs_image[4*4*1024];
+//int ffs_ram_image_address = (int) &ffs_image;
+
+
+/******************************************************************************
+ * Prototypes and Globals
+ ******************************************************************************/
+
+// Helper functions
+int case_cleanup(int min_space);
+int case_mk_rand_file(char *dirname, int max_size, int min_size);
+int ignore_file(char *pathname);
+int case_trace_mask(int p0, int p1);
+int case_reinit(int p0, int p1);
+int case_debug_help(int p0, int p1);
+
+struct object_s {
+    char *name;
+    struct xstat_s stat;
+};
+
+const struct testcase_s testcase[];
+
+// Benchmark (not in use yet)
+struct results_s {
+    int w16B;
+    int w256B;
+    int w4096B;
+    int rew4096B;
+    int r16B;
+    int r256B;
+    int r4096B;
+    int lfile;
+    int ldir;
+    int lonef;
+};
+
+/******************************************************************************
+ * Collective Test Cases
+ ******************************************************************************/
+
+// test cases: all, alot, most, much + specific ones
+
+int case_all(int p0, int p1)
+{
+#if (TARGET == 1)
+    UINT32 time_begin, elapsed;
+    time_begin = tffs_timer_begin();
+#endif
+    // We have to run test case 'init' after test case 'format'. This is
+    // because 'init' test case calls test_ffs_params_get() which
+    // initializes variables used in many of the testcases.
+    
+    error = test_run("ninit;format;i;world;eu;pcm;apiexc;"
+                     "bigf;open;rw;seek;append;ren;mopen;"
+                     "jnl;irec;drec;trunc;brec;stat;"
+                     "lu;fc;root;dirs;frd;bfull;dsync;"
+                     "ssym;find;ri;x;fwflags;query;octrl");
+#if (TARGET == 1)
+    elapsed = tffs_timer_end(time_begin);
+    ttw(ttr(TTrAll, "Time elapsed %ds" NL, elapsed / 1000));
+#endif
+
+    test_statistics_print();
+
+    return error;
+    // Not implemented test cases...
+    return test_run("rm;pcm;");
+}
+
+int case_alot(int p0, int p1)
+{
+    return test_run("ninit;format;ri;i;ri;world;ri;eu;ri;fwflags;ri;"
+                    "bigf;ri;open;ri;rw;ri;seek;ri;append;ri;ren;ri;"
+                    "jnl;ri;irec;ri;brec;ri;stat;ri;trunc;ri;mopen;ri;"
+                    "lu;ri;fc;ri;root;ri;dirs;ri;frd;ri;bfull;ri;"
+                    "ssym;ri;find;ri;x;ri;dsync;ri;pcm;ri;query;ri;octrl");
+}
+
+int case_tall(int p0, int p1)
+{
+    return test_run("ninit;format;i;world;eu;fwflags;"
+                    "bigf;jnl;irec;drec;ren;apiexc;"
+                    "stat;open;rw;seek;trunc;append;octrl;"
+                    "lu;fc;root;dirs;frd;bfull;pcm;query;"
+                    "ssym;find;x;ex;bf;nb;mopen;dsync;brec");
+}
+
+// Ad hoc test case
+int case_test(int p0, int p1)
+{
+    return test_run("format;i;world;eu;ri;mopen1;ri;fwflags;ri;"
+                    "bigf;ri;jnl;ri;irec;ri;drec;ri;brec;ri;pcm;ri;"
+                    "trunc1;ri;stat;open1;ri;rw1;ri;seek1;ri;ren;ri;"
+                    "lu;ri;fc;ri;root;ri;dirs;ri;frd;ri;bfull;ri;"
+                    "ssym;ri;find;ri;x;ri;append;ri;dsync;ri;");
+}
+
+extern struct dev_s dev;
+// Agressive all. Run case 'all' for dev.numblocks in the range dev.numblocks..4
+int case_aall(int p0, int p1)
+{
+    char myname[20];
+
+    int i, failed = 0;
+   
+    if (dev.numblocks * dev.blocksize > 1024*1024)
+        strcpy(myname, "/ffs/b999");
+    else
+        strcpy(myname, "/ffs/b99");
+
+    /** There's no need to test for i=127,126,125,124..3,2,1. So for i
+     * >= 20 we progress a little faster. */
+    for (i = dev.numblocks; i >= 3; i -= (i >= 20 ? i/4 : 1))
+    {
+        tw(tr(TR_FUNC, TrTest, "TEST aall. %d\n", i));
+        ttw(ttr(TTrTest, "TEST aall. %d" NL, i));
+
+        error = tffs_preformat(0xDEAD);
+        expect(error, EFFS_OK);
+
+        sprintf(myname, "/ffs/b%d", i);
+        tffs_format(myname, 0x2BAD);
+        expect(error, EFFS_OK);
+        
+        failed += test_run("i;world;eu;bigf;bfull;"
+                           "jnl;irec;drec;brec;stat;dsync;"
+                           "open;rw;seek;trunc;ren;mopen;"
+                           "lu;fc;root;dirs;frd;append;" 
+                           "ssym;find;ri;x");
+
+    }
+    return failed;
+}
+
+// This is a collection of all failing testcases to be investigated.
+int case_fail(int p0, int p1)
+{
+    int result;
+    const char imeifile[] = "/europe/norway/IMEI";
+
+    switch (p0) {
+    case 1:
+        tw(tr(TR_FUNC, TrTestHigh, 
+              "remember to run case_fcontrol before this one\n"));
+        // Make symlink to imeifile and try to update it
+        error = tffs_symlink("/europe/imie", imeifile);
+        expect(error, EFFS_ACCESS);
+
+        error = tffs_fwrite("/europe/imie", TDATA(1));
+        expect(error, EFFS_ACCESS);
+        break;
+    case 2:    
+        if (1) {
+            const char bigfile[] = "/iceberg";
+            int bytes_max, file_size;
+            char myname[] = "/ffs/b7";
+
+            error = tffs_preformat(0xDEAD);
+            expect(error, EFFS_OK);
+
+            error = tffs_format(myname, 0x2BAD);
+            expect(error, EFFS_OK);
+
+            ffs_query(Q_BYTES_FREE, (uint32 *) &bytes_max);
+  
+// File the system with this huge file
+            file_size = bytes_max;
+
+            ttw(ttr(TTrTest, "Bigfile of size %d" NL, file_size));
+            tw(tr(TR_FUNC, TrTestHigh, "Bigfile of size %d\n", file_size));
+
+            error = tffs_fcreate(bigfile, (char *) tdata[TDATA_HUGE], file_size);
+            expect(error, EFFS_OK);
+        }
+        break;
+            
+    default:
+        result = 1;
+    }
+        return result;
+}
+
+// zzz to easy search ;-)
+// NOTE: Move the below tests
+extern char *tdata_huge;
+// Test that a FFS API blocking call that not is able to send a mail to FFS fails as expected and don't lock the system (it must unlock and delete the mutex). 
+int case_okay(int p0, int p1)
+{
+
+    error = tffs_fwrite("/test", tdata[TDATA_HUGE], 20);
+    expect_ok(error);
+
+    error = tffs_fread("/test", bigbuf, 20);
+    expect_ok(error);
+
+    bigbuf[20] = 0;
+
+    tw(tr(TR_FUNC, TrTestHigh, "String '%s'\n", bigbuf));
+
+    return EFFS_OK;
+}
+
+// Run testcases in a random order. Only the test cases in the test case
+// table that are marked as re-runnable, are run.
+int case_rand(int p0, int p1)
+{
+    int i, n, seed, max = 0, error = 0;
+    const struct testcase_s *p;
+// This is a way to activate trace at a defined test number. If rand
+// test number 134 fail it is possible to activate trace at test number
+// 133 etc. Note we have to change activate_trace_nr manual before compile.
+    int activate_trace_nr = 0;       
+    int trace_mask = 0xFFDFF;
+// NOTE: use p1 as active_trace_nr? or make it
+
+    p0 = (p0 == 0 ? 117 : p0); // Number of test cases to run
+    p1 = (p1 == 0 ? 567 : p1); // Initial seed
+    seed = p1;
+    if (seed == 1) {
+        ; // TODO: Set seed as a variable of current time
+    }
+
+    // TODO: Initialize seed from p1.
+
+    // First count total number of test cases
+    for (p = testcase; p->name; p++)
+        max++;
+
+    tw(tr(TR_FUNC, TrTestHigh,
+          "Number of available random test cases = %d\n", max));
+
+    for (i = 0; i < p0; i++)
+    {
+        do {
+            n = rand() % max;
+        } while ((testcase[n].flags & RND) == 0);
+
+        if ((i + 1) == activate_trace_nr) {
+#if (TARGET == 0)
+            tr_init(trace_mask, 2, 0 );
+#else
+            ttr_init(trace_mask);
+#endif
+            tw(tr_bstat());
+        }
+
+        tw(tr(TR_FUNC, TrTest, "Nr: %d", i + 1));
+        ttw(ttr(TTrTest, "Nr: %d" NL, i + 1));
+        
+        if ((error = test_run(testcase[n].name)))
+            break;
+    }
+    
+    if (p1 == 1)
+        tw(tr(TR_FUNC, TrTestHigh, "Initial seed = %d\n", seed));
+    
+    test_statistics_print();
+    return error;
+}
+
+
+/******************************************************************************
+ * Population Tests
+ ******************************************************************************/
+
+int case_world(int p0, int p1)
+{
+    int i;
+    const char *dirs[] = { "/antarctica",    "/africa",
+                           "/asia",          "/europe",
+                           "/north-america", "/south-america",
+                           "/australia" };
+
+    // Cleanup
+    for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) {
+        tffs_remove(dirs[i]);
+    }
+
+    for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) {
+        error = tffs_mkdir(dirs[i]);
+        expect(error, EFFS_OK);
+    }
+    return 0;
+}
+
+
+int case_europe(int p0, int p1)
+{
+    int i;
+    const char *dirs[] = { "/europe/denmark", "/europe/sweden",
+                           "/europe/norway",  "/europe/finland" };
+
+    // Cleanup
+    for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) {
+        error = tffs_remove(dirs[i]);
+    }
+
+    for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) {
+        error = tffs_mkdir(dirs[i]);
+        expect(error, EFFS_OK);
+    }
+    return 0;
+}
+
+int case_denmark(int p0, int p1)
+{
+    // Cleanup
+    tffs_remove("/europe/denmark/jutland");
+    tffs_remove("/europe/denmark/sealand");
+
+    error = tffs_mkdir("/europe/denmark/jutland");
+    expect(error, EFFS_OK);
+    error = tffs_mkdir("/europe/denmark/sealand");
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+
+/******************************************************************************
+ * Atomic Tests
+ ******************************************************************************/
+
+int case_init(int p0, int p1)
+{
+    error = tffs_initialize();
+    // ignore error
+    error = test_ffs_params_get();
+    expect(error, EFFS_OK);
+    return 0;
+}
+
+int case_exit(int p0, int p1)
+{
+    error = tffs_exit();
+    expect(error, EFFS_OK);
+    return 0;
+}
+
+int case_only_preformat(int p0, int p1)
+{
+    tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    return 0;
+}
+
+int case_only_format(int p0, int p1)
+{
+    tffs_format("/ffs", 0x2BAD);
+    expect(error, EFFS_OK);
+    return 0;
+}
+
+int case_reset(int p0, int p1)
+{
+    error = tffs_initialize();
+    // ignore result
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs", 0x2BAD);
+    expect(error, EFFS_OK);
+    error = tffs_exit();
+    expect(error, EFFS_OK);
+    return 0;
+}
+
+int case_status(int p0, int p1)
+{
+    error = test_run("lsr");
+    return error;
+}
+
+
+/******************************************************************************
+ * Special Tests
+ ******************************************************************************/
+
+// Test FFS with only 2 blocks in device
+int case_twob(int p0, int p1)
+{
+    int space_left;
+    int size, i;
+    char myname[] = "/two_block99";
+
+    // Format ffs to use only 2 block no journal file and no reserved space.
+    // Make some directoryes.
+    // Fill ffs allmost to the edge and try to write over the edge.
+    // Read back all the files.
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs/b2j0m0", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    error = test_run("i;world;eu;x");
+    if(error) return 1;
+
+    // Calculate the amount of space that is left to user data because some space
+    // is used to directoryes
+    space_left = dev.blocksize - (13 * 20);
+    tw(tr(TR_FUNC, TrTestHigh, "Space left: %d\n", space_left));
+    
+    size = space_left;
+    for(i = 0; i < 6; i++) {
+        size = size/2;
+        sprintf(myname, "/two_block%d", i);
+        error = tffs_fwrite(myname, (char*)tdata[TDATA_HUGE], 
+                            size >= 20 ? size - 20 : 0);
+        expect(error, EFFS_OK);
+    }
+
+    error = tffs_fwrite(myname, (char*)tdata[TDATA_HUGE], space_left/5);
+    expect(error, EFFS_NOSPACE);
+    
+    // 20 is the average space used to the file name + word align. 
+    size = space_left;
+    for(i = 0; i < 6; i++) {
+        size = size/2;
+        sprintf(myname, "/two_block%d", i);
+        error = tffs_fread(myname, bigbuf, bigbuf_size);
+        expect(error, size >= 20 ? size - 20 : 0);
+    }
+    
+    //error = ffs_object_control(0, OC_DEV_DEVICE, 0x080D);
+    //if (error < 0) return error;
+
+    return 0;
+}
+
+// Test FFS with only 3 blocks in device
+int case_threeb(int p0, int p1)
+{
+    char mytest[20];
+    
+    // Format ffs to use only 3 blocks, make directoryes and run test case
+    // rand <p0> number of times.
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs/b3r24", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    error = test_run("i;world;eu;x");
+    if (error) return 1;
+
+    if(p0 == 0) p0 = 233;
+
+    sprintf(mytest, "rand%d", p0);
+    return test_run(mytest);
+}
+
+
+// Simulate a typical usage of ffs. We expect one part of the data will be
+// what we call 'static' data (calibration files etc) the other part is the
+// 'dynamic' data (wap, sms etc) we do also expect that they don't fill FFS
+// completely thus we have a 'free' part.
+int case_customer(int nblocks, int nloops)
+{
+    int free_part = 5, static_part = 47, dynamic_part = 47;
+    int free_size, static_size, dynamic_size; 
+    int bytes_free, bytes_max, bytes_used;
+    int file_size_max, file_size_min, file_size_avg;
+    int i, j, max_obj_block, num_static_files;
+    char myname[] = "/ffs/bxxx/";
+    char file_name[FFS_FILENAME_MAX + 1];
+    char path[FFS_FILENAME_MAX * 2];
+    char static_dir[] ="/READONLY";
+    char dynamic_dir[] = "/rand";
+    struct dir_s dir;
+
+    if (nblocks == 0)
+        nblocks = 7;
+    if (nloops == 0)
+        nloops = 300;
+
+    error = tffs_preformat(0xDEAD);      expect(error, EFFS_OK);
+    sprintf(myname, "/ffs/b%d", nblocks);
+    error = tffs_format(myname, 0x2BAD); expect(error, EFFS_OK);
+
+    tffs_mkdir(dynamic_dir); expect(error, EFFS_OK);
+    tffs_mkdir(static_dir);  expect(error, EFFS_OK);
+
+    ffs_query(Q_BYTES_FREE, &bytes_max);
+    free_size = bytes_max * free_part / 100;
+    static_size = bytes_max * static_part / 100;
+    dynamic_size = bytes_max * dynamic_part / 100;
+    tw(tr(TR_FUNC, TrTest, "Free:%d,%dkB. Static:%d,%dkB, Dynamic:%d,%dkB\n", 
+          free_part, free_size/1024, static_part, static_size/1024, 
+          dynamic_part, dynamic_size/1024));
+
+// Find max average objects per block
+    max_obj_block = fs.block_files_max;
+    if (max_obj_block > fs.objects_max / (dev.numblocks -1 - fs.blocks_free_min))
+        max_obj_block = fs.objects_max / (dev.numblocks -1 - fs.blocks_free_min);
+    tw(tr(TR_FUNC, TrTest, "Max average objects per block %d\n", max_obj_block));
+    ttw(ttr(TTrTest, "Max avg obj per block %d" NL, max_obj_block));
+
+// Average (minimum) file size (avoid to reach block_files_max and
+// objects_max)
+    file_size_avg = dev.blocksize / max_obj_block; 
+
+    ffs_query(Q_BYTES_USED, &bytes_used);
+    tw(tr(TR_FUNC, TrTest, "Write static files (avg size %d)\n", file_size_avg));
+    ttw(ttr(TTrTest, "avg size %d" NL, file_size_avg));
+    do {
+        i++;
+        file_size_min = 5;
+// For each 5 file we make one huge.
+        file_size_max = i % 5 ? file_size_avg * 2 : file_size_avg * 15;
+// For each 6 file we make one small.
+        file_size_max = i % 6 ? file_size_max : 5;
+
+// Saturate, avoid to make one file that parses the total static_size
+        if (file_size_max > static_size - bytes_used)
+            file_size_max = file_size_min = static_size - bytes_used;
+
+// For each 7 file we create one dynamic (If the block is full with only
+// valid objects do we risk that this block never will be reclaimed!).
+        if (i % 7)
+            error = case_mk_rand_file(dynamic_dir, file_size_max, file_size_min);
+        else
+            error = case_mk_rand_file(static_dir, file_size_max, file_size_min);
+        expect_ok(error);
+        ffs_query(Q_BYTES_USED, &bytes_used);
+    } while (bytes_used < static_size); 
+
+    num_static_files = tffs_opendir(static_dir, &dir);
+    expect_ok(num_static_files);
+    tw(tr(TR_FUNC, TrTest, "Written %d files\n", num_static_files));
+    ttw(ttr(TTrTest, "Written %d files" NL, num_static_files));
+// In a loop we continue to write data until only the wanted free_part is
+// left, after that we remove half of the just created files and then write
+// again and again...
+    j = 0;
+    tw(tr(TR_FUNC, TrTest, "Write and remove dynamic files\n"));
+    ttw(ttr(TTrTest, "Write and remove dynamic files" NL));
+    for (i = 0; i < nloops; i++) {
+        if (i % 10 == 0) {
+            tw(tr(TR_FUNC, TrTest, "loop %d\n", i));
+            ttw(ttr(TTrTest, "loop %d" NL, i));
+        }
+        ffs_query(Q_BYTES_FREE, &bytes_free);
+        do {
+            j++;
+            file_size_min = 5;
+            file_size_max = j % 5 ? file_size_avg * 2 : file_size_avg * 15;
+            file_size_max = j % 6 ? file_size_max : 5;
+// Saturate, avoid using the free space.
+            if (file_size_max > bytes_free - free_size)
+                file_size_max = file_size_min = bytes_free - free_size;
+
+            if (file_size_max < 0)
+                break;
+
+            error = case_mk_rand_file(dynamic_dir, file_size_max, file_size_min);
+// NOTE it is very difficult to avoid EFFS_FSFULL because cleanup will
+// sometimes only remove the big files thus there will exist a lot of small
+// that use all the inodes.
+            if (error == EFFS_FSFULL) {
+                tw(tr(TR_FUNC, TrTest, "Warning no free inodes\n"));
+                ttw(ttr(TTrTest, "Warning no free inodes" NL));
+                error = case_cleanup(free_size + dynamic_size);    
+            }
+            else
+                expect_ok(error);
+
+            ffs_query(Q_BYTES_FREE, &bytes_free);
+        } while (bytes_free > free_size); 
+
+        error = case_cleanup(free_size + dynamic_size / 2);    
+        expect_ok(error);
+    }
+
+    error = case_reinit(0, 0);
+    expect(EFFS_OK, error);
+
+    tw(tr(TR_FUNC, TrTest, "Verify all files\n"));
+    ttw(ttr(TTrTest, "Verify all files" NL));
+    for (i = 0; i < 2; i++) {
+        if (i == 0) {
+            error = tffs_opendir(static_dir, &dir);
+            expect_eq(error, num_static_files);
+        }
+        else {
+            error = tffs_opendir(dynamic_dir, &dir);
+            expect_ok(error);
+        }
+
+        while ((error = tffs_readdir(&dir, file_name, sizeof(file_name))) > 0) {
+            if (i == 0)
+                strcpy(path, static_dir);
+            else 
+                strcpy(path, dynamic_dir);
+            strcat(path, "/");
+            strcat(path, file_name);
+
+            error = tffs_stat(path, &stat);
+            expect_ok(error);
+            error = test_expect_file(path, tdata[TDATA_HUGE], stat.size); 
+            if (error) return 1;
+        }
+    }
+
+    test_statistics_print();
+    return 0;
+}
+
+
+// TODO cleanup this test. Use stat and verify some of the files etc.
+
+// Used to test ConQuest issue FFS_FIX-11368 We fill FFS with a lot of small
+// files. Then by turn remove some files and write new files, always very
+// close to max avaible bytes.
+
+// Note the below test is not able to run in big configuration because it
+// creates a lot of small files thus we reach EFFS_FSFULL 'out of inodes'
+int case_ffull(int p0, int p1)
+{       
+    int error, i, bytes_free, file_size, max_write_size = 1000;
+    char myname[] = "/ffs/bxxx/";
+
+    if (p0 == 0) 
+        p0 = 100; // Default 100 loops
+    if (p1 == 0 || p1 > 999)
+        p1 = 3;   // Default run in 3 blocks
+   
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+
+    sprintf(myname, "/ffs/b%d", p1);
+    error = tffs_format(myname, 0x2BAD);
+    expect(error, EFFS_OK);
+
+    tffs_mkdir("/rand");
+    expect(error, EFFS_OK);
+
+    tw(tr(TR_FUNC, TrTest, "Fill it with files until it fails\n"));
+    ttw(ttr(TTrTest, "Fill it with files until it fails" NL));
+
+// We have to avoid too many small files or else do we reach objects_max
+    ffs_query(Q_BYTES_FREE, &bytes_free);
+    max_write_size = bytes_free / fs.objects_max * 2.5;
+
+    do {
+        error = case_mk_rand_file("/rand", max_write_size, 0);
+    } while (error >= 0 );
+
+    tw(tr(TR_FUNC, TrTest, "Fill done (%d)\n" ,error));
+    ttw(ttr(TTrTest, "Fill done (%d)" NL, error));
+    expect(error, EFFS_NOSPACE);  // Now are we sure that it is full
+
+    tw(tr(TR_FUNC, TrTest, "Cleanup and fill again \n"));
+    for (i = 0; i < (1 + p0); i++) {
+        tw(tr(TR_FUNC, TrTestHigh, "Loop %d \n", i + 1));
+        ttw(ttr(TTrTest, "Loop %d" NL, i + 1));
+
+        tw(tr_bstat());
+        error = case_cleanup(max_write_size * 3);    
+        tw(tr_bstat());
+
+        do {
+            ffs_query(Q_BYTES_FREE, &bytes_free);
+// Saturate size
+            file_size = bytes_free > max_write_size ? max_write_size :bytes_free;
+// Query BYTES_FREE don't count the below data use.
+//file_size -= (FFS_FILENAME_MAX + 1 + dev.atomsize);
+            if (file_size < 0)
+                break;
+
+            error = case_mk_rand_file("/rand", file_size - (FFS_FILENAME_MAX+1), 0);
+
+            if (error == EFFS_FSFULL) { // Out of inodes
+                error = case_cleanup(max_write_size * 6);    
+                // Create bigger files to avoid '-11', auto fit :-)
+                max_write_size *= 1.1;  // Add 10%
+                tw(tr(TR_FUNC, TrTestHigh, "Out of inodes, write size: %d \n", 
+                      max_write_size));
+                continue;
+            }
+
+            expect_ok(error);  
+
+        } while (file_size != bytes_free);  
+    }
+
+    tw(tr(TR_FUNC, TrTest, "Test finish (%d) \n", error)); 
+    ttw(ttr(TTrTest, "Test finish (%d)" NL, error));
+
+    if (error >= 0)
+        return EFFS_OK;
+
+    return error;    
+}
+
+int case_rivtype(int p0, int p1)
+{
+    // Use the compiler to test if the types are correctly defined. We don't
+    // need to run this test just make a compilation.
+    T_FFS_OPEN_FLAGS flags = FFS_O_RDONLY;
+    T_FFS_SIZE size = 20;
+    T_FFS_RET error = -10;
+    T_FFS_WHENCE whence = FFS_SEEK_SET;
+    T_FFS_STAT stat;
+    
+    T_FFS_DIR dir;
+    T_FFS_FD fd = FFS_FD_OFFSET;
+    T_RV_RETURN callback;
+    T_FFS_FILE_CNF confirm;
+    T_FFS_OBJECT_TYPE objt = OT_FILE;
+
+    // Use the defined variables to avoid the boring warning: unused
+    // variable 'xx'
+    if (flags != FFS_O_RDONLY)  return 1;
+    if (size != 20)             return 1;
+    if (error != -10)           return 1;
+    if (whence != FFS_SEEK_SET) return 1;
+    if (fd != FFS_FD_OFFSET)    return 1;
+    if (objt != OT_FILE)        return 1;
+   
+    stat.type = 1;
+    if (stat.type != 1) return 1;
+    dir.this = 5;
+    if (dir.this != 5) return 1;
+    callback.addr_id = 3;
+    if (callback.addr_id != 3) return 1;
+    confirm.error = -1;
+    if (confirm.error != -1) return 1;
+
+    return 0;
+}
+
+/******************************************************************************
+ * Pseudo Tests
+ ******************************************************************************/
+
+// Recursively read objects in directory. Does NOT check for buffer
+// overflow!
+int case_dir_list(char *dirname, struct object_s **pplist, char **ppnames)
+{
+    struct object_s *plist, *plist_start, *plist_end;
+    char pathname[6 * 20];
+    struct dir_s dir;
+    char *pnames, *pn;
+    int i, pathlen;
+
+    //tw(tr(TR_BEGIN, TrTestHigh, "dir_list('%s', %d, 0x%x)\n",
+    //      dirname, (int)*pplist/sizeof(struct object_s), *ppnames));
+    plist_start = plist = *pplist;
+    pnames = *ppnames;
+
+    strcpy(pathname, dirname);
+    pathlen = strlen(pathname);
+
+    // remove trailing slash. It is tiring to handle the root directory
+    // differently from other directories. In a future ffs revision, this
+    // trailing slash should be allowed!
+    if (pathname[pathlen - 1] == '/') {
+        pathname[pathlen - 1] = 0;
+        pathlen--;
+    }
+        
+    if (strlen(pathname) == 0)
+        error = tffs_opendir("/", &dir);
+    else
+        error = tffs_opendir(pathname, &dir);
+    expect_ok(error);
+
+    pn = pathname + strlen(pathname);
+    *pn++ = '/';
+    *pn = 0;
+
+    error = 1;
+    for (i = 0; (error = tffs_readdir(&dir, pn, 21)) > 0; i++)
+    {
+        error = tffs_xlstat(pathname, &plist->stat);
+        expect(error, EFFS_OK);
+
+        // Copy full object pathname to buffer, working downwards.
+        pnames -= strlen(pathname) + 1;
+        // Check for buffer overflow (if pnames <= plist)
+        expect_gt((int) pnames, (int) plist);
+        strcpy(pnames, pathname);
+        plist->name = pnames;
+
+        plist++;
+    }
+    *pplist = plist;
+    *ppnames = pnames;
+    
+    // For each directory in the retrieved list, recurse.
+    plist_end = plist;
+    for (plist = plist_start; plist < plist_end; plist++) {
+        if (plist->stat.type == OT_DIR)
+            i += case_dir_list(plist->name, pplist, ppnames);
+    }
+    // tw(tr(TR_END, TrTestHigh, "} %d\n", i));
+    return i;
+}
+
+int case_find(int p0, int p1)
+{
+    struct object_s *plist, *plist_start;
+    char *pnames, *pnames_start;
+    int n, names_used, list_used;
+
+    plist  = plist_start  = (struct object_s *) bigbuf;
+    pnames = pnames_start = bigbuf + bigbuf_size;
+    n = case_dir_list("/", &plist, &pnames);
+
+    list_used = n * sizeof(struct object_s);
+    names_used = pnames_start - pnames;
+
+    tw(tr(TR_FUNC, TrTestHigh, "Buffer space used: %d + %d = %d\n",
+          list_used, names_used, list_used + names_used));
+    ttw(ttr(TTrTest, "Buffer space used: %d + %d = %d" NL,
+            list_used, names_used, list_used + names_used));
+
+    return 0;
+}
+
+// TODO: We should accumulate all stat.space and check it vs. the number of
+// bytes used!
+int case_lsr(int p0, int p1)
+{
+    struct object_s *plist, *plist_start;
+    char *pnames, *pnames_start;
+    char of[3];
+    int i, n;
+
+    plist  = plist_start  = (struct object_s *) bigbuf;
+    pnames = pnames_start = bigbuf + bigbuf_size;
+    n = case_dir_list("/", &plist, &pnames);
+    tw(tr(TR_FUNC, TrTestHigh, "Total %d objects.\n", n));
+    ttw(ttr(TTrTest, "Total %d objects" NL, n));
+
+    plist = plist_start;
+    for (i = 0; i < n; i++, plist++) {
+        strcpy(of, "  ");
+        switch (plist->stat.type) {
+        case OT_FILE: of[0] = ' '; break;
+        case OT_DIR:  of[0] = 'd'; break;
+        case OT_LINK: of[0] = 'l'; break;
+        }
+        if (plist->stat.flags & OF_READONLY)
+            of[1] = 'r';
+            
+#if (TARGET == 0)
+        printf("%3d: %s %3d %2d/%04X (%4d,%4d) %5d %s\n",
+               i, of, 
+               plist->stat.inode, plist->stat.block, 
+               plist->stat.location, plist->stat.sequence, plist->stat.updates, 
+               plist->stat.size, &plist->name[1]);
+#else
+        ttw(ttr(TTrTest, "%3d: %s %3d %2d/%04X (%4d,%4d) %5d %s" NL,
+                i, of, 
+                plist->stat.inode, plist->stat.block, 
+                plist->stat.location, plist->stat.sequence, plist->stat.updates, 
+                plist->stat.size, &plist->name[1]));
+#endif
+    }
+
+    return 0;
+}
+
+
+/******************************************************************************
+ * Normal Tests
+ ******************************************************************************/
+
+int case_format(int p0, int p1)
+{
+    error = tffs_preformat(0xD00D);
+    expect(error, EFFS_INVALID);
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs/", 0xDEAD);
+    expect(error, EFFS_INVALID);
+    error = tffs_format("ffs", 0x2BAD);
+    expect(error, EFFS_BADNAME);
+    error = tffs_format("", 0x2BAD);
+    expect(error, EFFS_BADNAME);
+    error = tffs_format("/", 0x2BAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs", 0x2BAD);
+    expect(error, EFFS_NOPREFORMAT);
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format(0, 0x2BAD);
+//error = tffs_format("/ffs/i256o128", 0x2BAD);
+    expect(error, EFFS_OK);
+    return 0;
+}
+
+// Test that it is illegal to modify root inode as if it was a normal file
+// or directory
+int case_root(int p0, int p1)
+{
+    error = tffs_opendir("/", &dir);
+    expect_ok(error);
+    error = tffs_fcreate("/", "foo", 3);
+    expect(error, EFFS_EXISTS);
+    error = tffs_fupdate("/", "bar", 3);
+    expect(error, EFFS_NOTAFILE);
+    error = tffs_fwrite("/", "foo", 3);
+    expect(error, EFFS_NOTAFILE);
+    error = tffs_remove("/");
+    expect(error, EFFS_ACCESS);
+    return 0;
+}
+
+// Test object lookup, object names etc.
+int case_lookup(int p0, int p1)
+{
+    // Swedish Provinces: Blekinge, Smaaland, Halland, Vaermland, Dalarna,
+    // Dalsland, Gotland, Gaestrikland, Haelsingland, Bohuslaen,
+    // Haerjedalen, Jaemtland, Lappland, Medelpad, Norrbotten, Naerke,
+    // Soedermanland, Uppland, Vaesterbotten
+
+    // Smaaland Cities: Vetlanda, Bodafors, Rottne, Ljungby, Nybro,
+    // Hultsfred, Oskarshamn, Vimmerby, Hyltebruk, Joenkoeping, Vaexjoe
+
+    tffs_mkdir("/europe");
+    tffs_mkdir("/europe/sweden");
+
+    // test init
+    error = tffs_mkdir(LUDIR "/Smaaland");
+    expect(error, EFFS_OK);
+    // test BAD_FILENAME
+    error = tffs_fcreate("", TDATA(0));
+    expect(error, EFFS_BADNAME);
+    // test EFFS_EXISTS
+    error = tffs_fcreate(LUDIR "/Smaaland/vetlanda", TDATA(0));
+    expect(error, EFFS_OK);
+    error = tffs_fcreate(LUDIR "/Smaaland/vetlanda", TDATA(0));
+    expect(error, EFFS_EXISTS);
+    error = tffs_mkdir(LUDIR "/Smaaland");
+    expect(error, EFFS_EXISTS);
+    error = tffs_fwrite(LUDIR "/Smaaland/vetlanda", TDATA(1));
+    expect(error, EFFS_OK);
+    // test EFFS_BADNAME
+    error = tffs_fcreate(LUDIR "/Smaaland/A_Zaz.0+9-7!", TDATA(2));
+    expect(error, EFFS_BADNAME);
+    error = tffs_fcreate(LUDIR "/Smaaland/A_Zaz.0+9-7#%$", TDATA(2));
+    expect(error, EFFS_OK);
+    // test ending slash
+    error = tffs_mkdir(LUDIR "/Smaaland/Vaexjoe/");
+    expect(error, EFFS_NOTADIR);
+    error = tffs_fcreate(LUDIR "/Smaaland/Vaexjoe/", TDATA(3));
+    expect(error, EFFS_NOTADIR);
+    // test EFFS_NAMETOOLONG
+    error = tffs_fcreate(LUDIR "/Smaaland/Hultsfred-is-21-chars", TDATA(4));
+    expect(error, EFFS_NAMETOOLONG);
+    error = tffs_fcreate(LUDIR "/Smaaland/Bodafors-is-20-chars", TDATA(4));
+    expect(error, EFFS_OK);
+    error = tffs_mkdir(LUDIR "/Vaermland-is-21-chars");
+    expect(error, EFFS_NAMETOOLONG);
+    error = tffs_mkdir(LUDIR "/Dalsland-is-20-chars");
+    expect(error, EFFS_OK);
+    // test EFFS_NOTADIR
+    error = tffs_mkdir(LUDIR "/DontMakeSeveral/DirsAt/TheSameTime");
+    expect(error, EFFS_NOTADIR);
+    error = tffs_fread(LUDIR "/Lappland/Bodafors-is-20-chars", bigbuf, 1024);
+    tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent 
+    expect(error, EFFS_NOTADIR);
+    error = tffs_fread(LUDIR "/Lappland/", bigbuf, 1024);
+    tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent 
+    expect(error, EFFS_NOTADIR);
+    error = tffs_fread(LUDIR "/Smaaland/Bodafors", TDATA(4));
+    tw(tr(TR_END, TrApi, "} %d\n", error)); // Avoid wrong indent 
+    expect(error, EFFS_NOTFOUND);
+    // test EFFS_PATHTOODEEP
+    error = tffs_mkdir(LUDIR "/Gotland"); // 3. level
+    expect(error, EFFS_OK);
+    error = tffs_mkdir(LUDIR "/Gotland/Visby"); // 4. level
+    expect(error, EFFS_OK);
+    error = tffs_mkdir(LUDIR "/Gotland/Visby/level5"); // 5. level
+    expect(error, EFFS_OK);
+    error = tffs_mkdir(LUDIR "/Gotland/Visby/level5/level6"); // 6. level
+    expect(error, EFFS_OK);
+    error = tffs_mkdir(LUDIR "/Gotland/Visby/level5/level6/level7"); // 7. level
+    expect(error, EFFS_PATHTOODEEP);
+    error = tffs_fcreate(LUDIR "/Gotland/Visby/level5/level6/level7",
+                         TDATA(5)); // 7. level
+    expect(error, EFFS_PATHTOODEEP);
+
+    // final checks
+    error = test_expect_file(LUDIR "/Smaaland/vetlanda", TDATA(1));
+    if (error) return 1;
+    error = test_expect_file(LUDIR "/Smaaland/Bodafors-is-20-chars", TDATA(4));
+    if (error) return 1;
+    error = tffs_opendir(LUDIR "/Dalsland-is-20-chars", &dir);
+    expect_ok(error);
+    error = tffs_opendir(LUDIR "/Gotland/Visby/level5/level6", &dir);
+    expect_ok(error);
+    
+    // cleanup
+    error = tffs_remove(LUDIR "/Smaaland/A_Zaz.0+9-7");
+    return 0;
+}
+
+
+// Test fcontrol and read-only semantics. TODO: We still need to perform
+// same tests on a dir and a symlink and thru a symlink.
+int case_fcontrol(int p0, int p1)
+{
+    struct ffs_state_s old, new;
+    const char rofile[]   = "/europe/norway/rofile";
+    const char imeifile[] = "/europe/norway/IMEI";
+    fd_t fdi;
+
+    // Cleanup
+    tffs_remove(rofile);
+    tffs_remove("/europe/norway");
+    tffs_remove("/europe");
+
+    // Initialize
+    error = tffs_mkdir("/europe");
+    error = tffs_mkdir("/europe/norway");
+    error = tffs_fcreate(rofile, TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_stat(rofile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, 0);
+
+    test_ffs_state_get(&old);
+
+    // set read-only flag
+    error = tffs_fcontrol(rofile, OC_FLAGS, OF_READONLY);
+    expect(error, EFFS_OK);
+    error = tffs_stat(rofile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, OF_READONLY);
+
+    test_ffs_state_get(&new);
+    expect_eq(new.objects_total, old.objects_total);
+    expect_ne(new.inodes_used,  old.inodes_used);
+    test_ffs_state_copy(&old, &new);
+
+    // Set illegal flags. Try to fupdate file. Then try to set read-only
+    // flag again.
+    error = tffs_fcontrol(rofile, OC_FLAGS, 1<<0);
+    expect(error, EFFS_INVALID);
+    error = tffs_fcontrol(rofile, OC_FLAGS, 1<<3);
+    expect(error, EFFS_INVALID);
+    error = tffs_fcontrol(rofile, OC_FLAGS, 1<<5);
+    expect(error, EFFS_INVALID);
+    error = tffs_fcontrol(rofile, OC_FLAGS, 1<<6);
+    expect(error, EFFS_INVALID);
+    error = tffs_fupdate(rofile, TDATA(3));
+    expect(error, EFFS_OK);
+    
+    error = tffs_fcreate("/europe/norway/tease", TDATA(2));
+    expect(error, EFFS_OK);
+    tffs_remove("/europe/norway/tease");
+
+    error = tffs_fcontrol(rofile, OC_FLAGS, OF_READONLY);
+    expect(error, EFFS_OK);
+    error = tffs_stat(rofile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, OF_READONLY);
+
+    test_ffs_state_get(&new);
+    expect_eq(new.objects_total, old.objects_total);
+    expect_ne(new.inodes_used,  old.inodes_used);
+    test_ffs_state_copy(&old, &new);
+
+    // clear read-only flag (this works because ffs_is_modifiable() by
+    // default returns true for all objects except for object names ending
+    // in "IMEI".
+    error = tffs_fcontrol(rofile, OC_FLAGS, 0);
+    expect(error, EFFS_OK);
+    error = tffs_stat(rofile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, 0);
+
+    test_ffs_state_get(&new);
+    expect_eq(new.objects_total, old.objects_total);
+    expect_ne(new.inodes_used,  old.inodes_used);
+    test_ffs_state_copy(&old, &new);
+
+    // Set read-only flag (again)
+    error = tffs_fcontrol(rofile, OC_FLAGS, OF_READONLY);
+    expect(error, EFFS_OK);
+    error = tffs_stat(rofile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, OF_READONLY);
+
+    test_ffs_state_get(&new);
+    expect_eq(new.objects_total, old.objects_total);
+    expect_ne(new.inodes_used,  old.inodes_used);
+    test_ffs_state_copy(&old, &new);
+
+    // Set read-only flag of IMEI file
+    error = tffs_fcreate(imeifile, TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_stat(imeifile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, 0);
+    error = tffs_fcontrol(imeifile, OC_FLAGS, OF_READONLY);
+    expect(error, EFFS_OK);
+    error = tffs_stat(imeifile, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.flags, OF_READONLY);
+
+    test_ffs_state_get(&new);
+    expect_eq(new.objects_total, old.objects_total + 1);
+    expect_ne(new.inodes_used,  old.inodes_used);
+    test_ffs_state_copy(&old, &new);
+
+    // Try to remove, fupdate, fwrite and fcontrol IMEI file.
+    error = tffs_remove(imeifile);
+    expect(error, EFFS_ACCESS);
+    error = tffs_fupdate(imeifile, TDATA(0));
+    expect(error, EFFS_ACCESS);
+    error = tffs_fwrite(imeifile, TDATA(0));
+    expect(error, EFFS_ACCESS);
+    error = tffs_fcontrol(imeifile, OC_FLAGS, 0);
+    expect(error, EFFS_ACCESS);
+
+    // Try to open IMEI file in write-only and read-only
+    fdi = tffs_open(imeifile, FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, EFFS_ACCESS);
+
+    fdi = tffs_open(imeifile, FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+// Test symlink functionality of simple symlink implementation.
+// Fixme: add remove file through symlink, stat a dir through a symlink.
+int case_ssym(int p0, int p1)
+{
+    int size;
+    fd_t fdi;
+    // two links, read files thru links
+    // link to link to file, open file
+    // link to non-valid object
+    // 
+    // make three test files, a link to each of these, one link to dir, one
+    // link to non-existing object, one link to link to file
+
+    tffs_mkdir("/europe");
+    tffs_mkdir("/europe/denmark");
+
+    error = tffs_fwrite("/europe/denmark/aalborg", TDATA(1));
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/europe/aal", "/europe/denmark/aalborg");
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/dk", "/europe/denmark");
+    expect(error, EFFS_OK);
+    error = tffs_fwrite("/europe/denmark/aarhus", TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/europe/aar", "/europe/denmark/aarhus");
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/europe/se", "/europe/non-existing");
+    expect(error, EFFS_OK);
+    error = tffs_fwrite("/europe/denmark/billund", TDATA(3));
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/europe/bil", "/europe/denmark/billund");
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/lego", "/europe/bil");
+    expect(error, EFFS_OK);
+    error = tffs_fwrite("/europe/denmark/norresundby", TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/europe/nor", "/europe/denmark/norresundby");
+    expect(error, EFFS_OK);
+
+    // Test link to dir
+    error = tffs_opendir("/dk", &dir);
+    expect(error, EFFS_NOTAFILE); // TODO: strange error!
+    error = tffs_stat("/dk", &stat);
+    expect(error, EFFS_NOTAFILE); // TODO: strange error!
+    error = tffs_linkstat("/dk", &stat);
+    expect(error, EFFS_OK);
+
+    // Test link to link to file
+    error = tffs_stat("/lego", &stat);
+    expect(error, EFFS_NOTAFILE); // TODO: strange error?!
+    error = tffs_linkstat("/lego", &stat);
+    expect(error, EFFS_OK);
+    error = tffs_fread("/lego", bigbuf, bigbuf_size);
+    tw(tr(TR_END, TrApi, "} %d\n", error));  // Avoid wrong indent 
+    expect(error, EFFS_NOTAFILE);
+
+    // Test link to non-existing object
+    error = tffs_opendir("/europe/se", &dir);
+    expect(error, EFFS_NOTFOUND);
+    error = tffs_stat("/europe/se", &stat);
+    expect(error, EFFS_NOTFOUND);
+    error = tffs_linkstat("/europe/se", &stat);
+    expect(error, EFFS_OK);
+
+    // Read files through links
+    error = test_expect_file("/europe/aal", TDATA(1));
+    if (error) return 1;
+    error = test_expect_file("/europe/aar", TDATA(2));
+    if (error) return 1;
+    error = test_expect_file("/europe/bil", TDATA(3));
+    if (error) return 1;
+
+    // Write files through links
+    error = tffs_fwrite("/europe/aal", TDATA(3));
+    expect(error, EFFS_OK);
+    error = tffs_fupdate("/europe/aar", TDATA(4));
+    expect(error, EFFS_OK);
+    error = tffs_fupdate("/europe/bil", TDATA(5));
+    expect(error, EFFS_OK);
+
+    // Open file and write and read files through links
+    fdi = tffs_open("/europe/nor", FFS_O_WRONLY | FFS_O_TRUNC | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);    
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 50);
+    expect(size, 50);
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    fdi = tffs_open("/europe/nor", FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);    
+    size = tffs_read(fdi, bigbuf, 62);
+    expect(size, 50);
+    error = test_expect_data((char*)tdata[TDATA_HUGE], bigbuf, 50);
+    if (error) return 1;
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    // remove "lego" link, recreate it to link to "billund", read file data
+    // through link, re-write file data through link
+    error = tffs_symlink("/lego", "/europe/denmark/billund");
+    expect(error, EFFS_NOTAFILE); // TODO: strange error?!
+    error = tffs_fupdate("/lego", "/europe/denmark/billund",
+                         strlen("/europe/denmark/billund"));
+    expect(error, EFFS_NOTAFILE);
+    error = tffs_remove("/lego");
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/lego", "/europe/denmark/billund");
+    expect(error, EFFS_OK);
+    error = test_expect_file("/lego", TDATA(5));
+    if (error) return 1;
+    error = tffs_fupdate("/lego", TDATA(2));
+    expect(error, EFFS_OK);
+
+    // Re-Read files through links
+    error = test_expect_file("/europe/aal", TDATA(3));
+    if (error) return 1;
+    error = test_expect_file("/europe/aar", TDATA(4));
+    if (error) return 1;
+    error = test_expect_file("/europe/bil", TDATA(2));
+    if (error) return 1;
+
+    // Clean up
+    error = tffs_remove("/europe/aal");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/dk");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/europe/aar");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/europe/se");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/europe/bil");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/lego");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/europe/nor");
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+// Test symlink functionality of full symlink implementation
+int case_fsym(int p0, int p1)
+{
+    fd_t fdi;
+    // make relative link to directory, stat link and directory
+    error = tffs_symlink("/sa", "/south-america"); // relative link
+    expect(error, EFFS_OK);
+
+    error = tffs_linkstat("/sa", &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.type, OT_LINK);
+
+    error = tffs_stat("/sa", &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.type, OT_DIR);
+
+    // create directory thru a symlink
+    error = tffs_mkdir("/sa/brazil");
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/br.ba", "/brazil/buenos-aires"); // relative link
+    expect(error, EFFS_OK);
+
+    // create file via symlink, stat the new file
+    error = tffs_fcreate("/sa/brazil/buenos-aires", TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_stat("/sa/br.ba", &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.type, OT_FILE);
+
+    fdi = tffs_open("/sa/peru", FFS_O_WRONLY | FFS_O_TRUNC | 
+                    FFS_O_APPEND | FFS_O_CREATE);
+    expect(fdi, FFS_FD_OFFSET);    
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    // create file thru a symlink, stat the new file. Will this work?
+    error = tffs_symlink("/br.br", "/brazil/brasilia"); // relative link
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/sa/br.br", TDATA(3)); // ???
+    expect(error, EFFS_OK);
+    error = tffs_stat("/sa/br.br", &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.type, OT_FILE);
+    
+    // Create symlink that is a link to absolute link path
+    error = tffs_symlink("/south-america/cape-horn", "/sa/ar"); // absolute link
+    expect(error, EFFS_OK);
+
+    error = tffs_fcreate("/south-america/argentina", TDATA(0));
+
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/sa/ar", "/south-america/argentina");
+    expect(error, EFFS_OK);
+    
+    // TODO: Test very deep path
+
+    // TODO: Test circular link
+
+    // TODO: Test if ending slash is allowed on dirs and symlinks
+
+    tw(tr(TR_FUNC, TrTest, "WARNING: Test case not implemented!\n"));
+    ttw(str(TTrTest, "Test case not implemented!" NL));
+
+    return 0;
+}
+
+// Check every combination of name length and data size within the device
+// atomsize,
+int case_fread(int p0, int p1)
+{
+    const char fullname[] = "123456789ABCDEF0123456789ABCDEF";
+    int i, j, dirlen, mysize;
+    char *mydata;
+    char myname[20+20+32] = "/australia/f";
+
+    case_cleanup(0x11 * param.atomsize * param.atomsize); 
+
+    tffs_mkdir("/australia");
+ 
+    mydata = (char *) tdata[TDATA_HUGE]; 
+    dirlen = strlen(myname);
+
+    for (j = 0; j < param.atomsize; j++) {
+        mysize = j * 0x11 /* + 0x100 */;
+        ttw(ttr(TTrTest, "frd: size = %x" NL, mysize));
+        tw(tr(TR_FUNC, TrTestHigh, "frd: size = %x\n", mysize));
+        // remove files
+        for (i = 0; i < param.atomsize; i++) {
+            strncpy(&myname[dirlen], fullname, i);
+            myname[dirlen + i] = 0;
+            error = tffs_remove(myname);
+        }
+        // fcreate files with varying name lengths but same alignment.
+        for (i = 0; i < param.atomsize; i++) {
+            strncpy(&myname[dirlen], fullname, i);
+            myname[dirlen + i] = 0;
+            error = tffs_fwrite(myname, mydata, mysize);
+            expect(error, EFFS_OK);
+        }
+        // Now check all the files written
+        for (i = 0; i < param.atomsize; i++) {
+            strncpy(&myname[dirlen], fullname, i);
+            myname[dirlen + i] = 0;
+            //tw(tr(TR_FUNC, TrTestHigh, "frd: txf('f...', %x, %d)\n",
+            //      mydata, mysize));
+            error = test_expect_file(myname, mydata, mysize);
+            if (error) return 1;
+        }
+        mydata += 0x10;
+    }
+    
+    for (i = 0; i < param.atomsize; i++) {
+        strncpy(&myname[dirlen], fullname, i);
+        myname[dirlen + i] = 0;
+        error = tffs_remove(myname);
+        expect(error, EFFS_OK);
+    }
+    return 0;
+}
+
+
+/******************************************************************************
+ * Non-finished
+ ******************************************************************************/
+
+// Test Directories
+int case_dirs(int p0, int p1)
+{
+    // remove empty dir, non-empty dir
+    // open/readdir empty dir, non-empty dir
+    char name[21];
+    int i, j;
+    struct dir_s dir[3];
+    const char *names[3][5] = {
+        { "china",    "japan",    "korea", "india", 0 },
+        { "bombay",   "newdelhi", 0,       0,       0 },
+        { "hongkong", "shanghai", "hk",    0,       0 }
+    };
+    
+    // Cleanup
+    tffs_mkdir("/asia");
+    tffs_remove("/asia/india/bombay");
+    tffs_remove("/asia/india/newdelhi");
+    tffs_remove("/asia/india");
+
+    error = tffs_mkdir("/asia/china");
+    expect(error, EFFS_OK);
+    error = tffs_mkdir("/asia/china/beijing");
+    expect(error, EFFS_OK);
+    error = tffs_mkdir("/asia/china/hongkong");
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/china/hongkong/hkfile1", TDATA(1));
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/china/shanghai", TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_symlink("/asia/china/hk", "/asia/china/hongkong");
+    expect(error, EFFS_OK);
+    error = tffs_mkdir("/asia/japan");
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/thailand", TDATA(0));
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/korea", TDATA(2));
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/japan/tokyo", TDATA(3));
+    expect(error, EFFS_OK);
+    error = tffs_fupdate("/asia/japan/tokyo", TDATA(4));
+    expect(error, EFFS_OK);
+    error = tffs_mkdir("/asia/india");
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/india/bombay", TDATA(0));
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/india/newdelhi", TDATA(1));
+    expect(error, EFFS_OK);
+    error = tffs_fcreate("/asia/india/calcutta", TDATA(2));
+    expect(error, EFFS_OK);
+
+    error = tffs_opendir("/asia", &dir[0]);
+    expect(error, 5);
+    error = tffs_opendir("/asia/india", &dir[1]);
+    expect(error, 3);
+    error = tffs_opendir("/asia/china", &dir[2]);
+    expect(error, 4);
+
+    // remove first, middle and last entry in a dir
+    error = tffs_remove("/asia/china/beijing");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/thailand");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/india/calcutta");
+    expect(error, EFFS_OK);
+
+    for (j = 0; j < 5; j++) {
+        for (i = 0; i < 3; i++) {
+            error = tffs_readdir(&dir[i], name, 21);
+            if (names[i][j] == NULL) {
+                expect(error, EFFS_OK);
+            }
+            else {
+                expect_gt(error, EFFS_OK);
+                tw(tr(TR_FUNC, TrTestHigh, "dir[%d]: %10s, expected: %s\n",
+                      i, name, names[i][j]));
+                test_expect_data(name, TDATA_STRING(names[i][j]));
+            }
+        }
+    }
+
+    error = tffs_remove("/asia/china");
+    expect(error, EFFS_DIRNOTEMPTY);
+    error = tffs_remove("/asia/china/hongkong");
+    expect(error, EFFS_DIRNOTEMPTY);
+    error = tffs_remove("/asia/china/hongkong/hkfile1");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/china/shanghai");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/china/hk");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/china");
+    expect(error, EFFS_DIRNOTEMPTY);
+    error = tffs_remove("/asia/china/hongkong");
+    expect(error, EFFS_OK);
+    error = tffs_opendir("/asia/china", &dir[2]);
+    expect(error, 0);
+    error = tffs_remove("/asia/china");
+    expect(error, EFFS_OK);
+
+    error = tffs_remove("/asia/korea");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/japan/tokyo");
+    expect(error, EFFS_OK);
+    error = tffs_remove("/asia/japan");
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+// Check that expected stat data was read
+int case_expect_stat(const char *name, int n)
+{
+    error = tffs_stat(name, &stat);
+    expect(error, EFFS_OK);
+    // test type, size, flags, space?
+    // test range of location, inode, block
+    return 0;
+}
+
+// Test stat
+int case_stat(int p0, int p1)
+{
+    struct xstat_s xstat;
+    struct stat_s stat;
+    char myname[] = "/Stat_file";
+    char sym_name[] = "/sf";
+    char stream_name[] = "/Stat_stream";
+    fd_t fdi;
+    int size, i, file_size = 0;
+
+    // test stat on dirs, symlinks and files
+    // check stat.block (by writing two HUGE files)
+
+    case_cleanup(fs.chunk_size_max / 5 * 20);
+
+    // NOTEME: this is a very limited test
+    error = tffs_fwrite(myname, (char *)tdata[TDATA_HUGE], 99); 
+    expect_ok(error);
+
+    error = tffs_stat(myname, &stat);
+    expect(error, EFFS_OK);
+    expect(stat.type, OT_FILE);
+    expect(stat.flags, 0);
+    expect_ok(stat.inode);
+    expect(stat.size, 99);
+    
+//    error = tffs_xstat(myname, &xstat);
+//    expect(error, EFFS_OK);
+    
+//    expect(error, EFFS_OK);
+//    expect(xstat.type, OT_FILE);
+//    expect(xstat.flags, 0);
+//    expect_ok(xstat.inode);
+//    expect(xstat.size, 99);
+    
+//    expect(xstat.space, 112);
+//    expect_ok(xstat.location);
+//   expect_ok(xstat.block);
+//    expect_ok(xstat.sequence);
+//    expect_ok(xstat.updates);
+
+    error = tffs_linkstat(myname, &stat);
+    expect(error, EFFS_OK);
+    
+    expect(error, EFFS_OK);
+    expect(stat.type, OT_FILE);
+    expect(stat.flags, 0);
+    expect_ok(stat.inode);
+    expect(stat.size, 99);
+    
+    error = tffs_xlstat(myname, &xstat);
+    expect(error, EFFS_OK);
+
+    expect(error, EFFS_OK);
+    expect(xstat.type, OT_FILE);
+    expect(xstat.flags, 0);
+    expect_ok(xstat.inode);
+    expect(xstat.size, 99);
+
+    expect(xstat.space, 112);
+    expect_ok(xstat.location);
+    expect_ok(xstat.block);
+    expect_ok(xstat.sequence);
+    expect_ok(xstat.updates);
+
+    // Symlink
+    tffs_symlink(sym_name, myname);  
+        
+    error = tffs_xlstat(sym_name, &xstat);
+    expect(error, EFFS_OK);
+
+    expect(error, EFFS_OK);
+    expect(xstat.type, OT_LINK);
+    expect(xstat.flags, 0);
+    expect_ok(xstat.inode);
+    expect(xstat.size, sizeof(myname));
+
+    expect(xstat.space, 16);
+    expect_ok(xstat.location);
+    expect_ok(xstat.block);
+    expect_ok(xstat.sequence);
+    expect_ok(xstat.updates);
+
+    // Stream stat test
+    // Use xstat to return the size of the file
+    fdi = tffs_open(stream_name, FFS_O_WRONLY | FFS_O_CREATE | 
+                    FFS_O_TRUNC  | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+
+    for (i = 0; i < 20; i++) {
+        size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 
+                          fs.chunk_size_max / 5);
+
+        expect(size, fs.chunk_size_max / 5);
+        file_size +=size;
+
+        error = tffs_xlstat(stream_name, &xstat);
+        expect(error, EFFS_OK);
+        expect_eq(xstat.size, file_size);
+
+        error = tffs_fstat(fdi, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, file_size);
+    }
+            
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    // Test if the file size is right if opened in read-only
+    fdi = tffs_open(stream_name, FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    
+    error = tffs_xlstat(stream_name, &xstat);
+    expect(error, EFFS_OK);
+    expect_eq(xstat.size, file_size);
+    
+    // Test a lot of difference fdi
+    for (i = -3; i < FFS_FD_OFFSET + fs.fd_max + 3; i++) {
+        error = tffs_fstat(i, &stat);
+        if (i == FFS_FD_OFFSET) { 
+            expect(error, EFFS_OK);
+        }
+        else expect(error, EFFS_BADFD);
+    }    
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+int case_remove(int p0, int p1)
+{
+    tw(tr(TR_FUNC, TrTest, "WARNING: Test case not implemented!\n"));
+    ttw(str(TTrTest, "Test case not implemented!" NL));
+
+    return 0;
+}
+
+int case_rename(int p0, int p1)
+{
+    fd_t fdi;
+    int size, i;
+    struct dir_s dir;
+    // create file A
+    // rename A to B
+    // check file A is gone
+    // check file B is same as file A
+    // do all the same for directory
+    // do all the same for symlink
+    // test and ensure that dir rename "foo" to "foo/bar" is impossible!
+    
+    // Cleanup before run
+    tffs_remove("/Walt_Disney/RUP");
+    tffs_remove("/Uncle_Scrooge");
+    tffs_remove("/Walt_Disney/Minnie");
+    tffs_remove("/Walt_Disney");
+    tffs_remove("/Duck");
+    
+    // Init
+    tffs_mkdir("/Disney");
+    tffs_mkdir("/Hell");
+
+    error = tffs_fwrite("/IMEI", TDATA(2));
+    if (error < 0 && error != EFFS_ACCESS) return 1;
+    error = tffs_fcontrol("/IMEI", OC_FLAGS, OF_READONLY);
+    if (error < 0 && error != EFFS_ACCESS) return 1;
+
+    tw(tr(TR_FUNC, TrTestHigh, "Rename file\n")); /* Rename file */
+
+    error = tffs_fwrite("/Mickey", TDATA(3));
+    expect(error, EFFS_OK);
+
+    error = tffs_fwrite("/Pluto", TDATA(2));
+    expect(error, EFFS_OK);
+
+    error = tffs_rename("/Pluto", "/Dog");
+    expect(error, EFFS_OK);
+
+    error = tffs_fupdate("/Pluto", TDATA(2));
+    expect(error, EFFS_NOTFOUND);
+
+    error = test_expect_file("/Dog", TDATA(2));
+    if (error) return 1;
+
+    error = tffs_rename("/Dog", "/Hell/RIP");
+    expect(error, EFFS_OK);
+
+    error = tffs_rename("/Hell/RIP", "/RAP");
+    expect(error, EFFS_OK);
+
+    error = tffs_rename("/RAP", "/Disney/RUP");
+    expect(error, EFFS_OK);
+
+    error = test_expect_file("/Disney/RUP", TDATA(2));
+    if (error) return 1;
+
+    // Rename a file to an existing file
+    error = tffs_rename("/Mickey", "/Disney/RUP");
+    expect(error, EFFS_OK);
+
+    // Have the data changed?
+    error = test_expect_file("/Disney/RUP", TDATA(3));
+    if (error) return 1;
+
+    // Try rename a file to an exisitng read-only file
+    error = tffs_rename("/Disney/RUP", "/IMEI");
+    expect(error, EFFS_ACCESS);
+
+    // Try rename a file to an existing dir
+    error = tffs_rename("/Disney/RUP", "/Hell");
+    expect(error, EFFS_NOTAFILE);
+
+    error = tffs_rename("/Disney/RUP", "/BADNAME?");
+    expect(error, EFFS_BADNAME);
+
+    error = tffs_remove("/Hell");
+    expect(error, EFFS_OK);
+
+    tw(tr(TR_FUNC, TrTestHigh, "Rename symlink\n")); /* Rename symlink */
+
+    tffs_symlink("/Goose", "/Disney/RUP"); // 5
+
+    error = tffs_rename("/Goose", "/Duck");
+    expect(error, EFFS_OK);
+
+    error = tffs_fupdate("/Goose", TDATA(2));
+    expect(error, EFFS_NOTFOUND);
+
+    error = test_expect_file("/Duck", TDATA(3));
+    if (error) return 1;
+
+    error = test_expect_file("/Disney/RUP", TDATA(3));
+    if (error) return 1;
+
+    tw(tr(TR_FUNC, TrTestHigh, "Rename dir\n"));     /* Rename dir */
+
+// * FIXME BUG * FIXME BUG * FIXME BUG * The below test to not fail instead
+// the directory is removed 
+// error = tffs_rename("/Disney", "/Disney/foo");
+// expect(error, EFFS_OK);
+    
+    tffs_mkdir("/Disney/Donald_Duck");
+    expect(error, EFFS_OK);
+    error = ffs_rename("/Disney/Donald_Duck", "/Uncle_Scrooge");
+    expect(error, EFFS_OK);
+    error = tffs_opendir("/Uncle_Scrooge", &dir);
+    expect(error, EFFS_OK);
+    error = tffs_opendir("/Disney/Donald_Duck", &dir);
+    expect(error, EFFS_NOTFOUND);
+
+    error = tffs_rename("/Disney", "/Walt_Disney");
+    expect(error, EFFS_OK);
+
+    tffs_mkdir("/Disney");  // Create 'Disney' dir again
+    expect(error, EFFS_OK);
+
+    // Try rename to existing dir
+    error = tffs_rename("/Disney", "/Walt_Disney");
+    expect(error, EFFS_EXISTS);
+
+    // Try rename to existing file
+    error = tffs_rename("/Disney", "/Walt_Disney/RUP"); 
+    expect(error, EFFS_EXISTS);
+
+    tw(tr(TR_FUNC, TrTestHigh, "Rename seghead\n")); /* Rename seghead */
+    
+    fdi = tffs_open("/Walt_Disney/Mickey", FFS_O_WRONLY | FFS_O_CREATE);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max + 1);
+    expect(size, fs.chunk_size_max + 1);  
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + size, fs.chunk_size_max);
+    expect(size, fs.chunk_size_max);  
+    
+    error = tffs_rename("/Walt_Disney/Mickey", "/Walt_Disney/Minnie");
+    expect(error, EFFS_LOCKED);
+    tffs_close(fdi);
+    
+    error = tffs_rename("/Walt_Disney/Mickey", "/Walt_Disney/Minnie");
+    expect(error, EFFS_OK);
+
+    fdi = tffs_open("/Walt_Disney/Minnie", FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    i = 0;
+    do {
+        size = tffs_read(fdi, bigbuf, bigbuf_size);
+        error = test_expect_data((char*)tdata[TDATA_HUGE] + i, bigbuf, size);
+        if (error) return 1;
+        i += size;
+    } while (size);
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    error = test_expect_file("/Walt_Disney/Minnie", (char *)tdata[TDATA_HUGE], 
+                             2 * fs.chunk_size_max + 1);
+    if (error) return 1;
+
+    // Rename a big file to an existing big file
+    error = tffs_fwrite("/Mickey", (char *)tdata[TDATA_HUGE] + 5, 
+                        2.5 * fs.chunk_size_max);
+    expect(error, EFFS_OK);
+
+    error = tffs_rename("/Mickey", "/Walt_Disney/Minnie");
+    expect(error, EFFS_OK);
+
+    error = test_expect_file("/Walt_Disney/Minnie", (char *)tdata[TDATA_HUGE] + 5, 
+                             2.5 * fs.chunk_size_max);
+    if (error) return 1;
+
+    error = tffs_fread("/Mickey", 0 , 0);
+    expect(error, EFFS_NOTFOUND);
+
+    return 0;
+}
+
+// One of the problems with the rename function is that we need to copy the
+// data part from the old obj to the new obj. When we allocate data for the
+// new obj we risk that the data alloc caused a data reclaim which relocated
+// the old obj thus the source have been moved! 
+int case_rename_extended(int p0, int p1)
+{       
+    int i, old_drec_most_lost, rename_file_relocated = 0;
+    int fsize, offset;  
+    char myname1[] = "/rename1/rename1/foo";
+    char myname2[] = "/rename2/rename2/bar";
+
+    if (p0 == 0) p0 = 100;
+    if (p1 == 0) p1 = 5;
+
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK); 
+    error = tffs_format("/ffs/b3r24", 0x2BAD); 
+    expect(error, EFFS_OK);
+
+    fsize = 2.5 * fs.chunk_size_max; // Test with more than one chunk
+
+    tffs_mkdir("/rename1");
+    tffs_mkdir("/rename1/rename1");
+    tffs_mkdir("/rename2");
+    tffs_mkdir("/rename2/rename2");
+
+    error = tffs_file_write(myname1, (char*)tdata[TDATA_HUGE], fsize, 
+                            FFS_O_CREATE | FFS_O_TRUNC);
+
+    // Test if rename can handle when the objects are relocaded while the
+    // rename is in progress
+    for (i = 0; i < p0; i++) {
+        tw(tr(TR_FUNC, TrTest, "Rename number %d\n", i));
+
+        offset = i % 2 ? 3 : 9; 
+        error = tffs_file_write(myname2, (char*)tdata[TDATA_HUGE] + offset, fsize, 
+                            FFS_O_CREATE | FFS_O_TRUNC);
+
+        // Get data reclaim candidate most_lost
+        old_drec_most_lost = stats.drec.most_lost;
+        error = tffs_rename(myname2, myname1);
+        expect(error, EFFS_OK);
+
+        error = test_expect_file(myname1, tdata[TDATA_HUGE] + offset, fsize); 
+        expect(error, EFFS_OK);
+
+        error = tffs_fread(myname2, 0, 0);
+        expect(error, EFFS_NOTFOUND);
+
+        // Has the rename triggered a data_reclaim()?
+        if (old_drec_most_lost != stats.drec.most_lost) {
+            rename_file_relocated++;
+            tw(tr(TR_FUNC, TrTest, "Rename objects relocated %d\n", 
+                  rename_file_relocated));
+            if (rename_file_relocated >= p1)
+                return EFFS_OK;
+        }
+    }
+    
+    return 1;
+}
+
+
+// Test Big files
+int case_bigfile(int p0, int p1)
+{
+    struct ffs_state_s old, new;
+    const char bigfile[] = "/antarctica/iceberg";
+    int bytes_max, file_size;
+
+#if 1
+    ttw(ttr(TTrTest, "WARNING: We need to re-implement this test. Skip test" NL));
+    tw(tr(TR_FUNC, TrTest, "WARNING: We need to re-implement this test. Skip test\n"));
+    return 0;
+#endif
+
+    if (param.data_blocks <= 1) {
+        ttw(ttr(TTrTest, "WARNING: Too few blocks to run. Skip test" NL));
+        tw(tr(TR_FUNC, TrTest, "WARNING: Too few blocks to run. Skip test\n"));
+        return 0;
+    }
+
+    error = case_cleanup(fs.filesize_max);
+    expect(error, EFFS_NOSPACE); // We can not cleanup this amount.
+
+    ffs_query(Q_BYTES_FREE, (uint32 *) &bytes_max);
+    test_ffs_state_get(&old);
+
+// We don't have enough space for this amount because the name dos also
+// use some space
+    file_size = bytes_max + 1;
+
+// Try to make a file of a size that is bigger than the total free space
+    // in the file system.
+    ttw(ttr(TTrTest, "Bigfile of size %d" NL, file_size));
+    tw(tr(TR_FUNC, TrTestHigh, "Bigfile of size %d\n", file_size));
+    error = tffs_fcreate(bigfile,
+                         (char *) tdata[TDATA_HUGE], file_size);
+    expect(error, EFFS_NOSPACE);
+
+    test_ffs_state_get(&new);
+    expect_eq(old.bytes_free, new.bytes_free);
+
+// File the system with this huge file
+    file_size = bytes_max - FFS_FILENAME_MAX - dev.atomsize;
+    ttw(ttr(TTrTest, "Bigfile of size %d" NL, file_size));
+    tw(tr(TR_FUNC, TrTestHigh, "Bigfile of size %d\n", file_size));
+    error = tffs_fcreate(bigfile,
+                         (char *) tdata[TDATA_HUGE], file_size);
+    expect(error, EFFS_OK);
+    
+    error = test_expect_file((char *) bigfile,
+                             (char *) tdata[TDATA_HUGE], file_size);
+    if (error) return 1;
+
+    test_ffs_state_get(&new);
+    expect_gt(old.bytes_free, new.bytes_free - file_size);
+    
+    tffs_remove(bigfile);
+
+    return 0;
+}
+
+
+/******************************************************************************
+ * Reclaim Test Cases
+ ******************************************************************************/
+
+// Test that ffs internal state is same after a re-ffs_init()
+int case_reinit(int p0, int p1)
+{
+    struct ffs_state_s old, new;
+
+    test_ffs_state_get(&old);
+    error = tffs_initialize();
+    expect(error, EFFS_OK);
+    test_ffs_state_get(&new);
+    error = test_expect_state(&old, &new);
+    if (error) return 1;
+
+    return 0;
+}
+    
+// Test inodes reclaim
+int case_irec(int p0, int p1)
+{
+    // African states: kenya, egypt, marocco, namibia, nigeria, mozambique,
+    // tanzania, ghana, togo, liberia, mali, congo
+    struct ffs_state_s old, new;
+    int i, j, updates;
+
+    if (p0 == 0)
+        p0 = 7;
+
+    tffs_mkdir("/africa");
+
+    // Initialize
+    tffs_fwrite("/africa/kenya", TDATA(0)); // 1
+    tffs_mkdir("/africa/east"); // 2
+    tffs_fwrite("/africa/tanzania", TDATA(1)); // 3
+    tffs_fwrite("/africa/east/egypt", TDATA(2)); // 4
+    tffs_symlink("/africa/et", "africa/east/egypt"); // 5
+    tffs_mkdir("/africa/west"); // 7
+    tffs_fupdate("/africa/et", TDATA(3)); // 6
+    tffs_fwrite("/africa/west/liberia", TDATA(0)); // 8
+
+    for (j = 0; j < p0; j++) {
+        test_ffs_state_get(&old);
+        updates = param.inodes_max - old.inodes_used;
+        ttw(ttr(TTrTest, "loop %d: updates = %d" NL, j, updates));
+        tw(tr(TR_FUNC, TrTestHigh, "loop %d: updates = %d\n", j, updates));
+        for (i = 0; i < (updates / 10) + 10; i++) {
+            // cleanup...
+            error = tffs_remove("/africa/east/egypt");
+            expect(error, EFFS_OK);
+            error = tffs_remove("/africa/east");
+            expect(error, EFFS_OK);
+            error = tffs_remove("/africa/et");
+            expect(error, EFFS_OK);
+            error = tffs_remove("/africa/west/liberia");
+            expect(error, EFFS_OK);
+            error = tffs_remove("/africa/west");
+            expect(error, EFFS_OK);
+            // use 10 inodes...
+            error = tffs_fwrite("/africa/kenya", TDATA(0)); // 1
+            expect(error, EFFS_OK);
+            error = tffs_mkdir("/africa/east"); // 2
+            expect(error, EFFS_OK);
+            error = tffs_fwrite("/africa/tanzania", (char *) tdata[0], 0); // 3
+            expect(error, EFFS_OK);
+            error = tffs_fcreate("/africa/east/egypt", TDATA(2)); // 4
+            expect(error, EFFS_OK);
+            error = tffs_symlink("/africa/et", "/africa/east/egypt"); // 5
+            expect(error, EFFS_OK);
+            error = tffs_mkdir("/africa/west"); // 7
+            expect(error, EFFS_OK);
+            error = tffs_fupdate("/africa/et", TDATA(3)); // 6
+            expect(error, EFFS_OK);
+            error = tffs_fcreate("/africa/west/liberia", TDATA(0)); // 8
+            expect(error, EFFS_OK);
+            error = tffs_fupdate("/africa/west/liberia", TDATA(1)); // 9
+            expect(error, EFFS_OK);
+            error = tffs_fupdate("/africa/tanzania", TDATA(2)); // 10
+            expect(error, EFFS_OK);
+        }
+        test_ffs_state_get(&new);
+        expect_eq(old.objects_total, new.objects_total);
+        error = test_expect_file("/africa/tanzania", TDATA(2));
+        if (error) return 1;
+        error = test_expect_file("/africa/west/liberia", TDATA(1));
+        if (error) return 1;
+        error = test_expect_file("/africa/east/egypt", TDATA(3));
+        if (error) return 1;
+        error = test_expect_file("/africa/kenya", TDATA(0));
+        if (error) return 1;
+    }
+
+    return 0;
+}
+
+#if 1
+// FIXME: Is this test case still valid after the new ffs_file_write() which
+// makes several chunks instead of on big?
+
+// Test data reclaim. Use up to maximum half the total space available.
+// drec params: percentage of avail to use, numupdates. We must not have too
+// big files due to fragmentation problems
+#define DREC_DIR "/north-america/usa"
+#define DREC_CHUNKS 6
+int case_drec(int p0, int p1)
+{
+    static struct test_file_s files[] =
+        {
+            { DREC_DIR "/alaska", 0, 0 },
+            { DREC_DIR "/arkansas", 0, 0 },
+            { DREC_DIR "/california", 0, 0 },
+            { DREC_DIR "/colorado", 0, 0 },
+            { DREC_DIR "/dakota", 0, 0 }, // north, south?
+            { DREC_DIR "/DistrictOfColumbia", 0, 0 }, // state?
+            { DREC_DIR "/florida", 0, 0 },
+            { DREC_DIR "/Georgia", 0, 0 },
+            { DREC_DIR "/hawaii", 0, 0 },
+            { DREC_DIR "/Idaho", 0, 0 },
+            { DREC_DIR "/Illinois", 0, 0 },
+            { DREC_DIR "/Iowa", 0, 0 },
+            { DREC_DIR "/kentucky", 0, 0 },
+            { DREC_DIR "/maine", 0, 0 },
+            { DREC_DIR "/Massachusettes", 0, 0 }, // spelling?
+            { DREC_DIR "/michigan", 0, 0 },
+            { DREC_DIR "/minnesota", 0, 0 },
+            { DREC_DIR "/mississippi", 0, 0 },
+            { DREC_DIR "/missouri", 0, 0 },
+            { DREC_DIR "/Montana", 0, 0 },
+            { DREC_DIR "/Nevada", 0, 0 },
+            { DREC_DIR "/NewHampshire", 0, 0 },
+            { DREC_DIR "/NewJersey", 0, 0 },
+            { DREC_DIR "/NewMexico", 0, 0 },
+            { DREC_DIR "/NewYork", 0, 0 }, // state?
+            { DREC_DIR "/north-carolina", 0, 0 },
+            { DREC_DIR "/ohio", 0, 0 },
+            { DREC_DIR "/oklahoma", 0, 0 },
+            { DREC_DIR "/Oregon", 0, 0 },
+            { DREC_DIR "/Pensylvania", 0, 0 },
+            { DREC_DIR "/RhodeIsland", 0, 0 }, // state?
+            { DREC_DIR "/south-carolina", 0, 0 },
+            { DREC_DIR "/Tennesee", 0, 0 },
+            { DREC_DIR "/texas", 0, 0 },
+            { DREC_DIR "/utah", 0, 0 },
+            { DREC_DIR "/Vermont", 0, 0 },
+            { DREC_DIR "/virginia", 0, 0 },
+            { DREC_DIR "/washington", 0, 0 },
+            { DREC_DIR "/Wyoming", 0, 0 },
+
+            { DREC_DIR "/40", 0, 0 },
+            { DREC_DIR "/41", 0, 0 },
+            { DREC_DIR "/42", 0, 0 },
+            { DREC_DIR "/43", 0, 0 },
+            { DREC_DIR "/44", 0, 0 },
+            { DREC_DIR "/45", 0, 0 },
+            { DREC_DIR "/46", 0, 0 },
+            { DREC_DIR "/47", 0, 0 },
+            { DREC_DIR "/48", 0, 0 },
+            { DREC_DIR "/49", 0, 0 },
+            { DREC_DIR "/50", 0, 0 },
+            { DREC_DIR "/51", 0, 0 },
+            { DREC_DIR "/52", 0, 0 },
+        };
+    struct chunk_s {
+        int ratio;
+        int high;
+        int low;
+    };
+    const struct chunk_s chunk[DREC_CHUNKS] = {
+        { 15, 65536, 32768 },
+        { 15, 32768, 16384 },
+        { 25, 16384,  8192 },
+        { 20,  8192,  4096 },
+        { 15,  4096,  2048 },
+        { 10,  2048,     0 }
+    };
+
+    int i, j, n, num_files;
+    int num, pct;
+    int size_used, size_max, size_chunk;
+    int size_chunk_used, size_chunk_low, size_chunk_high;
+
+    num = (p0 == 0 ? 11 : p0);
+    pct = (p1 == 0 ? 50 : p1);
+
+    tffs_mkdir("/north-america");
+    tffs_mkdir("/north-america/usa");
+
+    size_max   = pct * param.bytes_avail / 100;
+    size_used  = 0;
+    num_files  = sizeof(files) / sizeof(struct test_file_s);
+    n = 0;
+
+    tw(tr(TR_FUNC, TrTestHigh, "pct = %d%% = %dk\n",  pct, size_max/1024));
+
+    for (i = 0; i < DREC_CHUNKS; i++) {
+        size_chunk = chunk[i].ratio * size_max / 100;
+        size_chunk_low  = chunk[i].low  / 256 * fs.filesize_max / 256;
+        size_chunk_high = chunk[i].high / 256 * fs.filesize_max / 256;
+        tw(tr(TR_FUNC, TrTestHigh, "%4dk of [%d..%d]: ",
+              size_chunk/1024, size_chunk_high, size_chunk_low));
+        ttw(ttr(TTrTest, "%4dk of [%d..%d]: ",
+                size_chunk/1024, size_chunk_high, size_chunk_low));
+        size_chunk_used = 0;
+        // If the total chunk size can guaranteeable be contained...
+        if (size_chunk >= chunk[i].high) {
+            for (j = 0; j < size_chunk / size_chunk_high; j++) {
+                if (n >= num_files) {
+                    tw(tr(TR_FUNC, TrTestHigh, "j too big\n"));
+                    ttw(str(TTrTest, "j too big" NL));
+                    break;
+                }
+                files[n].size = size_chunk_low +
+                    rand() % (size_chunk_high - size_chunk_low);
+#ifdef WIN32
+                /* due to limitation in MS Visual C */
+                if( files[n].size  > 65535 )
+                  files[n].size = 65535;
+#endif //WIN32
+                files[n].data = (char *) tdata[TDATA_HUGE] + n;
+                tw(tr(TR_NULL, TrTestHigh, "%d:%s ",
+                      files[n].size, &files[n].name[strlen(DREC_DIR)+1]));
+                ttw(ttr(TTrTest, "%d:%s " NL,
+                        files[n].size, &files[n].name[strlen(DREC_DIR)+1]));
+                size_chunk_used += files[n].size;
+                n++;
+                // FIXME: We should let all the unused bytes from this
+                // chunk spill over into the next chunk so we use the
+                // full percentage specified by p1.
+            }
+            size_used += size_chunk_used;
+        }
+        tw(tr(TR_NULL, TrTestHigh, "(%dk)\n", size_chunk_used/1024));
+        ttw(ttr(TTrTest, "(%dk)" NL, size_chunk_used/1024));
+    }
+    tw(tr(TR_FUNC, TrTestHigh, "pct = %d%% = %dk\n",
+          100 * size_used/param.bytes_avail, size_used/1024));
+    ttw(ttr(TTrTest, "pct = %d%% = %dk" NL,
+            100 * size_used/param.bytes_avail, size_used/1024));
+    
+    for (j = 0; j < num; j++) {
+        ttw(ttr(TTrTest, "drec: %d. write" NL, j+1));
+        tw(tr(TR_FUNC, TrTestHigh, "drec: %d. write\n", j+1));
+        for (i = 0; i < n; i++) {
+            error = tffs_fwrite(files[i].name, files[i].data, files[i].size);
+            expect(error, EFFS_OK);
+        }
+    }
+    
+    for (i = 0; i < n; i++) {
+        error = test_expect_file(files[i].name, files[i].data, files[i].size);
+        if (error) 
+            return 1;
+        error = tffs_remove(files[i].name);
+        expect(error, EFFS_OK);
+    }
+    tffs_remove("/north-america/usa");
+    tffs_remove("/north-america");
+
+    return 0;
+}
+
+#else
+
+// Test data reclaim. Use up to maximum half the total space available.
+// drec params: percentage of avail to use, numupdates. We must not have too
+// big files due to fragmentation problems
+int case_drec(int p0, int p1)
+{
+    struct blabla_s {
+        int ratio;
+        int high;
+        int low;
+    };
+
+    struct blabla_s sizes[4] =
+    {
+        {  10, 65536, 32768 },
+        {  40, 21800, 16384 },
+        {  45, 16384,  2048 },
+        {   5,  2048,     0 }
+    };
+
+    static struct test_file_s files[] =
+    {
+        { DRECDIR "/alaska", 0, 0 },
+        { DRECDIR "/arkansas", 0, 0 },
+        { DRECDIR "/california", 0, 0 },
+        { DRECDIR "/colorado", 0, 0 },
+        { DRECDIR "/dakota", 0, 0 }, // north, south?
+        { DRECDIR "/DistrictOfColumbia", 0, 0 }, // state?
+        { DRECDIR "/florida", 0, 0 },
+        { DRECDIR "/Georgia", 0, 0 },
+        { DRECDIR "/hawaii", 0, 0 },
+        { DRECDIR "/Idaho", 0, 0 },
+        { DRECDIR "/Illinois", 0, 0 },
+        { DRECDIR "/Iowa", 0, 0 },
+        { DRECDIR "/kentucky", 0, 0 },
+        { DRECDIR "/maine", 0, 0 },
+        { DRECDIR "/Massachusettes", 0, 0 }, // spelling?
+        { DRECDIR "/michigan", 0, 0 },
+        { DRECDIR "/minnesota", 0, 0 },
+        { DRECDIR "/mississippi", 0, 0 },
+        { DRECDIR "/missouri", 0, 0 },
+        { DRECDIR "/Montana", 0, 0 },
+        { DRECDIR "/Nevada", 0, 0 },
+        { DRECDIR "/NewHampshire", 0, 0 },
+        { DRECDIR "/NewJersey", 0, 0 },
+        { DRECDIR "/NewMexico", 0, 0 },
+        { DRECDIR "/NewYork", 0, 0 }, // state?
+        { DRECDIR "/north-carolina", 0, 0 },
+        { DRECDIR "/ohio", 0, 0 },
+        { DRECDIR "/oklahoma", 0, 0 },
+        { DRECDIR "/Oregon", 0, 0 },
+        { DRECDIR "/Pensylvania", 0, 0 },
+        { DRECDIR "/RhodeIsland", 0, 0 }, // state?
+        { DRECDIR "/south-carolina", 0, 0 },
+        { DRECDIR "/Tennesee", 0, 0 },
+        { DRECDIR "/texas", 0, 0 },
+        { DRECDIR "/utah", 0, 0 },
+        { DRECDIR "/Vermont", 0, 0 },
+        { DRECDIR "/virginia", 0, 0 },
+        { DRECDIR "/washington", 0, 0 },
+        { DRECDIR "/Wyoming", 0, 0 },
+
+        { DRECDIR "/40", 0, 0 },
+        { DRECDIR "/41", 0, 0 },
+        { DRECDIR "/42", 0, 0 },
+        { DRECDIR "/43", 0, 0 },
+        { DRECDIR "/44", 0, 0 },
+        { DRECDIR "/45", 0, 0 },
+        { DRECDIR "/46", 0, 0 },
+        { DRECDIR "/47", 0, 0 },
+        { DRECDIR "/48", 0, 0 },
+        { DRECDIR "/49", 0, 0 },
+        { DRECDIR "/50", 0, 0 },
+        { DRECDIR "/51", 0, 0 },
+        { DRECDIR "/52", 0, 0 },
+    };
+
+    int i, j, n, size, size_target;
+    int num, percentage;
+
+    error = tffs_mkdir("/north-america");
+
+    percentage = (p1 == 0 ? 50 : p1);
+    n = sizeof(files)/sizeof(struct test_file_s);
+    size_target = percentage * param.bytes_avail / 100;
+    size = 0;
+    for (i = 0; i < 4; i++) {
+        sizes[i].ratio = sizes[i].ratio * size_target / 100;
+        sizes[i].high  = sizes[i].high / 256 * fs.filesize_max / 256;
+        sizes[i].low   = sizes[i].low  / 256 * fs.filesize_max / 256;
+        size += sizes[i].ratio;
+    }
+    ttw(ttr(TTrTest, "%4dk in total" NL, size / 1024));
+    tw(tr(TR_FUNC, TrTestHigh, "%4dk in total\n", size / 1024));
+
+    j = 0;
+    size = size_target = 0;
+    for (i = 0; i < 4; i++) {
+        ttw(ttr(TTrTest, "%4dk: %d..%d = ",
+              sizes[i].ratio / 1024, sizes[i].high, sizes[i].low));
+        tw(tr(TR_FUNC, TrTestHigh, "%4dk: %d..%d = ",
+              sizes[i].ratio / 1024, sizes[i].high, sizes[i].low));
+        size_target += sizes[i].ratio;
+        while (size < size_target) {
+            files[j].data = (char *) tdata[TDATA_HUGE] + j;
+            files[j].size = rand() % (sizes[i].high - sizes[i].low)
+                + sizes[i].low;
+            size += files[j].size;
+            ttw(ttr(TTrTest, "%d:%s, ",
+                    files[j].size, &files[j].name[strlen(DRECDIR)+1]));
+            tw(tr(TR_NULL, TrTestHigh, "%d:%s, ",
+                  files[j].size, &files[j].name[strlen(DRECDIR)+1]));
+            j++;
+            if (j >= n) {
+                // TODO: better error handling?
+                ttw(str(TTrTest, "j too big" NL));
+                tw(tr(TR_FUNC, TrTestHigh, "j too big\n"));
+                return -1;
+            }
+        }
+        ttw(str(TTrTest, "" NL));
+        tw(tr(TR_NULL, TrTestHigh, "\n"));
+    }
+    n = j;
+
+    error = tffs_mkdir(DRECDIR);
+
+    num = (p0 == 0 ? 5 : p0);
+    for (j = 0; j < num; j++) {
+        ttw(ttr(TTrTest, "drec: %d. write" NL, j+1));
+        tw(tr(TR_FUNC, TrTestHigh, "drec: %d. write\n", j+1));
+        for (i = 0; i < n; i++) {
+            error = tffs_fwrite(files[i].name, files[i].data, files[i].size);
+            expect(error, EFFS_OK);
+        }
+        // error = test_run("ri");
+        // if (error) return 1;
+    }
+    
+    for (i = 0; i < n; i++) {
+        error = test_expect_file(files[i].name, files[i].data, files[i].size);
+        if (error) return 1;
+        error = tffs_remove(files[i].name);
+        expect(error, EFFS_OK);
+    }
+
+    return 0;
+}
+
+#endif
+
+void save_block_ages(int *age)
+{
+    int i;
+    struct block_header_s *bhp;
+
+    for (i = 0; i < dev.numblocks; i++)
+    {
+        bhp = (struct block_header_s *) offset2addr(dev.binfo[i].offset);
+        age[i] = bhp->age;
+        tw(tr(TR_FUNC, TrTestHigh, "b,age(%d,%d)\n", i, age[i]));
+    }
+} 
+
+// NOTE: This chech includes the inode block thus the inode block also needs
+// to be reclaimed before this functions returns ok
+int has_all_block_ages_changed(int *age)
+{
+    int i;
+    struct block_header_s *bhp;
+
+    for (i = 0; i < dev.numblocks; i++)
+    {
+        bhp = (struct block_header_s *) offset2addr(dev.binfo[i].offset);
+        if (age[i] == bhp->age) 
+            return 0; // Age have not changed
+    }
+  
+    return 1;
+}
+
+#define chunkalign(size) (((size) + fs.chunk_size_max-1) & ~(fs.chunk_size_max-1))
+
+// Fill a data blocks with the maximum possible numbers of objects
+int fill_block_with_max_objects(void)
+{
+    static int n = 1000; // Avoid white spaces in the filename
+    int fsize, i, b, nobjects, bfree_space;
+    char myname[] = "Fb_max-xxxx";
+    char *mydata = (char *) tdata[TDATA_HUGE];
+
+    // Find an approximate objects size 
+    fsize = dev.blocksize / fs.block_files_max - sizeof(myname) - 1; 
+
+    // Fill approximate 75% of a data block
+    for (i = 0; i < fs.block_files_max / 4 * 3; i++, n++) {
+        sprintf(myname, "/Fb_max-%4d", n);
+        error = tffs_file_write(myname,(char*) mydata, fsize, FFS_O_CREATE);
+        expect_ok(error);
+    }
+
+    // Find the block we currently are filling with objects.
+    error = tffs_xlstat(myname, &xstat);
+    expect_ok(error);
+    
+    b = xstat.block;
+    bfree_space = dev.blocksize - bstat[b].used;
+    tw(tr(TR_FUNC, TrTestHigh, "Block: %d, Free space:%dkB\n", b ,bfree_space>>10));
+
+    // Calculate the exact file size to fill a block with max number of files  
+    nobjects = fs.block_files_max - bstat[b].objects - fs.block_files_reserved;
+
+    fsize = bfree_space / nobjects - sizeof(myname);
+    fsize &= ~dev.atomnotmask;     // Avoid padding
+    tw(tr(TR_FUNC, TrTestHigh, "Exact file size (%d)\n", fsize));
+    
+    // Fill the rest of the block
+    for (i = 0; i < nobjects; i++, n++) {
+        sprintf(myname, "/Fb_max-%4d", n);
+        error = tffs_file_write(myname, (char*) mydata, fsize, FFS_O_CREATE);
+        expect_ok(error);
+    }
+
+    tw(tr(TR_FUNC, TrTest, "Filled block %d done\n", b));
+
+    return EFFS_OK;
+}
+
+// Stress test data reclaim and test wearleveling.
+// NOTE: This test can not run in less than 7 blocks 
+int case_adrec(int nwrites, int nage_change)
+{
+    int i, j, n, inodes_reserved, nobjects, bytes_max;
+    int blocks, fsize;
+    int dynamic_fsize = 1000;
+    char static_name[] = "/Static-xxxx";
+    char dynamic_name[] = "/Dynamic";
+    int *age = (int*) smallbuf;
+
+/* Flow:
+   Format ffs.
+   Fill N number of blocks with the maximum possible numbers of objects.
+   Fill the rest of FFS except from a few kbytes. Use almost all the inodes.
+   Trigger data reclaim by continue to update a file.
+   Test if all flash blocks are used for wearleveling. 
+*/
+    if (nwrites == 0)  // Number of updates of the dynamic file (timeout)
+        nwrites = 1000000;
+    if (nage_change == 0) // 
+        nage_change = 2;
+
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    // Major hack, disable journal and reserved space or else there will be
+    // created new journals inside the blocks where we wish to have only
+    // static objects
+    fs.ijournal = 0;
+    fs.reserved_space = 0;
+
+    // Minimum amount of inodes to fill FFS:
+    ffs_query(Q_BYTES_FREE, &bytes_max);
+    inodes_reserved = bytes_max / fs.chunk_size_max;
+
+    // We need to calculate the amount of inodes we can use and still
+    // garanti that we have enough inodes to fill all data blocks with data.
+    nobjects  = fs.objects_max - inodes_reserved;
+
+    // How many blocks can we fill?    
+    blocks = nobjects / fs.block_files_max;
+
+    // Fill N number of data blocks with the maximum possible numbers of objects
+    tw(tr(TR_FUNC, TrTest, "Fill %d blocks with max obj \n", blocks));
+    n = 1000; // Avoid white spaces in the filename
+    for (j = 0; j < blocks; j++) {  
+        error = fill_block_with_max_objects();
+        expect_ok(error);
+    }
+    
+    // Restore journal and reserved space
+    error = tffs_initialize();
+    expect_ok(error);
+
+    // Fill the rest of FFS except from 3 times the dynamic size, futhermore
+    // keep 4 objects 'free'
+    ffs_query(Q_OBJECTS_FREE, &nobjects);
+    tw(tr(TR_FUNC, TrTest, "Fill almost the rest of FFS\n"));
+    n = 1000;        // Avoid white spaces in the filename
+    while (nobjects - 4 > 0) {    
+        ffs_query(Q_BYTES_FREE, &bytes_max);
+        fsize = (bytes_max - dynamic_fsize * 3) / (nobjects - 4);
+
+        tw(tr(TR_FUNC, TrTestHigh, "space,obj,fsize (%dk,%d,%d)\n", 
+              bytes_max/1024, nobjects, fsize));
+
+        if (fsize > fs.chunk_size_max) {
+            // Roundup to the closet complete chunk or else we use to many inodes
+            fsize = chunkalign(fsize);
+            tw(tr(TR_FUNC, TrTestHigh, "Chunkalign %d\n", fsize));
+        }
+        sprintf(static_name, "/Static-%4d", n++);
+        error = tffs_file_write(static_name, (char*)tdata[TDATA_HUGE], fsize, 
+                                FFS_O_CREATE);
+        if (error == EFFS_NOSPACE) {
+            tw(tr(TR_FUNC, TrTest, "WARNING: Fill failed with out of data space\n"));
+            break;
+        }
+        else
+            expect_ok(error);
+
+        ffs_query(Q_OBJECTS_FREE, &nobjects);
+    }
+    tw(tr(TR_FUNC, TrTest, "Fill done, all static objects are written\n"));
+
+    case_debug_help(2,0);  // bstat trace
+
+    // Save the age of all blocks
+    save_block_ages(age);
+
+    tw(tr(TR_FUNC, TrTest, "Update the dynamic file max %d times\n", nwrites));
+
+    for (i = 0, j = 0; i < nwrites; i++) {
+        error = tffs_file_write(dynamic_name, (char*)tdata[TDATA_HUGE], 
+                                dynamic_fsize, 
+                                FFS_O_CREATE | FFS_O_TRUNC);
+        expect_ok(error);
+        
+        if (i%1000 == 0)
+            tw(tr(TR_FUNC, TrTest, "Write number %d\n", i));
+
+         if (has_all_block_ages_changed(age) == 1) {
+            tw(tr(TR_FUNC, TrTest,"All block ages have changed %d\n", j));
+            j++;
+            save_block_ages(age);
+        }
+
+        if (j >= nage_change) 
+            break;
+    }
+    
+    test_statistics_print();
+
+    case_debug_help(2,0);  // bstat trace
+
+    if (j >= nage_change)
+        return 0;
+    
+    return 1;  //Error
+}
+
+/******************************************************************************
+ * Journalling and Recover Test Cases
+ ******************************************************************************/
+
+// Test journalling. Both for normal objects but also for journal file
+// itself! The following operations are tested for proper recovery: fcreate,
+// fupdate, relocate, delete, clean, fcontrol
+int case_journal(int p0, int p1)
+{
+    struct test_file_s tf;
+    struct ffs_state_s old, new;
+    struct xstat_s stat_old, stat_new;
+    int i, myspace = 0, mytmpspace, offset;
+    char mytmpname[] = "/test-journal-tmp";
+    int testflags[] = {
+        JOURNAL_TEST_EMPTY,      // object not committed
+        JOURNAL_TEST_WRITING,    // object not committed
+        JOURNAL_TEST_READY,      // object ok
+        JOURNAL_TEST_COMMITTING, // object ok
+        JOURNAL_TEST_COMMITTED,  // object ok
+        JOURNAL_TEST_DONE,       // object ok
+    };
+
+    tf.name = "/test-journal";
+    tf.data = (char *) tdata[2];
+    tf.size = sdata[2];
+
+#if 1
+// NOTEME: Workaround, the below use of state_get can not handle if we
+// create a new journal while we run the test. Instead we create a
+// new journal before the test if we are close to full.
+    if (fs.journal_pos >= fs.journal_size - (FFS_JOURNAL_MARGIN + 12) * 
+        sizeof(struct journal_s)) {
+        tw(tr(TR_FUNC, TrTest, "Journal file (near) full!\n"));
+        journal_create(fs.ijournal);
+    }
+
+// NOTEME: Workaround, this test is unabel to handle a
+// block_alloc(). The 'extra' amount of lost space caused by a
+// block_alloc() and its block header dos cheat the test to fail.
+    offset = data_prealloc(1024);
+    expect_gt(offset, 0);
+#endif
+
+    // init
+#if 1
+    error = tffs_fwrite(mytmpname, tf.data, tf.size);
+    expect(error, EFFS_OK);
+    error = tffs_xlstat(mytmpname, &stat_old);
+    expect(error, EFFS_OK);
+    mytmpspace = stat_old.space;
+    ttw(ttr(TTrTest, "file '%s' uses %d bytes" NL, mytmpname, mytmpspace));
+    tw(tr(TR_FUNC, TrTestHigh, "file '%s' uses %d bytes\n", mytmpname, mytmpspace));
+#endif
+    error = tffs_fcreate(tf.name, tf.data, tf.size);
+    expect(error, EFFS_OK);
+    error = tffs_xlstat(tf.name, &stat_old);
+    expect(error, EFFS_OK);
+    myspace = stat_old.space;
+    error = tffs_fcreate("/dummy", 0, 0);
+    expect(error, EFFS_OK);
+    ttw(ttr(TTrTest, "file '%s' uses %d bytes" NL, tf.name, myspace));
+    tw(tr(TR_FUNC, TrTestHigh, "file '%s' uses %d bytes\n", tf.name, myspace));
+
+    ttw(str(TTrTest, "fcreate:" NL));
+    tw(tr(TR_BEGIN, TrTestHigh, "fcreate:\n"));
+    stat_old.inode = 0;
+    for (i = 0; i < sizeof(testflags)/sizeof(int); i++)
+    {
+        // clean up from operation being tested
+        tffs_remove(tf.name);
+
+        ttw(ttr(TTrTest, "fs.testflags = 0x%x" NL, testflags[i]));
+        tw(tr(TR_FUNC, TrTestHigh, "fs.testflags = 0x%x\n", testflags[i]));
+        test_ffs_state_get(&old);
+
+        error = tffs_fcontrol("/dummy", OC_FS_TESTFLAGS, testflags[i]);
+        expect(error, EFFS_OK);
+
+        error = tffs_fcreate(tf.name, tf.data, tf.size);
+        expect(error, EFFS_OK);
+        
+        error = tffs_initialize();
+        expect(error, EFFS_OK);
+
+        test_ffs_state_get(&new);
+
+        tw(tr(TR_FUNC, TrTestHigh,
+              "bytes_used new = %7d, old = %7d, diff = %d\n",
+              new.bytes_used, old.bytes_used, new.bytes_used - old.bytes_used));
+        tw(tr(TR_FUNC, TrTestHigh,
+              "bytes_lost new = %7d, old = %7d, diff = %d\n",
+              new.bytes_lost, old.bytes_lost,
+              new.bytes_lost - old.bytes_lost));
+
+        expect_eq(new.bytes_used, old.bytes_used + myspace);
+
+        error = tffs_xlstat(tf.name, &stat_new);
+        if (i < 2) {
+            // object was not committed, so object must not exist
+            expect(error, EFFS_NOTFOUND);
+            expect_eq(new.objects_total, old.objects_total);
+            expect_eq(new.bytes_lost,    old.bytes_lost + myspace);
+        }
+        else {
+            // object was committed, so object must exist
+            expect(error, EFFS_OK);
+            expect_ne(stat_old.inode, stat_new.inode);
+            expect_eq(new.objects_total, old.objects_total + 1);
+            expect_eq(new.bytes_lost,    old.bytes_lost);
+        }
+    }
+    ttw(str(TTrTest, "" NL));
+    tw(tr(TR_END, TrTestHigh, ""));
+
+    ttw(str(TTrTest, "fupdate:" NL));
+    tw(tr(TR_BEGIN, TrTestHigh, "fupdate:\n"));
+    error = tffs_xlstat(tf.name, &stat_old);
+    expect(error, EFFS_OK);
+    for (i = 0; i < sizeof(testflags)/sizeof(int); i++)
+    {
+        ttw(ttr(TTrTest, "fs.testflags = 0x%x" NL, testflags[i]));
+        tw(tr(TR_FUNC, TrTestHigh, "fs.testflags = 0x%x\n", testflags[i]));
+        test_ffs_state_get(&old);
+
+        error = tffs_fcontrol("/dummy", OC_FS_TESTFLAGS, testflags[i]);
+        expect(error, EFFS_OK);
+
+        error = tffs_fupdate(tf.name, tf.data, tf.size);
+ 
+        error = tffs_initialize();
+        expect(error, EFFS_OK);
+
+        error = tffs_xlstat(tf.name, &stat_new);
+        expect(error, EFFS_OK);
+
+        if (i < 2) {
+            // object was not committed, so stats must be equal
+            error = test_expect_data(&stat_new, &stat_old, sizeof(stat));
+            if (error) return 1;
+        }
+        else {
+            // object was committed, so inodes must not be equal
+            expect_ne(stat_old.inode, stat_new.inode);
+        }
+
+        test_ffs_state_get(&new);
+
+        tw(tr(TR_FUNC, TrTestHigh,
+              "bytes_used new = %7d, old = %7d, diff = %d\n",
+              new.bytes_used, old.bytes_used, new.bytes_used - old.bytes_used));
+        tw(tr(TR_FUNC, TrTestHigh,
+              "bytes_lost new = %7d, old = %7d, diff = %d\n",
+              new.bytes_lost, old.bytes_lost,
+              new.bytes_lost - old.bytes_lost));
+
+        expect_eq(new.objects_total, old.objects_total);
+        expect_eq(new.bytes_used,    old.bytes_used + myspace);
+        expect_eq(new.bytes_lost,    old.bytes_lost + myspace);
+    }
+    ttw(str(TTrTest, "" NL));
+    tw(tr(TR_END, TrTestHigh, ""));
+
+    ttw(str(TTrTest, "rename:" NL));
+    tw(tr(TR_BEGIN, TrTestHigh, "rename:\n"));
+    error = tffs_fwrite(tf.name, tf.data, tf.size);
+    expect(error, EFFS_OK);
+    error = tffs_xlstat(tf.name, &stat_old);
+    expect(error, EFFS_OK);
+
+    for (i = 0; i < sizeof(testflags)/sizeof(int); i++)
+    {
+        ttw(ttr(TTrTest, "fs.testflags = 0x%x" NL, testflags[i]));
+        tw(tr(TR_FUNC, TrTestHigh, "fs.testflags = 0x%x\n", testflags[i]));
+
+        error = tffs_fwrite(mytmpname, tf.data, tf.size);
+        expect_ok(error);
+        error = tffs_fcontrol("/dummy", OC_FS_TESTFLAGS, testflags[i]);
+        expect(error, EFFS_OK);
+
+        test_ffs_state_get(&old);
+        error = tffs_rename(mytmpname, tf.name);
+        expect_ok(error);
+        error = tffs_initialize();
+        expect(error, EFFS_OK);
+        test_ffs_state_get(&new);
+
+        // tf.name MUST always exist
+        error = tffs_xlstat(tf.name, &stat_new);
+        expect(error, EFFS_OK);
+
+        tw(tr(TR_FUNC, TrTestHigh,
+              "bytes_used new = %7d, old = %7d, diff = %d\n",
+              new.bytes_used, old.bytes_used, new.bytes_used - old.bytes_used));
+        tw(tr(TR_FUNC, TrTestHigh,
+              "bytes_lost new = %7d, old = %7d, diff = %d\n",
+              new.bytes_lost, old.bytes_lost,
+              new.bytes_lost - old.bytes_lost));
+
+        error = tffs_xlstat(mytmpname, &stat_new);
+        if (i < 2) {
+            // Journal not READY, so test-journal-tmp must exist
+            expect(error, EFFS_OK); 
+            expect_eq(new.objects_total, old.objects_total);
+            expect_eq(new.bytes_used,    old.bytes_used + myspace);
+            expect_eq(new.bytes_lost,    old.bytes_lost + myspace);
+        }
+        else {
+            // Journal ready, so test-journal-tmp must not exist 
+            expect(error, EFFS_NOTFOUND);
+            expect_eq(new.objects_total, old.objects_total - 1);
+            expect_eq(new.bytes_used,    old.bytes_used + myspace);
+            expect_eq(new.bytes_lost,    old.bytes_lost + myspace + mytmpspace);
+            expect_ne(stat_old.inode, stat_new.inode);
+        }
+    }
+
+    ttw(str(TTrTest, "" NL));
+    tw(tr(TR_END, TrTestHigh, ""));
+
+    // cleanup
+    tffs_remove(tf.name);
+    tffs_remove("/dummy");
+
+    return 0;
+}
+
+// Test block recovery
+int case_brecover(int p0, int p1)
+{
+    struct test_file_s tf;
+    struct ffs_state_s old, new;
+    int j, inodes_block_old = 0, inodes_block_new = 0;
+    int i, error;
+    uint16 free_blocks;
+
+    int testflags[] = {
+        BLOCK_COMMIT_BEFORE,
+        BLOCK_COMMIT_NO_VALID,
+        BLOCK_COMMIT_OLD_FREE,
+        BLOCK_COMMIT_AFTER
+    };
+
+    int testflags_2[] = {
+        BLOCK_RECLAIM_ALLOC,
+        BLOCK_RECLAIM_CLEANING,
+        BLOCK_RECLAIM_NO_CLEAN,
+    };
+
+    tf.name = "/dummy4fctrl";
+    tf.data = (char *) tdata[0];
+    tf.size = sdata[0];
+
+    error = tffs_fwrite(tf.name, tf.data, tf.size);
+    expect(error, EFFS_OK);
+
+    for (j = 0; j < 3; j++)
+    {
+        test_ffs_state_get(&old);
+//case_lsr(0, 0);  // temp
+
+        error = ffs_query(Q_FS_INODES, (uint16 *) &inodes_block_old);
+        expect(error, EFFS_OK);
+
+        // Trigger block_commit() to fail
+        error = tffs_fcontrol(tf.name, OC_FS_TESTFLAGS, testflags[j]);
+        expect(error, EFFS_OK);
+        
+        inodes_reclaim();
+        
+        error = tffs_initialize();
+        expect(error, EFFS_OK);
+        
+        error = ffs_query(Q_FS_INODES, (uint16 *) &inodes_block_new);
+        expect(error, EFFS_OK);
+
+        ttw(ttr(TTrTest, "inodes block %d -> %d" NL,
+                inodes_block_old, inodes_block_new));
+        tw(tr(TR_FUNC, TrTestHigh, "inodes block %d -> %d\n",
+              inodes_block_old, inodes_block_new));
+        
+        switch (j) {
+        case 0: expect(inodes_block_old, inodes_block_new); break;
+        case 1: expect_ne(inodes_block_old, inodes_block_new); break;
+        case 2: expect_ne(inodes_block_old, inodes_block_new); break;
+        case 3: expect_ne(inodes_block_old, inodes_block_new); break;
+        }
+
+        test_ffs_state_get(&new);
+
+        if (test_expect_objects(&old, &new))
+            return 1;
+
+    }
+
+// FIXME: The below test often fails (recalaim data block and create new
+// jouranl file makes it to fail)
+    if (p0 == 9) {
+// Test BLOCK_RECLAIM Fill up all data blocks until only one is
+// free. 
+        tw(tr(TR_FUNC, TrTest, "Test Block reclaim\n"));
+        ttw(ttr(TTrTest, "Test Block reclaim..." ));
+        tffs_mkdir("/rand");
+
+        ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks);
+        while (free_blocks > 1) {
+            error = case_mk_rand_file("/rand", 10000, 0);
+            if (error < 0) {
+                tw(tr(TR_FUNC, TrTest, "ERROR: case_mk_rand_file failed\n"));
+                return 1;
+            }
+            ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks);
+        } 
+
+// case_mk_rand_file() will trigger a block_reclaim which will be
+// interruptet by the activated testflags. This will cause the FFS to
+// use the last free block! After a new init of ffs must it have
+// recovered.
+
+        ttw(ttr(TTrTest, "use last block..."));
+        for (i = 0; i < sizeof(testflags_2)/sizeof(int); i++)
+        {
+            error = tffs_fcontrol(tf.name, OC_FS_TESTFLAGS, testflags_2[i]);
+            expect(error, EFFS_OK);
+
+            do {
+                case_cleanup(20000);
+                error = case_mk_rand_file("/rand", 7000, 0);
+            } while (error >= 0);
+            expect(error, EFFS_NOSPACE);
+
+            ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks);
+            if (free_blocks != 0) {
+                tw(tr(TR_FUNC, TrTestHigh, "ERROR: We still have free blocks!\n"));
+                return 1;
+            }
+
+            error = tffs_initialize();// NOTE: error "WARNING: block_alloc failed" is okay.
+            expect_ok(error);
+
+            ffs_query(Q_BLOCKS_FREE, (uint16 *) &free_blocks);
+            if (free_blocks != 1) {
+                tw(tr(TR_FUNC, TrTestHigh,
+                      "ERROR: Wrong number of blocks free: %d\n", free_blocks));
+                return 1;
+            }
+        }
+// NOTE: We have to make this clenaup because we can not run if FFS is
+// near full
+        case_cleanup(dev.blocksize);
+
+// This test will make data_block_reclaim() to fail before it has
+// relocated all objects
+        ttw(ttr(TTrTest, "interrupt block_reclaim()...")); 
+        for (i = 0; i < 4; i++)
+        {
+            error = tffs_fcontrol(tf.name, OC_FS_TESTFLAGS, BLOCK_RECOVER_OBJECTS);
+            expect(error, EFFS_OK);
+
+            do {
+                case_cleanup(20000);
+                error = case_mk_rand_file("/rand", 7000, 0);
+            } while (error >= 0);
+            expect(error, EFFS_NOSPACE);
+// NOTE: error "WARNING: block_alloc failed" is okay.
+            error = tffs_initialize();  
+            expect_ok(error);
+        }
+
+// Free up some space to the next test case.
+        case_cleanup(dev.blocksize * 4);
+
+        ttw(ttr(TTrTest, "Done" NL));
+    }
+
+    return 0;
+}
+
+
+/******************************************************************************
+ * Specific/Special Test Cases
+ ******************************************************************************/
+
+// FIXME: Is this test case still valid after the new ffs_file_write() which
+// makes seveal chunks instead of on big?
+
+// Test filling a block to the full block size. We write N files of
+// decreasing powers of two, starting at half the block size. At the end we
+// are guaranteed to have at least one completelt full block. Also, we know
+// we have used at least <block_size> bytes of storage.
+int case_bfull(int p0, int p1)
+{
+    struct ffs_state_s old, new;
+    char myname[40] = "/antarctica/ice-";
+    int i, size, mysize, dirlen, space;
+
+    if (param.data_blocks <= 1) {
+        ttw(ttr(TTrTest, "WARNING: Too few blocks to run. Skip test" NL));
+        tw(tr(TR_FUNC, TrTest, "WARNING: Too few blocks to run. Skip test\n"));
+        return 0;
+    }
+
+    error = tffs_mkdir("/antarctica");
+
+    error = case_cleanup(param.block_size + 10000);
+    expect_ok(error);
+
+    test_ffs_state_get(&old);
+    dirlen = strlen(myname);
+    space = 0;
+
+    size = param.block_size/2;
+    for (i = 0; size > 0; i++) {
+        mysize = size - param.atomsize;
+        if (mysize < 0)
+            mysize = size;
+        sprintf(&myname[dirlen], "%d", size);
+        error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], mysize);
+        expect(error, EFFS_OK);
+        error = tffs_xlstat(myname, &xstat);
+        expect(error, EFFS_OK);
+        ttw(ttr(TTrTest, "%6d: %s" NL, xstat.space, myname));
+        tw(tr(TR_FUNC, TrTestHigh, "%6d: %s\n", xstat.space, myname));
+        space += xstat.space;
+        size >>= 1;
+    }
+
+    test_ffs_state_get(&new);
+    // Check space used. We have used a little more than <space> because we
+    // have probably allocated one or two new blocks, and that is
+    // dev.atomsize more bytes per block.
+    tw(tr(TR_FUNC, TrTestHigh,
+          "old.free = %d, new.free = %d, space used in test = %d\n",
+          old.bytes_free, new.bytes_free, space));
+    expect_gt(old.bytes_free, new.bytes_free + space - 1);
+
+    // remove half of the files
+    size = param.block_size/2;
+    for (i = 0; size > 0; i++) {
+        if (i & 1) {
+            sprintf(&myname[dirlen], "%d", size);
+            error = tffs_remove(myname);
+            expect(error, EFFS_OK);
+        }
+        size >>= 1;
+    }
+
+    return 0;
+}
+
+
+int case_list(int p0, int p1)
+{
+    const struct testcase_s *p;
+
+    tw(tr(TR_FUNC, TrTestHigh, "bigbuf   = 0x%X, %d\n", bigbuf,   bigbuf_size));
+    tw(tr(TR_FUNC, TrTestHigh, "smallbuf = 0x%X, %d\n", smallbuf, smallbuf_size));
+
+    ttw(ttr(TTrTest, "bigbuf   = 0x%X, %d" NL, bigbuf,   bigbuf_size));
+    ttw(ttr(TTrTest, "smallbuf = 0x%X, %d" NL, smallbuf, smallbuf_size));
+
+    ttw(str(TTrTest, "Test Cases:" NL));
+    for (p = testcase; p->name != 0; p++) {
+        tw(tr(TR_FUNC, TrTest, "%8s: %s\n", p->name, p->comment));
+        ttw(ttr(TTrTest, "%8s: %s" NL, p->name, p->comment));
+    }
+    return 0;
+}
+
+// Stress test the target.
+// p0 is number of times to run. Default is 10.
+// p1 is number of milli-seconds to wait between each file update.
+int case_stress(int p0, int p1)
+{
+    char myname[20];
+    int i, mysize;
+    char *mydata;
+ 
+    mydata = (char *) tdata[TDATA_HUGE];
+    mysize = 9 * param.block_size / 16;
+
+    if (p0 == 0) p0 = 10;
+    if (p1 == 0) p1 = 1000;
+
+    for (i = 0; i < p0; i++) {
+        sprintf(myname, "/stress-%d", i);
+        ttw(ttr(TTrTest, "/stress %d" NL, i));
+        error = tffs_fcreate(myname, (char *)mydata, mysize);
+        expect(error, EFFS_OK);
+        tffs_delay(p1);
+        error = tffs_remove(myname);
+        expect(error, EFFS_OK);
+    }
+
+    return 0;
+}
+
+// Test ffs with many (small) files. p0 is number of times to write all the
+// files. Default is two e.g. one create and one update
+int case_mfiles(int p0, int p1)
+{
+    char myname[40];
+    int i, j;
+ 
+    static struct test_file_s tf[] =
+        {
+            { MFDIR "/MSCAP",   0,    6 },
+            { MFDIR "/IMEI",    0,    8 },
+            { MFDIR "/CLASS2",  0,    3 },
+            { MFDIR "/CLASS3",  0,    2 },
+            { MFDIR "/MSSUP",   0,    5 },
+            { MFDIR "/MSSET",   0,   83 },
+            { MFDIR "/UPN",     0,  165 },
+            { MFDIR "/CTIM",    0,   92 },
+            { MFDIR "/CCNT",    0,   52 },
+            { MFDIR "/ECC",     0,   15 },
+            { MFDIR "/ORG",     0, 2650 },
+            { MFDIR "/BCCHINF", 0,   54 },
+            { MFDIR "/CCP",     0,    7 },
+            { MFDIR "/EXT1",    0,   13 },
+            { MFDIR "/SIMLCK",  0,   62 },
+            { MFDIR "/SIMLCKEXT",0, 172 },
+            { MFDIR "/SECURITY", 0,   8 },
+            { MFDIR "/MAIN",    0,    8 },
+            { MFDIR "/SFK",     0,    8 },
+            { MFDIR "/FAULT",   0,    8 },
+            { MFDIR "/DEBUG",   0,    8 },
+            { MFDIR "/POWER",   0,    8 },
+            { MFDIR "/KEYB",    0,   64 },
+            { MFDIR "/RADIO",   0,    8 },
+            { MFDIR "/CGMI",    0,   20 },
+            { MFDIR "/CGMM",    0,   20 },
+            { MFDIR "/CGMR",    0,   20 },
+            { MFDIR "/CGSN",    0,   20 },
+            { MFDIR "/SMSPRFL", 0,  206 },
+            { MFDIR "/PLMN",    0,   68 },
+            { MFDIR "/ATRADIO", 0, 2700 },
+            { MFDIR "/GROUP",   0, 1122 }
+        };
+
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/ffs/i2048o1024", 0x2BAD);
+    expect(error, EFFS_OK);
+    error = tffs_mkdir(MFDIR);
+    expect(error, EFFS_OK);
+
+    if (p0 == 0) p0 = 2;
+
+    for (j = 0; j < p0; j++) {
+        tw(tr(TR_FUNC, TrTestHigh, "mf: Writing many files, loop %d\n", j));
+
+        tw(tr(TR_FUNC, TrTestHigh, "SMS000..SMS099\n"));
+        for (i = 0; i < 100; i++) {
+            sprintf(myname, MFDIR "/SMS%03d", i);
+            error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 176);
+            expect(error, EFFS_OK);
+        }
+
+        tw(tr(TR_FUNC, TrTestHigh, "LDN/LRN/LMN000..LDN/LRN/LMN009\n"));
+        for (i = 0; i < 10; i++) {
+            sprintf(myname, MFDIR "/LDN%03d", i);
+            error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 31);
+            expect(error, EFFS_OK);
+            sprintf(myname, MFDIR "/LRN%03d", i);
+            error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 32);
+            expect(error, EFFS_OK);
+            sprintf(myname, MFDIR "/LMN%03d", i);
+            error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 30);
+            expect(error, EFFS_OK);
+        }
+
+        tw(tr(TR_FUNC, TrTestHigh, "ADN000..ADN149\n"));
+        for (i = 0; i < 150; i++) {
+            sprintf(myname, MFDIR "/ADN%03d", i);
+            error = tffs_fwrite(myname, (char *) tdata[TDATA_HUGE], 43);
+            expect(error, EFFS_OK);
+        }
+
+        tw(tr(TR_FUNC, TrTestHigh, "PCM Files...\n"));
+        for (i = 0; i < sizeof(tf)/sizeof(struct test_file_s); i++) {
+            error = tffs_fwrite(tf[i].name,
+                                (char *) tdata[TDATA_HUGE], tf[i].size);
+            expect(error, EFFS_OK);
+        }
+    }
+
+    error = tffs_exit();
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+
+int case_open(int p0, int p1)
+{
+    fd_t fdi;
+    char myname[20];
+    int i, size;
+
+#define RDONLY FFS_O_RDONLY
+#define WRONLY FFS_O_WRONLY
+#define APPEND FFS_O_APPEND
+#define CREATE FFS_O_CREATE
+#define EXCL   FFS_O_EXCL
+#define TRUNC  FFS_O_TRUNC
+
+    ffs_options_t non_exist_invalid[] = {                      
+        ( 0 ),
+        ( RDONLY |                   CREATE                ),                  
+        ( RDONLY |                   CREATE | EXCL         ),
+        ( RDONLY |                   CREATE |        TRUNC ),
+        ( RDONLY |                   CREATE | EXCL | TRUNC ),
+        ( RDONLY |                            EXCL         ),
+        ( RDONLY |                            EXCL | TRUNC ),
+        ( RDONLY |                                   TRUNC ),
+        (                                     EXCL         ),
+        (                                     EXCL | TRUNC ),
+        (                                            TRUNC ),
+        (                            CREATE |        TRUNC ),
+        (                            CREATE | EXCL | TRUNC ),
+        (                            CREATE | EXCL         ),
+        (                            CREATE                ),
+        (                   APPEND                         ),
+        (                   APPEND |          EXCL         ),
+        (                   APPEND |          EXCL | TRUNC ),
+        (                   APPEND |                 TRUNC ),
+        (                   APPEND | CREATE |        TRUNC ),
+        (                   APPEND | CREATE | EXCL         ),
+        (                   APPEND | CREATE | EXCL         ),
+        (                   APPEND | CREATE                ),
+        ( RDONLY |          APPEND                         ),
+        ( RDONLY |          APPEND |          EXCL         ),
+        ( RDONLY |          APPEND |          EXCL | TRUNC ),
+        ( RDONLY |          APPEND |                 TRUNC ),
+        ( RDONLY |          APPEND | CREATE |        TRUNC ),
+        ( RDONLY |          APPEND | CREATE | EXCL | TRUNC ),
+        ( RDONLY |          APPEND | CREATE | EXCL         ),
+        ( RDONLY |          APPEND | CREATE                )
+    };
+    
+    ffs_options_t non_exist_notfound[] = {                      
+        (          WRONLY | APPEND                         ),
+        (          WRONLY | APPEND |          EXCL         ),
+        (          WRONLY | APPEND |          EXCL | TRUNC ),
+        (          WRONLY | APPEND |                 TRUNC ),
+        (          WRONLY                                  ),
+        (          WRONLY |                   EXCL         ),
+        (          WRONLY |                   EXCL | TRUNC ),
+        (          WRONLY |                          TRUNC ),
+        ( RDONLY | WRONLY                                  ),
+        ( RDONLY | WRONLY |                   EXCL         ),
+        ( RDONLY | WRONLY |                   EXCL | TRUNC ),
+        ( RDONLY | WRONLY |                          TRUNC ),
+        ( RDONLY | WRONLY | APPEND                         ),
+        ( RDONLY | WRONLY | APPEND |          EXCL         ),
+        ( RDONLY | WRONLY | APPEND |          EXCL | TRUNC ),
+        ( RDONLY | WRONLY | APPEND |                 TRUNC ),
+        ( RDONLY                                           )
+    };
+    
+    ffs_options_t non_exist_fd_offset[] = {                      
+        (          WRONLY | APPEND | CREATE |        TRUNC ),
+        (          WRONLY | APPEND | CREATE | EXCL | TRUNC ),
+        (          WRONLY | APPEND | CREATE | EXCL         ),
+        (          WRONLY | APPEND | CREATE                ),
+        (          WRONLY |          CREATE |        TRUNC ),
+        (          WRONLY |          CREATE | EXCL | TRUNC ),
+        (          WRONLY |          CREATE | EXCL         ),
+        (          WRONLY |          CREATE                ),
+        ( RDONLY | WRONLY |          CREATE |        TRUNC ),
+        ( RDONLY | WRONLY |          CREATE | EXCL | TRUNC ),
+        ( RDONLY | WRONLY |          CREATE | EXCL         ),
+        ( RDONLY | WRONLY |          CREATE                ),    
+ 
+        ( RDONLY | WRONLY | APPEND | CREATE |        TRUNC ),
+        ( RDONLY | WRONLY | APPEND | CREATE | EXCL | TRUNC ),
+        ( RDONLY | WRONLY | APPEND | CREATE | EXCL         ),
+        ( RDONLY | WRONLY | APPEND | CREATE                )    
+    };          
+
+    ffs_options_t exist_invalid[] = {                      
+        (                                     EXCL         ),
+        (                                     EXCL | TRUNC ),
+        (                                            TRUNC ),
+        (                            CREATE |        TRUNC ),
+        (                            CREATE | EXCL | TRUNC ),
+        (                            CREATE | EXCL         ),
+        (                            CREATE                ),
+        (                   APPEND                         ),
+        (                   APPEND |          EXCL         ),
+        (                   APPEND |          EXCL | TRUNC ),
+        (                   APPEND |                 TRUNC ),
+        (                   APPEND | CREATE |        TRUNC ),
+        (                   APPEND | CREATE | EXCL | TRUNC ),
+        (                   APPEND | CREATE | EXCL         ),
+        (                   APPEND | CREATE                ),
+        ( RDONLY |          APPEND                         ),
+        ( RDONLY |          APPEND |          EXCL         ),
+        ( RDONLY |          APPEND |          EXCL | TRUNC ),
+        ( RDONLY |          APPEND |                 TRUNC ),
+        ( RDONLY |          APPEND | CREATE |        TRUNC ),
+        ( RDONLY |          APPEND | CREATE | EXCL | TRUNC ),
+        ( RDONLY |          APPEND | CREATE | EXCL         ),
+        ( RDONLY |          APPEND | CREATE                ),
+        ( RDONLY |                            EXCL         ),
+        ( RDONLY |                            EXCL | TRUNC ),
+        ( RDONLY |                                   TRUNC ),
+        ( RDONLY |                   CREATE |        TRUNC ),
+        ( RDONLY |                   CREATE | EXCL | TRUNC ),
+        ( RDONLY |                   CREATE | EXCL         ),
+        ( RDONLY |                   CREATE                )
+};
+    
+    ffs_options_t exist_exist[] = {                      
+        (          WRONLY | APPEND | CREATE | EXCL | TRUNC ),
+        (          WRONLY | APPEND | CREATE | EXCL         ),
+        (          WRONLY |          CREATE | EXCL | TRUNC ),
+        (          WRONLY |          CREATE | EXCL         ),
+        ( RDONLY | WRONLY |          CREATE | EXCL | TRUNC ),
+        ( RDONLY | WRONLY |          CREATE | EXCL         ),
+        ( RDONLY | WRONLY | APPEND | CREATE | EXCL | TRUNC ),
+        ( RDONLY | WRONLY | APPEND | CREATE | EXCL         )
+    };
+    
+    ffs_options_t exist_fd_offset[] = {                      
+        (          WRONLY | APPEND                         ),
+        (          WRONLY | APPEND |          EXCL         ),
+        (          WRONLY | APPEND |          EXCL | TRUNC ),
+        (          WRONLY | APPEND |                 TRUNC ),
+        (          WRONLY | APPEND | CREATE |        TRUNC ),
+        (          WRONLY | APPEND | CREATE                ),
+        ( RDONLY                                           ),
+        ( RDONLY | WRONLY                                  ),
+        ( RDONLY | WRONLY |                   EXCL         ),
+        ( RDONLY | WRONLY |                   EXCL | TRUNC ),
+        ( RDONLY | WRONLY |                          TRUNC ),
+        ( RDONLY | WRONLY |          CREATE |        TRUNC ),
+        ( RDONLY | WRONLY |          CREATE                ),    
+        ( RDONLY | WRONLY | APPEND                         ),
+        ( RDONLY | WRONLY | APPEND |          EXCL         ),
+        ( RDONLY | WRONLY | APPEND |          EXCL | TRUNC ),
+        ( RDONLY | WRONLY | APPEND |                 TRUNC ),
+        ( RDONLY | WRONLY | APPEND | CREATE |        TRUNC ),
+        ( RDONLY | WRONLY | APPEND | CREATE                ),    
+        (          WRONLY                                  ),
+        (          WRONLY |                   EXCL         ),
+        (          WRONLY |                   EXCL | TRUNC ),
+        (          WRONLY |                          TRUNC ),
+        ( WRONLY |                   CREATE |        TRUNC ),
+        ( WRONLY |                   CREATE                )
+
+    };
+
+    // Cleanup
+    for (i = 0; i < 20; i++) {
+        sprintf(myname, "/stream%d", i);
+        tffs_remove(myname);
+    }
+
+    tw(tr(TR_FUNC, TrTestHigh, "Various open options, file non-existing\n"));
+    ttw(str(TTrTest, "Various open options, file non-existing" NL));
+    
+    for (i = 0; i < sizeof(non_exist_invalid)/sizeof(ffs_options_t); i++) {
+        sprintf(myname, "/stream%d", i - i/20 * 20); 
+        fdi = tffs_open(myname, non_exist_invalid[i]);
+        expect(fdi, EFFS_INVALID);
+    }
+
+    for (i = 0; i < sizeof(non_exist_notfound)/sizeof(ffs_options_t); i++) {
+        sprintf(myname, "/stream%d", i - i/20 * 20); 
+        fdi = tffs_open(myname, non_exist_notfound[i]);
+        expect(fdi, EFFS_NOTFOUND);
+    }
+
+    for (i = 0; i < sizeof(non_exist_fd_offset)/sizeof(ffs_options_t); i++) {
+        sprintf(myname, "/stream%d", i - i/20 * 20); 
+        fdi = tffs_open(myname, non_exist_fd_offset[i]);
+        expect(fdi, FFS_FD_OFFSET);
+        tffs_close(fdi);
+    }
+
+    // Make FFS_FD_MAX number of files and write some data for later use
+    tw(tr(TR_FUNC, TrTestHigh, "Create %d files with data \n", fs.fd_max)); 
+    for (i = 0; i < fs.fd_max; i++) {
+        sprintf(myname, "/stream%d", i);
+        fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC);
+        expect(fdi, i + FFS_FD_OFFSET);
+        size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31);
+        expect(size, 31);
+    }
+   
+    // Try to open one more file, this will make a error!
+    sprintf(myname, "/stream%d", i++);
+    fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC);
+    expect(fdi, EFFS_NUMFD);
+
+    for (i = 0; i < fs.fd_max; i++) {
+        error = tffs_close(i + FFS_FD_OFFSET);
+        expect(error, EFFS_OK);
+    }
+
+    tw(tr(TR_FUNC, TrTestHigh,
+          "Open same file multiple times in RDONLY mode\n"));
+    for (i = 0; i < fs.fd_max; i++) {
+        fdi = tffs_open("/stream2", FFS_O_RDONLY);
+        expect(fdi, i + FFS_FD_OFFSET);
+    }
+
+    for (i = 0; i < fs.fd_max; i++) {
+        error = tffs_close(i + FFS_FD_OFFSET);
+        expect(error, 0);
+    }
+
+    tw(tr(TR_FUNC, TrTestHigh,
+          "Open in WRONLY and try to open same file in WR or RD\n"));
+    fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+    fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, EFFS_LOCKED);
+    fdi = tffs_open("/stream1", FFS_O_RDONLY );
+    expect(fdi, EFFS_LOCKED);
+    error = tffs_close(FFS_FD_OFFSET);
+    expect(error, 0);
+
+    tw(tr(TR_FUNC, TrTestHigh,
+          "Open in READONLY and try to open same file WRONLY\n"));
+    fdi = tffs_open("/stream1", FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, EFFS_LOCKED);
+    error = tffs_close(FFS_FD_OFFSET);
+    expect(error, 0);
+
+    tw(tr(TR_FUNC, TrTestHigh, "Various open options, file exists\n"));
+    ttw(str(TTrTest, "Various open options, file exists" NL));
+
+    for (i = 0; i < sizeof(exist_invalid)/sizeof(ffs_options_t); i++) {
+        sprintf(myname, "/stream%d", i - i/20 * 20); 
+        fdi = tffs_open(myname, exist_invalid[i]);
+        expect(fdi, EFFS_INVALID);
+    }
+
+    for (i = 0; i < sizeof(exist_exist)/sizeof(ffs_options_t); i++) {
+        sprintf(myname, "/stream%d", i - i/20 * 20); 
+        fdi = tffs_open(myname, exist_exist[i]);
+        expect(fdi, EFFS_EXISTS);
+        tffs_close(fdi);
+    }
+
+    for (i = 0; i < sizeof(exist_fd_offset)/sizeof(ffs_options_t); i++) {
+        sprintf(myname, "/stream%d", i - i/10 * 10); 
+        fdi = tffs_open(myname, exist_fd_offset[i]);
+        expect(fdi, FFS_FD_OFFSET);
+        tffs_close(fdi);
+    }
+
+    tw(tr(TR_FUNC, TrTestHigh, "Try to create a file with a dir name\n"));
+    error = tffs_mkdir("/streams");
+
+    fdi = tffs_open("/streams", FFS_O_WRONLY | FFS_O_APPEND | FFS_O_CREATE);
+    expect(fdi, EFFS_NOTAFILE);
+
+    tw(tr(TR_FUNC, TrTestHigh, 
+          "Try to use fwrite, fcreate, fread and remove on a open file\n"));
+    fdi = tffs_open("/stream1", FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+    
+    error = tffs_fcreate("/stream1", TDATA(2));
+    expect(error, EFFS_EXISTS);
+
+    error = tffs_file_write("/stream1", (char *) tdata[TDATA_HUGE], 31, 
+                            FFS_O_CREATE | FFS_O_TRUNC);
+    expect(error, EFFS_LOCKED);
+
+    error = tffs_file_read("/stream1", bigbuf, 31);
+    expect(error, EFFS_LOCKED);
+
+    error = tffs_remove("/stream1");
+    expect(error, EFFS_LOCKED);
+
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+#undef RDONLY 
+#undef WRONLY 
+#undef APPEND 
+#undef CREATE 
+#undef EXCL   
+#undef TRUNC  
+
+    return 0;
+}
+
+int twrite_seek(fd_t fdi, offset_t offset, int whence)
+{
+    int size;
+
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + 10, 100);
+    if (test_expect(size, 100) < 0) return -1;
+    
+    offset = tffs_seek(fdi, offset, whence);
+    if (test_expect_ok(offset)) return -1;
+
+    return offset;
+}
+
+int tseek_read(fd_t fdi, offset_t offset, int whence, offset_t src_offset)
+{
+    int size;
+
+    offset = tffs_seek(fdi, offset, whence);
+    if (test_expect_ok(offset)) return -1;
+
+    size = tffs_read(fdi, bigbuf, 100);     
+    if (test_expect(size, 100) < 0) return -1;
+
+    error = test_expect_data((char*)tdata[TDATA_HUGE] + src_offset, bigbuf, size);
+    if (error) return error;
+
+    return offset;
+}
+
+int tseek_write(fd_t fdi, offset_t offset, int whence, offset_t src_offset)
+{
+    int size;
+
+    offset = tffs_seek(fdi, offset, whence);
+    if (test_expect_ok(offset)) return -1;
+
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + src_offset + offset, 
+                      fs.chunk_size_max / 2);
+    if (test_expect(size, fs.chunk_size_max / 2) < 0) return -1;
+    
+    return offset;
+}
+
+int case_rw(int p0, int p1)
+{
+    int i, size, offset;
+    fd_t fdi;
+
+    const char *dirs[] = { "/streams", "/streams/rw", "/streams/rw/multi", 
+                           "/streams/rw/multi/write" };
+
+    error = case_cleanup(5 * fs.chunk_size_max);
+    expect_ok(error);
+
+    for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) {
+        error = tffs_mkdir(dirs[i]);
+    }
+
+    tw(tr(TR_FUNC, TrTestHigh, 
+          "Test create and append of file, small and huge\n"));
+    ttw(str(TTrTest, "Test create and append of file, small and huge" NL));
+    
+    fdi = tffs_open("/streams/rw_test", 
+                    FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31);
+    expect(size, 31);
+    error = tffs_close(fdi); expect(error, EFFS_OK);     
+
+    fdi = tffs_open("/streams/rw_test", FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + 31, 2 * fs.chunk_size_max);
+    expect(size, 2 * fs.chunk_size_max);
+
+    error = tffs_close(fdi); expect(error, EFFS_OK);     
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));
+    ttw(ttr(TTrTest, "Validate data" NL)); 
+    size = tffs_fread("/streams/rw_test", bigbuf, bigbuf_size);
+    expect(size, 31 + 2 * fs.chunk_size_max); 
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+
+    // Provoke EFFS_FILETOOBIG
+    error = tffs_fread("/streams/rw_test", bigbuf, size - 1);
+    expect(error, EFFS_FILETOOBIG); 
+    error = tffs_fread("/streams/rw_test", bigbuf, size + 1);
+    expect_ok(error); 
+    error = tffs_fread("/streams/rw_test", bigbuf, size);
+    expect_ok(error);
+
+    // Update file from zero, middle (between to chunks) and end. File with
+    // and without data in seghead. Update the first 100 bytes (new data
+    // have a offset of 10 so the data not is identical with the existing
+    // ones).
+    fdi = tffs_open("/streams/rw_test", FFS_O_RDWR);  
+    expect(fdi, FFS_FD_OFFSET);
+
+    // write 100 bytes and seek to 50 bytes before end of the first chunk
+    expect_ok(twrite_seek(fdi, fs.chunk_size_max - 50, FFS_SEEK_SET));
+
+    // write 100 bytes, seek to 50 bytes from the end of the file
+    expect_ok(twrite_seek(fdi, -50, FFS_SEEK_END));
+
+    // Write 100 bytes. This will update the last 19 bytes of second chunk,
+    // update and append data to the last chunk.  Read the last data but
+    // only 80 bytes because they are in the buffer
+    expect_ok(twrite_seek(fdi, -80, FFS_SEEK_CUR));
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));
+    ttw(ttr(TTrTest, "Validate data" NL)); 
+
+    size = tffs_read(fdi, bigbuf, 100); 
+    expect(size, 80);
+    error = test_expect_data((char *)tdata[TDATA_HUGE] + 10 + 20, bigbuf, size);
+    if (error) return 1;
+
+    // Seek to start of file and read the first 100 bytes that was updated
+    offset = tseek_read(fdi, 0, FFS_SEEK_SET, 10);
+    expect_ok(offset);
+
+    // Read 100 bytes more to make sure that the old data still is valid
+    offset = tseek_read(fdi, 0, FFS_SEEK_CUR, 100);
+    expect_ok(offset);
+
+    // Seek to 50 bytes before end of the first chunk and read 100 bytes
+    offset = tseek_read(fdi, fs.chunk_size_max - 50, FFS_SEEK_SET, 10);
+    expect_ok(offset);
+
+    // Read 100 bytes more to make sure that the old data still is valid
+    offset = tseek_read(fdi, 0, FFS_SEEK_CUR, offset + 100);
+    expect_ok(offset);
+
+    // Read the last 100 bytes (updated data from 2 chunks)
+    offset = tseek_read(fdi, -100, FFS_SEEK_END, 10);
+    expect_ok(offset);
+
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+    
+    // Test where there is data in the seghead
+    size = tffs_file_write("/streams/rw_test", (char*) tdata[TDATA_HUGE], 
+                           2 * fs.chunk_size_max, FFS_O_CREATE | FFS_O_TRUNC);
+    
+    fdi = tffs_open("/streams/rw_test", FFS_O_RDWR);
+    expect(fdi, FFS_FD_OFFSET);
+
+    // Update the last half of the last chunk
+    expect_ok(tseek_write(fdi, -fs.chunk_size_max / 2, FFS_SEEK_END, 10));
+
+    // Update the first half of the last chunk
+    expect_ok(tseek_write(fdi, fs.chunk_size_max, FFS_SEEK_SET, 10));
+
+    // Update the first half of the seghead
+    expect_ok(tseek_write(fdi, 0, FFS_SEEK_SET, 10));
+
+    // Update the last half of the seghead, but flush the buffer so it have
+    // to write and read the previous updated data
+    error = tffs_fdatasync(fdi);
+    expect(error, EFFS_OK);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE] + 10 + fs.chunk_size_max/2, 
+                      fs.chunk_size_max/2);
+    expect(size, fs.chunk_size_max/2);
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));
+    ttw(ttr(TTrTest, "Validate data" NL)); 
+    // Read the complete file, all the data should have a offset of 10 bytes now!
+    offset = tffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect_ok(offset);
+
+    size = tffs_read(fdi, bigbuf, bigbuf_size); 
+    expect(size, 2 * fs.chunk_size_max); 
+    error = test_expect_data((char *)tdata[TDATA_HUGE] + 10, bigbuf, size);
+    if (error) return 1;
+
+    error = tffs_close(fdi); expect(error, 0);
+    
+    // Test bad fdi, write in RDONLY and read from WRONLY
+    fdi = tffs_open("/streams/rw_test", FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_read(fdi + 1, bigbuf, 31);
+    expect(size, EFFS_BADFD);
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31);
+    tw(tr(TR_END, TrApi, "} %d\n", size)); // Avoid wrong indent 
+    expect(size, EFFS_INVALID);
+    error = tffs_close(fdi);  expect(error, 0);
+
+    fdi = tffs_open("/streams/rw_test", FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_read(fdi, bigbuf, 31);
+    expect(size, EFFS_INVALID);
+    error = tffs_close(fdi); expect(error, 0);
+
+    // Test for bad file name
+    fdi = tffs_open("/stream&!'*", FFS_O_WRONLY | FFS_O_CREATE);
+    expect(fdi, EFFS_BADNAME);
+
+    // Test for bad file name
+    fdi = tffs_open("/%$#.+-_,Z19", FFS_O_WRONLY | FFS_O_CREATE);
+    expect(fdi, FFS_FD_OFFSET);
+    tffs_close(fdi);
+
+    return 0;
+}
+
+int case_multi_open(int p0, int p1)
+{
+    int i, j, size;
+    fd_t fdi;
+
+    const char *dirs[] = { "/streams", "/streams/rw", "/streams/rw/multi", 
+                           "/streams/rw/multi/write" };
+
+    const char *file[] = { "/x-rw", "/streams/rw/x-rw", 
+                           "/streams/rw/multi/x-rw", 
+                           "/streams/rw/multi/write/x-rw" };
+
+    error = case_cleanup(fs.fd_max * 50 * 10 + 5000);
+    expect_ok(error);
+
+    for (i = 0; i < sizeof(dirs)/sizeof(char *); i++) {
+        error = tffs_mkdir(dirs[i]);
+    }
+
+    // Open multiply files from difference subdirectorys 
+    // and write/read X times to/from file (this also test truncate option)
+    for (i = 0; i < fs.fd_max; i++) {   
+        fdi = tffs_open( file[i], FFS_O_WRONLY | FFS_O_APPEND | 
+                         FFS_O_CREATE | FFS_O_TRUNC);
+        expect(fdi, i + FFS_FD_OFFSET);
+    }
+
+    for (i = 0; i < fs.fd_max; i++) {
+        for (j = 0; j < 10; j++) {
+            size = tffs_write(i + FFS_FD_OFFSET, (char *) tdata[TDATA_HUGE], 50);
+            expect(size, 50);
+        }
+    }
+    // Run test with p0 != 0 to stress the test
+    if (p0) { error = test_run("irec;drec;"); if (error > 0) return 1; }
+
+    for (i = 0; i < fs.fd_max; i++) {
+        error = tffs_close(i + FFS_FD_OFFSET);
+        expect(error, 0);
+    }
+
+    for (i = 0; i < fs.fd_max; i++) {   
+        fdi = tffs_open( file[i], FFS_O_RDONLY);
+        expect(fdi, i + FFS_FD_OFFSET);
+    }
+    
+    if(p0) { error = test_run("irec;drec;"); if (error > 0) return 1; }
+
+    for (i = 0; i < fs.fd_max; i++) {
+        for (j = 0; j < 10; j++) {
+            size = tffs_read(i + FFS_FD_OFFSET, bigbuf, 50);
+            expect(size, 50);
+            error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+            if (error) return 1;
+        }
+    }
+
+    for (i = 0; i < fs.fd_max; i++) {
+        error = tffs_close(i + FFS_FD_OFFSET);
+        expect(error, 0);
+    }
+
+    return 0;
+}
+
+
+int case_seek(int p0, int p1)
+{
+    fd_t fdi;
+    int size, offset;
+
+    error = case_cleanup(3 * fs.chunk_size_max);
+    expect_ok(error);
+
+// The seek function itself don't care if the file is open in read or
+    // write mode.
+    error = tffs_mkdir("/streams");
+    
+    offset = tffs_seek(FFS_FD_OFFSET, 0, FFS_SEEK_SET);
+    expect(offset, EFFS_BADFD);
+
+    /* Make file to seek on */
+    fdi = tffs_open("/streams/seek", FFS_O_RDWR | FFS_O_CREATE | FFS_O_TRUNC);
+    expect(fdi, FFS_FD_OFFSET);    
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 3 * fs.chunk_size_max);
+    expect(size, 3 * fs.chunk_size_max);
+    
+    /*  Simple test in RDWR without any writes. Test good and bad offset */
+    tw(tr(TR_FUNC, TrTestHigh, "seek and RDWR \n"));
+    ttw(str(TTrTest, "seek and RDWR" NL));
+
+    offset = ffs_seek(fdi, 0, 5);
+    expect(offset, EFFS_INVALID );
+    
+    tw(tr(TR_FUNC, TrTestHigh, "ffs_seek(FFS_SEEK_SET)\n"));
+    ttw(str(TTrTest, "ffs_seek(FFS_SEEK_SET)" NL));
+    offset = tffs_seek(fdi, -1, FFS_SEEK_SET);
+    expect(offset, EFFS_INVALID);
+    offset = tffs_seek(fdi, 3 * fs.chunk_size_max + 1, FFS_SEEK_SET);
+    expect(offset, EFFS_INVALID);
+
+    offset = tffs_seek(fdi, 15, FFS_SEEK_SET);
+    expect(offset, 15);
+    size = tffs_read(fdi, bigbuf, fs.chunk_size_max/10);
+    expect(size, fs.chunk_size_max/10);
+    error = test_expect_data((char *)tdata[TDATA_HUGE] + 15, 
+                             bigbuf, fs.chunk_size_max/10);
+    if (error) return 1;
+
+    offset = tffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(offset, 0);
+   
+    size = tffs_read(fdi, bigbuf, bigbuf_size);
+    error = test_expect_data((char*)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+   
+    tw(tr(TR_FUNC, TrTestHigh, "ffs_seek(FFS_SEEK_CUR)\n"));
+    ttw(str(TTrTest, "ffs_seek(FFS_SEEK_CUR)" NL));
+    offset = tffs_seek(fdi, -(3 * fs.chunk_size_max + 1), FFS_SEEK_CUR);
+    expect(offset, EFFS_INVALID);
+    offset = tffs_seek(fdi, 1, FFS_SEEK_CUR);
+    expect(offset, EFFS_INVALID);    
+    offset = tffs_seek(fdi, 0, FFS_SEEK_CUR);
+    expect(offset, 3 * fs.chunk_size_max);
+    offset = tffs_seek(fdi, -30, FFS_SEEK_CUR);
+    expect(offset, 3 * fs.chunk_size_max - 30);
+    offset = tffs_seek(fdi, 20, FFS_SEEK_CUR);
+    expect(offset, 3 * fs.chunk_size_max - 30 + 20);
+    size = tffs_read(fdi, bigbuf, 3 * fs.chunk_size_max);
+    expect(size, 10);
+    error = test_expect_data((char *)tdata[TDATA_HUGE] + 
+                             (3 * fs.chunk_size_max - 10), bigbuf, 10);
+    if (error) return 1;
+
+    tw(tr(TR_FUNC, TrTestHigh, "ffs_seek(FFS_SEEK_END)\n"));
+    ttw(str(TTrTest, "ffs_seek(FFS_SEEK_END)" NL));
+    offset = tffs_seek(fdi, -(3 * fs.chunk_size_max + 1), FFS_SEEK_END);
+    expect(offset, EFFS_INVALID);
+    offset = tffs_seek(fdi, 1, FFS_SEEK_END);
+    expect(offset, EFFS_INVALID);
+    offset = tffs_seek(fdi, 0, FFS_SEEK_END);
+    expect(offset, 3 * fs.chunk_size_max);
+    offset = tffs_seek(fdi, -15, FFS_SEEK_END);
+    expect(offset, 3 * fs.chunk_size_max - 15);
+    size = tffs_read(fdi, bigbuf, 20);
+    expect(size, 15);
+    error = test_expect_data((char *)tdata[TDATA_HUGE] + 
+                             (3 * fs.chunk_size_max - 15), bigbuf, size);
+    if (error) return 1;
+    
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    // Seek in write-mode with write in different places of the file. Test
+    // on the dirty flag to se if the buffer is flushed ad the rigth time
+    tw(tr(TR_FUNC, TrTestHigh, "seek and WRONLY \n"));
+    ttw(str(TTrTest, "seek and WRONLY" NL));
+
+    fdi = tffs_open("/streams/seek", FFS_O_WRONLY);
+
+    // Write and seek in the last chunk, buffer must be dirty so long the fp
+    // not have been moved away from that chunk!
+
+    offset = tffs_seek(fdi, -20, FFS_SEEK_END); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    offset = tffs_seek(fdi, -100, FFS_SEEK_CUR); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    offset = tffs_seek(fdi, -fs.chunk_size_max/4, FFS_SEEK_CUR); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    offset = tffs_seek(fdi, offset + 10, FFS_SEEK_SET); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    // Write and seek across several chunks, the buffer must be flushed after
+    // leaving a 'dirty' chunk.
+    
+    offset = tffs_seek(fdi, 10, FFS_SEEK_SET); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 10); expect(size, 10);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    offset = tffs_seek(fdi, -50, FFS_SEEK_END); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 100); expect(size, 100);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    offset = tffs_seek(fdi, -fs.chunk_size_max, FFS_SEEK_CUR); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], fs.chunk_size_max / 2); 
+    expect(size, fs.chunk_size_max / 2);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    offset = tffs_seek(fdi, fs.chunk_size_max, FFS_SEEK_SET); expect_ok(offset);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 0);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 50); expect(size, 50);
+    expect(fs.fd[fdi - FFS_FD_OFFSET].dirty, 1);
+
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    return 0;
+}
+
+// NOTEME: move to other place later
+int case_trunc(int p0, int p1)
+{
+    fd_t fdi;
+    int size, f_size, trunc_size, i;
+    T_FFS_STAT stat;
+    char fname[] = "/truncate/normal_file";
+    char sname[] = "/truncate/stream_file";
+    char imeifile[] = "/truncate/IMEI"; 
+    
+    tffs_remove(fname);
+    tffs_remove(sname);
+
+    error = case_cleanup(5 * fs.chunk_size_max);
+    expect_ok(error);
+
+    tffs_mkdir("/truncate");
+
+    // Try to truncate a non existing file
+    error = tffs_truncate(fname, 0);
+    expect(error, EFFS_NOTFOUND);
+
+    // Try to truncate a directory
+    error = tffs_truncate("/truncate", 0);
+    expect(error, EFFS_NOTAFILE);
+
+    f_size = fs.chunk_size_max + 100;
+    error = tffs_file_write(fname, (char *)tdata[TDATA_HUGE], f_size, 
+                            FFS_O_TRUNC | FFS_O_WRONLY | FFS_O_CREATE);
+    expect(error, EFFS_OK);
+    
+    /* Test truncate from file size + 3 to file size - 3 */
+    for (i = 0; i < 6; i++) {
+        trunc_size = f_size + 3 - i;
+        tw(tr(TR_FUNC, TrTestLow, "TRUNC file to size %d \n", trunc_size));
+        error = tffs_truncate(fname, trunc_size);
+        expect(error, EFFS_OK);
+        error = tffs_lstat(fname, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, (f_size < trunc_size ? f_size : trunc_size));
+    }
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread(fname, bigbuf, f_size);
+    expect(size, trunc_size);  // ++ because of the last -- in for()
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+
+    tw(tr(TR_FUNC, TrTestLow, "Truncate file while it is open \n"));
+    fdi = tffs_open(fname, FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_write(fdi, (char *) &tdata[TDATA_HUGE][trunc_size], 31);
+    expect(size, 31);
+    f_size = trunc_size + 31;
+
+    // Truncate to a size less than fp, this will fail
+    error = tffs_ftruncate(fdi, f_size - 1);
+    expect(error, EFFS_INVALID);
+
+    // Move fp otherwise it will not be possible to truncate
+    error = ffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(error, 0);
+
+    // Test truncate from file size + 3 to file size - 3 
+    for (i = 0; i < 6; i++) {
+        trunc_size = f_size + 3 - i;    
+        tw(tr(TR_FUNC, TrTestLow, "TRUNC file to size %d \n", trunc_size));
+        error = tffs_ftruncate(fdi, trunc_size);
+        expect(error, EFFS_OK);
+        error = tffs_lstat(fname, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, (f_size < trunc_size ? f_size : trunc_size));
+    }
+    
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread(fname, bigbuf, f_size);
+    expect(size, trunc_size);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+    
+    // We need to test ftruncate with a size less than the first chunk
+    fdi = tffs_open(fname, FFS_O_WRONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    
+    error = tffs_ftruncate(fdi, 10);
+    expect(error, EFFS_OK);
+    error = tffs_ftruncate(fdi, 10);  // same size twice to complicate it
+    expect(error, EFFS_OK);
+    error = tffs_lstat(fname, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.size, 10);
+    error = tffs_ftruncate(fdi, 0);
+    expect(error, EFFS_OK);
+    error = tffs_ftruncate(fdi, 0);
+    expect(error, EFFS_OK);
+    error = tffs_lstat(fname, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.size, 0);
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    // Stream file test, make 2 segments and test around the end of segment
+    // 1 (file closed)
+    fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC  
+                    | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max + 1);
+    expect(size, fs.chunk_size_max + 1);
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 31);
+    expect(size, 31);
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    f_size = fs.chunk_size_max + 1 + 31;
+
+    for (i = 0; i < 6; i++) {
+        trunc_size = fs.chunk_size_max + 1 + 3 - i;
+        tw(tr(TR_FUNC, TrTestLow, "TRUNC stream to size %d \n", trunc_size));
+        error = tffs_truncate(sname, trunc_size);
+        expect(error, EFFS_OK);
+        error = tffs_lstat(sname, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, trunc_size);
+    }
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread(sname, bigbuf, f_size);
+    expect(size, trunc_size);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+
+    // Try to enlarge the file.
+    tw(tr(TR_FUNC, TrTestLow, "Try to enlarge the file \n"));    
+    error = tffs_truncate(sname, trunc_size + 1);
+    expect(error, EFFS_OK);
+    error = tffs_lstat(sname, &stat);
+    expect(error, EFFS_OK);
+    expect_eq(stat.size, trunc_size);
+
+    fdi = tffs_open(sname, FFS_O_WRONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    error = tffs_ftruncate(fdi, trunc_size + 1);
+    expect(error, EFFS_OK);
+    error = tffs_lstat(sname, &stat); 
+    expect(error, EFFS_OK);
+    expect_eq(stat.size, trunc_size);
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    // Make a file with 2 segments + some data in the buffer, test around
+    // end of segment 2 and the begining of segment 1 (file open).
+    tw(tr(TR_FUNC, TrTestLow, "Truncate stream while it is open \n"));
+    // Make segment 1
+    fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_APPEND | FFS_O_TRUNC);
+    expect(fdi, FFS_FD_OFFSET);
+    f_size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 
+                        2 * fs.chunk_size_max + 1);
+    expect(f_size, 2 * fs.chunk_size_max + 1);
+    
+    // Move fp otherwise it will not be possible to truncate
+    error = ffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(error, 0);
+
+    // Test around end of segment 2
+    for (i = 0; i < 16; i++) {
+        trunc_size = f_size + 3 - i;
+        tw(tr(TR_FUNC, TrTestLow, "TRUNC stream to size %d \n", 
+              trunc_size));
+        error = tffs_ftruncate(fdi, trunc_size);
+        expect(error, EFFS_OK);
+        error = tffs_lstat(sname, &stat); expect(error, EFFS_OK);
+        expect_eq(stat.size, (f_size < trunc_size ? f_size : trunc_size));
+    }
+
+    // Test around begining of segment 1
+    for (i = 0; i < 6; i++) {
+        trunc_size = 3 - i;
+        tw(tr(TR_FUNC, TrTestLow, "TRUNC stream to size %d \n", 
+              trunc_size));
+        error = tffs_ftruncate(fdi, trunc_size);
+        if (trunc_size >= 0) {
+            expect(error, EFFS_OK);
+        }
+        else {
+            expect(error, EFFS_INVALID);
+            break;
+        }
+        error = tffs_lstat(sname, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, (trunc_size));
+    }
+
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    // Make, truncate and append to a file (use ffs_ftruncate()) 
+    fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC  
+                    | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+
+    f_size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max);
+    expect(f_size, fs.chunk_size_max );
+    
+    tw(tr(TR_FUNC, TrTestLow, "write 1/2 buf size, trunc 1/4 buf size\n"));
+    // write 1/2 buf size and truncate 1/4 buf size x times
+    for (i = 0; i < 8; i++) {
+        size = tffs_write(fdi, (char *) &tdata[TDATA_HUGE][f_size], 
+                          fs.chunk_size_max / 2);
+        if (size < 0) return size;
+        f_size += size;
+        size = tffs_seek(fdi, - fs.chunk_size_max / 4, FFS_SEEK_CUR);
+        expect(size, f_size - fs.chunk_size_max / 4);
+
+        error = tffs_ftruncate(fdi, f_size - fs.chunk_size_max / 4);
+        expect(error, EFFS_OK);
+        f_size -= fs.chunk_size_max / 4;
+        
+        error = tffs_lstat(sname, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, f_size);
+    }
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+    
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread(sname, bigbuf, bigbuf_size);
+    expect(size, f_size);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size);
+    if (error) return 1;
+
+    // backwards trunc 1/2 write 1/4 x times
+    tw(tr(TR_FUNC, TrTestLow, "trunc 1/2 buf size, write 1/4 buf size\n"));
+    fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+
+    for (i = 0; i < 8; i++) {
+        size = tffs_seek(fdi, - fs.chunk_size_max / 2, FFS_SEEK_CUR);
+        expect(size, f_size - fs.chunk_size_max / 2);
+
+        error = tffs_ftruncate(fdi, f_size - fs.chunk_size_max / 2);
+        expect(error, EFFS_OK);
+        f_size -= fs.chunk_size_max / 2;
+        
+        f_size += tffs_write(fdi, (char *) &tdata[TDATA_HUGE][f_size], 
+                             fs.chunk_size_max / 4);
+        error = tffs_lstat(sname, &stat);
+        expect(error, EFFS_OK);
+        expect_eq(stat.size, f_size);
+    }
+    
+    if (p0) { error = test_run("irec"); if (error > 0) return 1; }
+    
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+    
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread(sname, bigbuf, bigbuf_size);
+    expect(size, f_size);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size);
+    if (error) return 1;
+
+    tw(tr(TR_FUNC, TrTestLow, "Make 2 segments, truncate to zero and append\n"));
+    fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC  
+                    | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+    size = tffs_write(fdi, (char*) tdata[TDATA_HUGE], 2 * fs.chunk_size_max + 10);
+    expect(size, 2 * fs.chunk_size_max + 10);
+    
+    // Move fp otherwise it will not be possible to truncate
+    error = ffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(error, 0);
+
+    error = tffs_ftruncate(fdi, 0);
+    expect(error, EFFS_OK);
+    
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 150);
+    expect(size, 150 );
+
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    if (p0) { error = test_run("irec;brec"); if (error > 0) return 1; }
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    f_size = tffs_fread(sname, bigbuf, bigbuf_size);
+    expect(f_size, size);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size);
+    if (error) return 1;
+    
+    // Truncate through a symlink
+    error = tffs_symlink("/str", sname); 
+    expect(error, EFFS_OK);
+    error = tffs_truncate("/str", 100);
+    expect(error, EFFS_OK);
+    f_size = tffs_fread(sname, bigbuf, bigbuf_size);
+    expect(f_size, 100);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, f_size);
+    if (error) return 1;
+    tffs_remove("/str");
+
+    // truncate a file which only have data in the stream buffer
+    fdi = tffs_open(sname, FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC  
+                    | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);
+
+    f_size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], 3);
+    expect(f_size, 3);
+
+    // Move fp otherwise it will not be possible to truncate
+    error = ffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(error, 0);
+    
+    tw(tr(TR_FUNC, TrTestLow, "Truncate in buffer\n"));
+    for (i = 0; i < 4; i++) {
+        error = tffs_ftruncate(fdi, --f_size);
+        if (f_size >= 0) { 
+            expect(error, EFFS_OK);
+        
+            error = tffs_lstat(sname, &stat);
+            expect(error, EFFS_OK);
+            expect_eq(stat.size, f_size); 
+        }
+        else {
+            expect(error, EFFS_INVALID);
+        }
+    }
+    error = tffs_close(fdi);
+    expect(error, EFFS_OK);     
+
+    // Try to truncate a read-only file
+    error = tffs_fwrite(imeifile, TDATA(0));
+    // The file is maybe already created!
+    error = tffs_fcontrol(imeifile, OC_FLAGS, OF_READONLY);
+    error = tffs_truncate(imeifile, 0);
+    expect(error, EFFS_ACCESS);
+        
+    // Use ffs_truncate() on a file open in read mode
+    fdi = tffs_open(fname, FFS_O_RDONLY);
+    error = tffs_truncate(fname, 0);
+    expect(error, EFFS_LOCKED);
+    error = tffs_ftruncate(fdi, 0);
+    expect(error, EFFS_INVALID);
+    error = tffs_close(fdi);
+    expect_ok(error);
+
+    return 0;
+}
+
+
+int case_append(int p0, int p1)
+{
+    fd_t fdi;
+    int size, fsize;
+    char sname[] = "/stream/append1";
+    char fname[] = "/stream/append2";
+    int offset = 0; 
+  
+    if (param.data_blocks <= 1) {
+        ttw(ttr(TTrTest, "WARNING: Too few blocks to run. Skip test" NL));
+        tw(tr(TR_FUNC, TrTest, "WARNING: Too few blocks to run. Skip test\n"));
+        return 0;
+    }
+ 
+    case_cleanup(fs.chunk_size_max * 5);
+ 
+    tffs_mkdir("/stream");
+ 
+    fdi = tffs_open(sname, FFS_O_RDWR | FFS_O_APPEND | FFS_O_TRUNC | 
+                    FFS_O_CREATE);
+    expect(fdi, FFS_FD_OFFSET);    
+
+    // Write data in buf and seek in the buf
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE], fs.chunk_size_max / 2);
+    expect_gt(size, 0);
+
+    offset = ffs_seek(fdi, -fs.chunk_size_max / 4, FFS_SEEK_CUR);
+    expect_gt(offset, 0);
+    expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty); 
+
+    // Append data and seek in the buffer ad the end of the last chunk
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + 
+                      fs.fd[fdi - FFS_FD_OFFSET].size, fs.chunk_size_max);
+    expect_gt(size, 0);
+    
+    offset = ffs_seek(fdi, -fs.chunk_size_max / 4, FFS_SEEK_END);
+    expect_gt(offset, 0);
+
+    size = tffs_read(fdi, bigbuf, fs.chunk_size_max / 4);
+    expect(size, fs.chunk_size_max / 4);
+    expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty);
+
+    // Append data and seek away from buf 
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + 
+                      fs.fd[fdi - FFS_FD_OFFSET].size, fs.chunk_size_max * 1.5);
+    expect_gt(size, 0);
+    
+    offset = ffs_seek(fdi, -fs.chunk_size_max * 2, FFS_SEEK_END);
+    expect_gt(offset, 0);
+
+    size = tffs_read(fdi, bigbuf, fs.chunk_size_max / 4);
+    expect(size, fs.chunk_size_max / 4);
+
+    // Append again and validate the data
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + 
+                      fs.fd[fdi - FFS_FD_OFFSET].size, fs.chunk_size_max / 2);
+    expect_gt(size, 0);
+
+    offset = ffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(0, offset);
+
+    size = tffs_read(fdi, bigbuf, fs.fd[fdi - FFS_FD_OFFSET].size);
+    expect_gt(size, 0);
+
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+
+    error = tffs_close(fdi);
+    expect_ok(error);
+
+    // Append on a file with data in the seghead
+    fsize = fs.chunk_size_max / 4;
+    error = tffs_file_write(fname, (char *)tdata[TDATA_HUGE], fsize, 
+                            FFS_O_TRUNC | FFS_O_WRONLY | FFS_O_CREATE);
+    expect(error, EFFS_OK);
+    
+    fdi = tffs_open(fname, FFS_O_RDWR | FFS_O_APPEND);
+    expect(fdi, FFS_FD_OFFSET);    
+
+    // Write data in buf and seek in the buf
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + fsize, 
+                      fs.chunk_size_max / 2);
+    expect_gt(size, 0);
+    fsize += size;
+
+    offset = ffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect(offset, 0);
+    expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty); 
+
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + fsize, 
+                      fs.chunk_size_max / 2);
+    expect_gt(size, 0);
+    fsize += size;
+
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, fsize);
+    if (error) return 1;
+
+    error = tffs_close(fdi);
+    expect_ok(error);
+
+    return 0;
+}
+
+int case_datasync(int p0, int p1)
+{
+    fd_t fdi;
+    int size, fsize, offset, i;
+    char myname[] = "/datasync"; 
+   
+    error = case_cleanup(4 * fs.chunk_size_max);
+    expect_ok(error);
+
+    fdi = tffs_open(myname, FFS_O_RDWR | FFS_O_TRUNC | FFS_O_CREATE);
+    expect(fdi, FFS_FD_OFFSET);    
+
+    fsize = 0;
+    for (i = 0; i < 10; i++) {
+        // Write data in buf and use datasync
+        size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + fsize, 
+                          fs.chunk_size_max / 3);
+        expect_gt(size, 0);
+        fsize += size; 
+
+        error = tffs_fdatasync(fdi);
+        expect(error, EFFS_OK);
+        expect(0, fs.fd[fdi - FFS_FD_OFFSET].dirty);
+    }
+
+    error = tffs_fdatasync(fdi + 1);
+    expect(error, EFFS_BADFD);
+  
+    // Seek to chunk 2, write data, seek, use fdatasync
+    offset = tffs_seek(fdi, fs.chunk_size_max * 2.5, FFS_SEEK_SET);
+    expect_gt(offset, 0);
+   
+    size = tffs_write(fdi, (char *) tdata[TDATA_HUGE] + offset, 
+                      fs.chunk_size_max / 4);
+    expect_gt(size, 0);
+    
+    offset = tffs_seek(fdi, -fs.chunk_size_max / 2, FFS_SEEK_CUR);
+    expect_gt(offset, 0);
+
+    error = tffs_fdatasync(fdi);
+    expect(error, EFFS_OK);
+    expect(0, fs.fd[fdi - FFS_FD_OFFSET].dirty);
+
+    error = tffs_close(fdi);
+    expect_ok(error);
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread(myname, bigbuf, fsize);
+    tw(tr(TR_FUNC, TrTestLow, "size: %d fsize: %d \n", size, fsize));    
+    expect(size, fsize);
+    error = test_expect_data((char *)tdata[TDATA_HUGE], bigbuf, size);
+    if (error) return 1;
+
+    return 0;
+}
+
+int case_fw_flags(int p0, int p1)
+{       
+    int i;
+    char myname[] = "/file_write";
+
+    tffs_remove(myname);
+
+    tw(tr(TR_FUNC, TrTestHigh, "Test ffs_file_write() flags, file non-exist\n"));
+    for (i = 0; i < 0xFE; i++) {
+        error = tffs_file_write(myname, 0,0, i);
+
+        if (is_open_option(i, FFS_O_CREATE)) {
+            expect_ok(error);
+            error = tffs_remove(myname);
+            expect_ok(error);
+        }
+        else 
+            expect(EFFS_NOTFOUND, error);
+    }
+
+    tw(tr(TR_FUNC, TrTestHigh, "Test ffs_file_write() flags, file exist\n"));
+    error = tffs_file_write(myname, 0,0, FFS_O_CREATE);
+    expect_ok(error);
+
+    for (i = 0; i < 0xFF; i++) {
+        error = tffs_file_write(myname, 0,0, i);
+
+        if (is_open_option(i, FFS_O_EXCL) && is_open_option(i, FFS_O_CREATE)) {
+            expect(error, EFFS_EXISTS);
+        }
+
+        else 
+            expect_ok(error);
+    }
+
+    return 0;    
+}
+
+
+drv_Return_Type pcm_init(void);
+
+int case_pcm(int p0, int p1)
+{       
+    UBYTE version;
+    UBYTE imei[] = "12345678";
+    int size;
+
+    ffs_mkdir("/pcm");
+
+// Write imei file to ffs. Run init (this reads the imei file), remove
+// the file from flash, write the imei to flash from pcm and validate
+// data.
+    error = ffs_file_write("/pcm/IMEI", &imei, sizeof(imei), FFS_O_CREATE);
+    expect_ok(error);
+
+    error = pcm_init();
+    expect(PCM_INITIALIZED, error);
+
+    error = pcm_ReadFile((UBYTE *) EF_IMEI_ID, SIZE_EF_IMEI, imei, &version); 
+    expect(PCM_OK, error);
+
+    error = ffs_remove("/pcm/IMEI");
+    expect_ok(error);
+
+    error =  pcm_WriteFile((UBYTE *) EF_IMEI_ID, SIZE_EF_IMEI, imei);
+    expect(PCM_OK, error);
+
+    tw(tr(TR_FUNC, TrTestLow, "Validate data \n"));    
+    size = tffs_fread("/pcm/IMEI", bigbuf, bigbuf_size);
+    expect(size, SIZE_EF_IMEI);
+    error = test_expect_data(imei, bigbuf, size);
+    if (error) return 1;
+
+// TODO: test pcm_WriteRecord and pcm_ReadRecord.
+    return 0;    
+}
+
+
+int case_api_exceptions(int p0, int p1)
+{       
+    int i;
+    T_FFS_DIR dir;
+    T_FFS_FD myfdi;
+    char myname[] = "/BAD";
+    char mydir[] = "/tdir";
+    char mylink[] = "/tlink";
+    char mytfile[] = "/tfile";
+    char buf[] = "foobar";
+
+    // Create test file and dir
+    error = tffs_file_write(mytfile, buf, sizeof(buf), FFS_O_CREATE);
+    expect_ok(error);
+ 
+    error = tffs_mkdir(mydir);
+    if (error < 0 && error != EFFS_EXISTS) return 1;
+
+    error = tffs_symlink(mytfile, mylink);
+    if (error < 0 && error != EFFS_EXISTS) return 1;
+
+    error = tffs_opendir(mydir, &dir);
+    expect_ok(error);
+
+    myfdi = tffs_open("/tsream", FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC);
+    expect(myfdi, FFS_FD_OFFSET);
+
+    expect(tffs_write(myfdi, buf, sizeof(buf)), sizeof(buf));
+
+    // Test all API functions for pathname with null pointers.  
+    for (i = 0; i < 17; i++) {
+        switch (i) {
+        case 0: error = tffs_open(0, FFS_O_WRONLY | FFS_O_CREATE); break;
+        case 1: error = tffs_truncate(0, 1);    break;
+        case 2: error = tffs_file_write(0, buf, sizeof(buf), FFS_O_CREATE); break;
+        case 3: error = tffs_stat(0, &stat);    break;
+        case 4: error = tffs_lstat(0, &stat);   break;
+        case 5: error = tffs_xlstat(0, &xstat); break;
+        case 6: error = tffs_remove(0);         break;
+        case 7: error = tffs_mkdir(0);          break;
+        case 8: error = tffs_opendir(0, &dir);  break;
+        case 9: error = tffs_symlink(0, myname); break;
+        case 10: error = tffs_symlink("/link", 0); break;
+        case 11: error = tffs_readlink(0, buf, sizeof(buf)); break;
+        case 12: error = tffs_rename(0, "/test"); break;
+        case 13: error = tffs_rename(mytfile, 0); break;
+        case 14: error = tffs_file_write(0, buf, sizeof(buf), FFS_O_CREATE); break;
+        case 15: error = tffs_file_read(0, buf, sizeof(buf)); break;
+        case 16: error = tffs_fcontrol(0, OC_FLAGS, OF_READONLY); break;
+        default: error = EFFS_INVALID;
+        }
+        expect(error, EFFS_BADNAME);
+    }
+
+    // Test all API functions with buffer null pointers.  
+    for (i = 0; i < 13; i++) {
+        switch (i) {
+        case 0: error = tffs_file_write(myname, 0, 100, FFS_O_CREATE); break;
+        case 1: error = tffs_file_read(mytfile, 0, 40); break;
+        case 2: error = tffs_opendir(mydir, 0); break;
+        case 3: error = ffs_readdir (0, buf, sizeof(buf)); break;
+        case 4: error = ffs_readdir (&dir, 0, 100); break;
+        case 5: error = tffs_readlink(mylink, 0, 1); break;
+        case 6: error = tffs_stat(mytfile, 0); break;
+        case 7: error = tffs_lstat(mylink, 0); break;
+        case 8: error = tffs_xlstat(mylink, 0); break;
+        case 9: error = tffs_query(Q_BYTES_FREE, 0); break;
+        case 10: error = tffs_fstat(myfdi, 0); break;
+        case 11: error = tffs_write(myfdi, 0, 10); break;
+        case 12: error = tffs_read(myfdi, 0, 40); break;
+        default: error = 0;
+        }
+        expect(error, EFFS_INVALID);
+    }
+    expect_ok(tffs_close(myfdi));
+
+    // Make sure we still can create empty files!
+    error = tffs_file_write("/empty_file", 0, 0, FFS_O_CREATE);
+    expect_ok(error);
+
+    // Open file for test of negative size
+    myfdi = tffs_open(myname, FFS_O_RDWR | FFS_O_CREATE | 
+                    FFS_O_TRUNC | FFS_O_APPEND);
+    expect(myfdi, FFS_FD_OFFSET);
+
+    // Test all API 'size' parameters with a negative size
+    for (i = 0; i < 11; i++) {
+        switch (i) {
+            // Try modify
+        case 0: error = tffs_write(myfdi, buf, -1); break;
+        case 1: error = tffs_truncate(myname, -1); break;
+        case 2: error = tffs_fwrite(myname, buf, -2); break;
+        case 3: error = tffs_fcreate(myname, buf, -3); break;
+        case 4: error = tffs_fupdate(myname, buf, -56); break;
+        case 5: error = tffs_file_write(myname, buf, -100, FFS_O_CREATE); break;
+        // Try read
+        case 6: error = tffs_fread(mytfile, bigbuf, -1); break;
+        case 7: error = tffs_file_read(mytfile, bigbuf, -2); break;
+        case 8: error = tffs_readdir(&dir, bigbuf, -3); break;
+        case 9: error = tffs_readlink(mytfile, bigbuf, -4); break;
+        case 10: error = tffs_read(myfdi, bigbuf, -5); break;
+        default: error = 0;
+        }
+        expect(error, EFFS_INVALID);
+    }
+
+    error = tffs_close(myfdi);
+    expect_ok(error);
+
+    return EFFS_OK;
+}
+
+int case_api_notformated(int p0, int p1)
+{
+    int i;
+    struct dir_s dir;
+    fd_t fdi;
+    char buf[20];
+    uint16 q_out;
+    struct xstat_s xstat;
+
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+
+    for(i=1; i<24; i++)
+    {
+        switch(i)
+        {
+        case 1:  error = tffs_open("apinf", FFS_O_WRONLY);          break;
+        case 2:  error = tffs_close(fdi);                         break;
+        case 3:  error = tffs_write(fdi, "abcdefghij", 10);       break;
+        case 4:  error = tffs_read(fdi, buf, 2);                  break;
+        case 5:  error = tffs_seek(fdi, 0, FFS_SEEK_SET);         break;
+        case 6:  error = tffs_truncate("apinf", 0);                 break;
+        case 7:  error = tffs_fdatasync(fdi);                     break;
+        case 8:  error = tffs_stat("apinf", &stat);                 break;
+        case 9:  error = tffs_fstat(fdi, &stat);                  break;
+        case 10: error = tffs_lstat("apinf", &stat);                break;
+        case 11: error = tffs_xlstat("apinf", &xstat);              break;
+        case 12: error = ffs_remove("/apinf");                      break;
+        case 13: error = ffs_mkdir("/apinf");                       break;
+        case 14: error = ffs_opendir("/apinf", &dir);               break;
+        case 15: error = tffs_readdir(&dir, "/ffs", 21);          break;
+        case 16: error = tffs_symlink("/europe/imie", "imei");    break;
+        case 17: error = ffs_rename("/Pluto", "/Dog");            break;
+        case 18: error = ffs_file_write("/non-exist", "1234567890", 10, FFS_O_TRUNC);          break;
+        case 19: error = tffs_file_read("/stream1", buf, 10);     break;
+        case 20: error = tffs_fcreate("/", "apinf", 3);             break;
+        case 21: error = tffs_fupdate("/", "bar", 3);             break;
+        case 22: error = tffs_fwrite("/europe/imie","0123456789", 10);          break;
+        case 23: error = tffs_fcontrol("/apinf", OC_FLAGS, OF_READONLY);          break;
+      }
+
+      expect(error, EFFS_NOFORMAT);
+
+    }
+    /* query must return information even if the device isnt formated */
+    error = tffs_query(Q_FS_INODES, (uint16 *) &q_out);
+    expect(error, EFFS_OK);
+
+    return 0;
+}
+
+int case_query(int p0, int p1)
+{
+    int i;
+    uint32 ret_val32;
+    uint16 ret_val16;
+
+    for(i=1; i<27; i++)
+    {
+      switch(i)
+      {
+        case 1:  error = ffs_query(Q_TM_BUFADDR, (uint32 *)&ret_val32); break;
+        case 2:  error = ffs_query(Q_TM_BUFSIZE, (uint32 *)&ret_val32); break;
+        case 3:  error = ffs_query(Q_DEV_BASE, (uint32 *)&ret_val32); break;
+        case 4:  error = ffs_query(Q_FFS_API_VERSION, (uint16 *)&ret_val16); break;
+        case 5:  error = ffs_query(Q_FFS_DRV_VERSION, (uint16 *)&ret_val16); break;
+        case 6:  error = ffs_query(Q_FFS_REVISION, (uint16 *)&ret_val16); break;
+        case 7:  error = ffs_query(Q_FFS_FORMAT_WRITE, (uint16 *)&ret_val16); break;
+        case 8:  error = ffs_query(Q_FFS_FORMAT_READ, (uint16 *)&ret_val16); break;
+        case 9:  error = ffs_query(Q_FFS_LASTERROR, (uint16 *)&ret_val16); break;
+        case 10:  error = ffs_query(Q_FFS_TM_VERSION, (uint16 *)&ret_val16); break;
+        case 11:  error = ffs_query(Q_OBJECTS_MAX, (uint16 *)&ret_val16); break;
+        case 12:  error = ffs_query(Q_CHUNK_SIZE_MAX, (uint16 *)&ret_val16); break;
+        case 13:  error = ffs_query(Q_FD_BUF_SIZE, (uint32 *)&ret_val32); break;
+        case 14:  error = ffs_query(Q_FD_MAX, (uint16 *)&ret_val16); break;
+        case 15:  error = ffs_query(Q_DEV_MANUFACTURER, (uint16 *)&ret_val16); break;
+        case 16:  error = ffs_query(Q_DEV_DEVICE, (uint16 *)&ret_val16); break;
+        case 17:  error = ffs_query(Q_DEV_DRIVER, (uint16 *)&ret_val16); break;
+        case 18:  error = ffs_query(Q_LOST_HIGH, (uint16 *)&ret_val16); break;
+        case 19:  error = ffs_query(Q_FS_FLAGS, (uint16 *)&ret_val16); break;
+        case 20:  error = ffs_query(Q_FS_ROOT, (uint16 *)&ret_val16); break;
+        case 21:  error = ffs_query(Q_STATS_DRECLAIMS, (uint32 *)&ret_val32); break;
+        case 22:  error = ffs_query(Q_STATS_IRECLAIMS, (uint32 *)&ret_val32); break;
+        case 23:  error = ffs_query(Q_STATS_DATA_RECLAIMED, (uint32 *)&ret_val32); break;
+        case 24:  error = ffs_query(Q_STATS_INODES_RECLAIMED, (uint32 *)&ret_val32); break;
+        case 25:  error = ffs_query(Q_STATS_DATA_ALLOCATED, (uint32 *)&ret_val32); break;
+        case 26:  error = ffs_query(Q_REQUEST_ID_LAST, (uint32 *)&ret_val32); break;
+      }
+
+      expect(error, EFFS_OK);
+
+    }
+
+    return 0;
+}
+
+extern uint16 ffs_flash_device;
+extern uint16 ffs_flash_manufact;
+
+int case_octrl(int p0, int p1)
+{
+    int org_fsflags = fs.flags, org_manufact = ffs_flash_manufact;
+    int org_device = ffs_flash_device, org_testf = fs.testflags;
+
+    error = object_control(0, OC_FS_FLAGS, 0x02);
+    expect(error, EFFS_OK);
+    error = object_control(0, OC_DEV_MANUFACT, 'T');
+    expect(error, EFFS_OK);
+    error = object_control(0, OC_DEV_DEVICE, 0x0F12);
+    expect(error, EFFS_OK);
+    error = object_control(0, OC_DEBUG_0, 0xAFFE);
+    expect(error, EFFS_OK);
+
+    error = object_control(0, OC_DEBUG_LAST+1, 0);
+    expect(error, EFFS_INVALID);
+
+    // Restore the values or else it mess up the other tests
+    fs.flags = org_fsflags;
+    fs.testflags = org_testf;
+    ffs_flash_manufact = org_manufact;
+    ffs_flash_device = org_device;
+
+    return 0;
+}
+
+/***************************************************************************/
+/*          Examples from RIV111                                           */
+/***************************************************************************/
+#if (TARGET == 0)
+int case_examples(int p0, int p1)
+{
+    return 0;
+}
+#else
+
+static req_id_t my_request_id;
+static int removed_greeting;
+
+static void my_callback(T_FFS_FILE_CNF *confirm)
+{
+    ttw(ttr(TTrTest, "my_callback(%d, %s, %d)" NL, 
+            confirm->error, confirm->path, confirm->request_id));
+    
+    if (my_request_id !=  confirm->request_id) {
+        ttw(ttr(TTrFatal, "error (%d, %d)" NL, confirm->request_id, my_request_id));
+        return;
+    }
+
+    if (confirm->error < 0) {
+        ttw(ttr(TTrTest, "FATAL: my_callback error: %d" NL, confirm->error));
+    }
+    else {
+        ttw(ttr(TTrTest, "Remove 'greeting'" NL));
+        ffs_remove_nb("/greeting", 0);
+        removed_greeting = 1;
+    }
+
+    error = rvf_free_buf(confirm);
+    if (error < 0)
+        ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error);
+}
+
+// Using Function Callback
+T_RV_RETURN my_fc_cnfpath = {0, (CALLBACK_FUNC)my_callback};
+
+// Using Mail Callback
+#define MY_TASK_ID (MAX_RVF_TASKS - 1 - 1)  // same as FFS_TEST_TASK_ID
+T_RV_RETURN my_mail_cnfpath = {MY_TASK_ID, 0};
+
+int case_examples(int p0, int p1)
+{
+    if(1) {
+        // MMI Configuration scenario
+        struct {
+            int volume;
+            uint32 ringtype;
+        } mmi;
+    
+        int temp;
+        ttw(ttr(TTrTest, "Run MMI conf." NL));
+        mmi.volume = temp = 3;
+        mmi.ringtype = 1111;
+        ffs_mkdir("/mmi");
+        ffs_fwrite("/mmi/volume", &mmi.volume, sizeof(mmi.volume));
+        error = ffs_file_read("/mmi/volume", &mmi.volume, sizeof(mmi.volume));
+        if (error < 0)
+            return 1;    
+        error = test_expect_data(&temp, &mmi.volume, sizeof(mmi.volume));
+        if (error < 0)
+            return 1;
+    }
+
+    if(1) {
+        // Using Mail Callback
+        T_FFS_FILE_CNF *confirm_file;
+        T_FFS_STREAM_CNF *confirm_stream;
+        T_FFS_RET error;
+        T_FFS_FD fdi;
+        char hello[] = "Hello, world";
+        T_FFS_SIZE size;
+
+        ttw(ttr(TTrTest, "Use Mail Callback" NL));
+        if ((my_request_id = ffs_open_nb("/mmi/sound", 
+                                         FFS_O_WRONLY | FFS_O_CREATE | 
+                                         FFS_O_APPEND | FFS_O_TRUNC, 
+                                         &my_mail_cnfpath)) < 0)
+            return my_request_id;
+        
+        ttw(ttr(TTrTest, "Wait..." NL));
+        rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0);
+
+        ttw(ttr(TTrTest, "Get mail" NL));
+        confirm_file = (T_FFS_FILE_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0);
+
+        fdi = confirm_file->error;
+        expect(FFS_FD_OFFSET, fdi);
+        expect(my_request_id, confirm_file->request_id);
+        expect(FFS_MESSAGE_OFFSET, confirm_file->header.msg_id);
+        ttw(ttr(TTrTest, "Path '%s'" NL, confirm_file->path));
+
+        error = rvf_free_buf(confirm_file);
+        if (error < 0)
+            ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error);
+
+        if ((my_request_id = ffs_write_nb(fdi, hello, strlen(hello) ,
+                                          &my_mail_cnfpath)) < 0)
+            return my_request_id;
+
+        ttw(ttr(TTrTest, "Wait..." NL));
+        rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0);
+
+        ttw(ttr(TTrTest, "Get mail" NL));
+        confirm_stream = (T_FFS_STREAM_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0);
+        size = confirm_stream->error;
+        expect(strlen(hello), size);
+        expect(my_request_id, confirm_stream->request_id);
+        ttw(ttr(TTrTest, "fdi: %d" NL, confirm_stream->fdi));
+        error = rvf_free_buf(confirm_stream);
+        if (error < 0)
+            ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error);
+        
+        ttw(ttr(TTrTest, "Close file" NL));
+        if ((error = ffs_close(fdi)) < 0)
+            return error;
+    }
+
+    if(1) {
+        // Using Function Callback
+        char hello[] = "Hello, world";
+        T_FFS_STAT stat;
+
+        ttw(ttr(TTrTest, "Use Function Callback" NL));
+
+        if ((my_request_id = ffs_fcreate_nb("/greeting", hello, strlen(hello), 
+                                            &my_fc_cnfpath)) < 0)
+            return my_request_id;
+
+// Wait until my_callback() has removed the file "greeting"
+        removed_greeting = 0;
+        while (removed_greeting == 0)
+            tffs_delay(10);
+// NOTE: This is importent because if the test brec runs immediately
+// after his one will the brec test fail because the "greeting" file
+// is removed inside the brec test which don't expect that files is
+// removed.
+    }
+
+    return 0;
+}
+#endif
+/******************************************************************************
+ * Non blocking test ffs_xx_nb()
+ ******************************************************************************/
+
+#if (TARGET == 0)
+int case_nonblock(int p0, int p1)
+{
+    tw(tr(TR_FUNC, TrTest, 
+          "WARNING: This test can only run in target. Skip test\n"));
+    return 0;
+}
+
+#else
+extern int request_id_last;  // from task.c
+
+#define WAIT_GET_TEST      ttw(ttr(TTrTest, "Wait..." NL)); rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0); ttw(ttr(TTrTest, "Get mail" NL)); confirm_file = (T_FFS_FILE_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0); ttw(ttr(TTrTest, "Path '%s'" NL, confirm_file->path)); expect(FFS_MESSAGE_OFFSET, confirm_file->header.msg_id); expect(my_id, confirm_file->request_id); 
+
+#define WAIT_GET_TEST_FDI  ttw(ttr(TTrTest, "Wait..." NL)); rvf_wait(RVF_TASK_MBOX_0_EVT_MASK, 0); confirm_stream = (T_FFS_STREAM_CNF *) rvf_read_mbox(RVF_TASK_MBOX_0); ttw(ttr(TTrTest, "Get mail" NL)); ttw(ttr(TTrTest, "fdi: %d" NL, confirm_stream->fdi)); expect(FFS_MESSAGE_OFFSET, confirm_stream->header.msg_id); expect(FFS_FD_OFFSET, confirm_stream->fdi); expect(my_id, confirm_stream->request_id);
+
+#define FREE error = rvf_free_buf(confirm_file); if (error < 0) { ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); return 1;}
+
+#define FREE_FDI error = rvf_free_buf(confirm_stream); if (error < 0) { ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error); return 1;}
+
+int case_nonblock(int p0, int p1)
+{
+    T_FFS_FILE_CNF *confirm_file;
+    T_FFS_STREAM_CNF *confirm_stream;
+    T_FFS_RET error;
+    T_FFS_FD fdi;
+    char hello[] = "Hello, world";
+    char myfname[] = "/non_block/file";
+    char mysname[] = "/non_block/stream";
+    T_FFS_SIZE size;
+    int i;
+    T_FFS_REQ_ID my_id;
+    // mail confirm
+    T_RV_RETURN cnfpath = {MY_TASK_ID, 0};
+
+    // Test wrap arround in request_id_get(). Set id to 5 from max, the following
+    // function calls will trigger the wrap arround
+    request_id_last = 0x7FFFFFFF - 5;
+    ttw(ttr(TTrTest, "request :%d" NL, request_id_last));
+
+    // preformat, format, mkdir 
+    // open, write, ftruncate, close, remove,
+    // file_write, symlink, rename, truncate, fcontrol
+
+    my_id = ffs_preformat_nb(0xDEAD, &cnfpath);
+    expect_gt(my_id, -1);
+    WAIT_GET_TEST; FREE;
+
+    my_id = ffs_format_nb("/ffs", 0x2BAD, &cnfpath);
+    expect_gt(my_id, -1);
+    WAIT_GET_TEST; FREE;
+
+    my_id = ffs_mkdir_nb("/non_block", &cnfpath);
+    expect_gt(my_id, -1);
+    WAIT_GET_TEST; FREE;
+
+    if ((my_id = ffs_open_nb(mysname, FFS_O_WRONLY | FFS_O_CREATE,  
+                             &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST;   
+    fdi = confirm_file->error;
+    expect(FFS_FD_OFFSET, fdi);
+    FREE;
+    
+    if ((my_id = ffs_write_nb(fdi, hello, strlen(hello), &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST_FDI; FREE_FDI;
+
+    expect(1, fs.fd[fdi - FFS_FD_OFFSET].dirty);
+    if ((my_id = ffs_fdatasync_nb(fdi, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST_FDI; FREE_FDI;
+    expect(0, fs.fd[fdi - FFS_FD_OFFSET].dirty);
+
+    if ((my_id = ffs_seek_nb(fdi, 2, FFS_SEEK_SET, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST_FDI; FREE_FDI;
+    expect(2, fs.fd[fdi - FFS_FD_OFFSET].fp);
+
+    if ((my_id = ffs_ftruncate_nb(fdi, 3, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST_FDI; 
+    expect(EFFS_OK, confirm_stream->error);
+    FREE_FDI;
+
+    if ((my_id = ffs_close_nb(fdi, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST_FDI; 
+    expect(EFFS_OK, confirm_stream->error);
+    FREE_FDI;
+
+    if ((my_id = ffs_remove_nb(mysname, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST; 
+    expect(EFFS_OK, confirm_file->error);
+    FREE;
+
+    if ((my_id = ffs_file_write_nb(myfname, hello, strlen(hello), 
+                                   FFS_O_WRONLY | FFS_O_CREATE, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST; 
+    expect(EFFS_OK, confirm_file->error);
+    FREE;
+
+    if ((my_id = ffs_symlink_nb("/nb_file", myfname, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST; 
+    expect(EFFS_OK, confirm_file->error);
+    FREE;
+
+    if ((my_id = ffs_rename_nb("/nb_file", "/nbf", &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST; 
+    expect(EFFS_OK, confirm_file->error);
+    FREE;
+
+    if ((my_id = ffs_truncate_nb(myfname, 0, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST; 
+    expect(EFFS_OK, confirm_file->error);
+    FREE;
+
+    if ((my_id = ffs_fcontrol_nb(myfname, OC_FLAGS, OF_READONLY, &cnfpath)) < 0)
+        return my_id;
+    WAIT_GET_TEST; 
+    expect(EFFS_OK, confirm_file->error);
+    FREE;
+
+    ttw(ttr(TTrTest, "request :%d" NL, request_id_last));
+
+    // This should make a EFFS_MEMORY fail
+    for(i = 0; i < 10000; i++) {
+        my_id = ffs_fwrite_nb("/mem_test", TDATA(0), 0);
+        if (my_id < 0)
+            break;
+    }
+    ttw(ttr(TTrTest, "write nr: %d my_id: %d" NL, i, my_id));
+    expect(my_id, EFFS_MEMORY);
+    // All memory has been used so wait a while (let some of the writes finish)
+    tffs_delay(50);
+    // Make a call to a blocking function will make it possible for ffs to
+    // finish all the non blocking writes.
+    error = ffs_fwrite("/mem_test", TDATA(0));
+    expect_ok(error);
+
+    return 0;
+}
+#endif
+
+/******************************************************************************
+ * Blocking test 
+ ******************************************************************************/
+
+#if (TARGET == 0)
+int case_blocking(int p0, int p1)
+{
+    tw(tr(TR_FUNC, TrTest, 
+          "WARNING: This test can only run in target. Skip test\n"));
+    return 0;
+}
+#else
+
+#include "ffs/board/task.h"
+void my_mb_callback(T_RVF_MB_ID id)
+{ // Dummy callback function 
+}
+
+
+// Test that a FFS API blocking call that not is able to send a mail to FFS fails as expected and don't lock the system (it must unlock and delete the mutex). 
+int case_blocking(int p0, int p1)
+{       
+    UINT32 mem_unused;
+    T_RVF_MB_STATUS status;
+    char *buf;
+    extern T_OS_MB_ID ffs_mb_id;
+
+    // Later when all the memory is used the memory bank will be marked as
+    // RED by Riviera. The RED flag is erased when the buffer is freed but
+    // only if a callback function is applied.
+    rvf_set_callback_func(ffs_mb_id, my_mb_callback);  // Ignore error
+
+    mem_unused = rvf_get_mb_unused_mem(ffs_mb_id);
+    ttw(ttr(TTrTest,"Unused memory: %d" NL, mem_unused));
+
+    // When all the memory is used the blocking functions will not be able
+    // to allocate memory to the FFS mail thus it must fail. After the
+    // buffer has been freed the block call must again be fully functional.
+    if ((buf = (char *) target_malloc(mem_unused)) == 0)
+        return EFFS_MEMORY;
+ 
+    error = tffs_fwrite("/blocking_test", (char*)tdata[TDATA_HUGE], 20);
+
+    target_free(buf);
+
+    expect(error, EFFS_MEMORY);
+
+    error = tffs_fwrite("/blocking_test", (char*)tdata[TDATA_HUGE], 20);
+    expect_ok(error);
+
+    return EFFS_OK;
+}
+#endif
+
+/******************************************************************************
+ * Test erase_suspend and erase_resume 
+ ******************************************************************************
+ * Test erase suspend and resume by making a call to ffs_begin() followed by
+ * an ffs_read() while we are erasing. We trigger the erase by sending
+ * several write mails to FFS. We let FFS get the CPU for less time than an
+ * erase, which will guarantee that we interrupt the erase when we call
+ * ffs_begin().
+ ******************************************************************************/
+#if (TARGET == 1)
+static int write_mails_left;
+
+static void driver_callback(T_FFS_FILE_CNF *confirm)
+{
+    if (confirm->error < 0) {
+        ttw(ttr(TTrTest, "FATAL: driver_callback error: %d" NL, confirm->error));
+    }
+
+    error = rvf_free_buf(confirm);
+    if (error < 0)
+        ttr(TTrFatal, "FFS FATAL: os_free() %d" NL, error);
+
+    write_mails_left--;
+}
+#endif
+
+#if (TARGET == 0) 
+int case_erase_suspend(int p0, int p1)
+{
+    tw(tr(TR_FUNC, TrTestHigh, "Erase_suspend test not supported on PC sim\n")); 
+    return 1;
+}
+#else
+// TEST erase_suspend and erase_resume
+int case_erase_suspend(int p0, int p1)
+{
+    int i, j, error, nsuspend;
+    char myname[] = "/ffs/b4";      // Run test with only 4 block.
+    char myfname[] = "/driver_test";
+    int file_size = 1024;
+
+    T_RV_RETURN cnfpath = {0, (CALLBACK_FUNC)driver_callback};
+
+    ttw(ttr(TTrTest, "Erase suspend-resume test" NL));
+
+// To minimize the numbers of required writes before we are guarantied an
+// erase we run this test in only 4 blocks
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format(myname, 0x2BAD);
+    expect(error, EFFS_OK);
+
+    if (p0 == 0) p0 = 1;
+    for (j = 0; j < p0; j++) {
+        write_mails_left = 0;
+// Write 2 blocks of data (must trigger an erase)
+        for (i = 0; i < 2 * (dev.blocksize/file_size); i++)  
+        {
+// Non blockin write
+            if ((error = ffs_file_write_nb(myfname, (char *) tdata[TDATA_HUGE], 
+                                           file_size, 
+                                           FFS_O_WRONLY | FFS_O_CREATE | FFS_O_TRUNC,
+                                           &cnfpath)) < 0)
+                return error;
+            write_mails_left++;
+        }
+        ttw(ttr(TTrTest, "Finish write calls(%d)" NL, i));
+
+// NOTE only tested with AMD MB driver
+        switch (dev.driver) {
+        case FFS_DRIVER_AMD:
+        case FFS_DRIVER_SST:
+        case FFS_DRIVER_INTEL:
+        case FFS_DRIVER_AMD_SB:
+            ttw(ttr(TTrTest, "Start read test" NL));
+            nsuspend = 0;
+            do {
+// NOTEME: We can also test if we get the CPU and not is delay
+// by the erase
+
+// This will change state to ERASE_SUSPEND if we are in
+// ERASE mode (only valid for MB driver)
+                error = ffs_begin();
+                expect(error, EFFS_OK);
+
+                if (dev.state == DEV_ERASE_SUSPEND) {
+                    nsuspend++;
+                    // Read... Note it will also resume the erase (MB driver).
+                    error = tffs_file_read(myfname, bigbuf, file_size/4);
+                    expect(error, EFFS_FILETOOBIG);
+                }
+                rvf_delay(5);  // Let FFS get the CPU for some time
+            } while (write_mails_left > 0);  
+
+            if (nsuspend <= 0) {
+                ttw(ttr(TTrTest, "Arg no erase suspend" NL));
+                return 1;
+            }
+            ttw(ttr(TTrTest, "Erase suspended %d times" NL, nsuspend));
+            break;
+
+        case FFS_DRIVER_SST_SB:
+        case FFS_DRIVER_INTEL_SB:
+        default:
+            ttw(ttr(TTrTest, "Driver not supported by this test" NL));
+            // Do not return before the cnfpath resource not is used anymore
+            while (write_mails_left > 0) rvf_delay(100);  
+            return 1;
+        }
+    }
+    return 0;
+}
+#endif // TARGET == 0
+
+/******************************************************************************
+ * The 3 below testh_.. function is helper function used for the low level
+ * driver tests.
+ ******************************************************************************/
+#if (TARGET == 1)
+
+uint32 int_disable(void);
+void int_enable(uint32 tmp);
+
+// Only start an erase, don't wait until it is finish 
+// Note to use this function with SB drivers require a multi bank flash device
+int testh_nb_erase(uint8 block)
+{
+    volatile char *flash = dev.base;
+    volatile char *addr;
+    uint32 cpsr;
+
+    ttw(ttr(TTrTest, "e(%d)" NL, block));
+
+    addr = block2addr(block);
+    cpsr = int_disable();
+    switch (dev.driver) {
+    case FFS_DRIVER_AMD:
+    case FFS_DRIVER_AMD_SB:
+    case FFS_DRIVER_AMD_PSEUDO_SB:
+        flash[0xAAAA] = 0xAA; // AMD unlock cycle 1
+        flash[0x5555] = 0x55; // AMD unlock cycle 2
+        flash[0xAAAA] = 0x80; 
+        flash[0xAAAA] = 0xAA; // AMD unlock cycle 1
+        flash[0x5555] = 0x55; // AMD unlock cycle 2
+        *addr         = 0x30; // AMD erase sector command
+        int_enable(cpsr);  
+        break;
+    default:
+        return -1; // Not yet supported
+    }
+    return 0;
+}
+
+// Note to use this function with SB drivers require a multi bank flash device
+int testh_erase_suspend(uint8 block)
+{
+    volatile char *flash = dev.base;
+    volatile char *addr;
+
+    ttw(ttr(TTrTest, "esusp(%d)" NL, block));
+
+    addr = block2addr(block);
+    switch (dev.driver) {
+    case FFS_DRIVER_AMD:
+    case FFS_DRIVER_AMD_SB:
+    case FFS_DRIVER_AMD_PSEUDO_SB:
+        *addr         = 0xB0; // AMD erase suspend command
+        break;
+    default:
+        return -1; // Not yet supported
+    }
+    return 0;
+}
+
+int testh_get_free_block(void)
+{
+    uint8 b;
+
+    for (b = 0; b < dev.numblocks; b++) 
+    {
+        if (is_block(b, BF_IS_FREE) || is_block(b, BF_IS_EMPTY))
+            return b;
+    }
+    return -1;
+}
+#endif // TARGET == 1
+
+// NOTEME: The below test have not been used in this FFS version
+// NOTEME: We don't have an AMD init function 
+/******************************************************************************
+ * Test drv.init (low level driver test)
+ ******************************************************************************
+ * Test drv.init by start an erase, call drv.init and make sure that the
+ * erase is finish after we return from drv.init.
+ *
+ * Test drv.init by start erase, suspend the erase and make sure that the
+ * erase is resumed and finish before we return from drv.init. The test is
+ * valid for both AMD SB and MB driver
+ ******************************************************************************/
+
+#if (TARGET == 0) 
+int case_drv_init(int p0, int p1)
+{
+    tw(tr(TR_FUNC, TrTestHigh, "drv_init test not supported on PC sim\n")); 
+    return 1;
+}
+#else
+int case_drv_init(int p0, int p1)
+{
+    volatile char *flash = dev.base;
+    volatile char *addr;
+    char myname[] = "/drv_init";
+    uint32 cpsr;
+    uint8 block;
+    int free_b, i, j, command;
+    enum command { ERASE, WRITE, READ };
+    char action[6][3] = 
+        { 
+            { WRITE, READ, ERASE },
+            { WRITE, ERASE, READ },
+            { READ, WRITE, ERASE },
+            { READ, ERASE, WRITE },
+            { ERASE, READ, WRITE },
+            { ERASE, WRITE, READ }
+        };
+
+    ttw(ttr(TTrTest, "Test ffsdrv.init()" NL));
+
+// Test drv.init 6 times there the flash is in erase mode and 6 times
+// there the flash is in erase suspend mode.
+    for (i = 0; i < 12; i++) 
+    {
+        free_b = testh_get_free_block();
+        expect_ok(free_b);
+
+        fs.debug[0] = 0;
+        fs.debug[1] = 0;
+
+// Start erase, run driver init.
+        error = testh_nb_erase(free_b);
+        expect_ok(error);
+        rvf_delay(20); // Make sure that the erase has started
+
+        if (i > 6) {
+            error = testh_erase_suspend(free_b);
+            expect_ok(error);
+            rvf_delay(20); // Make sure that the erase is suspended
+        }
+
+        error = ffsdrv.init();  // Call ffsdrv_init() instead? (inc. autodetect)
+        expect_ok(error);
+
+        if (i > 6) {
+            expect(fs.debug[0], 1);    // Test that the erase was resumed
+            expect_gt(fs.debug[1], 0); // Test what we did wait for erase to finish
+        }
+        else {
+            expect(fs.debug[0], 0);    // Erase not resumed
+            expect_gt(fs.debug[1], 0); // We did wait for an erase to finish
+        }
+
+// To test that any combination of erase, read or write can be
+// performed after drv.init do we make the test below. The first
+// complete drv.init test will be like this: Start an erase, call
+// drv.init(), write a file, read the file and erase a free block.
+        for (j = 0; j < 3; j++) {
+            if (i < 6)
+                command = action[i][j];
+            else
+                command =  action[i-6][j];
+            switch (command) {
+            case ERASE: 
+                free_b = testh_get_free_block();
+                expect_ok(free_b);
+                ffsdrv.erase(free_b);
+                break;
+            case READ: 
+                error = test_expect_file(myname, TDATA(2));
+                if (error) return 1;
+                break;
+            case WRITE:
+                error = tffs_fwrite(myname, TDATA(2));
+                expect(error, EFFS_OK);
+                break;
+            default:
+                return 1;  
+            }
+        }
+    }
+    return 0;
+}
+#endif 
+
+uint32 get_cpsr(void);
+
+// Test disable and enable of interrupt (Note only valid for MB drivers)
+int case_interrupt(int p0, int p1)
+{       
+    extern void int_enable(uint32 tmp);
+    extern uint32 int_disable(void);
+    uint32 cpsr;
+    int i;
+    uint32 xcpsr;
+
+    switch (dev.driver) {
+    case FFS_DRIVER_AMD:
+    case FFS_DRIVER_INTEL:
+		break;
+	default:
+		return 1; // Not supported
+	}
+
+    p0 *= 100;
+  
+    ttw(ttr(TTrTest, "Test interrupt code" NL));
+
+    for (i = 0; i < p0; i++) {
+        cpsr = int_disable();
+        xcpsr = get_cpsr();
+        if ((xcpsr & 0xC0) != 0xC0) {
+            ttw(ttr(TTrTest, "FATAL int not disablet!" NL));
+            return 1;
+        }
+        int_enable(cpsr);
+        xcpsr = get_cpsr();
+        if ((xcpsr & 0xC0) != 0) {
+            ttw(ttr(TTrTest, "FATAL int not enablet!" NL));
+            return 1;
+        }                
+        if ((i % 1000) == 0) 
+            ttw(ttr(TTrTest, "loop (%d)" NL, i));
+    }
+
+    return 0;    
+}
+
+
+/******************************************************************************
+ * Benchmarking
+ ******************************************************************************/
+// Below define only for PC compile
+#if (TARGET == 0)
+#define UINT32   int
+#define tffs_timer_begin() 0 
+#define tffs_timer_end(time) 5000 - time 
+#endif
+
+const struct results_s old_results[] = 
+{
+    { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
+    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+};
+
+// NOTEME: Bencmark_results() not finished.
+int bencmark_results(int manufact, int driver, int sample, 
+                     struct results_s *meas_res)
+{
+    switch(manufact) {
+    case MANUFACT_AMD:
+        switch(driver) {
+//        case FFS_DRIVER_AMD: 
+        case FFS_DRIVER_AMD_SB:
+        default: return 0;
+        }
+    case MANUFACT_FUJITSU:
+        switch(driver) {
+//        case FFS_DRIVER_AMD:
+        case FFS_DRIVER_AMD_SB:
+        default: return 0;
+        }
+    default: return 0;
+    }
+}
+
+// Benchmark write and read operation. Measure write throughput as kBps in
+// idle and loopback mode. Both for an empty ffs where we don't have to
+// reclaim blocks and for a full ffs where block reclaims/erasures affect
+// the overall throughput. For SB flash driver as well as for DB driver. For
+// files of size:16, 256, 4096, bytes.
+int case_bm_stream_rw(int p0, int p1)
+{
+#if (TARGET == 1)
+    UINT32 time_begin, elapsed, bytes_max;
+    char myname[] = "/Benchmark0";
+    int i, j, k, nm_files, file_size;
+    int size, write_size[] = {16, 256, 4096}; 
+    fd_t fdi;
+
+    //ttw(ttr(TTrTest, "RVF_POOL_0_SIZE: %d" NL, RVF_POOL_0_SIZE));
+
+    // 1 block is used for inodes, 1 have to be free, 1/4 is used for
+    // journal and 1/2 is used as a margin
+
+// FIXME: changed to 4.75 because the SW TCS2.1 dos make some files and
+// because of this is there not enough data space left to this test.
+// NOTEME: Instead of hardwire this value then query it
+    bytes_max = (dev.numblocks - 4.75) * dev.blocksize;
+    file_size = bytes_max / dev.numblocks;
+    ttw(ttr(TTrTest, "bytes_max: %d(- 2.75 block)" NL, bytes_max));
+
+    // Format, measure write of 16B.
+    // Format, measure write of 256B.
+    // Format, measure write of 4096B.
+
+    for (j = 0; j < 3; j++) {
+        ttw(ttr(TTrTest, "Format, measure write of %dB" NL, write_size[j])); 
+       
+        error = tffs_preformat(0xDEAD);
+        expect(error, EFFS_OK);
+        error = tffs_format("/foo", 0x2BAD);
+        expect(error, EFFS_OK);
+    
+        time_begin = tffs_timer_begin();
+        for (i = 0; i < dev.numblocks; i++) {
+            myname[10] = i + (i <= 9 ? '0': 'A' -10);
+   
+            fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE);
+            expect(fdi, FFS_FD_OFFSET);
+ 
+            size = 0;
+            do {
+                size += error = tffs_write(fdi, (char*)tdata[TDATA_HUGE], 
+                                           write_size[j]);
+                if (error < 0) {
+                    if (error == EFFS_NOSPACE) {
+                        ttw(ttr(TTrTest, "Aarg out of space" NL)); 
+                        bytes_max = size;
+                        break;
+                    }
+                    else
+                        expect_ok(error);
+                }
+            } while (size < file_size);
+         
+            error = tffs_close(fdi);
+            expect_ok(error);
+        }
+    
+        elapsed = tffs_timer_end(time_begin);
+// FFS has used the CPU for a long time so let the trace task get
+// the CPU for a while
+        tffs_delay(50);  
+        ttw(ttr(TTrTest, "Write %dBytes %d times in %dms, %dkBps" NL NL, 
+                write_size[j], file_size/write_size[j], elapsed, 
+                (bytes_max * 1000) / (elapsed * 1024)));
+    }
+
+
+    ttw(ttr(TTrTest, "Rm all files, measure write of 4kB" NL)); 
+    for (i = 0; i < dev.numblocks; i++) {
+        myname[10] = i + (i <= 9 ? '0': 'A' -10);
+        error = tffs_remove(myname);
+        expect_ok(error);
+    }
+
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < dev.numblocks; i++) {
+        myname[10] = i + (i <= 9 ? '0': 'A' -10);
+        fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE);
+        expect(fdi, FFS_FD_OFFSET);
+ 
+        size = 0;
+        do {
+            size += tffs_write(fdi, (char*)tdata[TDATA_HUGE], write_size[2]);
+        } while (size < file_size);
+         
+        error = tffs_close(fdi);
+        expect_ok(error);
+    }
+    
+    elapsed = tffs_timer_end(time_begin);
+    tffs_delay(50);  
+    ttw(ttr(TTrTest, "Write %dBytes %d times in %dms, %dkBps" NL NL, 
+            write_size[2], file_size/write_size[2], elapsed, 
+            (bytes_max * 1000) / (elapsed * 1024)));
+
+
+// Read all files with 16B at a time
+    for (j = 0; j < 3; j++) {
+        ttw(ttr(TTrTest, "Read all files with %dB at a time" NL, write_size[j])); 
+        time_begin = tffs_timer_begin();
+
+        for (i = 0; i < dev.numblocks; i++) {
+            myname[10] = i + (i <= 9 ? '0': 'A' -10);
+            fdi = tffs_open(myname, FFS_O_RDONLY);
+            expect(fdi, FFS_FD_OFFSET);
+            size = 0;
+            do {
+                size += tffs_read(fdi, bigbuf, write_size[j]);
+            } while (size < file_size);
+        
+            error = tffs_close(fdi);
+            expect(error, 0);
+        }
+        elapsed = tffs_timer_end(time_begin);
+
+        ttw(ttr(TTrTest, "Read %d files of %dkB in %dms, %dkBps," NL NL, 
+                dev.numblocks, size/1024, elapsed, 
+                (dev.numblocks * size * 1000) / (elapsed * 1024))); 
+    }
+
+
+// Measure write and read of one big file
+    ttw(ttr(TTrTest, "Format, Write and read one big file" NL)); 
+
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+    
+    time_begin = tffs_timer_begin();
+
+    fdi = tffs_open(myname, FFS_O_WRONLY | FFS_O_CREATE);
+        
+    size = 0;
+    do {
+        size += tffs_write(fdi, bigbuf, write_size[2]);
+    } while (size < bytes_max);
+        
+    error = tffs_close(fdi);
+    expect(error, 0);
+
+    elapsed = tffs_timer_end(time_begin);
+
+    ttw(ttr(TTrTest, "Write %dkB in %dms, %dkBps" NL, 
+            size/1024 , elapsed, (size * 1000) / (elapsed * 1024)));
+
+
+    time_begin = tffs_timer_begin();
+
+// read one big file (reading one big file take more time than reading
+// many files of the same total size because there is a lot more inode
+// to look through)
+    fdi = tffs_open(myname, FFS_O_RDONLY);
+    expect(fdi, FFS_FD_OFFSET);
+    size = 0;
+    do {
+        size += tffs_read(fdi, bigbuf, write_size[2]);
+    } while (size < bytes_max);
+        
+    error = tffs_close(fdi);
+    expect(error, 0);
+        
+    elapsed = tffs_timer_end(time_begin);
+
+    ttw(ttr(TTrTest, "Read %dkB in %dms, %dkBps," NL, 
+            size/1024, elapsed, (size * 1000) / (elapsed * 1024)));
+
+    // Make a data base of old measurements her? compare with old data and
+    // make a warning if the performance has decreased?
+
+    return 0;
+#else    
+    return 1;
+#endif
+}
+
+// Benchmark ffs_file_write() and ffs_file_read() 
+int case_bm_file_rw(int p0, int p1)
+{
+    UINT32 time_begin, elapsed;
+    char myname[] = "/Benchmark";
+    int i, j;
+  
+    struct test_info_s {
+        int fsize;
+        int fnumber;
+    };
+    
+    struct test_info_s tinfo[] = {
+        {   16, 500  },
+        {  256, 200  },
+        { 4096, 200  },
+        {32768, 10   }
+    }; 
+
+    for (j = 0; j < 4; j++) {
+        ttw(ttr(TTrTest, "Format, measure write of %dB" NL, tinfo[j].fsize)); 
+        
+        error = tffs_preformat(0xDEAD);
+        expect(error, EFFS_OK);
+        error = tffs_format("/foo", 0x2BAD);
+        expect(error, EFFS_OK);
+    
+        time_begin = tffs_timer_begin();
+        for (i = 0; i < tinfo[j].fnumber; i++) {
+            error = tffs_file_write(myname, (char*)tdata[TDATA_HUGE], 
+                                    tinfo[j].fsize, FFS_O_CREATE);
+            expect_ok(error);
+        }
+        elapsed = tffs_timer_end(time_begin);
+
+        // FFS has used the CPU for a long time so let the trace task get
+        // the CPU for a while
+        tffs_delay(50);  
+        ttw(ttr(TTrTest, "Write %dBytes %d times in %dms, %dkBps" NL NL, 
+                tinfo[j].fsize, i, elapsed, 
+                (i * tinfo[j].fsize * 1000) / (elapsed * 1024)));
+        
+        time_begin = tffs_timer_begin();
+        for (i = 0; i < tinfo[j].fnumber; i++) {
+            error = tffs_file_read(myname, bigbuf, tinfo[j].fsize);
+            expect_ok(error);
+        }
+        elapsed = tffs_timer_end(time_begin);
+
+        ttw(ttr(TTrTest, "Read %dBytes %d times in %dms, %dkBps" NL NL, 
+                tinfo[j].fsize, i, elapsed, 
+                (i * tinfo[j].fsize * 1000) / (elapsed * 1024)));
+    }
+    tffs_delay(3000);  
+
+    return 0;
+}
+
+// We banchmark lookups by using ffs_stat()
+int case_bm_lookup(int p0, int p1)
+{
+    //format, update file x times, measure lookup with ffs_stat()
+    //format, make x difference files, measure lookup with ffs_stat()
+    //format, make a file in max directory depth, measure lookup with ffs_stat() 
+    //format, make one file, measure lookup with ffs_stat() (no traverse)
+    //format, make x dirs with x files, measure lookup of last file in last dir 
+#if (TARGET == 1)
+    UINT32 time_begin, elapsed;
+    int i, j;
+    char myname[] = "/benchmark";
+    char mydir[100] = "";
+    char depth[] = "/depth99";
+    char mypath[100] = "";
+
+    //format, update file 100 times, measure lookup with ffs_stat()
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    for (i = 0; i < 100; i++) {
+        error = tffs_file_write(myname, 0,0, FFS_O_CREATE);
+        expect_ok(error);
+    }
+    
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < 100; i++) {
+        error = tffs_stat(myname, &stat);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+    
+    ttw(ttr(TTrTest, "Lookup through 100 deleted objects 100 times in %dms(%d obj/s)" NL, elapsed, 100 * 1000 / elapsed));
+    
+    //format, make 100 difference files, measure lookup with ffs_stat()
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    for (i = 0; i < 100; i++) {
+        sprintf(myname, "/benchm%d", i);
+        error = tffs_file_write(myname, 0,0, FFS_O_CREATE);
+        expect_ok(error);
+    }
+    
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < 100; i++) {
+        error = tffs_stat(myname, &stat);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+    
+    ttw(ttr(TTrTest, "Lookup through 100 difference objects 100 times in %dms(%d obj/s)" 
+            NL, elapsed, 100 * 1000 / elapsed));
+    
+    //format, make a file in max directory depth, measure lookup with ffs_stat() 
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    for (i = 0; i < fs.path_depth_max - 1; i++) {
+        sprintf(depth, "/depth%d", i + 1);
+        strcat(mydir, depth);
+        error = tffs_mkdir(mydir);
+        expect_ok(error);
+    }
+
+    strcat(mydir, myname);
+    error = tffs_file_write(mydir, 0,0, FFS_O_CREATE);
+    expect_ok(error);
+
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < 1000; i++) {
+        error = tffs_stat(mydir, &stat);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+    
+    ttw(ttr(TTrTest, "Lookup througt %d directorys 1000 times in %dms(%d obj/s)" 
+            NL, fs.path_depth_max, elapsed, 1000 * 1000 / elapsed));
+
+    //format, make x files in each directory, measure lookup with ffs_stat() 
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+    
+    mydir[0] = 0;  // Reset/empty buffer
+
+    for (i = 0; i < fs.path_depth_max - 1; i++) {
+        sprintf(depth, "/depth%d", i + 1);
+        strcat(mydir, depth);
+        error = tffs_mkdir(mydir);
+        expect_ok(error);
+        
+        for (j = 0; j < 5; j++){
+            sprintf(myname, "/benchm%d", j);
+            strcpy(mypath, mydir);
+            strcat(mypath, myname);
+            error = tffs_file_write(mypath, 0,0, FFS_O_CREATE);
+            expect_ok(error);
+        }
+    }
+
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < 100; i++) {
+        error = tffs_stat(mypath, &stat);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+    
+    ttw(ttr(TTrTest, "Lookup througt %d directorys with %d files in each times in %dms(%d obj/s)" 
+            NL, fs.path_depth_max, j, elapsed, 100 * 1000 / elapsed));
+
+    //format, make one file, measure lookup with ffs_stat() (no traverse)
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    error = tffs_file_write(myname, 0,0, FFS_O_CREATE);
+    expect_ok(error);
+
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < 10000; i++) {
+        error = tffs_stat(myname, &stat);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+    
+    ttw(ttr(TTrTest, "Lookup one file 10000 times in %dms(%d obj/s)" 
+            NL, elapsed, 1000 * 10000 / elapsed));
+
+    //format, make x dirs with x files, measure lookup of last file in last dir 
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+    return 0;
+#else    
+    return 1;
+#endif
+}
+
+int case_bm_seek(int p0, int p1) 
+{
+    UINT32 time_begin, elapsed;
+    int i, pos, fsize = 20000;
+    char myname[] = "/benchmark";
+    fd_t fdi;
+
+    //format, update file 100 times, measure lookup with ffs_stat()
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    error = tffs_format("/foo", 0x2BAD);
+    expect(error, EFFS_OK);
+    
+    // Create test file
+    error = tffs_file_write(myname, (char*)tdata[TDATA_HUGE], fsize, FFS_O_CREATE);
+    expect_ok(error);
+    
+    fdi = tffs_open(myname, FFS_O_RDWR);
+    expect(fdi, FFS_FD_OFFSET);
+    
+    tw(tr(TR_FUNC, TrTest, "Run read reference\n"));
+    ttw(ttr(TTrTest, "Run read reference" NL));
+    
+    // Reference
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < fsize/4; i++) {
+        error = tffs_read(fdi, bigbuf, 4);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+    
+    tw(tr(TR_FUNC, TrTest, "Read %d entries of 4 bytes (bytes/s %d)\n", 
+          fsize/4, (fsize * 1000 / elapsed)));
+
+    ttw(ttr(TTrTest, "Read %d entries of 4 bytes in %dms (bytes/s %d)" NL, 
+            fsize/4, elapsed, (fsize * 1000 / elapsed)));
+    
+    tw(tr(TR_FUNC, TrTest, "Benchmark seek\n"));
+    ttw(ttr(TTrTest, "Benchmark seek" NL));
+    
+    error = tffs_seek(fdi, 0, FFS_SEEK_SET);
+    expect_ok(error);
+    pos = 0;
+
+    // Benchmark seek
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < fsize/4; i++) {
+        error = tffs_seek(fdi, pos, FFS_SEEK_SET);
+        expect_ok(error);
+        pos += 4;
+        error = tffs_read(fdi, bigbuf, 4);
+        expect_ok(error);
+    }
+    elapsed = tffs_timer_end(time_begin);
+
+    tw(tr(TR_FUNC, TrTest, "Seek and Read %d entries of 4 bytes (bytes/s %d)\n", 
+            fsize/4, (fsize * 1000 / elapsed)));
+
+    ttw(ttr(TTrTest, "Seek and Read %d entries of 4 bytes in %dms (bytes/s %d)" NL, 
+            fsize/4, elapsed, (fsize * 1000 / elapsed)));
+
+    error = tffs_close(fdi);
+    expect_ok(error);
+    
+    return EFFS_OK;
+}
+
+// Benchmark the blocking 'system'. Make n number of calls to ffs_format()
+// with bad magic.
+int case_bm_blocking(int p0, int p1)
+{
+    int i;
+    int time_begin, elapsed;
+ 
+    time_begin = tffs_timer_begin();
+    for (i = 0; i < 10000; i++)
+        tffs_format("/ffs", 0);
+    elapsed = tffs_timer_end(time_begin);
+
+    ttw(ttr(TTrTest, "Made %d blocking calls in %dms (ms/call %d)" NL, 
+            i, elapsed, elapsed / i));
+
+    // Make sure that it did fail as we expected
+    error = tffs_format("/ffs", 0);
+    expect(error, EFFS_INVALID);
+
+    return EFFS_OK;
+}
+/******************************************************************************
+ * Core test case
+ ******************************************************************************/
+
+int case_seekfile(int p0, int p1)
+{
+    // NOTEME: this is only a visual test add some expect() to finish it.
+    char *name;
+    iref_t i, dir, i_out;
+    int length, flength;
+    int segment_offset;
+    fd_t fdi;
+
+    error = tffs_fwrite("/File_seg", (char*)tdata[TDATA_HUGE], 50);
+    expect(error, EFFS_OK);
+
+    if ((i = object_lookup("/File_seg", &name, &dir)) < 0)
+        return i;
+
+    for (length = 52; length > 48; length--) {
+        flength = segfile_seek(i, length, &i_out, &segment_offset);
+        tw(tr(TR_FUNC, TrTest, 
+              "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n",
+              length, flength, segment_offset, i_out));
+    }
+
+    fdi = tffs_open("/Stream_seg", FFS_O_WRONLY | FFS_O_CREATE);
+    tffs_write(fdi, (char*)tdata[TDATA_HUGE], 55);
+    tffs_close(fdi);
+
+    fdi = tffs_open("/Stream_seg", FFS_O_WRONLY | FFS_O_APPEND);
+    tffs_write(fdi, (char*)tdata[TDATA_HUGE], 50);
+    tffs_close(fdi);
+
+    fdi = tffs_open("/Stream_seg", FFS_O_WRONLY | FFS_O_APPEND);
+    tffs_write(fdi, (char*)tdata[TDATA_HUGE], 45);
+    tffs_close(fdi);
+
+    if ((i = object_lookup("/Stream_seg", &name, &dir)) < 0)
+        return i;
+
+    for (length = 153; length > 148; length--) {
+        flength = segfile_seek(i, length, &i_out, &segment_offset);
+        tw(tr(TR_FUNC, TrTest, 
+              "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n",
+              length, flength, segment_offset, i_out));
+    }
+
+    for (length = 107; length > 103; length--) {
+        flength = segfile_seek(i, length, &i_out, &segment_offset);
+        tw(tr(TR_FUNC, TrTest, 
+              "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n",
+              length, flength, segment_offset, i_out));
+    }
+
+    for (length = 58; length > 53; length--) {
+        flength = segfile_seek(i, length, &i_out, &segment_offset);
+        tw(tr(TR_FUNC, TrTest, 
+              "*** Length %d, Flength %d, Seg_offset %2d, i %d ***\n",
+              length, flength, segment_offset, i_out));
+    }
+
+    return 0;
+}
+
+void display_fs_params(void) 
+{
+    int numdatablocks;
+
+    numdatablocks = dev.numblocks - fs.blocks_free_min - 1;
+
+    // Note expect only one free block!
+    tw(tr(TR_FUNC, TrTest, "Data blocks %d, size %dkB\n", 
+          numdatablocks, dev.blocksize / 1024));
+    tw(tr(TR_FUNC, TrTest, "    User data:       %dkB\n", 
+          (numdatablocks * dev.blocksize - fs.reserved_space) / 1024));
+    tw(tr(TR_FUNC, TrTest, "    reserved_space:  %dkB\n", fs.reserved_space/ 1024));
+    tw(tr(TR_FUNC, TrTest, "    inodes_max:      %d\n", fs.inodes_max));
+    tw(tr(TR_FUNC, TrTest, "    journal_size:    %d\n", fs.journal_size));
+    tw(tr(TR_FUNC, TrTest, "    objects_max:     %d\n", fs.objects_max));
+    tw(tr(TR_FUNC, TrTest, "    block_files_max: %d\n", fs.block_files_max));
+    tw(tr(TR_FUNC, TrTest, "    chunk_size:      %d\n\n", fs.chunk_size_max));
+}
+
+// NOTE only visual test
+int case_param_init(int p0, int p1)
+{
+    char myname[] = "/ffs/xx/xx/xx";
+    int numblocks[] = { 8, 3, 7, 15, 31, 63, 96, 127, 61, 127};
+    int i;
+
+    for (i = 0; i < sizeof(numblocks) / sizeof(int); i++)
+    {
+        dev.numblocks = numblocks[i];
+
+        if (i == 0)
+            dev.blocksize = 1024 * 8;
+        else if (i > 0 && i < 8)
+            dev.blocksize = 1024 * 64;
+        else 
+            dev.blocksize = 1024 * 128;
+
+        fs_params_init(myname);
+        display_fs_params();
+        
+// TODO add some checks, test format("/ffs/bx/ox") etc.
+    }
+
+    error = tffs_initialize(); // Use the 'real' blocksize
+    expect(error, EFFS_OK);
+
+// Test param input from the format string
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    tffs_format("/ffs/i4000/o3000", 0x2BAD);
+    expect(error, EFFS_OK);
+
+    display_fs_params();
+
+// Test small conf.
+    tw(tr(TR_FUNC, TrTest, "Test small conf\n"));
+    error = tffs_preformat(0xDEAD);
+    expect(error, EFFS_OK);
+    tffs_format("/ffs/b3/j8/r24/f100/o100", 0x2BAD);
+    expect(error, EFFS_OK);
+    display_fs_params();
+
+    return 0;
+}
+
+/******************************************************************************
+ * Trace mask
+ ******************************************************************************/
+
+// This is not a test case but a way to change the trace mask on the fly
+int case_trace_mask(int p0, int p1)
+{
+    unsigned int temp;
+    
+    // Because p0 and p1 only is of the type int and trace_mask is a
+    // unsigned int is p0 bit 1-28 and p1 is bit 29-32
+    temp = p1 << 28;
+    temp |= p0;
+
+#if (TARGET == 0)
+    tr_init(temp, 2, NULL );
+    tw(tr(TR_FUNC, TrAll, "trace mask = %x\n", temp));
+#else    
+    ttr_init(temp);
+    ttw(ttr(TTrTest, "trase mask = %x" NL, temp));
+#endif
+    return 0;
+}
+
+/******************************************************************************
+ * Helper function
+ ******************************************************************************/
+
+#define CLEANUP_MIN_SIZE 1
+
+int ignore_file(char *pathname)
+{
+    int i;
+    const char *ignore[] = {
+        "/.journal", "/.ffs-stats", "/.ffs-bstat.old","/dummy4fctrl" ,
+        "/truncate/IMEI", "/truncate/stream_file", "/gsm/com/rfcap", 
+        "/var/dbg/dar" };
+    const char readonly[] = "/READONLY"; 
+
+    for (i = 0; i < sizeof(ignore)/sizeof(char *); i++) {
+        if (ffs_strcmp(pathname, ignore[i]) == 0) {
+            return 0;
+        }
+    }
+
+// Special case, we have one directory where we don't delete any objects
+    if (memcmp(pathname, readonly, sizeof(readonly) - 1) == 0)
+        return 0;
+
+    return 1;
+}
+
+// Remove files in FFS until there is min_space left. Ignore all files that
+// are listed in the ignore string above.
+int case_cleanup(int min_space)
+{
+    int free, i, n, error;
+    struct object_s *plist, *plist_start;
+    char *pnames, *pnames_start;
+
+    tw(tr(TR_FUNC, TrTestLow, "case_cleanup(%d)?\n", min_space));
+
+    ffs_query(Q_BYTES_FREE, (uint32 *) &free); 
+    if (free > min_space) {
+        tw(tr(TR_FUNC, TrTestLow, "Total data free: %d\n", free));
+        return free;    // Nothing to do
+    }
+
+    plist  = plist_start  = (struct object_s *) bigbuf;
+    pnames = pnames_start = bigbuf + bigbuf_size;
+    n = case_dir_list("/", &plist, &pnames);
+    plist = plist_start;
+
+    for (i = 0; i < n; i++, plist++)
+    {
+        ffs_query(Q_BYTES_FREE, (uint32 *) &free); 
+        if (free > min_space) {
+            tw(tr(TR_FUNC, TrTestLow, "Total data free: %d\n", free));
+            return free;
+        }
+
+        if (plist->stat.size > CLEANUP_MIN_SIZE && ignore_file(plist->name)) {
+            if ((error = ffs_remove(plist->name)) < 0)
+                return error;
+        }
+    }
+    return EFFS_NOSPACE;
+}
+
+// Make a random file. Random filename length, random filename, random filesize.
+// Note it is up to the caller that the directory exists.
+int case_mk_rand_file(char *dirname, int max_size, int min_size)
+{
+    int size, diff, filenamelen, pathlen = 0, i, error;
+    char pathname[(FFS_FILENAME_MAX + 1) * FFS_PATH_DEPTH_MAX];
+// All valid filename chars
+    char tabel[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "abcdefghijklmnopqrtsuvwyz_-.,+%$#";
+
+    diff = max_size - min_size;
+    if (diff < 0)
+        return EFFS_INVALID;
+    else if (diff == 0)
+        size = max_size;
+    else
+        size = (rand() % diff) + min_size;
+
+    filenamelen = (rand() % (FFS_FILENAME_MAX - 1)) + 1;  // We need min one char
+    tw(tr(TR_FUNC, TrTestLow, "size:%5d, filenamelen:%3d,",size, filenamelen));
+
+    if (dirname != 0) {
+        strcpy(pathname, dirname);
+        pathlen = strlen(pathname);
+    }
+
+    pathname[pathlen++] = '/';
+
+    for (i = 0; i < filenamelen; pathlen++, i++) {
+        pathname[pathlen] = tabel[rand() % strlen(tabel)];
+    }
+    pathname[pathlen] = 0;  // Zero terminate
+
+    tw(tr(TR_FUNC, TrTestLow, "pathname:'%s'\n", pathname, size));
+
+    error = tffs_file_write(pathname, (char *) tdata[TDATA_HUGE], size, 
+                            FFS_O_CREATE | FFS_O_TRUNC);
+    return error;
+
+}
+
+// Various helper functions for debug 
+int case_debug_help(int p0, int p1)
+{
+    int tr_mask;
+
+    switch(p0) {
+    case 1: 
+    {
+// Write rfcap file
+        char rfcap_data[] = { 0, 0xf, 0x41, 0x10, 0, 0, 0, 0, 0x50, 0, 
+                              0, 0xa5, 0x5, 0, 0xc0, 0 };
+
+        ttw(ttr(TTrTest, "Write rfcap file..."));
+        tffs_mkdir("/gsm");  // ignore error
+        tffs_mkdir("/gsm/com");
+        error = tffs_file_write("/gsm/com/rfcap", rfcap_data, 
+                                sizeof(rfcap_data), FFS_O_CREATE | FFS_O_TRUNC);
+        expect_ok(error);
+        ttw(ttr(TTrTest, "done" NL));
+    }
+    break;
+    case 2:
+        tr_mask = tr_query(INT_MAX);
+#if (TARGET == 0)
+        tr_init(TrBstat, 2, NULL );
+        tr_bstat();   
+        tr_init(tr_mask, 2, NULL );
+#else    
+        ttr_init(TTrBstat);
+        tr_bstat();    
+        ttr_init(tr_mask);
+#endif
+        break;
+
+    case 3:
+// Make mem dump to screen
+#if (TARGET == 1)
+        rvf_dump_mem();
+        break;
+#else
+        tw(tr(TR_FUNC, TrTestLow, "Not supported on PC\n"));
+        return 1;  
+#endif
+
+    case 4:
+#if (TARGET == 1)
+        rvf_dump_tasks(); break;
+#else
+        tw(tr(TR_FUNC, TrTestLow, "Not supported on PC\n"));
+        return 1;  
+#endif
+    case 5:
+#if (TARGET == 1)
+        rvf_dump_pool(); break;
+#else
+        tw(tr(TR_FUNC, TrTestLow, "Not supported on PC\n"));
+        return 1;  
+#endif
+    default:
+        tw(tr(TR_FUNC, TrTest, "Available helper functions:\n"));
+        tw(tr(TR_FUNC, TrTest, "    1: Write rfcap file\n"));
+        tw(tr(TR_FUNC, TrTest, "    2: Display bstat trace\n"));
+
+        ttw(ttr(TTrTest, "Available helper functions:" NL));
+        ttw(ttr(TTrTest, "    1: Write rfcap file" NL));
+        ttw(ttr(TTrTest, "    2: Display bstat trace" NL));
+        ttw(ttr(TTrTest, "    3: Memory dump to screen" NL));
+        ttw(ttr(TTrTest, "    4: Tasks dump to screen" NL));
+        ttw(ttr(TTrTest, "    5: Pool dump to screen" NL));
+        return 0;
+    }
+
+    return 0;
+}
+
+/******************************************************************************
+ * Hexdumping
+ ******************************************************************************/
+#if 0
+void hexdump(const char *buf, int size, unsigned int address, int unitsize)
+{
+    char string[(8+1+1) + (1+16+1+1) + (3*16) + 1];
+    int n, i;
+    char *s;
+
+    while (size > 0)
+    {
+        s = string;
+        s += sprintf(s, "%8x: ", address); // print offset
+
+        n = (size > 16 ? 16 : size);
+
+        // print the textual representation
+        for (i = 0; i < n; i++) {
+            if (buf[i] >= ' ' && buf[i] < 127)
+                *s++ = buf[i];
+            else
+                *s++ = '.';
+        }
+        // pad textual representation with spaces
+        for (i = 0; i < 16 - n; i++) {
+            *s++ = ' ';
+        }
+        *s++ = ' ';
+
+        // print hexedecimal representation
+        for (i = 0; i < n; i += unitsize) {
+            switch (unitsize) {
+            case 1: s += sprintf(s, "%02x ", *(unsigned char  *) (buf+i)); break;
+            case 2: s += sprintf(s, "%04x ", *(unsigned short *) (buf+i)); break;
+            case 4: s += sprintf(s, "%08x ", *(unsigned int *) (buf+i)); break;
+            }
+        }
+        buf += 16;
+        address += 16;
+        size -= 16;
+        puts(string);
+    }
+}
+#endif
+
+/******************************************************************************
+ * Test Cases
+ ******************************************************************************/
+
+const struct testcase_s testcase[] =
+{
+    // Collective test cases
+    { "all",    PC       , case_all,      "All" },
+    { "alot",   PC       , case_alot,     "Almost all" },
+    { "tall",      IT    , case_tall,     "Target all" },
+    { "aall",   PC       , case_aall,     "Agressive all" },
+    { "list",   PC|IT    , case_list,     "List all testcases" },
+    { "lsr",    PC|IT    , case_lsr,      "Recursively list all objects" },
+    { "test",   PC|IT    , case_test,     "Ad hoc test" },
+    { "rand",   PC|IT    , case_rand,     "Random tests (NOT FINISHED)" },
+    { "fail",   PC|IT    , case_fail,     "Fail (just fail)" },
+    { "okay",   PC|IT    , case_okay,     "Okay (just succeed)" },
+
+    // Atomic/small test cases
+    { "s",      PC|IT    , case_status,   "Status: ffs_init(), lsr" },
+    { "r",      PC|IT    , case_reset,    "preformat(), format(), init(), exit()" },
+    { "i",      PC|IT    , case_init,           "ffs_init()" },
+    { "x",      PC|IT    , case_exit,           "ffs_exit()" },
+    { "p",      PC|IT    , case_only_preformat, "ffs_preformat()" },
+    { "f",      PC|IT    , case_only_format,    "ffs_format()" },
+
+    // Populate test cases
+    { "world",  PC|IT    , case_world,    "Make world" },
+    { "eu",     PC|IT    , case_europe,   "Make europe" },
+    { "dk",     PC|IT    , case_denmark,  "Make denmark" },
+
+    // Special test cases
+    { "mf",     PC|IT    , case_mfiles,   "Test FFS with many (small) files" },
+    { "threeb", PC|IT    , case_threeb,   "Test ffs in only three blocks" },
+    { "twob",   PC|IT    , case_twob,     "Test ffs in only two blocks" },
+    { "pcm",    PC|IT    , case_pcm,      "Test PCM interface" },
+    { "stress",    IT    , case_stress,   "Stress test erase/write" },
+    { "find",   PC|IT|RND, case_find,     "Recursively traverse all objects" },
+    { "nb",     IT       , case_nonblock, "Test non block functions" },
+    { "bf",     IT|RND   , case_blocking, "Test blocking function" },
+    { "cust",   PC       , case_customer, "Test customer typical use"},
+    { "esus",   IT       , case_erase_suspend, "Test erase suspend and resume" },
+
+    // Driver test cases
+    { "int",    IT       , case_interrupt,     "Test INT disable and enable" },  
+
+    // Benchmark test cases
+    { "bmsrw",     IT    , case_bm_stream_rw, "Benchmark stream read and writes" },
+    { "bmfrw",     IT    , case_bm_file_rw,   "Benchmark file read and writes" },
+    { "bmlu",      IT    , case_bm_lookup,    "Benchmark lookups" },
+    { "bmsk",    PC|IT   , case_bm_seek,      "Benchmark ffs_seek()" },
+    { "bmbl",    PC|IT   , case_bm_blocking,  "Benchmark blocking 'system'" },
+
+    // Normal test cases
+    { "format", PC       , case_format,   "Test ffs_pre/format()" },
+    { "lu",     PC|IT    , case_lookup,   "Test object_lookup()" },
+    { "fc",     PC|IT    , case_fcontrol, "Test fcontrol() and read-only" },
+    { "root",   PC|IT|RND, case_root,     "Test root inode is non-modifiable" },
+    { "dirs",   PC|IT|RND, case_dirs,     "Test Directories" },
+    { "frd",    PC|IT|RND, case_fread,    "Test fread() with varying sizes/names" },
+    { "bfull",  PC|IT    , case_bfull,    "Test filling a block completely" },
+    { "ffull",  PC|IT    , case_ffull,    "Test filling ffs completely" },
+    { "bigf",   PC       , case_bigfile,  "Test big files" },
+    { "stat",   PC|IT|RND, case_stat,     "Test ffs_stat()" },
+    { "rm",     PC|IT    , case_remove,   "Test ffs_remove()" },
+    { "ren",    PC|IT|RND, case_rename,   "Test ffs_rename()" },
+    { "renext", PC|IT    , case_rename_extended, "Extended test of ffs_rename()" },
+
+    { "irec",   PC|IT    , case_irec,     "Test inodes reclaim" },
+    { "drec",   PC       , case_drec,     "Test data reclaim" },
+    { "adrec",  PC       , case_adrec,    "Test xxxx reclaim" },
+
+    { "jnl",    PC|IT    , case_journal,  "Test journalling" },
+    { "brec",   PC|IT|RND, case_brecover, "Test block recovery" },
+
+    { "ssym",   PC|IT|RND, case_ssym,     "Test Simple Symlinks" },
+    { "fsym",   PC|IT    , case_fsym,     "Test Full Symlinks (NOT IMPLEMENTED)" },
+    { "ri",     PC|IT|RND, case_reinit,   "Test re-ffs_init()" },
+    { "open",   PC|IT|RND, case_open,     "Test open flags" }, 
+    { "rw",     PC|IT|RND, case_rw,       "Test read and write files" }, 
+    { "mopen",  PC|IT|RND, case_multi_open, "Test open of multiply files" }, 
+    { "seek",   PC|IT|RND, case_seek,     "Test seek on files " }, 
+    { "trunc",  PC|IT|RND, case_trunc,    "Test ffs_truncate() " }, 
+    { "append", PC|IT|RND, case_append,   "Test append on a open file" }, 
+    { "dsync",  PC|IT|RND, case_datasync, "Test ffs_fdatasync" }, 
+    { "ex",     IT|RND,    case_examples, "Test examples from RIV111 " }, 
+    { "fwflags",PC|IT|RND, case_fw_flags, "Test ffs_file_write() flags" }, 
+    { "pcm"    ,PC|IT|RND, case_pcm,      "Test pcm interface" }, 
+    { "apiexc" ,PC|IT,     case_api_exceptions, "Test API exceptions" }, 
+    { "ninit"  ,PC|IT,     case_api_notformated, "Test API on a nformated flash"},
+    { "query"  ,PC|IT|RND, case_query,    "Test query function" },
+    { "octrl"  ,PC|IT,     case_octrl,    "Test of object control" },
+
+    // Core test cases
+    { "seekf",  PC,        case_seekfile,  "Test core segfile_seek" },      
+    { "param",  PC,        case_param_init,"Test core param_init" },      
+
+    // Helper test case
+    { "tr",     PC|IT    , case_trace_mask, "Change trace mask on the fly " },
+    { "dh",     PC|IT    , case_debug_help, "Difference help functions " }, 
+    { 0,        0,         0,             0 }
+};
+
+#if (TARGET == 1)
+// Note like the interrupt functions in drv.c this asm needs to be places ad
+// the buttom of the file or else it crach!
+uint32 get_cpsr(void)
+{
+    asm("        .state16");
+    asm("        adr       A2, get_cpsr32");
+    asm("        bx        A2");
+    asm("        .state32");
+    asm("get_cpsr32");
+    asm("        mrs       A1,cpsr      ; get current CPSR");
+}
+#else
+uint32 get_cpsr(void){return 0;}
+#endif
+
+
+
+
+
+
+
+
+
+
+
+