changeset 1784:71a7aa469387

Major update of fatfs. FAT32 support and changes to the node cache.
author asl
date Tue, 05 Oct 2004 07:45:58 +0000
parents 5b91c0bea75a
children da11a07e3546
files packages/fs/fat/current/ChangeLog packages/fs/fat/current/cdl/fatfs.cdl packages/fs/fat/current/src/fatfs.c packages/fs/fat/current/src/fatfs.h packages/fs/fat/current/src/fatfs_ncache.c packages/fs/fat/current/src/fatfs_supp.c
diffstat 6 files changed, 1771 insertions(+), 1608 deletions(-) [+]
line wrap: on
line diff
--- a/packages/fs/fat/current/ChangeLog
+++ b/packages/fs/fat/current/ChangeLog
@@ -1,3 +1,39 @@
+2004-08-10  Savin Zlobec  <savin@elatec.si>
+
+        * src/fatfs.h:
+        * src/fatfs_supp.c:
+        Added FAT32 support.
+
+2004-07-13  Savin Zlobec  <savin@elatec.si>
+
+        * cdl/fatfs.cdl:
+        * src/fatfs.h:
+        * src/fatfs.c:
+        * src/fatfs_supp.c:
+        * src/fatfs_ncache.c:
+        Refactored the code and changed file node cache memory 
+        allocation from malloc to custom pool based one.
+
+2004-07-05  Savin Zlobec  <savin@elatec.si>
+
+        * cdl/fatfs.cdl:
+        * src/fatfs.h:
+        * src/fatfs.c:
+        * src/fatfs_supp.c:
+        * src/fatfs_ncache.c:
+        Removed FAT table cache - it added little or no speed gain to
+        the fatfs. Implemented private data for fatfs file descriptors which
+        holds the current FAT cluster position, this greatly improves
+        read/write times for big files comparing to the old implementation.
+        * src/fatfs_tcache.c: Removed.
+
+2004-06-24  Savin Zlobec  <savin@elatec.si>
+
+        * src/fatfs.h:
+        * src/fatfs_supp.c:
+        Implemented fatfs_get_disk_usage function for 
+        getting the number of total and free clusters.
+
 2004-01-19  Nick Garnett  <nickg@calivar.com>
 
 
@@ -65,7 +101,7 @@ 2003-07-07 Savin Zlobec <savin@elatec.si
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 2003 Savin Zlobec 
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
--- a/packages/fs/fat/current/cdl/fatfs.cdl
+++ b/packages/fs/fat/current/cdl/fatfs.cdl
@@ -8,7 +8,7 @@
 #####ECOSGPLCOPYRIGHTBEGIN####
 ## -------------------------------------------
 ## This file is part of eCos, the Embedded Configurable Operating System.
-## Copyright (C) 2003 Savin Zlobec 
+## Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
 ##
 ## eCos is free software; you can redistribute it and/or modify it under
 ## the terms of the GNU General Public License as published by the Free
@@ -38,7 +38,7 @@
 # ====================================================================
 ######DESCRIPTIONBEGIN####
 #
-# Author(s):      savin 
+# Author(s):      Savin Zlobec <savin@elatec.si> 
 # Contributors:   
 # Date:           2003-06-25
 #
@@ -63,8 +63,7 @@ cdl_package CYGPKG_FS_FAT {
     
     compile         -library=libextras.a fatfs.c        \
                                          fatfs_supp.c   \
-                                         fatfs_ncache.c \
-                                         fatfs_tcache.c
+                                         fatfs_ncache.c 
 
     cdl_option      CYGNUM_FS_FAT_NODE_HASH_TABLE_SIZE {
         display         "Node hash table size"
@@ -76,32 +75,16 @@ cdl_package CYGPKG_FS_FAT {
                          as keys."
     }
 
-    cdl_option      CYGNUM_FS_FAT_NODE_ALLOC_THRESHOLD {
-        display         "Node allocation treshold"
-        flavor          data
-        default_value   16
-        legal_values    1 to 9999999999
-        description     "This option controls at which point the filesystem 
-                         starts reusing dead file nodes rather then allocating
-                         memory for new nodes."
-    }
-   
-    cdl_option      CYGNUM_FS_FAT_FAT_TABLE_CACHE_MEMSIZE {
-        display         "FAT table cache memory size"
+    cdl_option      CYGNUM_FS_FAT_NODE_POOL_SIZE {
+        display         "Node pool size"
         flavor          data
-        default_value   10240
+        default_value   { (CYGNUM_FILEIO_NFILE + 2) }
         legal_values    1 to 9999999999
-        description     "This option controls the amount of memory used
-                         for the FAT table cache."
-    }
-
-    cdl_option      CYGNUM_FS_FAT_FAT_TABLE_CACHE_INCREMENT {
-        display         "FAT table cache size increment"
-        flavor          data
-        default_value   10
-        legal_values    1 to 9999999999
-        description     "This option controls the amount of memory by which 
-                         the per-file FAT table cache will grow."
+        requires        { CYGNUM_FS_FAT_NODE_POOL_SIZE >= (CYGNUM_FILEIO_NFILE+2) }
+        description     "This option controls the size of the node pool used
+                         for storing file nodes. This value should be set to
+                         the maximum required number of simultaneously open 
+                         files plus the desired size of unused node cache."
     }
    
     cdl_option      CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE {
--- a/packages/fs/fat/current/src/fatfs.c
+++ b/packages/fs/fat/current/src/fatfs.c
@@ -8,8 +8,7 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
-// Copyright (C) 2003 Savin Zlobec
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -41,7 +40,7 @@
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
-// Author(s):           savin (based on ramfs.c)
+// Author(s):           Savin Zlobec <savin@elatec.si> (based on ramfs.c)
 // Original data:       nickg
 // Date:                2003-06-29
 // Purpose:             FAT file system
@@ -53,11 +52,10 @@
 
 #include <pkgconf/system.h>
 #include <pkgconf/hal.h>
-#include <pkgconf/kernel.h>
 #include <pkgconf/io_fileio.h>
 #include <pkgconf/fs_fat.h>
 
-#include <cyg/kernel/ktypes.h>         // base kernel types
+#include <cyg/infra/cyg_type.h>   
 #include <cyg/infra/cyg_trac.h>        // tracing macros
 #include <cyg/infra/cyg_ass.h>         // assertion macros
 
@@ -71,7 +69,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <cyg/kernel/kapi.h>
 #include <cyg/infra/diag.h>
 #include <cyg/fileio/fileio.h>
 #include <cyg/io/io.h>
@@ -199,7 +196,7 @@ static cyg_fileops fatfs_dirops =
 // Parameters for a directory search. The fields of this structure are
 // updated as we follow a pathname through the directory tree.
 
-struct fatfs_dirsearch_t
+typedef struct fatfs_dirsearch_s
 {
     fatfs_disk_t        *disk;     // Disk info 
     fatfs_node_t        *dir;      // Directory to search
@@ -208,9 +205,20 @@ struct fatfs_dirsearch_t
     const char          *name;     // Last name fragment used
     int                  namelen;  // Name fragment length
     cyg_bool             last;     // Last name in path?
-};
+} fatfs_dirsearch_t;
+
+// -------------------------------------------------------------------------
+// FATFS file descriptor data
 
-typedef struct fatfs_dirsearch_t fatfs_dirsearch_t;
+typedef struct fatfs_fd_s
+{
+    fatfs_node_t      *node;
+    fatfs_data_pos_t   pos;
+} fatfs_fd_t;
+
+static fatfs_fd_t  fatfs_fds_base[CYGNUM_FILEIO_NFD];
+static fatfs_fd_t *fatfs_fds_pool[CYGNUM_FILEIO_NFD];
+static cyg_uint32  fatfs_fds_free_cnt;
 
 //==========================================================================
 
@@ -232,16 +240,59 @@ print_disk_info(fatfs_disk_t *disk)
 #endif
 
 static void
+init_fatfs_fds(void)
+{
+    static bool initialized = false;
+
+    int i;
+
+    if (initialized)
+        return;
+    
+    initialized = true;
+    
+    for (i = 0; i < CYGNUM_FILEIO_NFD; i++)
+    {
+        fatfs_fds_pool[i] = &fatfs_fds_base[i];    
+    }
+    fatfs_fds_free_cnt = i;
+}
+
+static fatfs_fd_t *
+alloc_fatfs_fd(fatfs_disk_t *disk, fatfs_node_t *node)
+{
+    fatfs_fd_t *fd = NULL;
+
+    if (fatfs_fds_free_cnt > 0)
+    {
+        fd = fatfs_fds_pool[--fatfs_fds_free_cnt];
+
+        fd->node = node;
+        fatfs_initpos(disk, &node->dentry, &fd->pos);
+    }
+    
+    return fd;
+}
+
+static void
+free_fatfs_fd(fatfs_fd_t *fd)
+{
+    fatfs_fds_pool[fatfs_fds_free_cnt++] = fd;
+}
+
+static void
 init_dirsearch(fatfs_dirsearch_t *ds,
                fatfs_disk_t      *disk, 
                fatfs_node_t      *dir,
                const char        *name)
 {
-    ds->disk    = disk;
+    ds->disk = disk;
+    
     if (NULL == dir)
         ds->dir = disk->root;
     else
         ds->dir = dir;
+    
     ds->path    = name;
     ds->node    = ds->dir;
     ds->namelen = 0;
@@ -251,67 +302,82 @@ init_dirsearch(fatfs_dirsearch_t *ds,
 static int
 find_direntry(fatfs_dirsearch_t *ds)
 {
-    int err;
-    cyg_uint32 pos = 0;
-    fatfs_node_t node_data;
+    fatfs_dir_entry_t  dentry;
+    fatfs_data_pos_t   pos;
+    int                err;
+
+    CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name);
 
-    CYG_TRACE1(TFS, "Finding dir entry '%s'", ds->name);
-
-    ds->node = fatfs_node_find(ds->disk, ds->name, 
-                               ds->namelen, ds->dir->cluster);
+    // First check the cache
+    
+    ds->node = fatfs_node_find(ds->disk, 
+                               ds->name, 
+                               ds->namelen, 
+                               ds->dir->dentry.cluster);
 
     if (ds->node != NULL)
     {
-        CYG_TRACE1(TFS, "Found dir entry '%s' in cache", ds->name);
+        // Dir entry found in cache
+        
+        CYG_TRACE0(TFS, "dir entry found in cache");
+
         fatfs_node_touch(ds->disk, ds->node);
         return ENOERR;
     }
-    
+
+    // Dir entry not in cache - search the current dir
+
+    fatfs_initpos(ds->disk, &ds->dir->dentry, &pos);
+
     while (true)
-    {   
-        err = fatfs_get_dir_entry_node(ds->disk, ds->dir, &pos, &node_data);
+    {  
+        // Read next dir entry 
+        
+        err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry);
         if (err != ENOERR)
             return (err == EEOF ? ENOERR : err);
 
-        if ('\0' == node_data.filename[ds->namelen] &&
-            0 == strncasecmp(node_data.filename, ds->name, ds->namelen))
+        // Compare filenames
+        
+        if ('\0' == dentry.filename[ds->namelen] &&
+               0 == strncasecmp(dentry.filename, ds->name, ds->namelen))
         {
-            CYG_TRACE2(TFS, "Read dir entry '%s' at %d", 
-                            node_data.filename, pos);
+            // Dir entry found - allocate new node and return
+
+            CYG_TRACE0(TFS, "dir entry found");
 
-            ds->node = fatfs_node_alloc(ds->disk, &node_data);
+            ds->node = fatfs_node_alloc(ds->disk, &dentry);
             if (NULL == ds->node)
-                return ENOMEM;
+                return EMFILE;
+
             return ENOERR;
         }
-        pos++;
     }
 }
 
 static int 
 find_entry(fatfs_dirsearch_t *ds)
 {
-    int err;
-    const char *name = ds->path;
-    const char *n = name;
-    char namelen = 0;
+    const char  *name     = ds->path;
+    const char  *n        = name;
+    char         namelen  = 0;
+    int          err;
     
-    // check that we really have a directory
-    if( !S_ISDIR(ds->dir->mode) )
+    if( !S_ISDIR(ds->dir->dentry.mode) )
     {
-        CYG_TRACE1(TFS, "Entry '%s' not dir", ds->dir->filename);
+        CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename);
         return ENOTDIR;
     }
     
-    // Isolate the next element of the path name.
+    // Isolate the next element of the path name
     while (*n != '\0' && *n != '/')
         n++, namelen++;
 
-    // If we terminated on a NUL, set last flag.
+    // If we terminated on a NUL, set last flag
     if (*n == '\0')
         ds->last = true;
 
-    // update name in dirsearch object
+    // Update name in dirsearch object
     ds->name    = name;
     ds->namelen = namelen;
 
@@ -319,7 +385,7 @@ find_entry(fatfs_dirsearch_t *ds)
     if (err != ENOERR)
         return err;
 
-    CYG_TRACE2(TFS, "Entry '%s' %s", name, (ds->node ? "found" : "not found"));
+    CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found"));
     
     if (ds->node != NULL)
        return ENOERR;
@@ -332,14 +398,13 @@ fatfs_find(fatfs_dirsearch_t *ds)
 {
     int err;
 
-    CYG_TRACE1(TFS, "Find path='%s'", ds->path);
+    CYG_TRACE1(TFS, "find path='%s'", ds->path);
     
     // Short circuit empty paths
     if (*(ds->path) == '\0')
         return ENOERR;
     
-    // Iterate down directory tree until we find the object
-    // we want.
+    // Iterate down directory tree until we find the object we want
     for(;;)
     {
         err = find_entry(ds);
@@ -349,18 +414,18 @@ fatfs_find(fatfs_dirsearch_t *ds)
         
         if (ds->last)
         {
-            CYG_TRACE0(TFS, "Entry found");
+            CYG_TRACE0(TFS, "entry found");
             return ENOERR;
         }
 
-        // Update dirsearch object to search next directory.
-        ds->dir = ds->node;
+        // Update dirsearch object to search next directory
+        ds->dir   = ds->node;
         ds->path += ds->namelen;
         
         // Skip dirname separators
         if (*(ds->path) == '/') ds->path++;
         
-        CYG_TRACE1(TFS, "Find path to go='%s'", ds->path);
+        CYG_TRACE1(TFS, "find path to go='%s'", ds->path);
     }
 }
 
@@ -375,14 +440,16 @@ fatfs_find(fatfs_dirsearch_t *ds)
 static int 
 fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
 {
-    cyg_io_handle_t dev_h;
-    Cyg_ErrNo err;
-    fatfs_disk_t *disk;
-    fatfs_node_t root_data;
+    cyg_io_handle_t     dev_h;
+    fatfs_disk_t       *disk;
+    fatfs_dir_entry_t   root_dentry;
+    Cyg_ErrNo           err;
 
-    CYG_TRACE2(TFS, "Mount fste=%p mte=%p", fste, mte);
+    CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);
+
+    init_fatfs_fds();
     
-    CYG_TRACE1(TFS, "Looking up disk device '%s'", mte->devname);
+    CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
     
     err = cyg_io_lookup(mte->devname, &dev_h);
     if (err != ENOERR)
@@ -392,21 +459,11 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m
     if (NULL == disk)
         return ENOMEM;
         
-    CYG_TRACE0(TFS, "Initializing FAT table cache"); 
-   
-    if (ENOERR != fatfs_tcache_create(disk, 
-                      CYGNUM_FS_FAT_FAT_TABLE_CACHE_MEMSIZE))
-    {
-        free(disk);
-        return ENOMEM;
-    }
-    
-    CYG_TRACE0(TFS, "Initializing block cache"); 
+    CYG_TRACE0(TFS, "initializing block cache"); 
 
     disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
     if (NULL == disk->bcache_mem)
     {
-        fatfs_tcache_delete(disk);
         free(disk);
         return ENOMEM;
     }
@@ -415,7 +472,6 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m
             CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib);
     if (err != ENOERR)
     {
-        fatfs_tcache_delete(disk);
         free(disk->bcache_mem);
         free(disk);
         return err;
@@ -423,12 +479,11 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m
     
     disk->dev_h = dev_h;
 
-    CYG_TRACE0(TFS, "Initializing disk");
+    CYG_TRACE0(TFS, "initializing disk");
     
-    err = fatfs_get_disk_info(disk);
+    err = fatfs_init(disk);
     if (err != ENOERR)
     {
-        fatfs_tcache_delete(disk);
         cyg_blib_delete(&disk->blib);
         free(disk->bcache_mem);
         free(disk);
@@ -439,20 +494,22 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m
     print_disk_info(disk);
 #endif
 
-    CYG_TRACE0(TFS, "Initializing node cache");
+    CYG_TRACE0(TFS, "initializing node cache");
 
     fatfs_node_cache_init(disk);
     
-    CYG_TRACE0(TFS, "Initializing root node");
+    CYG_TRACE0(TFS, "initializing root node");
     
-    fatfs_get_root_node(disk, &root_data);
-    disk->root = fatfs_node_alloc(disk, &root_data);
+    fatfs_get_root_dir_entry(disk, &root_dentry);
+    
+    disk->root = fatfs_node_alloc(disk, &root_dentry);
+
     fatfs_node_ref(disk, disk->root);
     
     mte->root = (cyg_dir)disk->root;
     mte->data = (CYG_ADDRWORD)disk;
 
-    CYG_TRACE0(TFS, "Disk mounted");
+    CYG_TRACE0(TFS, "disk mounted");
 
     return ENOERR;
 }
@@ -465,10 +522,10 @@ fatfs_mount(cyg_fstab_entry *fste, cyg_m
 static int
 fatfs_umount(cyg_mtab_entry *mte)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_node_t *root = (fatfs_node_t *)mte->root;
+    fatfs_disk_t  *disk  = (fatfs_disk_t *) mte->data;
+    fatfs_node_t  *root  = (fatfs_node_t *) mte->root;
 
-    CYG_TRACE3(TFS, "Umount mte=%p %d live nodes %d dead nodes", 
+    CYG_TRACE3(TFS, "umount mte=%p %d live nodes %d dead nodes", 
                     mte, fatfs_get_live_node_count(disk), 
                     fatfs_get_dead_node_count(disk));
 
@@ -480,16 +537,15 @@ fatfs_umount(cyg_mtab_entry *mte)
 
     fatfs_node_unref(disk, root);
     fatfs_node_cache_flush(disk);
-    fatfs_tcache_delete(disk);
     // FIXME: cache delete can fail if cache can't be synced
     cyg_blib_delete(&disk->blib); 
     free(disk->bcache_mem);
     free(disk);
     
     mte->root = CYG_DIR_NULL;
-    mte->data = (CYG_ADDRWORD)NULL;
+    mte->data = (CYG_ADDRWORD) NULL;
     
-    CYG_TRACE0(TFS, "Disk umounted");
+    CYG_TRACE0(TFS, "disk umounted");
     
     return ENOERR;
 }
@@ -505,15 +561,16 @@ fatfs_open(cyg_mtab_entry *mte,
            int             mode,  
            cyg_file       *file)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_node_t *node = NULL;
-    fatfs_dirsearch_t ds;
-    int err;
+    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
+    fatfs_node_t       *node = NULL;
+    fatfs_fd_t         *fd;
+    fatfs_dirsearch_t   ds;
+    int                 err;
 
-    CYG_TRACE5(TFS, "Open mte=%p dir=%p name='%s' mode=%d file=%p", 
+    CYG_TRACE5(TFS, "open mte=%p dir=%p name='%s' mode=%d file=%p", 
                     mte, dir, name, mode, file);
 
-    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
 
     err = fatfs_find(&ds);
 
@@ -521,26 +578,29 @@ fatfs_open(cyg_mtab_entry *mte,
     {
         if (ds.last && (mode & O_CREAT))
         {
-            fatfs_node_t node_data;
+            fatfs_dir_entry_t new_file_dentry;
             
             // No node there, if the O_CREAT bit is set then we must
             // create a new one. The dir and name fields of the dirsearch
             // object will have been updated so we know where to put it.
 
-            CYG_TRACE1(TFS, "Creating new file '%s'", name); 
+            CYG_TRACE1(TFS, "creating new file '%s'", name); 
 
-            err = fatfs_create_file(disk, ds.dir, ds.name, 
-                                    ds.namelen, &node_data);
+            err = fatfs_create_file(disk, 
+                                    &ds.dir->dentry, 
+                                    ds.name, 
+                                    ds.namelen, 
+                                    &new_file_dentry);
             if (err != ENOERR)
                 return err;
 
-            node = fatfs_node_alloc(disk, &node_data);
+            node = fatfs_node_alloc(disk, &new_file_dentry);
             if (NULL == node)
-                return ENOMEM;
+                return EMFILE;
            
             // Update directory times
-            ds.dir->atime =
-            ds.dir->mtime = cyg_timestamp();
+            ds.dir->dentry.atime =
+            ds.dir->dentry.mtime = cyg_timestamp();
             
             err = ENOERR;
         }
@@ -548,7 +608,7 @@ fatfs_open(cyg_mtab_entry *mte,
     else if (err == ENOERR)
     {
         // The node exists. If the O_CREAT and O_EXCL bits are set, we
-        // must fail the open.
+        // must fail the open
 
         if ((mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
             err = EEXIST;
@@ -558,28 +618,36 @@ fatfs_open(cyg_mtab_entry *mte,
 
     if (err == ENOERR && (mode & O_TRUNC))
     {
-        // If the O_TRUNC bit is set we must clean out the file data.
-        CYG_TRACE0(TFS, "Truncating file"); 
-        fatfs_trunc_file(disk, node);
+        // If the O_TRUNC bit is set we must clean out the file data
+        CYG_TRACE0(TFS, "truncating file"); 
+        fatfs_trunc_file(disk, &node->dentry);
     }
 
     if (err != ENOERR)
         return err;
     
-    // Check that we actually have a file here
-    if (S_ISDIR(node->mode))
+    if (S_ISDIR(node->dentry.mode))
         return EISDIR;
 
-    // Make a reference to this file node     
+    // Allocate file object private data and
+    // make a reference to this file node
+
+    fd = alloc_fatfs_fd(disk, node);
+    if (NULL == fd)
+        return EMFILE;
+
     fatfs_node_ref(disk, node);
 
     // Initialize the file object
 
+    if (mode & O_APPEND)
+        fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);  
+    
     file->f_flag   |= mode & CYG_FILE_MODE_MASK;
     file->f_type    = CYG_FILE_TYPE_FILE;
     file->f_ops     = &fatfs_fileops;
-    file->f_offset  = (mode & O_APPEND) ? node->size : 0;
-    file->f_data    = (CYG_ADDRWORD)node;
+    file->f_offset  = (mode & O_APPEND) ? node->dentry.size : 0;
+    file->f_data    = (CYG_ADDRWORD) fd;
     file->f_xops    = 0;
 
     return ENOERR;
@@ -594,11 +662,11 @@ fatfs_unlink(cyg_mtab_entry *mte,
              cyg_dir         dir, 
              const char     *name)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_dirsearch_t ds;
-    int err;
+    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t   ds;
+    int                 err;
 
-    CYG_TRACE3(TFS, "Unlink mte=%p dir=%p name='%s'", mte, dir, name);
+    CYG_TRACE3(TFS, "unlink mte=%p dir=%p name='%s'", mte, dir, name);
 
     init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
 
@@ -606,12 +674,11 @@ fatfs_unlink(cyg_mtab_entry *mte,
 
     if (err != ENOERR)
         return err;
-  
+
     if (ds.node->refcnt > 0)
         return EBUSY;
     
-    // Delete node
-    err = fatfs_delete_file(disk, ds.node);
+    err = fatfs_delete_file(disk, &ds.node->dentry);
     if (err == ENOERR)
         fatfs_node_free(disk, ds.node);
     
@@ -625,13 +692,13 @@ fatfs_unlink(cyg_mtab_entry *mte,
 static int
 fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_dirsearch_t ds;
-    int err;
+    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t   ds;
+    int                 err;
     
-    CYG_TRACE3(TFS, "Mkdir mte=%p dir=%p name='%s'", mte, dir, name);
+    CYG_TRACE3(TFS, "mkdir mte=%p dir=%p name='%s'", mte, dir, name);
 
-    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
 
     err = fatfs_find(&ds);
 
@@ -639,17 +706,20 @@ fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir
     {
         if (ds.last)
         {
-            fatfs_node_t node_data;
+            fatfs_dir_entry_t new_dir_dentry;
             
             // The entry does not exist, and it is the last element in
-            // the pathname, so we can create it here.
+            // the pathname, so we can create it here
 
-            err = fatfs_create_dir(disk, ds.dir, ds.name, 
-                                   ds.namelen, &node_data);
+            err = fatfs_create_dir(disk, 
+                                   &ds.dir->dentry, 
+                                   ds.name, 
+                                   ds.namelen, 
+                                   &new_dir_dentry);
             if (err != ENOERR)
                 return err;
             
-            fatfs_node_alloc(disk, &node_data);
+            fatfs_node_alloc(disk, &new_dir_dentry);
 
             return ENOERR;
         }
@@ -669,27 +739,26 @@ fatfs_mkdir(cyg_mtab_entry *mte, cyg_dir
 static int 
 fatfs_rmdir(cyg_mtab_entry *mte, cyg_dir dir, const char *name)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_dirsearch_t ds;
-    int err;
+    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t  ds;
+    int                err;
 
-    CYG_TRACE3(TFS, "Rmdir mte=%p dir=%p name='%s'", mte, dir, name);
+    CYG_TRACE3(TFS, "rmdir mte=%p dir=%p name='%s'", mte, dir, name);
 
-    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
 
     err = fatfs_find(&ds);
 
     if (err != ENOERR)
         return err;
   
-    // Check that this is actually a directory.
-    if (!S_ISDIR(ds.node->mode))
+    if (!S_ISDIR(ds.node->dentry.mode))
         return EPERM;
  
     if (ds.node->refcnt > 0)
         return EBUSY;
     
-    err = fatfs_delete_file(disk, ds.node);
+    err = fatfs_delete_file(disk, &ds.node->dentry);
     if (err == ENOERR)
         fatfs_node_free(disk, ds.node);
     
@@ -707,11 +776,11 @@ fatfs_rename(cyg_mtab_entry *mte,
              cyg_dir         dir2, 
              const char     *name2)
 {
-    fatfs_disk_t *disk  = (fatfs_disk_t *)mte->data;
-    fatfs_dirsearch_t ds1, ds2;
-    int err;
+    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t   ds1, ds2;
+    int                 err;
  
-    CYG_TRACE5(TFS, "Rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", 
+    CYG_TRACE5(TFS, "rename mte=%p dir1=%p name1='%s' dir2=%p name2='%s'", 
                     mte, dir1, name1, dir2, name2);
 
     init_dirsearch(&ds1, disk, (fatfs_node_t *)dir1, name1);
@@ -720,44 +789,53 @@ fatfs_rename(cyg_mtab_entry *mte,
     if (err != ENOERR)
         return err;
 
-    // Protect the found nodes from being reused by the
-    // following search
+    // Protect the found nodes from being reused 
+    // by the search for the ds2 dir/node pair 
     fatfs_node_ref(disk, ds1.dir);
     fatfs_node_ref(disk, ds1.node);
     
-    init_dirsearch(&ds2, disk, (fatfs_node_t *)dir2, name2);
+    init_dirsearch(&ds2, disk, (fatfs_node_t *) dir2, name2);
    
     err = fatfs_find(&ds2);
 
+    // Check if the target name already exists
     if (err == ENOERR && ds2.last)
     {
         err = EEXIST;  
         goto out;  
     }
     
+    // Check if the target dir doesn't exist
     if (err == ENOENT && !ds2.last)
         goto out;
     
+    // Check if the target and the source are the same
     if (ds1.node == ds2.node)
     {
         err = ENOERR;
         goto out;
     }
     
-    err = fatfs_rename_file(disk, ds1.dir, ds1.node, ds2.dir, 
-                            ds2.name, ds2.namelen);  
+    err = fatfs_rename_file(disk, 
+                            &ds1.dir->dentry, 
+                            &ds1.node->dentry, 
+                            &ds2.dir->dentry, 
+                            ds2.name, 
+                            ds2.namelen);  
+
     fatfs_node_rehash(disk, ds1.node);
 
 out:
+    // Unreference previousely protected nodes
     fatfs_node_unref(disk, ds1.dir);
     fatfs_node_unref(disk, ds1.node);
    
     if (err == ENOERR)
     {
-        ds1.dir->atime =
-        ds1.dir->mtime = 
-        ds2.dir->atime = 
-        ds2.dir->mtime = cyg_timestamp();    
+        ds1.dir->dentry.atime =
+        ds1.dir->dentry.mtime = 
+        ds2.dir->dentry.atime = 
+        ds2.dir->dentry.mtime = cyg_timestamp();    
     } 
     return err;
 }
@@ -774,7 +852,7 @@ fatfs_link(cyg_mtab_entry *mte,
            const char     *name2, 
            int             type)
 {
-    CYG_TRACE6(TFS, "Link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
+    CYG_TRACE6(TFS, "link mte=%p dir1=%p name1='%s' dir2=%p name2='%s' type=%d",
                     mte, dir1, name1, dir2, name2, type);
 
     // Linking not supported
@@ -791,33 +869,39 @@ fatfs_opendir(cyg_mtab_entry *mte,
               const char     *name,
               cyg_file       *file)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_dirsearch_t ds;
-    int err;
+    fatfs_disk_t       *disk = (fatfs_disk_t *) mte->data;
+    fatfs_fd_t         *fd;
+    fatfs_dirsearch_t   ds;
+    int                 err;
 
-    CYG_TRACE4(TFS, "Opendir mte=%p dir=%p name='%s' file=%p", 
+    CYG_TRACE4(TFS, "opendir mte=%p dir=%p name='%s' file=%p", 
                     mte, dir, name, file);
 
-    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
 
     err = fatfs_find(&ds);
-
     if (err != ENOERR)
         return err;
 
-    // Check it is really a directory.
-    if (!S_ISDIR(ds.node->mode)) 
+    if (!S_ISDIR(ds.node->dentry.mode)) 
         return ENOTDIR;
-  
-    // Make a reference to this dir node
+
+    // Allocate file object private data and
+    // make a reference to this file node
+
+    fd = alloc_fatfs_fd(disk, ds.node);
+    if (NULL == fd)
+        return EMFILE;
+    
     fatfs_node_ref(disk, ds.node);
     
     // Initialize the file object
-    file->f_type        = CYG_FILE_TYPE_FILE;
-    file->f_ops         = &fatfs_dirops;
-    file->f_data        = (CYG_ADDRWORD)ds.node;
-    file->f_xops        = 0;
-    file->f_offset      = 0;
+
+    file->f_type    = CYG_FILE_TYPE_FILE;
+    file->f_ops     = &fatfs_dirops;
+    file->f_data    = (CYG_ADDRWORD) fd;
+    file->f_xops    = 0;
+    file->f_offset  = 0;
 
     return ENOERR;
 }
@@ -832,33 +916,31 @@ fatfs_chdir(cyg_mtab_entry *mte,
             const char     *name,
             cyg_dir        *dir_out)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
+    fatfs_disk_t *disk = (fatfs_disk_t *) mte->data;
 
-    CYG_TRACE4(TFS, "Chdir mte=%p dir=%p dir_out=%p name=%d", 
+    CYG_TRACE4(TFS, "chdir mte=%p dir=%p dir_out=%p name=%d", 
                     mte, dir, dir_out, name);
 
     if (dir_out != NULL)
     {
-        // This is a request to get a new directory pointer in
-        // *dir_out.
+        // This is a request to get a new directory pointer in *dir_out
         
         fatfs_dirsearch_t ds;
-        int err;
+        int               err;
 
-        init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
+        init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
 
         err = fatfs_find(&ds);
-
         if (err != ENOERR)
             return err;
 
-        // Check it is a directory
-        if (!S_ISDIR(ds.node->mode))
+        if (!S_ISDIR(ds.node->dentry.mode))
             return ENOTDIR;
 
         if (ds.node != disk->root)
-            fatfs_node_ref(disk, ds.node); 
-        *dir_out = (cyg_dir)ds.node;
+            fatfs_node_ref(disk, ds.node);
+        
+        *dir_out = (cyg_dir) ds.node;
     }
     else
     {
@@ -866,7 +948,7 @@ fatfs_chdir(cyg_mtab_entry *mte,
         // dir arguments are the current cdir setting and we should
         // forget this fact.
 
-        fatfs_node_t *node = (fatfs_node_t *)dir;
+        fatfs_node_t *node = (fatfs_node_t *) dir;
 
         if (node != disk->root)
             fatfs_node_unref(disk, node);
@@ -885,31 +967,31 @@ fatfs_stat(cyg_mtab_entry *mte,
            const char     *name,
            struct stat    *buf)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)mte->data;
-    fatfs_dirsearch_t ds;
-    int err;
+    fatfs_disk_t      *disk = (fatfs_disk_t *) mte->data;
+    fatfs_dirsearch_t  ds;
+    int                err;
 
-    CYG_TRACE4(TFS, "Stat mte=%p dir=%p name='%s' buf=%p", 
+    CYG_TRACE4(TFS, "stat mte=%p dir=%p name='%s' buf=%p", 
                     mte, dir, name, buf);
 
-    init_dirsearch(&ds, disk, (fatfs_node_t *)dir, name);
+    init_dirsearch(&ds, disk, (fatfs_node_t *) dir, name);
 
     err = fatfs_find(&ds);
-
     if (err != ENOERR)
         return err;
 
     // Fill in the status
-    buf->st_mode        = ds.node->mode;
-    buf->st_ino         = (ino_t)ds.node->cluster;
-    buf->st_dev         = 0;
-    buf->st_nlink       = 1;
-    buf->st_uid         = 0;
-    buf->st_gid         = 0;
-    buf->st_size        = ds.node->size;
-    buf->st_atime       = ds.node->atime;
-    buf->st_mtime       = ds.node->mtime;
-    buf->st_ctime       = ds.node->ctime;
+    
+    buf->st_mode   = ds.node->dentry.mode;
+    buf->st_ino    = (ino_t) ds.node->dentry.cluster;
+    buf->st_dev    = 0;
+    buf->st_nlink  = 1;
+    buf->st_uid    = 0;
+    buf->st_gid    = 0;
+    buf->st_size   = ds.node->dentry.size;
+    buf->st_atime  = ds.node->dentry.atime;
+    buf->st_mtime  = ds.node->dentry.mtime;
+    buf->st_ctime  = ds.node->dentry.ctime;
 
     return ENOERR;
 }
@@ -926,7 +1008,7 @@ fatfs_getinfo(cyg_mtab_entry *mte,
               void           *buf, 
               int             len)
 {
-    CYG_TRACE6(TFS, "Getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
+    CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
                     mte, dir, name, key, buf, len);
     return EINVAL;
 }
@@ -943,7 +1025,7 @@ fatfs_setinfo(cyg_mtab_entry *mte,
               void           *buf, 
               int             len)
 {
-    CYG_TRACE6(TFS, "Getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
+    CYG_TRACE6(TFS, "getinfo mte=%p dir=%p name='%s' key=%d buf=%p len=%d",
                     mte, dir, name, key, buf, len);
     return EINVAL;
 }
@@ -958,38 +1040,40 @@ fatfs_setinfo(cyg_mtab_entry *mte,
 static int 
 fatfs_fo_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data;
-    fatfs_node_t *node = (fatfs_node_t *)fp->f_data;
-    cyg_uint32 pos = fp->f_offset;
-    ssize_t resid = uio->uio_resid;
-    int i;
+    fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
+    fatfs_node_t  *node   = fd->node;
+    cyg_uint32     pos    = fp->f_offset;
+    ssize_t        resid  = uio->uio_resid;
+    int            i;
 
-    CYG_TRACE3(TFO, "Read fp=%p uio=%p pos=%d", fp, uio, pos);
+    CYG_TRACE3(TFO, "read fp=%p uio=%p pos=%d", fp, uio, pos);
 
     // Loop over the io vectors until there are none left
+
     for (i = 0; i < uio->uio_iovcnt; i++)
     {
-        cyg_iovec *iov = &uio->uio_iov[i];
-        char *buf = (char *)iov->iov_base;
-        off_t len = iov->iov_len;
+        cyg_iovec  *iov  = &uio->uio_iov[i];
+        char       *buf  = (char *) iov->iov_base;
+        off_t       len  = iov->iov_len;
 
-        // Loop over each vector filling it with data from the file.
-        while (len > 0 && pos < node->size)
+        // Loop over each vector filling it with data from the file
+        
+        while (len > 0 && pos < node->dentry.size)
         {
             cyg_uint32 l = len;
-            int err;
+            int        err;
 
             // Adjust size to end of file if necessary
-            if (l > node->size-pos)
-                l = node->size-pos;
+            if (l > node->dentry.size-pos)
+                l = node->dentry.size-pos;
 
-            // Read data
-            err = fatfs_read_data(disk, node, buf, &l, pos);
-
+            err = fatfs_read_data(disk, &node->dentry, &fd->pos, buf, &l);
             if (err != ENOERR)
                 return err;
 
             // Update working vars
+
             len   -= l;
             buf   += l;
             pos   += l;
@@ -997,11 +1081,12 @@ fatfs_fo_read(struct CYG_FILE_TAG *fp, s
         }
     }
 
-    // We successfully read some data,
-    // update the access time, file offset and transfer residue.
-    node->atime    = cyg_timestamp(); 
-    uio->uio_resid = resid;
-    fp->f_offset   = (off_t)pos;
+    // We successfully read some data, update the access time, 
+    // file offset and transfer residue
+
+    node->dentry.atime = cyg_timestamp(); 
+    uio->uio_resid     = resid;
+    fp->f_offset       = (off_t) pos;
 
     return ENOERR;
 }
@@ -1013,49 +1098,53 @@ fatfs_fo_read(struct CYG_FILE_TAG *fp, s
 static int 
 fatfs_fo_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data;
-    fatfs_node_t *node = (fatfs_node_t *)fp->f_data;
-    cyg_uint32 pos = fp->f_offset;
-    ssize_t resid = uio->uio_resid;
-    int err = ENOERR;
-    int i;
+    fatfs_disk_t  *disk   = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd     = (fatfs_fd_t *)   fp->f_data;
+    fatfs_node_t  *node   = fd->node;
+    cyg_uint32     pos    = fp->f_offset;
+    ssize_t        resid  = uio->uio_resid;
+    int            err    = ENOERR;
+    int            i;
 
-    CYG_TRACE3(TFO, "Write fp=%p uio=%p pos=%d", fp, uio, pos);
+    CYG_TRACE3(TFO, "write fp=%p uio=%p pos=%d", fp, uio, pos);
     
     // If the APPEND mode bit was supplied, force all writes to
-    // the end of the file.
+    // the end of the file
     if (fp->f_flag & CYG_FAPPEND)
-        pos = fp->f_offset = node->size;
-
-    // Check that pos is within current file size, or at the very end.
-    if (pos < 0 || pos > node->size)
+    {
+        fatfs_setpos(disk, &node->dentry, &fd->pos, node->dentry.size);
+        pos = fp->f_offset = node->dentry.size;
+    }
+    
+    // Check that pos is within current file size, or at the very end
+    if (pos < 0 || pos > node->dentry.size)
         return EINVAL;
    
-    // Now loop over the iovecs until they are all done, or
-    // we get an error.
+    // Now loop over the iovecs until they are all done, or we get an error
+    
     for (i = 0; i < uio->uio_iovcnt; i++)
     {
-        cyg_iovec *iov = &uio->uio_iov[i];
-        char *buf = (char *)iov->iov_base;
-        off_t len = iov->iov_len;
+        cyg_iovec  *iov  = &uio->uio_iov[i];
+        char       *buf  = (char *) iov->iov_base;
+        off_t       len  = iov->iov_len;
  
-        // Loop over the vector writing it to the file until it has
-        // all been done.
+        // Loop over the vector writing it to the file 
+        // until it has all been done
+
         while (len > 0)
         {
             cyg_uint32 l = len;
 
-            // Write data
-            err = fatfs_write_data(disk, node, buf, &l, pos);
+            err = fatfs_write_data(disk, &node->dentry, &fd->pos, buf, &l);
 
             // Update working vars
+
             len   -= l;
             buf   += l;
             pos   += l;
             resid -= l;
 
-            // Stop writing if there is no more space in the file and
-            // indicate end of data.
+            // Stop writing if there is no more space in the file
             if (err == ENOSPC)
                 break;
             
@@ -1067,13 +1156,15 @@ fatfs_fo_write(struct CYG_FILE_TAG *fp, 
     // We wrote some data successfully, update the modified and access
     // times of the node, increase its size appropriately, and update
     // the file offset and transfer residue.
-    node->mtime = 
-    node->atime = cyg_timestamp();
-    if (pos > node->size)
-        node->size = pos;
+
+    node->dentry.mtime = 
+    node->dentry.atime = cyg_timestamp();
+
+    if (pos > node->dentry.size)
+        node->dentry.size = pos;
 
     uio->uio_resid = resid;
-    fp->f_offset = (off_t)pos;
+    fp->f_offset   = (off_t) pos;
 
     return err;
 }
@@ -1085,39 +1176,45 @@ fatfs_fo_write(struct CYG_FILE_TAG *fp, 
 static int 
 fatfs_fo_lseek(struct CYG_FILE_TAG *fp, off_t *apos, int whence)
 {
-    fatfs_node_t *node = (fatfs_node_t *)fp->f_data;
-    off_t pos = *apos;
-
-    CYG_TRACE3(TFO, "Lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);
+    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
+    off_t          pos   = *apos;
+    int            err;
+    
+    CYG_TRACE3(TFO, "lseek fp=%p pos=%d whence=%d", fp, fp->f_offset, whence);
 
     switch (whence)
     {
         case SEEK_SET:
-            // Pos is already where we want to be.
+            // Pos is already where we want to be
             break;
          case SEEK_CUR:
-            // Add pos to current offset.
+            // Add pos to current offset
             pos += fp->f_offset;
             break;
          case SEEK_END:
-            // Add pos to file size.
-            pos += node->size;
+            // Add pos to file size
+            pos += fd->node->dentry.size;
             break;
          default:
             return EINVAL;
     }
 
-    // Check that pos is still within current file size, or at the
-    // very end.
-    if (pos < 0 || pos > node->size)
+    // Check that pos is still within current file size, 
+    // or at the very end
+    if (pos < 0 || pos > fd->node->dentry.size)
         return EINVAL;
   
-    // All OK, set fp offset and return new position.
-    *apos = fp->f_offset = pos;
+    // All OK, set fp offset and return new position
+    
+    err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, pos);
 
-    CYG_TRACE2(TFO, "Lseek fp=%p new pos=%d", fp, *apos);
+    if (ENOERR == err)
+        *apos = fp->f_offset = pos;
+    
+    CYG_TRACE2(TFO, "lseek fp=%p new pos=%d", fp, *apos);
 
-    return ENOERR;
+    return err;
 }
 
 // -------------------------------------------------------------------------
@@ -1127,7 +1224,7 @@ fatfs_fo_lseek(struct CYG_FILE_TAG *fp, 
 static int 
 fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD com, CYG_ADDRWORD data)
 {
-    CYG_TRACE3(TFO, "Ioctl fp=%p com=%x data=%x", fp, com, data);
+    CYG_TRACE3(TFO, "ioctl fp=%p com=%x data=%x", fp, com, data);
     return EINVAL;
 }
 
@@ -1138,15 +1235,18 @@ fatfs_fo_ioctl(struct CYG_FILE_TAG *fp, 
 static int 
 fatfs_fo_fsync(struct CYG_FILE_TAG *fp, int mode)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data;
-    fatfs_node_t *node = (fatfs_node_t *)fp->f_data;
-    int err;
+    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
+    fatfs_node_t  *node  = fd->node;
+    int            err;
     
-    CYG_TRACE2(TFO, "Fsync fp=%p mode=%d", fp, mode);
+    CYG_TRACE2(TFO, "fsync fp=%p mode=%d", fp, mode);
 
-    err = fatfs_write_file_attr(disk, node);
+    err = fatfs_write_dir_entry(disk, &node->dentry);
+
     if (ENOERR == err)
         err = cyg_blib_sync(&disk->blib);
+    
     return err;
 }
 
@@ -1157,16 +1257,23 @@ fatfs_fo_fsync(struct CYG_FILE_TAG *fp, 
 static int
 fatfs_fo_close(struct CYG_FILE_TAG *fp)
 {    
-    fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data;
-    fatfs_node_t *node = (fatfs_node_t *)fp->f_data;
-    int err = ENOERR;
+    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
+    fatfs_node_t  *node  = fd->node;
+    int            err   = ENOERR;
 
-    CYG_TRACE1(TFO, "Close fp=%p", fp);
+    CYG_TRACE1(TFO, "close fp=%p", fp);
+
+    // Write file attributes to disk, unreference 
+    // the file node and free its private data
 
     if (node != disk->root)
-        err = fatfs_write_file_attr(disk, node);
+        err = fatfs_write_dir_entry(disk, &node->dentry);
+
     fatfs_node_unref(disk, node);    
 
+    free_fatfs_fd(fd);
+    
     return err;
 }
 
@@ -1177,21 +1284,23 @@ fatfs_fo_close(struct CYG_FILE_TAG *fp)
 static int
 fatfs_fo_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
 {
-    fatfs_node_t *node = (fatfs_node_t *)fp->f_data;
+    fatfs_fd_t    *fd    = (fatfs_fd_t *) fp->f_data;
+    fatfs_node_t  *node  = fd->node;
     
-    CYG_TRACE2(TFO, "Fstat fp=%p buf=%p", fp, buf);
+    CYG_TRACE2(TFO, "fstat fp=%p buf=%p", fp, buf);
 
     // Fill in the status
-    buf->st_mode   = node->mode;
-    buf->st_ino    = (ino_t)node->cluster;
+
+    buf->st_mode   = node->dentry.mode;
+    buf->st_ino    = (ino_t) node->dentry.cluster;
     buf->st_dev    = 0;
     buf->st_nlink  = 1;
     buf->st_uid    = 0;
     buf->st_gid    = 0;
-    buf->st_size   = node->size;
-    buf->st_atime  = node->atime;
-    buf->st_mtime  = node->mtime;
-    buf->st_ctime  = node->ctime;
+    buf->st_size   = node->dentry.size;
+    buf->st_atime  = node->dentry.atime;
+    buf->st_mtime  = node->dentry.mtime;
+    buf->st_ctime  = node->dentry.ctime;
 
     return ENOERR;
 }
@@ -1203,7 +1312,7 @@ fatfs_fo_fstat(struct CYG_FILE_TAG *fp, 
 static int
 fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
 {
-    CYG_TRACE4(TFO, "Getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
+    CYG_TRACE4(TFO, "getinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
     return EINVAL;
 }
 
@@ -1214,7 +1323,7 @@ fatfs_fo_getinfo(struct CYG_FILE_TAG *fp
 static int
 fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, void *buf, int len)
 {
-    CYG_TRACE4(TFO, "Setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
+    CYG_TRACE4(TFO, "setinfo fp=%p key=%d buf=%p len=%d", fp, key, buf, len);
     return EINVAL;
 }
 
@@ -1228,30 +1337,29 @@ fatfs_fo_setinfo(struct CYG_FILE_TAG *fp
 static int 
 fatfs_fo_dirread(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
 {
-    fatfs_disk_t *disk = (fatfs_disk_t *)fp->f_mte->data;
-    fatfs_node_t *dir  = (fatfs_node_t *)fp->f_data;
-    struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
-    cyg_uint32 pos     = fp->f_offset;
-    char *nbuf         = ent->d_name;
-    off_t len          = uio->uio_iov[0].iov_len;
-    fatfs_node_t node;
-    int err;
+    fatfs_disk_t      *disk    = (fatfs_disk_t *)  fp->f_mte->data;
+    fatfs_fd_t        *fd      = (fatfs_fd_t *)    fp->f_data;
+    struct dirent     *ent     = (struct dirent *) uio->uio_iov[0].iov_base;
+    char              *nbuf    = ent->d_name;
+    off_t              len     = uio->uio_iov[0].iov_len;
+    fatfs_dir_entry_t  dentry;
+    int                err;
     
-    CYG_TRACE3(TFO, "Dirread fp=%p uio=%p pos=%d", fp, uio, pos);
+    CYG_TRACE3(TFO, "dirread fp=%p uio=%p pos=%d", fp, uio, fp->f_offset);
 
     if (len < sizeof(struct dirent))
         return EINVAL;
 
-    err = fatfs_get_dir_entry_node(disk, dir, &pos, &node);
+    err = fatfs_read_dir_entry(disk, &fd->node->dentry, &fd->pos, &dentry);
 
     if (err != ENOERR)
         return (err == EEOF ? ENOERR : err);
 
-    strcpy(nbuf, node.filename);
+    strcpy(nbuf, dentry.filename);
 
-    dir->atime      = cyg_timestamp();
-    uio->uio_resid -= sizeof(struct dirent);
-    fp->f_offset    = (off_t)(pos + 1);
+    fd->node->dentry.atime  = cyg_timestamp();
+    uio->uio_resid         -= sizeof(struct dirent);
+    fp->f_offset++;
     
     return ENOERR;
 }
@@ -1263,15 +1371,23 @@ fatfs_fo_dirread(struct CYG_FILE_TAG *fp
 static int 
 fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence)
 {
-    CYG_TRACE2(TFO, "Dirlseek fp=%p whence=%d", fp, whence);
+    fatfs_disk_t  *disk  = (fatfs_disk_t *) fp->f_mte->data;
+    fatfs_fd_t    *fd    = (fatfs_fd_t *)   fp->f_data;
+    int            err;
+    
+    CYG_TRACE2(TFO, "dirlseek fp=%p whence=%d", fp, whence);
 
     // Only allow SEEK_SET to zero
     
     if (whence != SEEK_SET || *pos != 0)
         return EINVAL;
+   
+    err = fatfs_setpos(disk, &fd->node->dentry, &fd->pos, 0);
+
+    if (ENOERR == err)
+        *pos = fp->f_offset = 0;
     
-    *pos = fp->f_offset = 0;
-    return ENOERR;
+    return err;
 }
 
 // -------------------------------------------------------------------------
--- a/packages/fs/fat/current/src/fatfs.h
+++ b/packages/fs/fat/current/src/fatfs.h
@@ -10,7 +10,7 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 2003 Savin Zlobec 
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc. 
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -40,7 +40,7 @@
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
-// Author(s):           savin 
+// Author(s):           Savin Zlobec <savin@elatec.si> 
 // Date:                2003-06-29
 //
 //####DESCRIPTIONEND####
@@ -48,9 +48,10 @@
 //==========================================================================
 
 #include <pkgconf/fs_fat.h>
-#include <cyg/kernel/kapi.h>
+
 #include <cyg/infra/cyg_type.h>
 #include <cyg/io/io.h>
+#include <cyg/fileio/fileio.h>
 #include <blib/blib.h>
 
 #include <unistd.h>
@@ -63,15 +64,11 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <cyg/fileio/fileio.h>
-
 // --------------------------------------------------------------------------
 
 #define FATFS_HASH_TABLE_SIZE CYGNUM_FS_FAT_NODE_HASH_TABLE_SIZE 
 
-#define FATFS_NODE_ALLOC_THRESHOLD CYGNUM_FS_FAT_NODE_ALLOC_THRESHOLD 
-
-#define FATFS_FAT_TABLE_CACHE_INCREMENT CYGNUM_FS_FAT_FAT_TABLE_CACHE_INCREMENT 
+#define FATFS_NODE_POOL_SIZE  CYGNUM_FS_FAT_NODE_POOL_SIZE
 
 #ifdef CYGDBG_FS_FAT_NODE_CACHE_EXTRA_CHECKS
 # define FATFS_NODE_CACHE_EXTRA_CHECKS 1
@@ -82,12 +79,6 @@
 // Node cache tracing support
 //#define FATFS_TRACE_NODE_CACHE 1
 
-// FAT table cache tracing support
-//#define FATFS_TRACE_FAT_TABLE_CACHE 1
-
-// FAT table operations tracing support 
-//#define FATFS_TRACE_FAT_TABLE 1
-
 // FAT dir entry operations tracing support 
 //#define FATFS_TRACE_DIR_ENTRY 1
 
@@ -108,7 +99,8 @@
 typedef enum fatfs_type_e
 {
     FATFS_FAT12 = 0,    
-    FATFS_FAT16         
+    FATFS_FAT16,         
+    FATFS_FAT32         
 } fatfs_type_t;
 
 typedef struct fatfs_data_pos_s
@@ -120,32 +112,28 @@ typedef struct fatfs_data_pos_s
     cyg_uint32 cluster_pos;  // Position inside cluster
 } fatfs_data_pos_t;
 
-typedef struct fatfs_tcache_s
+typedef struct fatfs_dir_entry_s
 {
-    cyg_uint32 *clusters; // Cached clusters array
-    cyg_uint32  size;     // Number of cached clusters in array
-    cyg_uint32  max_size; // Size of array (allocated space)
-} fatfs_tcache_t;
+    char              filename[12+1]; // File name
+    mode_t            mode;           // Node type
+    size_t            size;           // Size of file in bytes
+    time_t            ctime;          // Creation timestamp
+    time_t            atime;          // Last access timestamp
+    time_t            mtime;          // Last write timestamp
+    cyg_uint8         priv_data;      // Private data
+    cyg_uint32        cluster;        // First cluster number
+    cyg_uint32        parent_cluster; // First cluster of parent dentry
+    fatfs_data_pos_t  disk_pos;       // Position of dir entry on disk
+} fatfs_dir_entry_t;
 
 typedef struct fatfs_node_s
 {
-    char                 filename[12+1]; // File name
-    mode_t               mode;           // Node type
-    cyg_ucount32         refcnt;         // Open file/current dir references
-    size_t               size;           // Size of file in bytes
-    time_t               ctime;          // Creation timestamp
-    time_t               atime;          // Last access timestamp
-    time_t               mtime;          // Last write timestamp
-    cyg_uint8            priv_data;      // Private data
-    cyg_uint32           cluster;        // First cluster number
-    cyg_uint32           parent_cluster; // First cluster of parent dentry
-    fatfs_data_pos_t     dentry_pos;     // Position of node's dir entry on disk
+    fatfs_dir_entry_t    dentry;     // Dir entry data
+    cyg_ucount32         refcnt;     // Open file/current dir references
 
-    struct fatfs_node_s *list_prev;      // Next node in list
-    struct fatfs_node_s *list_next;      // Prev node in list
-    struct fatfs_node_s *hash_next;      // Next node in hash
-
-    fatfs_tcache_t       tcache;         // Node FAT table clusters cache 
+    struct fatfs_node_s *list_prev;  // Next node in list
+    struct fatfs_node_s *list_next;  // Prev node in list
+    struct fatfs_node_s *hash_next;  // Next node in hash
 } fatfs_node_t;
 
 typedef struct fatfs_hash_table_s 
@@ -164,84 +152,102 @@ typedef struct fatfs_node_list_s
 
 typedef struct fatfs_disk_s
 {
-    cyg_uint32   sector_size;        // Sector size in bytes
-    cyg_uint32   sector_size_log2;   // Sector size log2
-    cyg_uint32   cluster_size;       // Cluster size in bytes
-    cyg_uint32   cluster_size_log2;  // Cluster size log2 
-    cyg_uint32   fat_tbl_pos;        // Position of the first FAT table
-    cyg_uint32   fat_tbl_size;       // FAT table size in bytes
-    cyg_uint32   fat_tbl_nents;      // Number of entries in FAT table
-    cyg_uint32   fat_tbls_num;       // Number of FAT tables
-    cyg_uint32   fat_root_dir_pos;   // Position of the root dir
-    cyg_uint32   fat_root_dir_size;  // Root dir size in bytes 
-    cyg_uint32   fat_root_dir_nents; // Max number of entries in root dir
-    cyg_uint32   fat_data_pos;       // Position of data area
-    fatfs_type_t fat_type;           // Type of FAT - 12 or 16
+    cyg_uint32    sector_size;          // Sector size in bytes
+    cyg_uint32    sector_size_log2;     // Sector size log2
+    cyg_uint32    cluster_size;         // Cluster size in bytes
+    cyg_uint32    cluster_size_log2;    // Cluster size log2 
+    cyg_uint32    fat_tbl_pos;          // Position of the first FAT table
+    cyg_uint32    fat_tbl_size;         // FAT table size in bytes
+    cyg_uint32    fat_tbl_nents;        // Number of entries in FAT table
+    cyg_uint32    fat_tbls_num;         // Number of FAT tables
+    cyg_uint32    fat_root_dir_pos;     // Position of the root dir
+    cyg_uint32    fat_root_dir_size;    // Root dir size in bytes 
+    cyg_uint32    fat_root_dir_nents;   // Max number of entries in root dir
+    cyg_uint32    fat_root_dir_cluster; // Cluster number of root dir (FAT32) 
+    cyg_uint32    fat_data_pos;         // Position of data area
+    fatfs_type_t  fat_type;             // Type of FAT - 12, 16 or 32 
     
-    cyg_io_handle_t  dev_h;          // Disk device handle
-    fatfs_node_t    *root;           // Root dir node
+    cyg_io_handle_t  dev_h;           // Disk device handle
+    fatfs_node_t    *root;            // Root dir node
 
-    cyg_uint8       *tcache_mem;     // FAT table cache memory base
-    cyg_handle_t     tcache_mpool_h; // FAT table cache memory pool handle 
-    cyg_mempool_var  tcache_mpool;   // FAT table cache memory pool struct 
+    cyg_uint8       *bcache_mem;      // Block cache memory base
+    cyg_blib_t       blib;            // Block cache and access library instance
 
-    cyg_uint8       *bcache_mem;     // Block cache memory base
-    cyg_blib_t       blib;           // Block cache and access library instance
-
-    fatfs_node_list_t  live_nlist;   // List of nodes with refcnt > 0
-    fatfs_node_list_t  dead_nlist;   // List of nodes with refcnt == 0
-    fatfs_hash_table_t node_hash;    // Hash of nodes in live and dead lists
+    fatfs_node_t  node_pool_base[FATFS_NODE_POOL_SIZE]; // Node pool base   
+    fatfs_node_t *node_pool[FATFS_NODE_POOL_SIZE];      // Node pool 
+    cyg_uint32    node_pool_free_cnt;                   // Node pool free cnt
+    
+    fatfs_node_list_t  live_nlist;    // List of nodes with refcnt > 0
+    fatfs_node_list_t  dead_nlist;    // List of nodes with refcnt == 0
+    fatfs_hash_table_t node_hash;     // Hash of nodes in live and dead lists
 } fatfs_disk_t;
 
 // --------------------------------------------------------------------------
 
-int  fatfs_get_disk_info(fatfs_disk_t *disk);
+int  fatfs_init(fatfs_disk_t *disk);
+
+void fatfs_get_root_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry);
+
+bool fatfs_is_root_dir_dentry(fatfs_dir_entry_t *dentry);
 
-void fatfs_get_root_node(fatfs_disk_t *disk, fatfs_node_t *root);
+int  fatfs_get_disk_usage(fatfs_disk_t *disk,
+                          cyg_uint32   *total_clusters,
+                          cyg_uint32   *free_clusters);
 
-bool fatfs_is_node_root_node(fatfs_node_t *node);
+int  fatfs_initpos(fatfs_disk_t      *disk,
+                   fatfs_dir_entry_t *file,
+                   fatfs_data_pos_t  *pos);
 
-int  fatfs_get_dir_entry_node(fatfs_disk_t *disk,
-                              fatfs_node_t *dir,
-                              cyg_uint32   *pos,
-                              fatfs_node_t *node);
+int  fatfs_setpos(fatfs_disk_t      *disk,
+                  fatfs_dir_entry_t *file,
+                  fatfs_data_pos_t  *pos,
+                  cyg_uint32         offset);
 
-int  fatfs_write_file_attr(fatfs_disk_t *disk, fatfs_node_t *node);
+cyg_uint32 fatfs_getpos(fatfs_disk_t      *disk, 
+                        fatfs_dir_entry_t *file,
+                        fatfs_data_pos_t  *pos);
 
-int  fatfs_delete_file(fatfs_disk_t *disk, fatfs_node_t *node);
+int  fatfs_read_dir_entry(fatfs_disk_t      *disk,
+                          fatfs_dir_entry_t *dir,
+                          fatfs_data_pos_t  *pos,
+                          fatfs_dir_entry_t *dentry);
 
-int  fatfs_create_file(fatfs_disk_t *disk, 
-                       fatfs_node_t *dir, 
-                       const char   *name,
-                       int           namelen,
-                       fatfs_node_t *node);
+int  fatfs_write_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry);
+
+int  fatfs_delete_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file);
 
-int  fatfs_create_dir(fatfs_disk_t *disk, 
-                      fatfs_node_t *dir, 
-                      const char   *name,
-                      int           namelen,
-                      fatfs_node_t *node);
+int  fatfs_create_file(fatfs_disk_t      *disk, 
+                       fatfs_dir_entry_t *dir, 
+                       const char        *name,
+                       int                namelen,
+                       fatfs_dir_entry_t *dentry);
 
-int  fatfs_trunc_file(fatfs_disk_t *disk, fatfs_node_t *node);
+int  fatfs_create_dir(fatfs_disk_t      *disk, 
+                      fatfs_dir_entry_t *dir, 
+                      const char        *name,
+                      int                namelen,
+                      fatfs_dir_entry_t *dentry);
+
+int  fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file);
 
-int  fatfs_rename_file(fatfs_disk_t *disk, 
-                       fatfs_node_t *dir1,
-                       fatfs_node_t *node,
-                       fatfs_node_t *dir2,
-                       const char   *name,
-                       int           namelen);
+int  fatfs_rename_file(fatfs_disk_t      *disk,
+                       fatfs_dir_entry_t *dir1,
+                       fatfs_dir_entry_t *target,
+                       fatfs_dir_entry_t *dir2,
+                       const char        *name,
+                       int                namelen);
 
-int  fatfs_read_data(fatfs_disk_t *disk,
-                     fatfs_node_t *node,
-                     void         *data,
-                     cyg_uint32   *len,
-                     cyg_uint32    off);
+int  fatfs_read_data(fatfs_disk_t      *disk,
+                     fatfs_dir_entry_t *file,
+                     fatfs_data_pos_t  *pos,
+                     void              *data,
+                     cyg_uint32        *len);
 
-int  fatfs_write_data(fatfs_disk_t *disk,
-                      fatfs_node_t *node,
-                      void         *data,
-                      cyg_uint32   *len,
-                      cyg_uint32    off);
+int  fatfs_write_data(fatfs_disk_t      *disk,
+                      fatfs_dir_entry_t *file,
+                      fatfs_data_pos_t  *pos,
+                      void              *data,
+                      cyg_uint32        *len);
 
 // --------------------------------------------------------------------------
 
@@ -249,7 +255,7 @@ void fatfs_node_cache_init(fatfs_disk_t 
 
 void fatfs_node_cache_flush(fatfs_disk_t *disk);
 
-fatfs_node_t *fatfs_node_alloc(fatfs_disk_t *disk, fatfs_node_t *node_data);
+fatfs_node_t *fatfs_node_alloc(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry);
 
 void fatfs_node_ref(fatfs_disk_t *disk, fatfs_node_t *node);
 
@@ -270,33 +276,6 @@ int  fatfs_get_live_node_count(fatfs_dis
 
 int  fatfs_get_dead_node_count(fatfs_disk_t *disk);
 
-void fatfs_node_flush_dead_tcache(fatfs_disk_t *disk);
-
-// --------------------------------------------------------------------------
-
-int  fatfs_tcache_create(fatfs_disk_t *disk, cyg_uint32 mem_size);
-
-void fatfs_tcache_delete(fatfs_disk_t *disk);
-
-void fatfs_tcache_init(fatfs_disk_t *disk, fatfs_tcache_t *tcache);
-
-void fatfs_tcache_flush(fatfs_disk_t *disk, fatfs_tcache_t *tcache);
-
-bool fatfs_tcache_get(fatfs_disk_t   *disk,
-                      fatfs_tcache_t *tcache, 
-                      cyg_uint32      num, 
-                      cyg_uint32     *cluster);
-
-bool fatfs_tcache_get_last(fatfs_disk_t   *disk,
-                           fatfs_tcache_t *tcache, 
-                           cyg_uint32     *num, 
-                           cyg_uint32     *cluster);
-
-bool fatfs_tcache_set(fatfs_disk_t   *disk,
-                      fatfs_tcache_t *tcache, 
-                      cyg_uint32      num, 
-                      cyg_uint32      cluster);
-
 // --------------------------------------------------------------------------
 // Support routines
 // These enable the definition of local versions of certain routines
--- a/packages/fs/fat/current/src/fatfs_ncache.c
+++ b/packages/fs/fat/current/src/fatfs_ncache.c
@@ -8,7 +8,7 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 2003 Savin Zlobec 
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -38,7 +38,7 @@
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
-// Author(s):           savin 
+// Author(s):           Savin Zlobec <savin@elatec.si> 
 // Date:                2003-06-26
 //
 //####DESCRIPTIONEND####
@@ -73,10 +73,8 @@
 # define TNC 0
 #endif
 
-// This defines how many nodes should always be kept in
-// dead list regardless of node allocation treshold - it 
-// should always be >= 2 or the file finding code may not
-// work correctly!
+// This defines how many nodes should always be kept in dead list - 
+// it should be >= 2 or the file finding code may not work correctly!
 #define DLIST_KEEP_NUM 2 
 
 //==========================================================================
@@ -85,7 +83,7 @@
 static void
 node_list_init(fatfs_node_list_t *list)
 {
-    list->size = 0;
+    list->size  = 0;
     list->first = list->last = NULL;
 }
 
@@ -267,10 +265,6 @@ node_lists_check(fatfs_disk_t* disk)
 {
     node_list_check(&disk->live_nlist, 1, 99999);                        
     node_list_check(&disk->dead_nlist, 0, 0);                           
-
-    if ((disk->live_nlist.size + disk->dead_nlist.size) > 
-        FATFS_NODE_ALLOC_THRESHOLD)
-        CYG_ASSERTC(disk->dead_nlist.size <= DLIST_KEEP_NUM);
 }
 #endif // USE_XCHECKS
 
@@ -305,9 +299,10 @@ node_hash_add(fatfs_hash_table_t *tbl, f
     unsigned int hval;
    
     // Calculate hash of given node filename
-    hval = hash_fn(node->filename, strlen(node->filename)) % tbl->size;
+    hval = hash_fn(node->dentry.filename, 
+                   strlen(node->dentry.filename)) % tbl->size;
 
-    CYG_TRACE2(TNC, "name='%s' hval=%d", node->filename, hval);
+    CYG_TRACE2(TNC, "name='%s' hval=%d", node->dentry.filename, hval);
 
     if (tbl->nodes[hval] == NULL)
     {
@@ -331,7 +326,7 @@ node_hash_add(fatfs_hash_table_t *tbl, f
             if (lnode == node)
                 return false;
             
-            if (strcasecmp(lnode->filename, node->filename) > 0)
+            if (strcasecmp(lnode->dentry.filename, node->dentry.filename) > 0)
             {
                 if (pnode != NULL)
                     pnode->hash_next = node; // Insert in the middle
@@ -359,7 +354,7 @@ node_hash_find(fatfs_hash_table_t *tbl,
                unsigned int        namelen,
                unsigned int        parent_cluster)
 {   
-    unsigned int hval; 
+    unsigned int  hval; 
     fatfs_node_t *node;
 
     // Calculate hash of name and get the first node in slot
@@ -375,10 +370,10 @@ node_hash_find(fatfs_hash_table_t *tbl,
         // First compare the parent cluster number and 
         // check filename length since it is faster than 
         // comparing filenames
-        if (parent_cluster == node->parent_cluster &&
-            '\0' == node->filename[namelen])
+        if (parent_cluster == node->dentry.parent_cluster &&
+            '\0' == node->dentry.filename[namelen])
         {
-            int i = strncasecmp(node->filename, name, namelen);
+            int i = strncasecmp(node->dentry.filename, name, namelen);
 
             if (i == 0)
                 return node;
@@ -435,7 +430,8 @@ node_hash_remove(fatfs_hash_table_t *tbl
     fatfs_node_t *lnode, *pnode;
    
     // Calculate hash of name and get the first node in slot
-    hval = hash_fn(node->filename, strlen(node->filename)) % tbl->size;
+    hval = hash_fn(node->dentry.filename, 
+                   strlen(node->dentry.filename)) % tbl->size;
     lnode = tbl->nodes[hval];
 
     // Now find the node in list and remove it
@@ -480,9 +476,9 @@ node_hash_check(fatfs_hash_table_t *tbl)
         {
             if (pnode != NULL)
             {
-                int c = strcasecmp(pnode->filename, lnode->filename);
+                int c = strcasecmp(pnode->dentry.filename, lnode->dentry.filename);
                 CYG_ASSERT(c <= 0, "hash table not sorted");
-                CYG_ASSERT(pnode->parent_cluster != lnode->parent_cluster ||
+                CYG_ASSERT(pnode->dentry.parent_cluster != lnode->dentry.parent_cluster ||
                            0 != c, "duplicated node in hash table");
             }
             n++;
@@ -504,9 +500,9 @@ node_hash_not_found_check(fatfs_disk_t *
     node = node_list_get_head(&disk->live_nlist);
     while (NULL != node)
     {
-        if (node->parent_cluster == parent_cluster          &&
-            namelen == strlen(node->filename)               &&
-            0 == strncasecmp(name, node->filename, namelen))
+        if (node->dentry.parent_cluster == parent_cluster          &&
+            namelen == strlen(node->dentry.filename)               &&
+            0 == strncasecmp(name, node->dentry.filename, namelen))
             CYG_ASSERT(false, "node not found in hash, "
                               "but exists in live list");
         node = node_list_get_next(node);
@@ -515,9 +511,9 @@ node_hash_not_found_check(fatfs_disk_t *
     node = node_list_get_head(&disk->dead_nlist);
     while (NULL != node)
     {
-        if (node->parent_cluster == parent_cluster          &&
-            namelen == strlen(node->filename)               &&
-            0 == strncasecmp(name, node->filename, namelen))
+        if (node->dentry.parent_cluster == parent_cluster          &&
+            namelen == strlen(node->dentry.filename)               &&
+            0 == strncasecmp(name, node->dentry.filename, namelen))
             CYG_ASSERT(false, "node not found in hash, "
                               "but exists in dead list");
         node = node_list_get_next(node);
@@ -531,16 +527,16 @@ node_hash_found_check(fatfs_disk_t *disk
                       unsigned int  parent_cluster,
                       fatfs_node_t* node)
 {
-    fatfs_node_t* n;
+    fatfs_node_t *n;
 
     n = node_list_get_head(&disk->live_nlist);
     while (NULL != n)
     {
         if (n == node) 
         {
-            if (node->parent_cluster != parent_cluster ||
-                namelen != strlen(node->filename)      ||
-                0 != strncasecmp(name, node->filename, namelen))
+            if (node->dentry.parent_cluster != parent_cluster ||
+                namelen != strlen(node->dentry.filename)      ||
+                0 != strncasecmp(name, node->dentry.filename, namelen))
                 CYG_ASSERT(false, "node_hash_find returned wrong node");
             return;
         }
@@ -552,9 +548,9 @@ node_hash_found_check(fatfs_disk_t *disk
     {
         if (n == node)
         {
-            if (node->parent_cluster != parent_cluster ||
-                namelen != strlen(node->filename)      ||
-                0 != strncasecmp(name, node->filename, namelen))
+            if (node->dentry.parent_cluster != parent_cluster ||
+                namelen != strlen(node->dentry.filename)      ||
+                0 != strncasecmp(name, node->dentry.filename, namelen))
                 CYG_ASSERT(false, "node_hash_find returned wrong node");
             return;
         } 
@@ -592,6 +588,37 @@ node_hash_found_check(fatfs_disk_t *disk
 #endif // not USE_XCHECKS
 
 //==========================================================================
+// Node pool allocation functions
+
+static void
+node_pool_init(fatfs_disk_t *disk)
+{
+    int i;
+
+    for (i = 0; i < FATFS_NODE_POOL_SIZE; i++)
+        disk->node_pool[i] = &disk->node_pool_base[i];
+
+    disk->node_pool_free_cnt = i;
+}
+
+static fatfs_node_t *
+node_pool_alloc(fatfs_disk_t *disk)
+{
+    fatfs_node_t *node = NULL;
+
+    if (disk->node_pool_free_cnt > 0)
+        node = disk->node_pool[--disk->node_pool_free_cnt];
+
+    return node;
+}
+
+static void
+node_pool_free(fatfs_disk_t *disk, fatfs_node_t *node)
+{
+    disk->node_pool[disk->node_pool_free_cnt++] = node;
+}
+    
+//==========================================================================
 //==========================================================================
 // Exported functions 
 
@@ -607,7 +634,8 @@ fatfs_node_cache_init(fatfs_disk_t *disk
     node_list_init(&disk->live_nlist);
     node_list_init(&disk->dead_nlist);
     node_hash_init(&disk->node_hash);
-
+    node_pool_init(disk);
+    
     SANITY_CHECK();
 }
 
@@ -628,8 +656,7 @@ fatfs_node_cache_flush(fatfs_disk_t *dis
         node_list_remove(&disk->live_nlist, node);
         if (!node_hash_remove(&disk->node_hash, node))
             CYG_ASSERT(false, "Node not in hash");
-        fatfs_tcache_flush(disk, &node->tcache);
-        free(node);
+        node_pool_free(disk, node);
         node = next_node;
     }
 
@@ -641,8 +668,7 @@ fatfs_node_cache_flush(fatfs_disk_t *dis
         node_list_remove(&disk->dead_nlist, node);
         if (!node_hash_remove(&disk->node_hash, node))
             CYG_ASSERT(false, "Node not in hash");
-        fatfs_tcache_flush(disk, &node->tcache);
-        free(node);
+        node_pool_free(disk, node);
         node = next_node;
     }
 
@@ -654,62 +680,45 @@ fatfs_node_cache_flush(fatfs_disk_t *dis
 // Allocates a new node.  
 
 fatfs_node_t*
-fatfs_node_alloc(fatfs_disk_t *disk, fatfs_node_t *node_data)
+fatfs_node_alloc(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
 {
-    int lsize, dsize;
-    fatfs_node_t *anode;
+    fatfs_node_t *node;
 
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node_data);
+    CYG_CHECK_DATA_PTRC(dentry);
  
-    lsize = node_list_get_size(&disk->live_nlist);
-    dsize = node_list_get_size(&disk->dead_nlist);
-   
-    CYG_TRACE2(TNC, "lsize=%d dsize=%d", lsize, dsize);
-    
-    // Allocate space for a new node if we haven't reached the 
-    // allocation treshold or if we can't reuse dead nodes space
-    if (dsize > DLIST_KEEP_NUM && (lsize + dsize) >= 
-        (FATFS_NODE_ALLOC_THRESHOLD - 1))
-        anode = NULL;
-    else
-        anode = (fatfs_node_t *)malloc(sizeof(fatfs_node_t));
+    node = node_pool_alloc(disk);
         
-    if (NULL == anode)
+    if (NULL == node)
     {
-        CYG_TRACE0(TNC, "getting node from dead list");
+        CYG_TRACE2(TNC, "getting node from dead list (size=%d keep=%d)",
+                        node_list_get_size(&disk->dead_nlist), DLIST_KEEP_NUM);
         
-        if (dsize <= DLIST_KEEP_NUM)
+        if (node_list_get_size(&disk->dead_nlist) <= DLIST_KEEP_NUM)
             return NULL;
         
-        anode = node_list_tail_get(&disk->dead_nlist);
-        if (NULL == anode)
+        node = node_list_tail_get(&disk->dead_nlist);
+        if (NULL == node)
             return NULL;
         
-        CYG_TRACE1(TNC, "recycling node='%s'", anode->filename); 
+        CYG_TRACE1(TNC, "recycling node='%s'", node->dentry.filename); 
 
-        // Flush FAT table cache
-        fatfs_tcache_flush(disk, &anode->tcache);
-        
-        node_list_remove(&disk->dead_nlist, anode);
-        if (!node_hash_remove(&disk->node_hash, anode))
-            CYG_ASSERT(false, "Node not in hash");
+        node_list_remove(&disk->dead_nlist, node);
+        if (!node_hash_remove(&disk->node_hash, node))
+            CYG_ASSERT(false, "node not in hash");
     }     
 
     // Init new node    
-    *anode = *node_data;
-    anode->refcnt = 0;
+    node->dentry = *dentry;
+    node->refcnt = 0;
 
-    // Init FAT table cache
-    fatfs_tcache_init(disk, &anode->tcache);
-
-    node_list_head_add(&disk->dead_nlist, anode);
-    if (!node_hash_add(&disk->node_hash, anode))
-        CYG_ASSERT(false, "Node already in hash");
+    node_list_head_add(&disk->dead_nlist, node);
+    if (!node_hash_add(&disk->node_hash, node))
+        CYG_ASSERT(false, "node already in hash");
 
     SANITY_CHECK();
 
-    return anode;
+    return node;
 }
 
 //--------------------------------------------------------------------------
@@ -722,7 +731,7 @@ fatfs_node_touch(fatfs_disk_t *disk, fat
 {
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(node);
-    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt);
+    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt);
 
     if (node->refcnt == 0)
     {
@@ -749,14 +758,15 @@ fatfs_node_ref(fatfs_disk_t *disk, fatfs
 {
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(node);
-    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt);
+    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt);
     
-    // Increase node reference counter
     node->refcnt++;    
     if (1 == node->refcnt)
     {
-        CYG_TRACE1(TNC, "node='%s' to live list", node->filename);
         // First reference - move node from dead to live list
+
+        CYG_TRACE1(TNC, "node='%s' to live list", node->dentry.filename);
+        
         node_list_remove(&disk->dead_nlist, node);
         node_list_head_add(&disk->live_nlist, node);
     }
@@ -770,41 +780,24 @@ fatfs_node_ref(fatfs_disk_t *disk, fatfs
 // If the reference goes from 1 to 0, than the node
 // is moved from live list to top of dead list.
 // (When reusing dead node it is always taken from the bottom of list)
-// If we are over the allocation treshold the bottom node of
-// dead list if freed.
 
 void
 fatfs_node_unref(fatfs_disk_t *disk, fatfs_node_t *node)
 {
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(node);
-    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt);
+    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt);
     CYG_ASSERT(node->refcnt > 0, "node->refcnt <= 0");
 
     node->refcnt--;
-    if (node->refcnt == 0)
+    if (0 == node->refcnt)
     {
         // No more references - move node from live to dead list
-        CYG_TRACE1(TNC, "node='%s' to dead list", node->filename);
+
+        CYG_TRACE1(TNC, "node='%s' to dead list", node->dentry.filename);
+
         node_list_remove(&disk->live_nlist, node);
         node_list_head_add(&disk->dead_nlist, node);
-
-        // Check the number of allocated nodes and free 
-        // the last node in dead list if we are over 
-        // the treshold and we have enough dead nodes
-        {
-            int lsize = node_list_get_size(&disk->live_nlist);
-            int dsize = node_list_get_size(&disk->dead_nlist);
-   
-            if (dsize > DLIST_KEEP_NUM && 
-                (lsize + dsize) >= FATFS_NODE_ALLOC_THRESHOLD) 
-            {
-                fatfs_node_t *n = node_list_get_tail(&disk->dead_nlist);
-                CYG_TRACE1(TNC, "freeing node='%s' - to satisfy "
-                                "alloc treshold", n->filename);
-                fatfs_node_free(disk, n);
-            }
-        }
     }
 
     SANITY_CHECK();
@@ -820,18 +813,17 @@ fatfs_node_free(fatfs_disk_t *disk, fatf
 {
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(node);
-    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->filename, node->refcnt);
+    CYG_TRACE2(TNC, "node='%s' refcnt=%d", node->dentry.filename, node->refcnt);
     CYG_ASSERTC(node->refcnt == 0);
     CYG_ASSERTC(node != disk->root);
 
-    // Flush FAT table cache    
-    fatfs_tcache_flush(disk, &node->tcache);
+    // Remove from dead list, from hash and free ptr
 
-    // Remove from dead list and from hash and free ptr
     node_list_remove(&disk->dead_nlist, node);
     if (!node_hash_remove(&disk->node_hash, node))
-        CYG_ASSERT(false, "node not in hash");    
-    free(node);
+        CYG_ASSERT(false, "node not in hash");   
+    
+    node_pool_free(disk, node);
 
     SANITY_CHECK();
 }
@@ -847,10 +839,10 @@ fatfs_node_rehash(fatfs_disk_t *disk, fa
     CYG_CHECK_DATA_PTRC(node);
     
     if (!node_hash_remove_keyless(&disk->node_hash, node))
-        CYG_ASSERT(false, "Node not in hash");
+        CYG_ASSERT(false, "node not in hash");
     
     if (!node_hash_add(&disk->node_hash, node))
-        CYG_ASSERT(false, "Node already in hash");
+        CYG_ASSERT(false, "node already in hash");
     
     SANITY_CHECK();
 }
@@ -901,26 +893,5 @@ fatfs_get_dead_node_count(fatfs_disk_t *
     return node_list_get_size(&disk->dead_nlist);
 }
 
-//--------------------------------------------------------------------------
-// fatfs_node_flush_dead_tcache()
-// Flushes FAT table cache of dead nodes.
-
-void
-fatfs_node_flush_dead_tcache(fatfs_disk_t *disk)
-{
-    fatfs_node_t *node;
- 
-    CYG_CHECK_DATA_PTRC(disk);
-    
-    node = node_list_get_tail(&disk->dead_nlist);
-
-    while (NULL != node)
-    {
-        CYG_TRACE1(TNC, "node='%s'", node->filename);
-        fatfs_tcache_flush(disk, &node->tcache);
-        node = node_list_get_prev(node);
-    }
-}
-
 // -------------------------------------------------------------------------
 // EOF fatfs_ncache.c
--- a/packages/fs/fat/current/src/fatfs_supp.c
+++ b/packages/fs/fat/current/src/fatfs_supp.c
@@ -8,7 +8,7 @@
 //####ECOSGPLCOPYRIGHTBEGIN####
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
-// Copyright (C) 2003 Savin Zlobec 
+// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -38,7 +38,7 @@
 //==========================================================================
 //#####DESCRIPTIONBEGIN####
 //
-// Author(s):           savin 
+// Author(s):           Savin Zlobec <savin@elatec.si> 
 // Date:                2003-06-30
 //
 //####DESCRIPTIONEND####
@@ -47,12 +47,14 @@
 
 #include <pkgconf/fs_fat.h>
 #include <pkgconf/infra.h>
+
 #include <cyg/infra/cyg_type.h>
 #include <cyg/infra/cyg_ass.h>
 #include <cyg/infra/cyg_trac.h>
 #include <cyg/infra/diag.h>
 #include <cyg/io/io.h>
 #include <blib/blib.h>
+
 #include <sys/types.h>
 #include <ctype.h>
 
@@ -82,10 +84,10 @@
 #define DENTRY_IS_ARCHIVE(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_ARCHIVE)
 
 #define DENTRY_IS_DELETED(_dentry_) \
-    (0xE5 == (unsigned char)((_dentry_)->name[0]))
+    (0xE5 == (cyg_uint8)((_dentry_)->name[0]))
 
 #define DENTRY_IS_ZERO(_dentry_) \
-    (0x00 == (unsigned char)((_dentry_)->name[0]))
+    (0x00 == (cyg_uint8)((_dentry_)->name[0]))
 
 // -------------------------------------------------------------------------
 // FAT disk data access macros
@@ -140,7 +142,7 @@
 // -------------------------------------------------------------------------
 // FAT table structures size 
 
-#define DENTRY_SIZE      0x20 // Dir entry size
+#define DENTRY_SIZE 0x20 // Dir entry size
 
 // -------------------------------------------------------------------------
 // Time & date defines 
@@ -150,12 +152,6 @@
 // -------------------------------------------------------------------------
 // Code tracing defines 
 
-#ifdef FATFS_TRACE_FAT_TABLE
-# define TFT 1
-#else
-# define TFT 0
-#endif
-
 #ifdef FATFS_TRACE_DIR_ENTRY
 # define TDE 1
 #else
@@ -174,15 +170,6 @@
 # define TDO 0
 #endif
     
-// -------------------------------------------------------------------------
-// FAT table entry type strings 
-
-#if TFT
-static const char *tentry_type_name[5] = {
-    "REGULAR", "FREE", "LAST", "RESERVED", "BAD"
-};   
-#endif
-
 //==========================================================================
 // FAT structures 
 
@@ -195,7 +182,7 @@ typedef struct fat_boot_record_s
 //  cyg_uint8     jump0;          //                 + NOP
     char          oem_name[8+1];  // 03h : OEM name
     cyg_uint16    bytes_per_sec;  // 0Bh : cyg_bytes per sector
-    cyg_uint8     sec_per_clust;  // 0Dh : Sectors per cluster
+    cyg_uint8     sec_per_clu;    // 0Dh : Sectors per cluster
     cyg_uint16    res_sec_num;    // 0Eh : Number of reserved sectors
     cyg_uint8     fat_tbls_num;   // 10h : Number of copies of fat
     cyg_uint16    max_root_dents; // 11h : Maximum number of root dir entries
@@ -206,36 +193,48 @@ typedef struct fat_boot_record_s
     cyg_uint16    heads_num;      // 1Ah : Number of heads
     cyg_uint32    hsec_num;       // 1Ch : Number of hidden sectors
     cyg_uint32    sec_num;        // 20h : Number of sectors in partition
-    cyg_uint16    ldrv_num;       // 24h : Logical drive number of partition
-    cyg_uint8     ext_sig;        // 26h : Extended signature
-    cyg_uint32    ser_num;        // 27h : Serial number of partition
-    char          vol_name[11+1]; // 2Bh : Volume name of partition
-    char          fat_name[8+1];  // 36h : FAT name
-//  unsigned char exe_code[448];  // 3Eh : Executable code
-    unsigned char exe_marker[2];  // 1FEh: Executable marker (55h AAh)
+    cyg_uint8     exe_marker[2];  // 1FEh: Executable marker (55h AAh)
+
+// FAT32 specific fields
+ 
+    cyg_uint32    sec_per_fat_32; // 24h : Sectors per FAT
+    cyg_uint16    ext_flags;      // 28h : Flags
+    cyg_uint16    fs_ver;         // 2Ah : FS version
+    cyg_uint32    root_cluster;   // 2Ch : Root dir cluster
+    cyg_uint16    fs_info_sec;    // 30h : Sector number of FSINFO structure
+    cyg_uint16    bk_boot_sec;    // 32h : Sector number of backup boot record
+//  cyg_uint8     reserved[12];   // 34h : Reserved
+
+// Fields with different locations on FAT12/16 and FAT32 
+        
+    cyg_uint8     drv_num;        // 24h (40h) : Drive number of partition 
+//  cyg_uint8     reserved1;      // 25h (41h) : Reserved 1
+    cyg_uint8     ext_sig;        // 26h (42h) : Extended signature
+    cyg_uint32    ser_num;        // 27h (43h) : Serial number of partition
+    char          vol_name[11+1]; // 2Bh (47h) : Volume name of partition
+    char          fat_name[8+1];  // 36h (52h) : FAT name
+   
 } fat_boot_record_t;
 
 // -------------------------------------------------------------------------
 // FAT dir entry structure 
  
-typedef struct fat_dir_entry_s
+typedef struct fat_raw_dir_entry_s
 {
-    char       name[8+1];       // 00h : Name
-    char       ext[3+1];        // 08h : Extension
-    cyg_uint8  attr;            // 0Bh : Attribute
-    cyg_uint8  nt_reserved;     // 0Ch : Win NT Reserved field
-    cyg_uint8  crt_sec_100;     // 0Dh : Creation time ms stamp 0 - 199
-    cyg_uint16 crt_time;        // 0Eh : Creation time
-    cyg_uint16 crt_date;        // 10h : Creation date
-    cyg_uint16 acc_date;        // 12h : Last access date
-    cyg_uint16 cluster_HI;      // 14h : Starting cluster HI WORD (FAT32)
-    cyg_uint16 wrt_time;        // 16h : Time    
-    cyg_uint16 wrt_date;        // 18h : Date
-    cyg_uint16 cluster;         // 1Ah : Starting cluster 
-    cyg_uint32 size;            // 1Ch : Size of the file    
-
-    fatfs_data_pos_t pos;       // Positon on disk
-} fat_dir_entry_t;
+    char       name[8+1];   // 00h : Name
+    char       ext[3+1];    // 08h : Extension
+    cyg_uint8  attr;        // 0Bh : Attribute
+    cyg_uint8  nt_reserved; // 0Ch : Win NT Reserved field
+    cyg_uint8  crt_sec_100; // 0Dh : Creation time ms stamp 0 - 199
+    cyg_uint16 crt_time;    // 0Eh : Creation time
+    cyg_uint16 crt_date;    // 10h : Creation date
+    cyg_uint16 acc_date;    // 12h : Last access date
+    cyg_uint16 cluster_HI;  // 14h : Starting cluster HI WORD (FAT32)
+    cyg_uint16 wrt_time;    // 16h : Time    
+    cyg_uint16 wrt_date;    // 18h : Date
+    cyg_uint16 cluster;     // 1Ah : Starting cluster 
+    cyg_uint32 size;        // 1Ch : Size of the file    
+} fat_raw_dir_entry_t;
 
 // -------------------------------------------------------------------------
 // FAT cluster opts 
@@ -253,36 +252,111 @@ typedef enum cluster_opts_e
 
 // -------------------------------------------------------------------------
 // get_val_log2()
-// Gets the log2 of given value or returns 0 if value is 
-// not power of 2. 
+// Gets the log2 of given value or returns 0 if value is not a power of 2. 
  
 static cyg_uint32 
 get_val_log2(cyg_uint32 val)
 {
     cyg_uint32 i, log2;
     
-    i = val;
+    i    = val;
     log2 = 0;
+    
     while (0 == (i & 1))
     {
         i >>= 1;
         log2++;
     }
-    if (i != 1)
-        return 0;
-    else
-        return log2;
+
+    if (i != 1) return 0;
+    else        return log2;
+}
+
+// -------------------------------------------------------------------------
+// cluster_to_block_pos()
+// Converts cluster position to blib block position.
+
+static void
+cluster_to_block_pos(fatfs_disk_t *disk,
+                     cyg_uint32    cluster,
+                     cyg_uint32    cluster_pos,
+                     cyg_uint32   *block, 
+                     cyg_uint32   *block_pos)
+{
+    cyg_uint32 block_size      = cyg_blib_get_block_size(&disk->blib);
+    cyg_uint32 block_size_log2 = cyg_blib_get_block_size_log2(&disk->blib);
+    
+    *block = (cluster - 2) << (disk->cluster_size_log2 - block_size_log2);
+    
+    *block_pos = disk->fat_data_pos + cluster_pos;  
+
+    if (*block_pos > block_size)
+    {
+        *block     += *block_pos >> block_size_log2;
+        *block_pos  = *block_pos & (block_size - 1);
+    }
+}
+
+// -------------------------------------------------------------------------
+// disk_write()
+// Writes data to disk.
+
+static __inline__ int
+disk_write(fatfs_disk_t *disk, 
+           void         *buf,
+           cyg_uint32   *len,
+           cyg_uint32    pos)
+{
+    return cyg_blib_write(&disk->blib, buf, len, 0, pos);
 }
 
 // -------------------------------------------------------------------------
-// get_data_disk_apos()
-// Gets the absolute data position on disk from cluster number and
-// position inside given cluster. 
- 
-static __inline__ cyg_uint32
-get_data_disk_apos(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 pos)
+// disk_read()
+// Reads data from disk.
+
+static __inline__ int
+disk_read(fatfs_disk_t *disk, 
+          void         *buf,
+          cyg_uint32   *len,
+          cyg_uint32    pos)
+{
+    return cyg_blib_read(&disk->blib, buf, len, 0, pos);
+}
+
+// -------------------------------------------------------------------------
+// disk_cluster_write()
+// Writes data to disk at specified cluster position.
+
+static __inline__ int
+disk_cluster_write(fatfs_disk_t *disk,
+                   void         *buf,
+                   cyg_uint32   *len,
+                   cyg_uint32    cluster,
+                   cyg_uint32    cluster_pos)
 {
-    return (disk->fat_data_pos + disk->cluster_size * (cluster - 2) + pos);
+    cyg_uint32 block, block_pos;
+
+    cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
+
+    return cyg_blib_write(&disk->blib, buf, len, block, block_pos);
+}
+
+// -------------------------------------------------------------------------
+// disk_cluster_read()
+// Reads data from disk at specified cluster position.
+
+static __inline__ int
+disk_cluster_read(fatfs_disk_t *disk,
+                  void         *buf,
+                  cyg_uint32   *len,
+                  cyg_uint32    cluster,
+                  cyg_uint32    cluster_pos)
+{
+    cyg_uint32 block, block_pos;
+
+    cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
+
+    return cyg_blib_read(&disk->blib, buf, len, block, block_pos);
 }
 
 // -------------------------------------------------------------------------
@@ -330,8 +404,8 @@ date_unix2dos(cyg_uint32  unix_timestamp
 {
     cyg_uint32 jd;
     cyg_uint16 dtime, ddate;
-    int hour, min, sec;
-    int day, month, year;
+    int        hour, min, sec;
+    int        day, month, year;
     
     hour = (unix_timestamp / 3600) % 24;
     min  = (unix_timestamp / 60) % 60;
@@ -340,8 +414,8 @@ date_unix2dos(cyg_uint32  unix_timestamp
     jd = JD_1_JAN_1970 + unix_timestamp / (3600 * 24);
     jdays_to_gdate(jd, &day, &month, &year);
 
-    CYG_TRACE7(TDE, "ts=%d date=%d:%d:%d %d-%d-%d",
-                   unix_timestamp, hour, min, sec, year, month, day);
+    CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
+               unix_timestamp, hour, min, sec, year, month, day);
 
     if (year < 1980)
         year = 1980;
@@ -364,25 +438,26 @@ date_dos2unix(cyg_uint16  dos_time,
               cyg_uint16  dos_date, 
               cyg_uint32 *unix_timestamp)
 {
-    int hour, min, sec;
-    int day, month, year;
     cyg_uint32 ts; 
+    int        hour, min, sec;
+    int        day, month, year;
     
-    sec = (dos_time & ((1<<5)-1)) * 2;
+    sec        = (dos_time & ((1<<5)-1)) * 2;
     dos_time >>= 5;
-    min = (dos_time & ((1<<6)-1));
+    min        = (dos_time & ((1<<6)-1));
     dos_time >>= 6;
-    hour = dos_time;
+    hour       = dos_time;
     
-    day = (dos_date & ((1<<5)-1));
+    day        = (dos_date & ((1<<5)-1));
     dos_date >>= 5;
-    month = (dos_date & ((1<<4)-1));
+    month      = (dos_date & ((1<<4)-1));
     dos_date >>= 4;
-    year = dos_date + 1980;
+    year       = dos_date + 1980;
 
     gdate_to_jdays(day, month, year, &ts);
+
     ts -= JD_1_JAN_1970;
-    ts = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600);
+    ts  = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600);
     
     *unix_timestamp = ts;
 
@@ -394,18 +469,19 @@ date_dos2unix(cyg_uint16  dos_time,
 //==========================================================================
 // FAT boot record functions 
 
+#if TDE 
+
 // -------------------------------------------------------------------------
 // print_boot_record()
 // Prints FAT boot record.
 
-#if TFT 
 static void
 print_boot_record(fat_boot_record_t* fbr)
 {
     diag_printf("FAT: FBR jump code:       0x%02X\n", fbr->jump);
     diag_printf("FAT: FBR oem name:       '%.8s'\n",  fbr->oem_name);
     diag_printf("FAT: FBR bytes per sec:   %u\n",     fbr->bytes_per_sec);
-    diag_printf("FAT: FBR sec per cluster: %u\n",     fbr->sec_per_clust);
+    diag_printf("FAT: FBR sec per cluster: %u\n",     fbr->sec_per_clu);
     diag_printf("FAT: FBR reserved sec:    %u\n",     fbr->res_sec_num);
     diag_printf("FAT: FBR fat tbls num:    %u\n",     fbr->fat_tbls_num);
     diag_printf("FAT: FBR max root dents:  %u\n",     fbr->max_root_dents);
@@ -416,7 +492,17 @@ print_boot_record(fat_boot_record_t* fbr
     diag_printf("FAT: FBR heads num:       %u\n",     fbr->heads_num);
     diag_printf("FAT: FBR hidden sec num:  %u\n",     fbr->hsec_num);
     diag_printf("FAT: FBR sec num:         %u\n",     fbr->sec_num);
-    diag_printf("FAT: FBR log drv num:     %u\n",     fbr->ldrv_num);
+
+    if (0 == fbr->sec_per_fat)
+    {
+        diag_printf("FAT: FBR sec per fat32:   %u\n",     fbr->sec_per_fat_32);
+        diag_printf("FAT: FBR ext flags:       0x%04X\n", fbr->ext_flags);
+        diag_printf("FAT: FBR fs ver:          %u\n",     fbr->fs_ver);
+        diag_printf("FAT: FBR root cluster:    %u\n",     fbr->root_cluster);
+        diag_printf("FAT: FBR fs info sec:     %u\n",     fbr->fs_info_sec);
+    }
+    
+    diag_printf("FAT: FBR drv num:         %u\n",     fbr->drv_num);
     diag_printf("FAT: FBR ext sig:         0x%02X\n", fbr->ext_sig);
     diag_printf("FAT: FBR ser num:         0x%08X\n", fbr->ser_num);
     diag_printf("FAT: FBR vol name:       '%.11s'\n", fbr->vol_name);
@@ -424,7 +510,8 @@ print_boot_record(fat_boot_record_t* fbr
     diag_printf("FAT: FBR exe mark:        0x%02X 0x%02X\n", 
                 fbr->exe_marker[0], fbr->exe_marker[1]);
 }
-#endif // TFT
+
+#endif // TDE
 
 // -------------------------------------------------------------------------
 // read_boot_record()
@@ -433,18 +520,18 @@ print_boot_record(fat_boot_record_t* fbr
 static int 
 read_boot_record(fatfs_disk_t *disk, fat_boot_record_t *fbr)
 {
-    int len, err;
-    unsigned char data[0x3E];
+    cyg_uint8 data[0x5A];
+    int       len, err;
     
-    len = 0x3E;
-    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, 0);
+    len = 0x5A;
+    err = disk_read(disk, (void*)data, &len, 0);
     if (err != ENOERR)
         return err;
    
     GET_WORD(data,  fbr->jump,           0x00);
     GET_BYTES(data, fbr->oem_name, 8,    0x03);
     GET_WORD(data,  fbr->bytes_per_sec,  0x0B);
-    GET_BYTE(data,  fbr->sec_per_clust,  0x0D);
+    GET_BYTE(data,  fbr->sec_per_clu,    0x0D);
     GET_WORD(data,  fbr->res_sec_num,    0x0E);
     GET_BYTE(data,  fbr->fat_tbls_num,   0x10);
     GET_WORD(data,  fbr->max_root_dents, 0x11);
@@ -455,15 +542,37 @@ read_boot_record(fatfs_disk_t *disk, fat
     GET_WORD(data,  fbr->heads_num,      0x1A);
     GET_DWORD(data, fbr->hsec_num,       0x1C);
     GET_DWORD(data, fbr->sec_num,        0x20);
-    GET_WORD(data,  fbr->ldrv_num,       0x24);
-    GET_BYTE(data,  fbr->ext_sig,        0x26);
-    GET_DWORD(data, fbr->ser_num,        0x27);
-    GET_BYTES(data, fbr->vol_name, 11,   0x2B);
-    GET_BYTES(data, fbr->fat_name, 8,    0x36);
 
-    // Skip the exe code and read the end marker
+    // This is a quick check for FAT12/16 or FAT32 boot record.
+    // The sec_per_fat field must be 0 on FAT32, since this
+    // field plays a crucial role in detection of the FAT type 
+    // (12,16,32) it is quite safe to make this assumption.
+    if (0 == fbr->sec_per_fat)
+    {
+        GET_DWORD(data, fbr->sec_per_fat_32, 0x24);
+        GET_WORD(data,  fbr->ext_flags,      0x28);
+        GET_WORD(data,  fbr->fs_ver,         0x2A);
+        GET_DWORD(data, fbr->root_cluster,   0x2C);
+        GET_WORD(data,  fbr->fs_info_sec,    0x30);
+        GET_WORD(data,  fbr->bk_boot_sec,    0x32);
+        GET_BYTE(data,  fbr->drv_num,        0x40);
+        GET_BYTE(data,  fbr->ext_sig,        0x42);
+        GET_DWORD(data, fbr->ser_num,        0x43);
+        GET_BYTES(data, fbr->vol_name, 11,   0x47);
+        GET_BYTES(data, fbr->fat_name, 8,    0x52);
+    }
+    else
+    {
+        GET_BYTE(data,  fbr->drv_num,        0x24);
+        GET_BYTE(data,  fbr->ext_sig,        0x26);
+        GET_DWORD(data, fbr->ser_num,        0x27);
+        GET_BYTES(data, fbr->vol_name, 11,   0x2B);
+        GET_BYTES(data, fbr->fat_name, 8,    0x36);
+    }
+    
+    // Read the end marker
     len = 0x02;
-    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, 0x1FE);
+    err = disk_read(disk, (void*)data, &len, 0x1FE);
     if (err != ENOERR)
         return err;
 
@@ -473,8 +582,8 @@ read_boot_record(fatfs_disk_t *disk, fat
     fbr->oem_name[8]  = '\0';
     fbr->vol_name[11] = '\0';
     fbr->fat_name[8]  = '\0';
-  
-#if TFT 
+ 
+#if TDE 
     print_boot_record(fbr);
 #endif
     
@@ -489,65 +598,61 @@ read_boot_record(fatfs_disk_t *disk, fat
 // Reads FAT table entry from disk.
 
 static int
-read_tentry_fat12(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
-{
-    unsigned char data[2];
-    cyg_uint32 pos, num3;
-    cyg_uint16 e;
-    int len, err;
-
-    num3 = num * 3;
-    pos  = disk->fat_tbl_pos + (num3 >> 1);
-    len  = 2;
-    
-    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, pos);
-    if (err != ENOERR)
-        return err;
-
-    GET_WORD(data, e, 0x00);
-
-    if (0 == (num3 & 1))
-        *entry = e & 0x0FFF;
-    else
-        *entry = (e >> 4) & 0x0FFF;
-        
-    CYG_TRACE3(TFT, "tentry=%x num=%d at %d", *entry, num, pos);
-    
-    return ENOERR;
-}
-
-static int
-read_tentry_fat16(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
-{
-    unsigned char data[2];
-    cyg_uint32 pos;
-    cyg_uint16 e;
-    int len, err;
-
-    pos = disk->fat_tbl_pos + (num << 1);
-    len = 2;
-    
-    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, pos);
-    if (err != ENOERR)
-        return err;
-
-    GET_WORD(data, e, 0x00);
-    *entry = e;
-
-    CYG_TRACE3(TFT, "tentry=%x num=%d at %d", *entry, num, pos);
-    
-    return ENOERR;
-}
-
-static int
 read_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
 {
+    cyg_uint8  data[4];
+    cyg_uint32 pos, num3;
+    cyg_uint32 e;
+    int        len, err;
+
     switch (disk->fat_type)
     {
-        case FATFS_FAT12: return read_tentry_fat12(disk, num, entry);
-        case FATFS_FAT16: return read_tentry_fat16(disk, num, entry);
-        default: return EINVAL;                  
+        case FATFS_FAT12:
+            num3 = num * 3;
+            pos  = disk->fat_tbl_pos + (num3 >> 1);
+            len  = 2;
+    
+            err = disk_read(disk, (void*)data, &len, pos);
+            if (err != ENOERR)
+                return err;
+
+            GET_WORD(data, e, 0x00);
+
+            if (0 == (num3 & 1)) *entry = e        & 0x0FFF;
+            else                 *entry = (e >> 4) & 0x0FFF;
+
+            break;
+            
+        case FATFS_FAT16:
+            pos = disk->fat_tbl_pos + (num << 1);
+            len = 2;
+    
+            err = disk_read(disk, (void*)data, &len, pos);
+            if (err != ENOERR)
+                return err;
+
+            GET_WORD(data, e, 0x00);
+            *entry = e;
+
+            break; 
+            
+        case FATFS_FAT32:
+            pos = disk->fat_tbl_pos + (num << 2);
+            len = 4;
+    
+            err = disk_read(disk, (void*)data, &len, pos);
+            if (err != ENOERR)
+                return err;
+
+            GET_DWORD(data, e, 0x00);
+            *entry = e & 0x0FFFFFFF;
+
+            break;
+
+        default:
+            CYG_ASSERT(false, "Unknown FAT type");
     }
+    return ENOERR;
 }
 
 // -------------------------------------------------------------------------
@@ -555,138 +660,127 @@ read_tentry(fatfs_disk_t *disk, cyg_uint
 // Writes FAT table entry to disk (to all copies of FAT).
  
 static int
-write_tentry_fat12(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
+write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
 {
-    unsigned char data[2];
-    cyg_uint32 pos, num3; 
-    cyg_uint16 e;
-    int i, len, err;
+    cyg_uint8  data[4];
+    cyg_uint32 pos=0, num3; 
+    cyg_uint32 e;
+    int        i, len, err;
 
-    num3 = num * 3;
-    pos  = disk->fat_tbl_pos + (num3 >> 1);
-    len  = 2;
+    switch (disk->fat_type)
+    {
+        case FATFS_FAT12:
+            num3 = num * 3;
+            pos  = disk->fat_tbl_pos + (num3 >> 1);
+            len  = 2;
    
-    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, pos);
-    if (err != ENOERR)
-        return err;
+            err = disk_read(disk, (void*)data, &len, pos);
+            if (err != ENOERR)
+                return err;
 
-    GET_WORD(data, e, 0x00);
+            GET_WORD(data, e, 0x00);
   
-    if (0 == (num3 & 1)) 
-        e = (e & 0xF000) | (*entry & 0x0FFF);
-    else
-        e = (e & 0x000F) | ((*entry & 0x0FFF) << 4);
+            if (0 == (num3 & 1)) e = (e & 0xF000) | (*entry & 0x0FFF);
+            else                 e = (e & 0x000F) | ((*entry & 0x0FFF) << 4);
+    
+            SET_WORD(data, e, 0x00);
+
+            break;
+
+        case FATFS_FAT16:
+            pos = disk->fat_tbl_pos + (num << 1);
+            len = 2;
     
-    SET_WORD(data, e, 0x00);
+            e = *entry;
+            SET_WORD(data, e, 0x00);
+
+            break;  
+            
+        case FATFS_FAT32:
+            pos = disk->fat_tbl_pos + (num << 2);
+            len = 4;
+    
+            err = disk_read(disk, (void*)data, &len, pos);
+            if (err != ENOERR)
+                return err;
 
+            GET_DWORD(data, e, 0x00);
+
+            e = (e & 0xF0000000) | *entry;
+    
+            SET_DWORD(data, e, 0x00);
+
+            break; 
+
+        default:
+            CYG_ASSERT(false, "Unknown FAT type");
+    }
+    
     for (i = 0; i < disk->fat_tbls_num; i++)
     {
-        err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, pos);
+        err = disk_write(disk, (void*)data, &len, pos);
         if (err != ENOERR)
             return err;
 
-        CYG_TRACE4(TFT, "tentry=%x num=%d at %d tbl=%d", *entry, num, pos, i);
-
         pos += disk->fat_tbl_size;
     }
     
     return ENOERR;
 }
 
-static int
-write_tentry_fat16(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
-{
-    unsigned char data[2];
-    cyg_uint32 pos; 
-    cyg_uint16 e;
-    int i, len, err;
-
-    pos = disk->fat_tbl_pos + (num << 1);
-    len = 2;
-    
-    e = *entry;
-    SET_WORD(data, e, 0x00);
-
-    for (i = 0; i < disk->fat_tbls_num; i++)
-    {
-        err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, pos);
-        if (err != ENOERR)
-            return err;
-
-        CYG_TRACE4(TFT, "tentry=%x num=%d at %d tbl=%d", *entry, num, pos, i);
-
-        pos += disk->fat_tbl_size;
-    }
-    
-    return ENOERR;
-}
-
-static int
-write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
-{
-    switch (disk->fat_type)
-    {
-        case FATFS_FAT12: return write_tentry_fat12(disk, num, entry);
-        case FATFS_FAT16: return write_tentry_fat16(disk, num, entry);
-        default: return EINVAL;                  
-    }
-}
-
 // -------------------------------------------------------------------------
 // get_tentry_type()
 // Gets the type of FAT table entry.
  
 static int
-get_tentry_type_fat12(fatfs_disk_t *disk, cyg_uint32 entry)
-{
-    int type;
-
-    if (entry < 0x0FF0)
-    {
-        if (0x0000 == entry)  type = TENTRY_FREE;
-        else                  type = TENTRY_REGULAR;
-    }
-    else if (entry >= 0x0FF8) type = TENTRY_LAST;
-    else if (0x0FF7 == entry) type = TENTRY_BAD;
-    else                      type = TENTRY_RESERVED;
-
-#if TFT
-    CYG_TRACE2(TFT, "tentry=%04X type=%s", entry, tentry_type_name[type]);
-#endif
-
-    return type;
-}
-
-static int
-get_tentry_type_fat16(fatfs_disk_t *disk, cyg_uint32 entry)
+get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry)
 {
     int type;
 
-    if (entry < 0xFFF0)
-    {
-        if (0x0000 == entry)  type = TENTRY_FREE;
-        else                  type = TENTRY_REGULAR;
-    }
-    else if (entry >= 0xFFF8) type = TENTRY_LAST;
-    else if (0xFFF7 == entry) type = TENTRY_BAD;
-    else                      type = TENTRY_RESERVED;
-
-#if TFT
-    CYG_TRACE2(TFT, "tentry=%04X type=%s", entry, tentry_type_name[type]);
-#endif
-
-    return type;
-}
-
-static int
-get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry)
-{
     switch (disk->fat_type)
     {
-        case FATFS_FAT12: return get_tentry_type_fat12(disk, entry);
-        case FATFS_FAT16: return get_tentry_type_fat16(disk, entry);
-        default: return TENTRY_BAD;
+        case FATFS_FAT12:
+            if (entry < 0x0FF0)
+            {
+                if (0x0000 == entry)  type = TENTRY_FREE;
+                else                  type = TENTRY_REGULAR;
+            }
+            else if (entry >= 0x0FF8) type = TENTRY_LAST;
+            else if (0x0FF7 == entry) type = TENTRY_BAD;
+            else                      type = TENTRY_RESERVED;
+
+            break;
+
+        case FATFS_FAT16:
+            if (entry < 0xFFF0)
+            {
+                if (0x0000 == entry)  type = TENTRY_FREE;
+                else                  type = TENTRY_REGULAR;
+            }
+            else if (entry >= 0xFFF8) type = TENTRY_LAST;
+            else if (0xFFF7 == entry) type = TENTRY_BAD;
+            else                      type = TENTRY_RESERVED;
+
+            break;
+
+        case FATFS_FAT32:
+
+            if (entry < 0x0FFFFFF0)
+            {
+                if (0x00000000 == entry)  type = TENTRY_FREE;
+                else                      type = TENTRY_REGULAR;
+            }
+            else if (entry >= 0x0FFFFFF8) type = TENTRY_LAST;
+            else if (0x0FFFFFF7 == entry) type = TENTRY_BAD;
+            else                          type = TENTRY_RESERVED;
+
+            break;
+
+        default:
+            CYG_ASSERT(false, "Unknown FAT type");
+            type = TENTRY_BAD; // least likely to cause damage
     }
+    return type;
 }
 
 // -------------------------------------------------------------------------
@@ -694,40 +788,48 @@ get_tentry_type(fatfs_disk_t *disk, cyg_
 // Sets the type of FAT table entry.
  
 static void 
-set_tentry_type_fat12(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
-{
-    switch (type)
-    {
-        case TENTRY_FREE:     *entry = 0x0000; break;
-        case TENTRY_LAST:     *entry = 0x0FF8; break;
-        case TENTRY_RESERVED: *entry = 0x0FF0; break;
-        case TENTRY_BAD:      *entry = 0x0FF7; break;      
-        default:
-            CYG_ASSERT(false, "Unknown tentry type");
-    }
-}
-
-static void 
-set_tentry_type_fat16(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
-{
-    switch (type)
-    {
-        case TENTRY_FREE:     *entry = 0x0000; break;
-        case TENTRY_LAST:     *entry = 0xFFF8; break;
-        case TENTRY_RESERVED: *entry = 0xFFF0; break;
-        case TENTRY_BAD:      *entry = 0xFFF7; break;      
-        default:
-            CYG_ASSERT(false, "Unknown tentry type");
-    }
-}
-
-static void 
 set_tentry_type(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
 {
     switch (disk->fat_type)
     {
-        case FATFS_FAT12: set_tentry_type_fat12(disk, entry, type);
-        case FATFS_FAT16: set_tentry_type_fat16(disk, entry, type);
+        case FATFS_FAT12:
+            switch (type)
+            {
+                case TENTRY_FREE:     *entry = 0x0000; return;
+                case TENTRY_LAST:     *entry = 0x0FF8; return;
+                case TENTRY_RESERVED: *entry = 0x0FF0; return;
+                case TENTRY_BAD:      *entry = 0x0FF7; return;      
+                default:
+                    CYG_ASSERT(false, "Unknown tentry type");
+            }
+            break;
+            
+        case FATFS_FAT16:
+            switch (type)
+            {
+                case TENTRY_FREE:     *entry = 0x0000; return;
+                case TENTRY_LAST:     *entry = 0xFFF8; return;
+                case TENTRY_RESERVED: *entry = 0xFFF0; return;
+                case TENTRY_BAD:      *entry = 0xFFF7; return;
+                default:
+                    CYG_ASSERT(false, "Unknown tentry type");
+            }
+            break;
+            
+        case FATFS_FAT32:
+            switch (type)
+            {
+                case TENTRY_FREE:     *entry = 0x00000000; return;
+                case TENTRY_LAST:     *entry = 0x0FFFFFF8; return;
+                case TENTRY_RESERVED: *entry = 0x0FFFFFF0; return;
+                case TENTRY_BAD:      *entry = 0x0FFFFFF7; return;      
+                default:
+                    CYG_ASSERT(false, "Unknown tentry type");
+            }
+            break;
+
+        default:
+            CYG_ASSERT(false, "Unknown FAT type");
     }
 }
 
@@ -757,38 +859,29 @@ set_tentry_next_cluster(fatfs_disk_t *di
 // FAT cluster functions 
 
 // -------------------------------------------------------------------------
-// is_pos_inside_cluster()
-// Checks if the given position is inside cluster size.
-
-static __inline__ bool 
-is_pos_inside_cluster(fatfs_disk_t *disk, cyg_uint32 pos)
-{
-    return (pos < disk->cluster_size);
-}
-
-// -------------------------------------------------------------------------
 // erase_cluster()
-// Erases cluster (fills with 0x00). 
+// Erases cluster (fills with 0x00).
 
 static int
 erase_cluster(fatfs_disk_t *disk, cyg_uint32 cluster)
 {
-    unsigned char data[32];
-    cyg_uint32 apos;
-    int err, len, i;
+    cyg_uint8  data[32];
+    cyg_uint32 pos;
+    int        err, len, i;
     
+    pos = 0;
     len = 32;
     memset((void*)data, 0x00, len);
-    apos = get_data_disk_apos(disk, cluster, 0);
     
-    CYG_TRACE1(TCL, "cluster=%d", cluster);
+    CYG_TRACE1(TCL, "erasing cluster=%d", cluster);
 
     for (i = 0; i < (disk->cluster_size >> 5); i++)
     {
-        err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, apos);
+        err = disk_cluster_write(disk, (void*)data, &len, cluster, pos);
         if (err != ENOERR)
             return err;
-        apos += len;
+
+        pos += len;
     }
     
     return ENOERR;
@@ -802,14 +895,9 @@ static int
 mark_cluster(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 type)
 {
     cyg_uint32 tentry;
-    int err;
  
     set_tentry_type(disk, &tentry, type);
-    err = write_tentry(disk, cluster, &tentry);
-
-    CYG_TRACE3(TCL, "cluster=%d type=%d tentry=%d", 
-                    cluster, type, tentry);
-    return err;
+    return write_tentry(disk, cluster, &tentry);
 }
 
 // -------------------------------------------------------------------------
@@ -820,45 +908,39 @@ static int
 link_cluster(fatfs_disk_t *disk, cyg_uint32 cluster1, cyg_uint32 cluster2)
 {
     cyg_uint32 tentry;
-    int err;
     
     set_tentry_next_cluster(disk, &tentry, cluster2);
-    err = write_tentry(disk, cluster1, &tentry);
- 
-    CYG_TRACE3(TCL, "cluster1=%d cluster2=%d tentry=%d", 
-                    cluster1, cluster2, tentry);
-    return err;
+    return write_tentry(disk, cluster1, &tentry);
 }
 
 // -------------------------------------------------------------------------
 // find_next_free_cluster()
 // Finds first free cluster starting from given cluster.
 // If none is available free_cluster is set to 0.
-// If mark_as_last is set the found cluster is marked as LAST.
+// If CO_MARK_LAST is set in opts the found cluster is marked as LAST.
+// If CO_ERASE_NEW is set in opts the found cluster is erased.
 
 static int
-find_next_free_cluster(fatfs_disk_t  *disk,
-                       cyg_uint32     start_cluster, 
-                       cyg_uint32    *free_cluster,
-                       cluster_opts_t opts)
+find_next_free_cluster(fatfs_disk_t   *disk,
+                       cyg_uint32      start_cluster, 
+                       cyg_uint32     *free_cluster,
+                       cluster_opts_t  opts)
 {
     cyg_uint32 c, tentry;
-    int err;
+    int        err;
 
-    if (start_cluster < 2)
-        c = 2;
-    else
-        c = start_cluster + 1;
+    if (start_cluster < 2) c = 2;
+    else                   c = start_cluster + 1;
 
     *free_cluster = 0;
 
-    CYG_TRACE1(TCL, "c=%d", c);
+    CYG_TRACE1(TCL, "starting at cluster=%d", c);
    
     // Search from the starting cluster to the end of FAT and
-    // from start of FAT to the starting cluster 
+    // from start of FAT to the starting cluster
     while (c != start_cluster)
     {
-        // End of FAT check
+        // Check for end of FAT
         if (c >= disk->fat_tbl_nents)
         {
             c = 2;
@@ -872,21 +954,24 @@ find_next_free_cluster(fatfs_disk_t  *di
 
         if (TENTRY_FREE == get_tentry_type(disk, tentry))
         {
-            CYG_TRACE1(TCL, "free_cluster=%d", c);
+            CYG_TRACE1(TCL, "found free cluster=%d", c);
+            
             *free_cluster = c;
+            
             if (opts & CO_MARK_LAST)
                 err = mark_cluster(disk, c, TENTRY_LAST);
             if ((err == ENOERR) && (opts & CO_ERASE_NEW))
                 err = erase_cluster(disk, c);
+            
             return err;
         }
         c++;
     }   
 
     // No free clusters found
+
     CYG_TRACE0(TCL, "!!! no free clusters found");
  
-    // Return out of space
     return ENOSPC;
 }
 
@@ -896,92 +981,59 @@ find_next_free_cluster(fatfs_disk_t  *di
 // New cluster is marked as LAST. 
 
 static int
-find_and_append_cluster(fatfs_disk_t  *disk, 
-                        cyg_uint32     cluster, 
-                        cyg_uint32    *new_cluster,
-                        cluster_opts_t opts)
+find_and_append_cluster(fatfs_disk_t   *disk, 
+                        cyg_uint32      cluster, 
+                        cyg_uint32     *new_cluster,
+                        cluster_opts_t  opts)
 {
     cyg_uint32 free_cluster;
-    int err;
+    int        err;
 
-    CYG_TRACE1(TCL, "cluster=%d", cluster);
-    
     err = find_next_free_cluster(disk, cluster, 
-            &free_cluster, opts | CO_MARK_LAST);
+        &free_cluster, opts | CO_MARK_LAST);
     if (err != ENOERR)
         return err;
 
-    CYG_TRACE1(TCL, "free_cluster=%d", free_cluster);
-    
-    // Link clusters    
     err = link_cluster(disk, cluster, free_cluster);
     if (err != ENOERR)
         return err;
 
     *new_cluster = free_cluster;
 
-    CYG_TRACE1(TCL, "new_cluster=%d", free_cluster);
+    CYG_TRACE2(TCL, "appending new cluster=%d to cluster=%d", 
+                    free_cluster, cluster);
     
     return ENOERR;
 }
 
 // -------------------------------------------------------------------------
 // find_nth_cluster0()
-// Finds nth cluster in chain (ie nth cluster of file).
-// Searching from given position.
+// Finds nth cluster in chain (ie nth cluster of file) searching
+// from given position. The result is returned by the same position
+// variable. 
  
 static int
 find_nth_cluster0(fatfs_disk_t     *disk,
-                  fatfs_data_pos_t *dpos, 
-                  cyg_uint32        n,
-                  fatfs_tcache_t   *tcache)
+                  fatfs_data_pos_t *pos, 
+                  cyg_uint32        n)
 {
     cyg_uint32 cluster, cluster_snum;
-    int err = ENOERR;
+    int        err = ENOERR;
  
-    // Trivial case check
-    if (dpos->cluster_snum == n)
+    if (pos->cluster_snum == n)
         return ENOERR;
 
-    // First look in cache
-    if (NULL != tcache)
-    {
-        cyg_uint32 c, ln;
-        if (fatfs_tcache_get(disk, tcache, n, &c))
-        {
-            // Cluster in cache
-            dpos->cluster = c;
-            dpos->cluster_snum = n;
-            CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d in cache", c, n);
-            return ENOERR;
-        }
-        else if (fatfs_tcache_get_last(disk, tcache, &ln, &c))
-        {
-            // Cluster not in cache - get last
-            // in cache and search from there
-            dpos->cluster = c;
-            dpos->cluster_snum = ln;  
-            CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d last in cache", c, ln);
-        }
-        else
-        {
-            // Empty cache - put first cluster in
-            fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->cluster);
-        }
-    }
+    cluster      = pos->cluster;
+    cluster_snum = pos->cluster_snum;
    
-    cluster      = dpos->cluster;
-    cluster_snum = dpos->cluster_snum;
-   
-    CYG_TRACE4(TCL, "cluster=%d cluster_snum=%d n=%d n_to_search=%d",
+    CYG_TRACE4(TCL, "cluster=%d snum=%d n=%d n_to_search=%d",
                     cluster, cluster_snum, n, n-cluster_snum);
    
     // Adjust the number of clusters that should be
     // walked according to the given position
     n -= cluster_snum;
 
-    // Walk the cluster chain for n clusters or
-    // until last cluster
+    // Walk the cluster chain for n clusters or until last cluster
     while (n > 0)
     {
         cyg_uint32 tentry;
@@ -995,8 +1047,7 @@ find_nth_cluster0(fatfs_disk_t     *disk
             case TENTRY_REGULAR:
                 break;
             case TENTRY_LAST:
-                // Oops early last cluster
-                CYG_TRACE1(TCL, "chain end n=%d", n);
+                CYG_TRACE1(TCL, "chain end at n=%d", n);
                 err = EEOF; // File has less clusters than given n
                             // this err should be caught by the 
                             // calling function 
@@ -1010,67 +1061,57 @@ find_nth_cluster0(fatfs_disk_t     *disk
         }
         cluster = get_tentry_next_cluster(disk, tentry);
         cluster_snum++;
-        if (NULL != tcache)
-            fatfs_tcache_set(disk, tcache, cluster_snum, cluster);
         n--;
     }
     
 out:
-    dpos->cluster      = cluster;
-    dpos->cluster_snum = cluster_snum;
+    pos->cluster      = cluster;
+    pos->cluster_snum = cluster_snum;
 
-    CYG_TRACE2(TCL, "nth cluster=%d cluster_snum=%d", cluster, cluster_snum);
+    CYG_TRACE2(TCL, "nth cluster=%d snum=%d", cluster, cluster_snum);
+
     return err;
 }
 
 // -------------------------------------------------------------------------
 // find_nth_cluster()
 // Finds nth cluster in chain (ie nth cluster of file) searching 
-// from given position. If the chain ends one cluster before the 
-// given nth cluster and the CO_EXTEND is specifide, than the 
-// chain is extended by one cluster.
+// from given position. The result is returned by the same position
+// variable. If the chain ends one cluster before the given nth cluster 
+// and the CO_EXTEND is specified, than the chain is extended by one cluster.
  
 static int
 find_nth_cluster(fatfs_disk_t     *disk,
-                 fatfs_data_pos_t *dpos, 
+                 fatfs_data_pos_t *pos, 
                  cyg_uint32        n,
-                 fatfs_tcache_t   *tcache,
                  cluster_opts_t    opts)
 {
     int err;
    
     // Find nth cluster 
-    err = find_nth_cluster0(disk, dpos, n, tcache);    
+    err = find_nth_cluster0(disk, pos, n);    
 
     // EEOF meens that the cluster chain ended early
     if ((err != EEOF) || !(opts & CO_EXTEND))
         return err;
     
-    CYG_TRACE2(TCL, "cluster_snum=%d n=%d", dpos->cluster_snum, n);
-    
     // Check if one cluster short
-    if (dpos->cluster_snum == (n - 1))
+    if (pos->cluster_snum == (n - 1))
     {
         // Extend the chain for one cluster
         cyg_uint32 new_cluster;
 
         // Append new cluster to the end of chain
-        err = find_and_append_cluster(disk, dpos->cluster, 
-                                      &new_cluster, opts);
+        err = find_and_append_cluster(disk, pos->cluster, &new_cluster, opts);
         if (err != ENOERR)
             return err;
 
         // Update position
-        dpos->cluster = new_cluster;
-        dpos->cluster_snum++;
-        dpos->cluster_pos = 0;
+        pos->cluster       = new_cluster;
+        pos->cluster_snum += 1;
+        pos->cluster_pos   = 0;
 
-        CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", 
-                        dpos->cluster, dpos->cluster_snum);
-        
-        // Update cache
-        if (NULL != tcache)
-            fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->cluster);
+        CYG_TRACE1(TCL, "appended new cluster=%d", new_cluster);
     }
     
     return err;
@@ -1079,71 +1120,72 @@ find_nth_cluster(fatfs_disk_t     *disk,
 // -------------------------------------------------------------------------
 // get_next_cluster()
 // Gets next cluster in chain (ie next cluster of file).
-// If CO_EXTEND is specified and the current cluster is last in 
+// If CO_EXTEND is specified and the current cluster is last in the 
 // chain then the chain is extended by one cluster.
 
 static int
 get_next_cluster(fatfs_disk_t     *disk,
-                 fatfs_data_pos_t *dpos,
-                 fatfs_tcache_t   *tcache,
+                 fatfs_data_pos_t *pos,
                  cluster_opts_t    opts)
 {
     int err;
 
-    CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", 
-                    dpos->cluster, dpos->cluster_snum);
-
-    err = find_nth_cluster(disk, dpos, dpos->cluster_snum + 1, tcache, opts);
-
+    err = find_nth_cluster(disk, pos, pos->cluster_snum + 1, opts);
     if (err != ENOERR)
         return err;
 
-    // Update position
-    dpos->cluster_pos = 0;
+    // Reset inside cluster position
+    pos->cluster_pos = 0;
  
-    CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", 
-                    dpos->cluster, dpos->cluster_snum);
-    
     return ENOERR;
 }
 
 // -------------------------------------------------------------------------
-// get_data_position_from_off()
-// Gets data position from given file offset.
-// If CO_EXTEND is specified the file is extended if 
-// one cluster too short. 
- 
-static int 
-get_data_position_from_off(fatfs_disk_t     *disk,
-                           cyg_uint32        first_cluster, 
-                           cyg_uint32        offset, 
-                           fatfs_data_pos_t *dpos,
-                           fatfs_tcache_t   *tcache,
-                           cluster_opts_t    opts)
+// get_position_from_off()
+// Gets position from given offset. The search is started from the
+// given position and the result is returned by the same variable. 
+// If CO_EXTEND is specified the file is extended if one cluster too short.
+
+static int
+get_position_from_off(fatfs_disk_t     *disk,
+                      cyg_uint32        first_cluster,
+                      cyg_uint32        offset,
+                      fatfs_data_pos_t *pos,
+                      cluster_opts_t    opts)
 {
-    cyg_uint32 n;
-    int err;
+    fatfs_data_pos_t new_pos;
+    cyg_uint32       n;
+    int              err;
 
     // Position inside the cluster
-    dpos->cluster_pos = offset & (disk->cluster_size - 1);
+    new_pos.cluster_pos = offset & (disk->cluster_size - 1);
 
     // Cluster seq number to be searched for
     n = offset >> disk->cluster_size_log2;
 
-    // Start searching from first cluster
-    dpos->cluster      = first_cluster;
-    dpos->cluster_snum = 0;
+    if (n < pos->cluster_snum)
+    { 
+        // Start searching from first cluster
+        new_pos.cluster      = first_cluster;
+        new_pos.cluster_snum = 0;
+    }
+    else
+    {
+        // Start searching from the current position
+        new_pos.cluster      = pos->cluster;
+        new_pos.cluster_snum = pos->cluster_snum;
+    }
 
-    CYG_TRACE4(TCL, "off=%d first_cluster=%d cluster_pos=%d n=%d\n",
-                    offset, first_cluster, dpos->cluster_pos, n);
-
-    err = find_nth_cluster(disk, dpos, n, tcache, opts);
-
+    err = find_nth_cluster(disk, &new_pos, n, opts);
+    
     // Err could be EEOF wich means that the given 
     // offset if out of given file (cluster chain)
 
+    if (ENOERR == err)
+        *pos = new_pos; 
+    
     return err;
-}
+} 
 
 // -------------------------------------------------------------------------
 // free_cluster_chain()
@@ -1153,10 +1195,10 @@ static int
 free_cluster_chain(fatfs_disk_t *disk, cyg_uint32 start_cluster)
 {
     cyg_uint32 c, next_c, tentry;
-    bool last;
-    int err;
+    bool       last;
+    int        err;
 
-    CYG_TRACE1(TCL, "start_cluster=%d", start_cluster);
+    CYG_TRACE1(TCL, "start cluster=%d", start_cluster);
 
     c = next_c = start_cluster;
     last = false;
@@ -1192,7 +1234,7 @@ free_cluster_chain(fatfs_disk_t *disk, c
         c = next_c; 
     }
 
-    CYG_TRACE1(TCL, "last_cluster=%d", c);
+    CYG_TRACE1(TCL, "last cluster=%d", c);
     
     return ENOERR;
 }
@@ -1201,166 +1243,161 @@ free_cluster_chain(fatfs_disk_t *disk, c
 // FAT dir entry functions 
 
 // -------------------------------------------------------------------------
-// print_dentry()
+// print_raw_dentry()
 // Prints FAT directory entry. 
 
 #if TDE
 static void
-print_dentry(fat_dir_entry_t* fde)
+print_raw_dentry(fat_raw_dir_entry_t* dentry)
 {
-    if (DENTRY_IS_DELETED(fde))
-        diag_printf("FAT: FDE name:    '?%.7s'\n", &fde->name[1]);
+    if (DENTRY_IS_DELETED(dentry))
+        diag_printf("FAT: FDE name:    '?%.7s'\n", &dentry->name[1]);
     else    
-        diag_printf("FAT: FDE name:    '%.8s'\n", fde->name);
-    diag_printf("FAT: FDE ext:     '%.3s'\n", fde->ext);
+        diag_printf("FAT: FDE name:    '%.8s'\n", dentry->name);
+    diag_printf("FAT: FDE ext:     '%.3s'\n", dentry->ext);
     diag_printf("FAT: FDE attr:     %c%c%c%c%c%c\n", 
-                (DENTRY_IS_RDONLY(fde)  ? 'R' : '-'),
-                (DENTRY_IS_HIDDEN(fde)  ? 'H' : '-'),
-                (DENTRY_IS_SYSTEM(fde)  ? 'S' : '-'),
-                (DENTRY_IS_VOLUME(fde)  ? 'V' : '-'),
-                (DENTRY_IS_DIR(fde)     ? 'D' : '-'),
-                (DENTRY_IS_ARCHIVE(fde) ? 'A' : '-'));
-    diag_printf("FAT: FDE crt time: %u\n", fde->crt_time);
-    diag_printf("FAT: FDE crt date: %u\n", fde->crt_date);
-    diag_printf("FAT: FDE acc date: %u\n", fde->acc_date);
-    diag_printf("FAT: FDE wrt time: %u\n", fde->wrt_time);
-    diag_printf("FAT: FDE wrt date: %u\n", fde->wrt_date);
-    diag_printf("FAT: FDE cluster:  %u\n", fde->cluster);
-    diag_printf("FAT: FDE size:     %u\n", fde->size);
+                (DENTRY_IS_RDONLY(dentry)  ? 'R' : '-'),
+                (DENTRY_IS_HIDDEN(dentry)  ? 'H' : '-'),
+                (DENTRY_IS_SYSTEM(dentry)  ? 'S' : '-'),
+                (DENTRY_IS_VOLUME(dentry)  ? 'V' : '-'),
+                (DENTRY_IS_DIR(dentry)     ? 'D' : '-'),
+                (DENTRY_IS_ARCHIVE(dentry) ? 'A' : '-'));
+    diag_printf("FAT: FDE crt time: %u\n", dentry->crt_time);
+    diag_printf("FAT: FDE crt date: %u\n", dentry->crt_date);
+    diag_printf("FAT: FDE acc date: %u\n", dentry->acc_date);
+    diag_printf("FAT: FDE wrt time: %u\n", dentry->wrt_time);
+    diag_printf("FAT: FDE wrt date: %u\n", dentry->wrt_date);
+    diag_printf("FAT: FDE cluster:  %u\n", dentry->cluster);
+    diag_printf("FAT: FDE size:     %u\n", dentry->size);
 }
 #endif // TDE
 
 // -------------------------------------------------------------------------
-// read_dentry()
-// Reads dir entry from disk. 
-// If cluster is 0 reads from root dir.
+// read_raw_dentry()
+// Reads dir entry from disk.
  
 static int
-read_dentry(fatfs_disk_t     *disk,
-            fatfs_data_pos_t *dpos, 
-            fat_dir_entry_t  *fde)
+read_raw_dentry(fatfs_disk_t        *disk,
+                fatfs_data_pos_t    *pos, 
+                fat_raw_dir_entry_t *dentry)
 {
-    unsigned char data[DENTRY_SIZE];
-    cyg_uint32 apos;
-    int len, err;
+    cyg_uint8  data[DENTRY_SIZE];
+    int        len, err;
+ 
+    CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
+               pos->cluster, pos->cluster_snum, pos->cluster_pos); 
    
-    // Check if we are reading the root directory
-    if (0 == dpos->cluster)
-        apos = disk->fat_root_dir_pos + dpos->cluster_pos;
+    len = DENTRY_SIZE;
+
+    // Check if we are reading the FAT12/16 root directory
+    if (0 == pos->cluster)
+        err = disk_read(disk, (void*)data, &len,  
+                        disk->fat_root_dir_pos + pos->cluster_pos);
     else
-        apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);    
-   
-    CYG_TRACE3(TDE, "cluster=%d pos=%d apos=%d",
-                    dpos->cluster, dpos->cluster_pos, apos); 
-    
-    len = DENTRY_SIZE;
-    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, apos);
+        err = disk_cluster_read(disk, (void*)data, &len, 
+                                pos->cluster, pos->cluster_pos);
     if (err != ENOERR)
         return err;
 
-    GET_BYTES(data, fde->name,     8, 0x00);
-    GET_BYTES(data, fde->ext,      3, 0x08);
-    GET_BYTE(data,  fde->attr,        0x0B);
-    GET_BYTE(data,  fde->nt_reserved, 0x0C);
-    GET_BYTE(data,  fde->crt_sec_100, 0x0D);
-    GET_WORD(data,  fde->crt_time,    0x0E);
-    GET_WORD(data,  fde->crt_date,    0x10);
-    GET_WORD(data,  fde->acc_date,    0x12);
-    GET_WORD(data,  fde->cluster_HI,  0x14);
-    GET_WORD(data,  fde->wrt_time,    0x16);
-    GET_WORD(data,  fde->wrt_date,    0x18);
-    GET_WORD(data,  fde->cluster,     0x1A);
-    GET_DWORD(data, fde->size,        0x1C);
+    GET_BYTES(data, dentry->name,     8, 0x00);
+    GET_BYTES(data, dentry->ext,      3, 0x08);
+    GET_BYTE(data,  dentry->attr,        0x0B);
+    GET_BYTE(data,  dentry->nt_reserved, 0x0C);
+    GET_BYTE(data,  dentry->crt_sec_100, 0x0D);
+    GET_WORD(data,  dentry->crt_time,    0x0E);
+    GET_WORD(data,  dentry->crt_date,    0x10);
+    GET_WORD(data,  dentry->acc_date,    0x12);
+    GET_WORD(data,  dentry->cluster_HI,  0x14);
+    GET_WORD(data,  dentry->wrt_time,    0x16);
+    GET_WORD(data,  dentry->wrt_date,    0x18);
+    GET_WORD(data,  dentry->cluster,     0x1A);
+    GET_DWORD(data, dentry->size,        0x1C);
 
      // Zero terminate strings
-    fde->name[8] = '\0';    
-    fde->ext[3]  = '\0';    
+    dentry->name[8] = '\0';    
+    dentry->ext[3]  = '\0';    
   
-    // Store position
-    fde->pos = *dpos;
-       
 #if TDE    
-    print_dentry(fde);
+    print_raw_dentry(dentry);
 #endif
 
     return ENOERR;
 }
 
 // -------------------------------------------------------------------------
-// write_dentry()
-// Writes dir entry to disk. 
-// If cluster is 0 writes to root dir.
+// write_raw_dentry()
+// Writes raw dir entry to disk. 
  
 static int
-write_dentry(fatfs_disk_t     *disk,
-             fatfs_data_pos_t *dpos, 
-             fat_dir_entry_t  *fde)
+write_raw_dentry(fatfs_disk_t        *disk,
+                 fatfs_data_pos_t    *pos, 
+                 fat_raw_dir_entry_t *dentry)
 {
-    unsigned char data[DENTRY_SIZE];
-    cyg_uint32 apos;
-    int len, err;
-    
-    // Check if we are writting to the root directory
-    if (0 == dpos->cluster)
-        apos = disk->fat_root_dir_pos + dpos->cluster_pos;
-    else
-        apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);    
+    cyg_uint8  data[DENTRY_SIZE];
+    int        len, err;
  
-    CYG_TRACE3(TDE, "cluster=%d pos=%d apos=%d",
-                    dpos->cluster, dpos->cluster_pos, apos); 
-
-    SET_BYTES(data, fde->name,     8, 0x00);
-    SET_BYTES(data, fde->ext,      3, 0x08);
-    SET_BYTE(data,  fde->attr,        0x0B);
-    SET_BYTE(data,  fde->nt_reserved, 0x0C);
-    SET_BYTE(data,  fde->crt_sec_100, 0x0D);
-    SET_WORD(data,  fde->crt_time,    0x0E);
-    SET_WORD(data,  fde->crt_date,    0x10);
-    SET_WORD(data,  fde->acc_date,    0x12);
-    SET_WORD(data,  fde->cluster_HI,  0x14);
-    SET_WORD(data,  fde->wrt_time,    0x16);
-    SET_WORD(data,  fde->wrt_date,    0x18);
-    SET_WORD(data,  fde->cluster,     0x1A);
-    SET_DWORD(data, fde->size,        0x1C);
+    CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
+               pos->cluster, pos->cluster_snum, pos->cluster_pos); 
+   
+    SET_BYTES(data, dentry->name,     8, 0x00);
+    SET_BYTES(data, dentry->ext,      3, 0x08);
+    SET_BYTE(data,  dentry->attr,        0x0B);
+    SET_BYTE(data,  dentry->nt_reserved, 0x0C);
+    SET_BYTE(data,  dentry->crt_sec_100, 0x0D);
+    SET_WORD(data,  dentry->crt_time,    0x0E);
+    SET_WORD(data,  dentry->crt_date,    0x10);
+    SET_WORD(data,  dentry->acc_date,    0x12);
+    SET_WORD(data,  dentry->cluster_HI,  0x14);
+    SET_WORD(data,  dentry->wrt_time,    0x16);
+    SET_WORD(data,  dentry->wrt_date,    0x18);
+    SET_WORD(data,  dentry->cluster,     0x1A);
+    SET_DWORD(data, dentry->size,        0x1C);
    
     len = DENTRY_SIZE;
-    err = cyg_blib_write(&disk->blib, (void*)data, &len, 0, apos);
+
+    // Check if we are writting to the FAT12/16 root directory
+    if (0 == pos->cluster)
+        err = disk_write(disk, (void*)data, &len, 
+                         disk->fat_root_dir_pos + pos->cluster_pos);
+    else
+        err = disk_cluster_write(disk, (void*)data, &len,
+                                 pos->cluster, pos->cluster_pos); 
     if (err != ENOERR)
         return err;
 
 #if TDE    
-    print_dentry(fde);
+    print_raw_dentry(dentry);
 #endif
 
     return ENOERR;
 }
 
 // -------------------------------------------------------------------------
-// dentry_set_deleted()
+// raw_dentry_set_deleted()
 // Sets the dentry filename first char to 0xE5 (ie deleted). 
  
 static __inline__ void 
-dentry_set_deleted(fatfs_disk_t *disk, fat_dir_entry_t *dentry)
+raw_dentry_set_deleted(fatfs_disk_t *disk, fat_raw_dir_entry_t *dentry)
 {
     dentry->name[0] = 0xE5;
 }
 
 // -------------------------------------------------------------------------
-// get_dentry_filename()
+// get_raw_dentry_filename()
 // Gets the filename from given dir entry. 
  
 static void 
-get_dentry_filename(fat_dir_entry_t *fde, char *name)
+get_raw_dentry_filename(fat_raw_dir_entry_t *dentry, char *name)
 {
-    int i = 0;
-    char *cptr  = fde->name;
+    int   i     = 0;
+    char *cptr  = dentry->name;
     char *cname = name;
 
     while (*cptr != ' ' && i < 8)
     {
         *cname++ = *cptr++; i++;
     }
-    cptr = fde->ext;
+    cptr = dentry->ext;
 
     if (*cptr != ' ')
     {
@@ -1372,34 +1409,36 @@ get_dentry_filename(fat_dir_entry_t *fde
     }
     *cname = '\0';
 
-    CYG_TRACE3(TDE, "dos_name='%s' dos_ext='%s' filename='%s'",
-                    fde->name, fde->ext, name);
+    CYG_TRACE3(TDE, "dos name='%s' dos ext='%s' filename='%s'",
+                    dentry->name, dentry->ext, name);
 }
 
 // -------------------------------------------------------------------------
-// set_dentry_filename()
-// Sets the filename to given dir entry. 
+// set_raw_dentry_filename()
+// Sets the filename of given dir entry. 
  
 static void 
-set_dentry_filename(fat_dir_entry_t *fde, const char *name, int namelen)
+set_raw_dentry_filename(fat_raw_dir_entry_t *dentry, 
+                        const char          *name, 
+                        int                  namelen)
 {
-    int i, nidx;
+    int         i, nidx;
     const char *cname;
-    char *cptr;
+    char       *cptr;
 
     // Special case check
-    if (name[0] == '.')
+    if ('.' == name[0])
     {
-        if (name[1] == '\0')
+        if ('\0' == name[1])
         {
-            strcpy(fde->name, ".       ");
-            strcpy(fde->ext,  "   ");
+            strcpy(dentry->name, ".       ");
+            strcpy(dentry->ext,  "   ");
             return;
         }
-        else if (name[1] == '.' && name[2] == '\0')
+        else if ('.' == name[1] && '\0' == name[2])
         {
-            strcpy(fde->name, "..      ");
-            strcpy(fde->ext,  "   ");
+            strcpy(dentry->name, "..      ");
+            strcpy(dentry->ext,  "   ");
             return;
         }
     }
@@ -1409,7 +1448,7 @@ set_dentry_filename(fat_dir_entry_t *fde
     
     nidx  = 0;
     cname = name;
-    cptr  = fde->name;
+    cptr  = dentry->name;
     for (i = 0; i < 8; i++)
     {
         if (*cname != '.' && *cname != '\0' && nidx++ < namelen)
@@ -1422,10 +1461,10 @@ set_dentry_filename(fat_dir_entry_t *fde
     while (*cname != '.' && *cname != '\0' && nidx++ < namelen)
         cname++;
    
-    if (*cname == '.' && nidx++ < namelen) 
+    if ('.' == *cname && nidx++ < namelen) 
         cname++;
     
-    cptr = fde->ext;
+    cptr = dentry->ext;
     for (i = 0; i < 3; i++)
     {
         if (*cname != '.' && *cname != '\0' && nidx++ < namelen)
@@ -1435,66 +1474,46 @@ set_dentry_filename(fat_dir_entry_t *fde
     }
     *cptr = '\0';
 
-    CYG_TRACE4(TDE, "filename='%s' namelen=%d dos_name='%s' dos_ext='%s'", 
-                    name, namelen, fde->name, fde->ext);
+    CYG_TRACE4(TDE, "filename='%s' namelen=%d dos name='%s' dos ext='%s'", 
+                    name, namelen, dentry->name, dentry->ext);
 }
 
 // -------------------------------------------------------------------------
-// get_next_dentry()
+// read_next_raw_dentry()
 // Gets next dir entry searching from given position to the end.
-// Position is expected in DENTRY_SIZE units.
-// If EEOF is returned there are no more extries in given dir.
+// If EEOF is returned there are no more entries in given dir.
  
 static int
-get_next_dentry(fatfs_disk_t    *disk,
-                fatfs_node_t    *dir,
-                cyg_uint32      *pos,
-                fat_dir_entry_t *dentry)
+read_next_raw_dentry(fatfs_disk_t        *disk,
+                     fatfs_data_pos_t    *pos,
+                     fat_raw_dir_entry_t *dentry)
 {
-    fatfs_data_pos_t dpos;
-    cyg_uint32 off;
     int err = ENOERR;
 
-    // Calculate dentry offset
-    off = *pos * DENTRY_SIZE;
-    
-    CYG_TRACE4(TDE, "pos=%d off=%d dir=%p cluster=%d",
-                    off, *pos, dir, dir->cluster);
-
-    // Root dir check
-    if (0 == dir->cluster)
-    {
-        dpos.cluster      = 0;
-        dpos.cluster_snum = 0;
-        dpos.cluster_pos  = off;
-    }
-    else
-    {
-        err = get_data_position_from_off(disk, dir->cluster, 
-            off, &dpos, &dir->tcache, false);
-        if (err != ENOERR)
-            return err;
-    }
-
+    // If we are reading the root dir on FAT32 we have
+    // to correct the position to the root dir cluster
+    if (FATFS_FAT32 == disk->fat_type && 0 == pos->cluster)
+        pos->cluster = disk->fat_root_dir_cluster;
+        
     while (true)
     {
-        // Root dir check
-        if (0 != dir->cluster) 
+        // FAT12/16 root dir check
+        if (0 == pos->cluster) 
         {
-            // Change cluster if needed
-            if (!is_pos_inside_cluster(disk, dpos.cluster_pos))
-                err = get_next_cluster(disk, &dpos, &dir->tcache, CO_NONE);
+            if (pos->cluster_pos >= disk->fat_root_dir_nents)
+                err = EEOF;
         }
         else
         {
-            if (*pos >= disk->fat_root_dir_nents)
-                err = EEOF;
+            // Change cluster if needed
+            if (pos->cluster_pos >= disk->cluster_size)
+                err = get_next_cluster(disk, pos, CO_NONE);
         }
 
         if (err != ENOERR)
             break;
 
-        err = read_dentry(disk, &dpos, dentry);
+        err = read_raw_dentry(disk, pos, dentry);
         if (err != ENOERR)
             return err;
 
@@ -1502,148 +1521,142 @@ get_next_dentry(fatfs_disk_t    *disk,
         {
             // If we get a ZERO dir entry, we assume that
             // there are no more entries in current dir
-            CYG_TRACE0(TDE, "ZERO dentry"); 
+            CYG_TRACE0(TDE, "end of dir"); 
             err = EEOF;
             break;
         }
         else if (!DENTRY_IS_DELETED(dentry))
         {
             // Dir entry found
-            CYG_TRACE3(TDE, "dentry_pos=%d cluster=%d pos=%d",
-                            *pos, dpos.cluster, dpos.cluster_pos);
+            CYG_TRACE3(TDE, "found new dentry at cluster=%d snum=%d pos=%d",
+                            pos->cluster, pos->cluster_snum, pos->cluster_pos);
             break;
         }
 
-        // Increment offset and position
-        dpos.cluster_pos += DENTRY_SIZE;
-        (*pos)++;
+        pos->cluster_pos += DENTRY_SIZE;
     }
 
-    if (EEOF == err) CYG_TRACE0(TDE, "end of dir");
-            
     // EEOF could be returned if there are no more entries in this
     // dir - this should be cought by the calling function 
+
     return err;
 }
 
 // -------------------------------------------------------------------------
-// get_free_dentry()
-// Gets free dir entry slot searching from given position.
-// If an deleated entry is found, its clusters are freed and the
-// entry is reused. 
-// The directory is extended if needed.
+// get_free_raw_dentry()
+// Gets free dir entry slot searching from given position extending the
+// directory if needed. If an deleated entry is found it is reused.
 
 static int
-get_free_dentry(fatfs_disk_t     *disk, 
-                fatfs_data_pos_t *dpos,
-                fatfs_tcache_t   *tcache)
+get_free_raw_dentry(fatfs_disk_t     *disk, 
+                    fatfs_data_pos_t *pos)
 {
-    fat_dir_entry_t  dentry;
-    fatfs_data_pos_t cdpos;
-    int err = ENOERR;
+    fat_raw_dir_entry_t raw_dentry;
+    fatfs_data_pos_t    cpos;
+    int                 err = ENOERR;
     
-    CYG_TRACE3(TDE, "cluster=%d cluster_snum=%d cluster_pos=%d", 
-                    dpos->cluster, dpos->cluster_snum, dpos->cluster_pos);
-    cdpos = *dpos;
+    cpos = *pos;
 
+    // If we are reading the root dir on FAT32 we have
+    // to correct the position to the root dir cluster
+    if (FATFS_FAT32 == disk->fat_type && 0 == cpos.cluster)
+        cpos.cluster = disk->fat_root_dir_cluster;
+ 
+    CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d", 
+                    pos->cluster, pos->cluster_snum, pos->cluster_pos);
+ 
     while (true)
     {
-        // Root dir check
-        if (0 != cdpos.cluster) 
+        // FAT12/16 root dir check
+        if (0 == cpos.cluster) 
         {
-            // Change cluster if needed
-            if (!is_pos_inside_cluster(disk, cdpos.cluster_pos))
-                err = get_next_cluster(disk, &cdpos, tcache, 
-                                       CO_EXTEND | CO_ERASE_NEW);
+            if (cpos.cluster_pos >= disk->fat_root_dir_size)
+                err = ENOSPC;
         }
         else
-        {
-            if (cdpos.cluster_pos >= disk->fat_root_dir_size)
-                err = ENOSPC;
+        { 
+            // Change cluster if needed
+            if (cpos.cluster_pos >= disk->cluster_size)
+                err = get_next_cluster(disk, &cpos, CO_EXTEND | CO_ERASE_NEW);
         }
 
         if (err != ENOERR)
             return err;
 
-        err = read_dentry(disk, &cdpos, &dentry);
+        err = read_raw_dentry(disk, &cpos, &raw_dentry);
         if (err != ENOERR)
             return err;
 
-        if (DENTRY_IS_DELETED(&dentry))
+        if (DENTRY_IS_DELETED(&raw_dentry))
         {
-            CYG_TRACE3(TDE, "deleted dentry at cluster=%d cluster_snum=%d "
-                            "cluster_pos=%d", cdpos.cluster, cdpos.cluster_snum,
-                            cdpos.cluster_pos);
+            CYG_TRACE3(TDE, "deleted dentry at cluster=%d snum=%d pos=%d",
+                            cpos.cluster, cpos.cluster_snum, cpos.cluster_pos);
 
-            // Retrun found dentry position
-            *dpos = cdpos;
+            *pos = cpos;
             return ENOERR;
         }
-        else if (DENTRY_IS_ZERO(&dentry))
+        else if (DENTRY_IS_ZERO(&raw_dentry))
         {
-            CYG_TRACE3(TDE, "zero dentry at cluster=%d cluster_snum=%d "
-                            "cluster_pos=%d", cdpos.cluster, cdpos.cluster_snum,
-                            cdpos.cluster_pos);
+            CYG_TRACE3(TDE, "zero dentry at cluster=%d snum=%d pos=%d",
+                            cpos.cluster, cpos.cluster_snum, cpos.cluster_pos);
 
-            // Retrun found dentry position
-            *dpos = cdpos;
+            *pos = cpos;
             return ENOERR;  
         }
        
-        // Increment current position
-        cdpos.cluster_pos += DENTRY_SIZE;
+        cpos.cluster_pos += DENTRY_SIZE;
     }
 }
  
 // -------------------------------------------------------------------------
-// dentry_to_node()
-// Converts FAT dir entry to node. 
+// raw_to_dentry()
+// Converts raw FAT dir entry to dir entry. 
  
 static void
-dentry_to_node(fat_dir_entry_t *dentry, 
-               fatfs_node_t    *node)
+raw_to_dentry(fat_raw_dir_entry_t *raw_dentry,
+              fatfs_data_pos_t    *raw_dentry_pos,
+              fatfs_dir_entry_t   *dentry)
 {
-    get_dentry_filename(dentry, node->filename);
+    get_raw_dentry_filename(raw_dentry, dentry->filename);
 
-    if (DENTRY_IS_DIR(dentry))
-        node->mode = __stat_mode_DIR;
+    if (DENTRY_IS_DIR(raw_dentry))
+        dentry->mode = __stat_mode_DIR;
     else
-        node->mode = __stat_mode_REG;
+        dentry->mode = __stat_mode_REG;
     
-    date_dos2unix(dentry->crt_time, dentry->crt_date, &node->ctime);
-    date_dos2unix(0,                dentry->acc_date, &node->atime);
-    date_dos2unix(dentry->wrt_time, dentry->wrt_date, &node->mtime);
+    date_dos2unix(raw_dentry->crt_time, raw_dentry->crt_date, &dentry->ctime);
+    date_dos2unix(0,                    raw_dentry->acc_date, &dentry->atime);
+    date_dos2unix(raw_dentry->wrt_time, raw_dentry->wrt_date, &dentry->mtime);
     
-    node->size       = dentry->size;
-    node->priv_data  = dentry->nt_reserved;
-    node->cluster    = dentry->cluster;
-    node->dentry_pos = dentry->pos;
+    dentry->size       = raw_dentry->size;
+    dentry->priv_data  = raw_dentry->nt_reserved;
+    dentry->cluster    = raw_dentry->cluster | (raw_dentry->cluster_HI << 16);
+    dentry->disk_pos   = *raw_dentry_pos;
 }
 
 // -------------------------------------------------------------------------
-// node_to_dentry()
-// Converts node to FAT dir entry. 
+// dentry_to_raw()
+// Converts dir entry to raw FAT dir entry. 
  
 static void
-node_to_dentry(fatfs_node_t *node, fat_dir_entry_t *dentry)
+dentry_to_raw(fatfs_dir_entry_t *dentry, fat_raw_dir_entry_t *raw_dentry)
 {
-    set_dentry_filename(dentry, node->filename, 0);
+    set_raw_dentry_filename(raw_dentry, dentry->filename, 0);
 
-    if (node->mode == __stat_mode_DIR)
-        dentry->attr = DENTRY_ATTR_DIR;
+    if (__stat_mode_DIR == dentry->mode)
+        raw_dentry->attr = DENTRY_ATTR_DIR;
     else
-        dentry->attr = DENTRY_ATTR_ARCHIVE;
+        raw_dentry->attr = DENTRY_ATTR_ARCHIVE;
         
-    date_unix2dos(node->ctime, &dentry->crt_time, &dentry->crt_date);
-    date_unix2dos(node->atime, NULL,              &dentry->acc_date);
-    date_unix2dos(node->mtime, &dentry->wrt_time, &dentry->wrt_date);
+    date_unix2dos(dentry->ctime, &raw_dentry->crt_time, &raw_dentry->crt_date);
+    date_unix2dos(dentry->atime, NULL,                  &raw_dentry->acc_date);
+    date_unix2dos(dentry->mtime, &raw_dentry->wrt_time, &raw_dentry->wrt_date);
     
-    dentry->crt_sec_100 = 0; //FIXME
-    dentry->size        = node->size;
-    dentry->nt_reserved = node->priv_data;
-    dentry->cluster     = node->cluster;
-    dentry->cluster_HI  = 0;
-    dentry->pos         = node->dentry_pos;
+    raw_dentry->crt_sec_100 = 0; //FIXME
+    raw_dentry->size        = dentry->size;
+    raw_dentry->nt_reserved = dentry->priv_data;
+    raw_dentry->cluster     = dentry->cluster & 0xFFFF;
+    raw_dentry->cluster_HI  = dentry->cluster >> 16;
 }
 
 //==========================================================================
@@ -1657,59 +1670,49 @@ static int
 read_data(fatfs_disk_t     *disk,
           void             *data,
           cyg_uint32       *len,
-          fatfs_data_pos_t *dpos,
-          fatfs_tcache_t   *tcache)
+          fatfs_data_pos_t *pos)
 {
-    unsigned char *buf;
-    cyg_uint32 apos;
-    cyg_uint32 size;
-    int err;
+    cyg_uint8   *buf   = (cyg_uint8 *) data;
+    cyg_uint32   size  = *len;
+    int          err   = ENOERR;
 
-    // Initialize variables and get the absolute starting pos on disk
-    buf   = (unsigned char *)data;
-    size  = *len;
-    apos  = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);
-    err   = ENOERR;
-  
-    CYG_TRACE5(TDO, "len=%d cluster=%d cluster_pos=%d "
-                    "cluster_snum=%d apos=%d", *len, dpos->cluster, 
-                    dpos->cluster_pos, dpos->cluster_snum, apos);
+    CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d",
+                    *len, pos->cluster, pos->cluster_snum, 
+                    pos->cluster_pos);
 
     while (size > 0)
     {
         cyg_uint32 csize;
 
         // Check if we are still inside current cluster
-        if (!is_pos_inside_cluster(disk, dpos->cluster_pos))
+        if (pos->cluster_pos >= disk->cluster_size)
         {
-            // Get next cluster of file and adjust absolute disk position 
-            err = get_next_cluster(disk, dpos, tcache, CO_NONE);
+            // Get next cluster of file 
+            err = get_next_cluster(disk, pos, CO_NONE);
             if (err != ENOERR)
                 goto out;
-            apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);
         }
         
         // Adjust the data chunk size to be read to the cluster boundary
-        if (size > (disk->cluster_size - dpos->cluster_pos))
-            csize = disk->cluster_size - dpos->cluster_pos;
+        if (size > (disk->cluster_size - pos->cluster_pos))
+            csize = disk->cluster_size - pos->cluster_pos;
         else
             csize = size;
 
-        CYG_TRACE5(TDO, "-- len=%d cluster=%d cluster_pos=%d "
-                        "cluster_snum=%d apos=%d", csize, dpos->cluster,
-                        dpos->cluster_pos, dpos->cluster_snum, apos);
+        CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d",
+                        csize, pos->cluster, pos->cluster_snum,
+                        pos->cluster_pos);
 
-        // Read data chunk 
-        err = cyg_blib_read(&disk->blib, (void*)buf, &csize, 0, apos);
-
+        err = disk_cluster_read(disk, (void*)buf, &csize, 
+                                pos->cluster, pos->cluster_pos);
         if (err != ENOERR)
             goto out;
 
         // Adjust running variables
-        buf               += csize;
-        dpos->cluster_pos += csize;
-        apos              += csize;
-        size              -= csize;    
+
+        buf              += csize;
+        pos->cluster_pos += csize;
+        size             -= csize;    
     }
     
 out:
@@ -1728,60 +1731,50 @@ static int
 write_data(fatfs_disk_t     *disk,
            void             *data,
            cyg_uint32       *len,
-           fatfs_data_pos_t *dpos,
-           fatfs_tcache_t   *tcache)
+           fatfs_data_pos_t *pos)
 {
-    unsigned char *buf;
-    cyg_uint32 apos;
-    cyg_uint32 size;
-    int err;
+    cyg_uint8   *buf   = (cyg_uint8 *) data;
+    cyg_uint32   size  = *len;
+    int          err   = ENOERR;
 
-    // Initialize variables and get the absolute starting pos on disk
-    buf   = (unsigned char *)data;
-    size  = *len;
-    apos  = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);
-    err   = ENOERR;
-  
-    CYG_TRACE5(TDO, "len=%d cluster=%d cluster_pos=%d "
-                    "cluster_snum=%d apos=%d", *len, dpos->cluster, 
-                    dpos->cluster_pos, dpos->cluster_snum, apos);
+    CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d",
+                    *len, pos->cluster, pos->cluster_snum, 
+                    pos->cluster_pos);
 
     while (size > 0)
     {
         cyg_uint32 csize;
 
         // Check if we are still inside current cluster
-        if (!is_pos_inside_cluster(disk, dpos->cluster_pos))
+        if (pos->cluster_pos >= disk->cluster_size)
         {
-            // Get next cluster of file and adjust absolute disk position,
-            // if at the last cluster try to extend the cluster chain 
-            err = get_next_cluster(disk, dpos, tcache, CO_EXTEND);
+            // Get next cluster of file, if at the last 
+            // cluster try to extend the cluster chain 
+            err = get_next_cluster(disk, pos, CO_EXTEND);
             if (err != ENOERR)
                 goto out;
-            apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);
         }
         
         // Adjust the data chunk size to be read to the cluster boundary
-        if (size > (disk->cluster_size - dpos->cluster_pos))
-            csize = disk->cluster_size - dpos->cluster_pos;
+        if (size > (disk->cluster_size - pos->cluster_pos))
+            csize = disk->cluster_size - pos->cluster_pos;
         else
             csize = size;
  
-        CYG_TRACE5(TDO, "-- len=%d cluster=%d cluster_pos=%d "
-                        "cluster_snum=%d apos=%d", csize, dpos->cluster,
-                        dpos->cluster_pos, dpos->cluster_snum, apos);
+        CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d",
+                        csize, pos->cluster, pos->cluster_snum, 
+                        pos->cluster_pos);
 
-        // Write data chunk 
-        err = cyg_blib_write(&disk->blib, (void*)buf, &csize, 0, apos);
-
+        err = disk_cluster_write(disk, (void*)buf, &csize, 
+                                 pos->cluster, pos->cluster_pos);
         if (err != ENOERR)
             goto out;
 
         // Adjust running variables
-        buf               += csize;
-        dpos->cluster_pos += csize;
-        apos              += csize;
-        size              -= csize;    
+        
+        buf              += csize;
+        pos->cluster_pos += csize;
+        size             -= csize;    
     }
     
 out:
@@ -1796,43 +1789,44 @@ out:
 // Misc functions 
 
 // -------------------------------------------------------------------------
-// init_node()
-// Initializes file attributes of a new node. 
+// init_dir_entry()
+// Initializes attributes of a new dir entry. 
  
 static void
-init_node_fattr(fatfs_node_t     *node, 
-                const char       *name, 
-                int               namelen,
-                mode_t            mode,
-                cyg_uint32        parent_cluster, 
-                fatfs_data_pos_t *dentry_pos)
+init_dir_entry(fatfs_dir_entry_t *dentry, 
+               const char        *name, 
+               int                namelen,
+               mode_t             mode,
+               cyg_uint32         parent_cluster, 
+               cyg_uint32         first_cluster, 
+               fatfs_data_pos_t  *pos)
 {
-    if (namelen == 0)
+    if (0 == namelen)
         namelen = 12;
     
-    strncpy(node->filename, name, namelen);
-    node->filename[namelen] = '\0';
+    strncpy(dentry->filename, name, namelen);
+    dentry->filename[namelen] = '\0';
     
-    node->mode  = mode;
-    node->ctime = 
-    node->atime =
-    node->mtime = cyg_timestamp();
+    dentry->mode  = mode;
+    dentry->ctime = 
+    dentry->atime =
+    dentry->mtime = cyg_timestamp();
 
-    node->priv_data      = 0;
-    node->size           = 0;
-    node->cluster        = 0;
-    node->parent_cluster = parent_cluster;
-    node->dentry_pos     = *dentry_pos;
+    dentry->priv_data      = 0;
+    dentry->size           = 0;
+    dentry->cluster        = first_cluster;
+    dentry->parent_cluster = parent_cluster;
+    dentry->disk_pos       = *pos;
 }
 
 // -------------------------------------------------------------------------
-// is_node_root_node()
-// Check if the given node is the root dir node 
+// is_root_dir_entry()
+// Check if the given dir entry is the root dir entry. 
  
 static __inline__ bool
-is_node_root_node(fatfs_node_t *node)
+is_root_dir_entry(fatfs_dir_entry_t *dentry)
 {
-    return (node->filename[0] == '\0' && node->cluster == 0);
+    return ('\0' == dentry->filename[0] && 0 == dentry->cluster);
 }
 
 //==========================================================================
@@ -1840,16 +1834,16 @@ is_node_root_node(fatfs_node_t *node)
 // Exported functions 
 
 // -------------------------------------------------------------------------
-// fatfs_get_disk_info()
+// fatfs_init()
 // Gets disk info. 
  
 int
-fatfs_get_disk_info(fatfs_disk_t *disk)
+fatfs_init(fatfs_disk_t *disk)
 {
-    int err;
-    cyg_uint32 sec_num, root_dir_sec_num;
-    cyg_uint32 data_sec_num, data_clu_num;
+    cyg_uint32        sec_num, sec_per_fat, root_dir_sec_num;
+    cyg_uint32        data_sec_num, data_clu_num;
     fat_boot_record_t boot_rec;
+    int               err;
 
     CYG_CHECK_DATA_PTRC(disk);
  
@@ -1863,11 +1857,27 @@ fatfs_get_disk_info(fatfs_disk_t *disk)
         0xAA != boot_rec.exe_marker[1])
         return EINVAL;
 
+    // Sector and cluster sizes 
+    disk->sector_size       = boot_rec.bytes_per_sec;
+    disk->sector_size_log2  = get_val_log2(disk->sector_size);
+    disk->cluster_size      = boot_rec.bytes_per_sec * boot_rec.sec_per_clu;
+    disk->cluster_size_log2 = get_val_log2(disk->cluster_size);
+
+    // Sector and cluster size should always be a power of 2
+    if (0 == disk->sector_size_log2 || 0 == disk->cluster_size_log2)
+        return EINVAL;
+
     // Determine number of sectors
     if (boot_rec.sec_num_32 != 0)
         sec_num = boot_rec.sec_num_32;
     else
         sec_num = boot_rec.sec_num;
+
+    // Determine number of sectors per fat
+    if (boot_rec.sec_per_fat != 0)
+        sec_per_fat = boot_rec.sec_per_fat;
+    else
+        sec_per_fat = boot_rec.sec_per_fat_32;
     
     // Number of sectors used by root directory 
     root_dir_sec_num = ((boot_rec.max_root_dents * DENTRY_SIZE) +
@@ -1875,167 +1885,252 @@ fatfs_get_disk_info(fatfs_disk_t *disk)
         
     // Number of data sectors
     data_sec_num = sec_num - (boot_rec.res_sec_num + 
-        (boot_rec.fat_tbls_num * boot_rec.sec_per_fat) + root_dir_sec_num);
+        (boot_rec.fat_tbls_num * sec_per_fat) + root_dir_sec_num);
     
     // Number of data clusters
-    data_clu_num = data_sec_num / boot_rec.sec_per_clust;
+    data_clu_num = data_sec_num / boot_rec.sec_per_clu;
+
+    // FAT table size and position
+    disk->fat_tbl_pos   = boot_rec.bytes_per_sec * boot_rec.res_sec_num;
+    disk->fat_tbl_size  = boot_rec.bytes_per_sec * sec_per_fat;   
+    disk->fat_tbl_nents = data_clu_num + 2;
+    disk->fat_tbls_num  = boot_rec.fat_tbls_num;
 
     // Determine the type of FAT based on number of data clusters
-    if (data_clu_num < 4085) 
-        disk->fat_type = FATFS_FAT12;
+    if (data_clu_num < 4085)
+        disk->fat_type  = FATFS_FAT12;
     else if (data_clu_num < 65525) 
-        disk->fat_type = FATFS_FAT16;
-    else // FAT32
-        return EINVAL;
+        disk->fat_type  = FATFS_FAT16;
+    else 
+        disk->fat_type  = FATFS_FAT32;
+
+    // Determine root dir and data positions
+    if (FATFS_FAT32 != disk->fat_type)
+    {
+        disk->fat_root_dir_pos     = disk->fat_tbl_pos + 
+                                     disk->fat_tbls_num * disk->fat_tbl_size;
+        disk->fat_root_dir_size    = boot_rec.max_root_dents * DENTRY_SIZE;
+        disk->fat_root_dir_nents   = boot_rec.max_root_dents;
+        disk->fat_root_dir_cluster = 0;
+        disk->fat_data_pos         = disk->fat_root_dir_pos + 
+                                     disk->fat_root_dir_size;
+    }
+    else
+    {
+        disk->fat_root_dir_pos     = 0;
+        disk->fat_root_dir_size    = 0;
+        disk->fat_root_dir_nents   = 0;
+        disk->fat_root_dir_cluster = boot_rec.root_cluster; 
+        disk->fat_data_pos         = disk->fat_tbl_pos +
+                                     disk->fat_tbls_num * disk->fat_tbl_size;
+    }
     
-    // Sector and cluster sizes 
-    disk->sector_size       = boot_rec.bytes_per_sec;
-    disk->sector_size_log2  = get_val_log2(disk->sector_size);
-    disk->cluster_size      = boot_rec.bytes_per_sec * boot_rec.sec_per_clust;
-    disk->cluster_size_log2 = get_val_log2(disk->cluster_size);
+    return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// fatfs_get_root_dir_entry()
+// Gets root dir entry. 
+
+void
+fatfs_get_root_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
+{
+    CYG_CHECK_DATA_PTRC(disk);
+    CYG_CHECK_DATA_PTRC(dentry);
+    
+    dentry->mode           = __stat_mode_DIR;
+    dentry->size           = disk->fat_root_dir_size;
+    dentry->ctime          = 0;
+    dentry->atime          = 0;
+    dentry->mtime          = 0;
+    dentry->filename[0]    = '\0';
+    dentry->cluster        = 0;
+    dentry->parent_cluster = 0;
+
+    dentry->disk_pos.cluster      = 0;
+    dentry->disk_pos.cluster_snum = 0;
+    dentry->disk_pos.cluster_pos  = 0;
+}
+
+// -------------------------------------------------------------------------
+// fatfs_get_disk_usage()
+// Gets disk space.
+
+int
+fatfs_get_disk_usage(fatfs_disk_t *disk,
+                     cyg_uint32   *total_clusters,
+                     cyg_uint32   *free_clusters)
+{
+    cyg_uint32 c, nfree, tentry;
+    int        err;
 
-    // Sector and cluster size should always be a power of 2
-    if (0 == disk->sector_size_log2 || 0 == disk->cluster_size_log2)
-        return EINVAL;
+    nfree = 0;
+    for (c = 2; c < disk->fat_tbl_nents; c++)
+    {
+        err = read_tentry(disk, c, &tentry);
+        if (err != ENOERR)
+            return err;
+
+        if (TENTRY_FREE == get_tentry_type(disk, tentry))
+            nfree++;
+    }
+
+    *total_clusters = disk->fat_tbl_nents - 2;
+    *free_clusters  = nfree;
+  
+    return ENOERR;
+}
+
+
+// -------------------------------------------------------------------------
+// fatfs_read_dir_entry()
+// Reads dir entry at given position.
+// If there is no dir entry at given position the next closest is returned 
+// and the position is updated. If EEOF error is returned, then there are 
+// no more dir entries in given dir. 
+
+int
+fatfs_read_dir_entry(fatfs_disk_t      *disk,
+                     fatfs_dir_entry_t *dir,
+                     fatfs_data_pos_t  *pos,
+                     fatfs_dir_entry_t *dentry)
+{
+    fat_raw_dir_entry_t raw_dentry;
+    int                 err;
 
-    // FAT table and root dir sizes and position
-    disk->fat_tbl_pos        = boot_rec.bytes_per_sec * boot_rec.res_sec_num;
-    disk->fat_tbl_size       = boot_rec.bytes_per_sec * boot_rec.sec_per_fat;   
-    disk->fat_tbl_nents      = data_clu_num + 2;
-    disk->fat_tbls_num       = boot_rec.fat_tbls_num;
-    disk->fat_root_dir_pos   = disk->fat_tbl_pos + 
-                               disk->fat_tbls_num * disk->fat_tbl_size;
-    disk->fat_root_dir_size  = boot_rec.max_root_dents * DENTRY_SIZE;
-    disk->fat_root_dir_nents = boot_rec.max_root_dents;
-    disk->fat_data_pos       = disk->fat_root_dir_pos + disk->fat_root_dir_size;
+    CYG_CHECK_DATA_PTRC(disk);
+    CYG_CHECK_DATA_PTRC(dir);
+    CYG_CHECK_DATA_PTRC(pos);
+    CYG_CHECK_DATA_PTRC(dentry);
+ 
+    err = read_next_raw_dentry(disk, pos, &raw_dentry);
+    if (err != ENOERR)
+       return err;
+
+    raw_to_dentry(&raw_dentry, pos, dentry);
+    dentry->parent_cluster = dir->cluster;
+
+    // Increment position for next call
+    pos->cluster_pos += DENTRY_SIZE;
+    
+    return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// fatfs_initpos()
+// Initializes position to the start of the given file.
+
+int
+fatfs_initpos(fatfs_disk_t      *disk, 
+              fatfs_dir_entry_t *file,
+              fatfs_data_pos_t  *pos)
+{
+    CYG_CHECK_DATA_PTRC(disk);
+    CYG_CHECK_DATA_PTRC(file);
+    CYG_CHECK_DATA_PTRC(pos);
+    
+    pos->cluster      = file->cluster;
+    pos->cluster_snum = 0;
+    pos->cluster_pos  = 0;
 
     return ENOERR;
 }
 
 // -------------------------------------------------------------------------
-// fatfs_get_root_node()
-// Gets root dir node. 
+// fatfs_setpos()
+// Sets the file position from offset.
 
-void
-fatfs_get_root_node(fatfs_disk_t *disk, fatfs_node_t *node)
+int
+fatfs_setpos(fatfs_disk_t      *disk, 
+             fatfs_dir_entry_t *file,
+             fatfs_data_pos_t  *pos,
+             cyg_uint32         offset)
 {
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(file);
+    CYG_CHECK_DATA_PTRC(pos);
     
-    node->mode           = __stat_mode_DIR;
-    node->size           = disk->fat_root_dir_size;
-    node->ctime          = 0;
-    node->atime          = 0;
-    node->mtime          = 0;
-    node->filename[0]    = '\0';
-    node->cluster        = 0;
-    node->parent_cluster = 0;
-
-    node->dentry_pos.cluster      = 0;
-    node->dentry_pos.cluster_snum = 0;
-    node->dentry_pos.cluster_pos  = 0;
-}
-
-// -------------------------------------------------------------------------
-// fatfs_is_node_root_node()
-// Check if the given node is root dir node. 
-
-bool
-fatfs_is_node_root_node(fatfs_node_t *node)
-{
-    return(is_node_root_node(node));
+    return get_position_from_off(disk, file->cluster, offset, pos, CO_NONE);
 }
 
 // -------------------------------------------------------------------------
-// fatfs_get_dir_entry_node()
-// Gets dir entry node at given position.
-// If there is no dir entry at given position the next closest
-// dir entry and its position are returned. 
-// If EEOF error is returned, then there are no more dir
-// entries in given dir. 
+// fatfs_getpos()
+// Gets the file offset from position.
 
-int
-fatfs_get_dir_entry_node(fatfs_disk_t *disk,
-                         fatfs_node_t *dir,
-                         cyg_uint32   *pos,
-                         fatfs_node_t *node)
+cyg_uint32 
+fatfs_getpos(fatfs_disk_t      *disk,
+             fatfs_dir_entry_t *file,
+             fatfs_data_pos_t  *pos)
 {
-    fat_dir_entry_t dentry;
-    int err;
-
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(dir);
+    CYG_CHECK_DATA_PTRC(file);
     CYG_CHECK_DATA_PTRC(pos);
-    CYG_CHECK_DATA_PTRC(node);
- 
-    err = get_next_dentry(disk, dir, pos, &dentry);
-  
-    if (err != ENOERR)
-       return err;
-
-    dentry_to_node(&dentry, node);
-    node->parent_cluster = dir->cluster;
-
-    return ENOERR;
+    
+    return (pos->cluster_snum << disk->cluster_size_log2) + pos->cluster_pos;
 }
 
 // -------------------------------------------------------------------------
-// fatfs_write_node()
-// Writes node attributes to its dir entry (to disk).
+// fatfs_write_dir_entry()
+// Writes dir entry to disk.
  
 int
-fatfs_write_file_attr(fatfs_disk_t *disk, fatfs_node_t *node)
+fatfs_write_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
 {
-    fat_dir_entry_t dentry;
-    int err;
+    fat_raw_dir_entry_t raw_dentry;
+    int                 err;
 
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(dentry);
  
-    node_to_dentry(node, &dentry);
-    err = write_dentry(disk, &dentry.pos, &dentry);
+    dentry_to_raw(dentry, &raw_dentry);
+    err = write_raw_dentry(disk, &dentry->disk_pos, &raw_dentry);
     return err;
 }
 
 // -------------------------------------------------------------------------
 // fatfs_delete_file()
-// Marks file dir entry as deleted.
+// Marks dir entry as deleted and frees its cluster chain.
  
 int
-fatfs_delete_file(fatfs_disk_t *disk, fatfs_node_t *node)
+fatfs_delete_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file)
 {
-    fat_dir_entry_t dentry;
-    int err;
+    fat_raw_dir_entry_t raw_dentry;
+    int                 err;
 
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(file);
 
-    // Can't delete root
-    if (is_node_root_node(node))
+    if (is_root_dir_entry(file))
         return EINVAL;
     
-    CYG_TRACE1(TDE, "filename='%s'", node->filename);
+    CYG_TRACE1(TDE, "filename='%s'", file->filename);
 
-    node_to_dentry(node, &dentry);
+    dentry_to_raw(file, &raw_dentry);
 
     // Check if we are about to delete a directory
-    if (DENTRY_IS_DIR(&dentry))
+    if (DENTRY_IS_DIR(&raw_dentry))
     {
-        fat_dir_entry_t cdentry;
-        cyg_uint32 pos = 0;
-        int i = 0;
+        fat_raw_dir_entry_t raw_cdentry;
+        fatfs_data_pos_t    pos;
+        int                 i = 0;
+        
+        fatfs_initpos(disk, file, &pos);
         
         CYG_TRACE0(TDE, "got directory");
+
         // Count number of entries in this dir    
+
         while (true)
         {
-            err = get_next_dentry(disk, node, &pos, &cdentry);
+            err = read_next_raw_dentry(disk, &pos, &raw_cdentry);
 
             if (EEOF == err)
                 break;
             else if (err != ENOERR)
                 return err;
-            i++; pos++;
+
+            pos.cluster_pos += DENTRY_SIZE;
+            i++; 
         }
         CYG_TRACE1(TDE, "child count=%d", i);
         
@@ -2045,9 +2140,9 @@ fatfs_delete_file(fatfs_disk_t *disk, fa
     }    
     
     // Free file clusters
-    free_cluster_chain(disk, dentry.cluster);
-    dentry_set_deleted(disk, &dentry);
-    err = write_dentry(disk, &dentry.pos, &dentry);
+    free_cluster_chain(disk, raw_dentry.cluster);
+    raw_dentry_set_deleted(disk, &raw_dentry);
+    err = write_raw_dentry(disk, &file->disk_pos, &raw_dentry);
     return err;
 } 
 
@@ -2056,38 +2151,40 @@ fatfs_delete_file(fatfs_disk_t *disk, fa
 // Creates a new file.
  
 int
-fatfs_create_file(fatfs_disk_t *disk, 
-                  fatfs_node_t *dir, 
-                  const char   *name,
-                  int           namelen,
-                  fatfs_node_t *node)
+fatfs_create_file(fatfs_disk_t      *disk, 
+                  fatfs_dir_entry_t *dir, 
+                  const char        *name,
+                  int                namelen,
+                  fatfs_dir_entry_t *dentry)
 {
-    fat_dir_entry_t dentry;
-    int err;
+    fatfs_data_pos_t pos;
+    int              err;
 
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(dir);
     CYG_CHECK_DATA_PTRC(name);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(dentry);
  
     CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename);
 
-    dentry.pos.cluster      = dir->cluster;
-    dentry.pos.cluster_snum = 0;
-    dentry.pos.cluster_pos  = 0;
+    fatfs_initpos(disk, dir, &pos);
 
     // Get free dir entry in parent dir
-    err = get_free_dentry(disk, &dentry.pos, &dir->tcache);
+    err = get_free_raw_dentry(disk, &pos);
     if (err != ENOERR)
         return err;
 
-    // Set new file attributes
-    init_node_fattr(node, name, namelen, __stat_mode_REG, 
-                    dir->cluster, &dentry.pos); 
+    // Create new file dir entry
+    
+    init_dir_entry(dentry, 
+                   name, 
+                   namelen, 
+                   __stat_mode_REG, 
+                   dir->cluster, 
+                   0, 
+                   &pos); 
 
-    // Write new dir dentry  
-    node_to_dentry(node, &dentry);
-    err = write_dentry(disk, &dentry.pos, &dentry);
+    err = fatfs_write_dir_entry(disk, dentry);
     if (err != ENOERR)
        return err;
  
@@ -2099,78 +2196,84 @@ fatfs_create_file(fatfs_disk_t *disk,
 // Creates a new directory.
  
 int
-fatfs_create_dir(fatfs_disk_t *disk, 
-                 fatfs_node_t *dir, 
-                 const char   *name,
-                 int           namelen,
-                 fatfs_node_t *node)
+fatfs_create_dir(fatfs_disk_t      *disk, 
+                 fatfs_dir_entry_t *dir, 
+                 const char        *name,
+                 int                namelen,
+                 fatfs_dir_entry_t *dentry)
 {
-    fat_dir_entry_t dentry;
-    fatfs_node_t    cnode;
-    cyg_uint32 free_cluster;
-    int err;
+    fatfs_dir_entry_t cdentry;
+    fatfs_data_pos_t  pos;
+    cyg_uint32        free_cluster;
+    int               err;
 
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(dir);
     CYG_CHECK_DATA_PTRC(name);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(dentry);
  
     CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename);
 
     // Get free cluster
-    err = find_next_free_cluster(disk, 0, &free_cluster, 
+    err = find_next_free_cluster(disk, 
+                                 0, 
+                                 &free_cluster, 
                                  CO_MARK_LAST | CO_ERASE_NEW);
     if (err != ENOERR)
         return err;
 
-    dentry.pos.cluster      = dir->cluster;
-    dentry.pos.cluster_snum = 0;
-    dentry.pos.cluster_pos  = 0;
+    fatfs_initpos(disk, dir, &pos);
 
     // Get free dir entry in parent dir
-    err = get_free_dentry(disk, &dentry.pos, &dir->tcache);
+    err = get_free_raw_dentry(disk, &pos);
     if (err != ENOERR)
         return err;
 
-    // Set new dir attributes
-    init_node_fattr(node, name, namelen, __stat_mode_DIR, 
-                    dir->cluster, &dentry.pos); 
-    node->cluster = free_cluster;
+    // Create new dir entry
 
-    // Write new dir dentry  
-    node_to_dentry(node, &dentry);
-    err = write_dentry(disk, &dentry.pos, &dentry);
+    init_dir_entry(dentry, 
+                   name, 
+                   namelen, 
+                   __stat_mode_DIR, 
+                   dir->cluster, 
+                   free_cluster, 
+                   &pos); 
+
+    err = fatfs_write_dir_entry(disk, dentry);
     if (err != ENOERR)
        return err;
 
-    // Starting position of new dir entries
-    dentry.pos.cluster      = node->cluster;
-    dentry.pos.cluster_snum = 0;
-    dentry.pos.cluster_pos  = 0;
+    // Create '.' and '..' dir entries
+
+    fatfs_initpos(disk, dentry, &pos);
 
     CYG_TRACE0(TDE, "Creating '.' entry");
-    // Set '.' dir attributes
-    init_node_fattr(&cnode, ".", 0, __stat_mode_DIR, 
-                    node->cluster, &dentry.pos); 
-    cnode.cluster = node->cluster;
 
-    // Write '.' dentry
-    node_to_dentry(&cnode, &dentry); 
-    err = write_dentry(disk, &dentry.pos, &dentry);
+    init_dir_entry(&cdentry, 
+                   ".", 
+                   0, 
+                   __stat_mode_DIR, 
+                   dentry->cluster, 
+                   dentry->cluster, 
+                   &pos);
+
+    err = fatfs_write_dir_entry(disk, &cdentry);
     if (err != ENOERR)
         return err;
           
-    dentry.pos.cluster_pos += DENTRY_SIZE;
+    pos.cluster_pos += DENTRY_SIZE;
 
     CYG_TRACE0(TDE, "Creating '..' entry");
-    // Set '..' dir attributes
-    init_node_fattr(&cnode, "..", 0, __stat_mode_DIR,
-                    node->cluster, &dentry.pos); 
-    cnode.cluster = dir->cluster;
     
-    // Write '..' dentry
-    node_to_dentry(&cnode, &dentry); 
-    err = write_dentry(disk, &dentry.pos, &dentry);
+    init_dir_entry(&cdentry, 
+                   "..", 
+                   0, 
+                   __stat_mode_DIR,
+                   dentry->cluster, 
+                   dir->cluster, 
+                   &pos); 
+    
+    err = fatfs_write_dir_entry(disk, &cdentry);
     if (err != ENOERR)
         return err;
   
@@ -2182,45 +2285,33 @@ fatfs_create_dir(fatfs_disk_t *disk,
 // Truncates a file to zero length.
 
 int
-fatfs_trunc_file(fatfs_disk_t *disk, fatfs_node_t *node)
+fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file)
 {
-    fat_dir_entry_t dentry;
     int err;
     
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(file);
  
-    CYG_TRACE1(TDE, "file='%s'", node->filename);
+    CYG_TRACE1(TDE, "file='%s'", file->filename);
   
-    // Check for dir
-    if (S_ISDIR(node->mode))
+    if (S_ISDIR(file->mode))
         return EINVAL; 
 
-    // Trivial case check
-    if (0 == node->size)
+    if (0 == file->size)
         return ENOERR;
    
-    // Free cluster chain 
-    err = free_cluster_chain(disk, node->cluster);
+    err = free_cluster_chain(disk, file->cluster);
     if (err != ENOERR)
         return err;
     
-    // Flush tcache
-    fatfs_tcache_flush(disk, &node->tcache);
-    
-    // Update node attributes
-    node->cluster = 0;
-    node->size    = 0;
-    node->mtime   =
-    node->atime   = cyg_timestamp();
+    // Update file attributes
 
-    // Write dentry
-    node_to_dentry(node, &dentry);
-    err = write_dentry(disk, &dentry.pos, &dentry);
-    if (err != ENOERR)
-        return err;
-    
-    return ENOERR;
+    file->cluster = 0;
+    file->size    = 0;
+    file->mtime   =
+    file->atime   = cyg_timestamp();
+
+    return fatfs_write_dir_entry(disk, file);
 }
 
 // -------------------------------------------------------------------------
@@ -2228,104 +2319,105 @@ fatfs_trunc_file(fatfs_disk_t *disk, fat
 // Renames a file.
  
 int
-fatfs_rename_file(fatfs_disk_t *disk, 
-                  fatfs_node_t *dir1, 
-                  fatfs_node_t *node,
-                  fatfs_node_t *dir2, 
-                  const char   *name,
-                  int           namelen)
+fatfs_rename_file(fatfs_disk_t      *disk, 
+                  fatfs_dir_entry_t *dir1, 
+                  fatfs_dir_entry_t *target,
+                  fatfs_dir_entry_t *dir2, 
+                  const char        *name,
+                  int                namelen)
 {
-    fat_dir_entry_t  dentry;
-    fatfs_data_pos_t dpos;
-    int err;
+    fat_raw_dir_entry_t raw_dentry;
+    fatfs_data_pos_t    new_pos;
+    int                 err;
 
     CYG_CHECK_DATA_PTRC(disk);
     CYG_CHECK_DATA_PTRC(dir1);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(target);
     CYG_CHECK_DATA_PTRC(dir2);
     CYG_CHECK_DATA_PTRC(name);
  
-    // Can't rename root 
-    if (is_node_root_node(node))
+    if (is_root_dir_entry(target))
         return EINVAL;
  
-    CYG_TRACE5(TDE, "dir1=%p '%s' to dir2=%p '%s' (%d)", 
-                    dir1, node->filename, dir2, name, namelen);
-
-    strncpy(node->filename, name, namelen);
-    node->filename[namelen] = '\0';
+    strncpy(target->filename, name, namelen);
+    target->filename[namelen] = '\0';
    
     // Moving around in same dir
+
     if (dir1 == dir2)
     {
-        CYG_TRACE0(TDE, "same dir"); 
-        node_to_dentry(node, &dentry);
-        err = write_dentry(disk, &dentry.pos, &dentry);
-        return err;
+        CYG_TRACE0(TDE, "same dir");
+        return fatfs_write_dir_entry(disk, target); 
     }
     
     CYG_TRACE0(TDE, "different dirs"); 
     
     // Moveing around in different dirs
 
-    dpos.cluster      = dir2->cluster;
-    dpos.cluster_snum = 0;
-    dpos.cluster_pos  = 0;
+    fatfs_initpos(disk, dir2, &new_pos);
 
     CYG_TRACE0(TDE, "writting to new dir"); 
 
     // Get free dir entry in target dir
-    err = get_free_dentry(disk, &dpos, &dir2->tcache);
+
+    err = get_free_raw_dentry(disk, &new_pos);
     if (err != ENOERR)
         return err;
 
-    // Write node dentry to new location
-    node_to_dentry(node, &dentry);
-    err = write_dentry(disk, &dpos, &dentry);
+    // Write file dentry to new location
+
+    dentry_to_raw(target, &raw_dentry);
+    err = write_raw_dentry(disk, &new_pos, &raw_dentry);
     if (err != ENOERR)
         return err;
    
     CYG_TRACE0(TDE, "deleting from old dir"); 
     
     // Deleate dentry at old location
-    dentry_set_deleted(disk, &dentry);
-    dentry.size    = 0;
-    dentry.cluster = 0;
-    err = write_dentry(disk, &dentry.pos, &dentry);
+
+    raw_dentry_set_deleted(disk, &raw_dentry);
+    raw_dentry.size    = 0;
+    raw_dentry.cluster = 0;
+    err = write_raw_dentry(disk, &target->disk_pos, &raw_dentry);
     if (err != ENOERR)
         return err;
    
-    // Set node new position and parent cluster
-    node->dentry_pos     = dpos;
-    node->parent_cluster = dir2->cluster;
+    // Set file new position and parent cluster
+
+    target->disk_pos       = new_pos;
+    target->parent_cluster = dir2->cluster;
  
     // If we moved a directory, we also have to correct the '..' entry  
-    if (__stat_mode_DIR == node->mode)
+
+    if (__stat_mode_DIR == target->mode)
     {
-        fat_dir_entry_t cdentry;
-        cyg_uint32 pos = 0;
-        
+        fat_raw_dir_entry_t raw_cdentry;
+        fatfs_data_pos_t    pos;
+       
+        fatfs_initpos(disk, target, &pos);
+
         CYG_TRACE0(TDE, "moving directory - correcting '..' entry");
 
         while (true)
         {
-            err = get_next_dentry(disk, node, &pos, &cdentry);
+            err = read_next_raw_dentry(disk, &pos, &raw_cdentry);
 
             if (EEOF == err)
-                return EIO; // This dir doesn't have the '..' entry,
-                            // that means something is very wrong
+                return EINVAL; // This dir doesn't have the '..' entry,
+                               // that means something is very wrong
             else if (err != ENOERR)
                 return err;
 
-            if (0 == strncmp("..", cdentry.name, 2))
+            if (0 == strncmp("..", raw_cdentry.name, 2))
             {
-                cdentry.cluster = dir2->cluster;
-                err = write_dentry(disk, &cdentry.pos, &cdentry);
+                raw_cdentry.cluster = dir2->cluster;
+                err = write_raw_dentry(disk, &pos, &raw_cdentry);
                 if (err != ENOERR)
                     return err;
                 break;
             }
-            pos++;
+
+            pos.cluster_pos += DENTRY_SIZE;
         }
     }
    
@@ -2337,27 +2429,19 @@ fatfs_rename_file(fatfs_disk_t *disk,
 // Reads data from disk. 
  
 int
-fatfs_read_data(fatfs_disk_t *disk,
-                fatfs_node_t *node,
-                void         *data,
-                cyg_uint32   *len,
-                cyg_uint32    off)
+fatfs_read_data(fatfs_disk_t      *disk,
+                fatfs_dir_entry_t *file,
+                fatfs_data_pos_t  *pos,
+                void              *data,
+                cyg_uint32        *len)
 {
-    int err;
-    fatfs_data_pos_t dpos;
-
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(file);
     CYG_CHECK_DATA_PTRC(data);
     CYG_CHECK_DATA_PTRC(len);
- 
-    err = get_data_position_from_off(disk, node->cluster, off, 
-                                     &dpos, &node->tcache, CO_NONE);
-    if (err != ENOERR)
-        return err;
+    CYG_CHECK_DATA_PTRC(pos);
 
-    err = read_data(disk, data, len, &dpos, &node->tcache);
-    return err;
+    return read_data(disk, data, len, pos);
 }
 
 // -------------------------------------------------------------------------
@@ -2365,47 +2449,41 @@ fatfs_read_data(fatfs_disk_t *disk,
 // Writes data to disk. 
  
 int
-fatfs_write_data(fatfs_disk_t *disk,
-                 fatfs_node_t *node,
-                 void         *data,
-                 cyg_uint32   *len,
-                 cyg_uint32    off)
+fatfs_write_data(fatfs_disk_t      *disk,
+                 fatfs_dir_entry_t *file,
+                 fatfs_data_pos_t  *pos,
+                 void              *data,
+                 cyg_uint32        *len)
 {
     int err;
-    fatfs_data_pos_t dpos;
 
     CYG_CHECK_DATA_PTRC(disk);
-    CYG_CHECK_DATA_PTRC(node);
+    CYG_CHECK_DATA_PTRC(file);
     CYG_CHECK_DATA_PTRC(data);
     CYG_CHECK_DATA_PTRC(len);
+    CYG_CHECK_DATA_PTRC(pos);
 
     // Check if this file has a zero size and no first cluster
-    if (0 == node->size && 0 == node->cluster)
+
+    if (0 == file->size && 0 == file->cluster)
     {
         cyg_uint32 free_cluster;
 
         CYG_TRACE0(TDO, "new cluster for zero file");
-        // Get free cluster
+
         err = find_next_free_cluster(disk, 0, &free_cluster, CO_MARK_LAST);
+
         if (err != ENOERR)
         {
             *len = 0;
             return err;
         }
-        node->cluster = free_cluster;
+
+        file->cluster = free_cluster;
+        fatfs_initpos(disk, file, pos);
     }
 
-    err = get_data_position_from_off(disk, node->cluster, off, 
-                                     &dpos, &node->tcache, 
-                                     CO_MARK_LAST | CO_EXTEND);
-    if (err != ENOERR)
-    {
-        *len = 0;
-        return err;
-    }
-    
-    err = write_data(disk, data, len, &dpos, &node->tcache);
-    return err;
+    return write_data(disk, data, len, pos);
 }
 
 // -------------------------------------------------------------------------