Index: soft/giet_vm/giet_fat32/fat32.c
===================================================================
--- soft/giet_vm/giet_fat32/fat32.c	(revision 750)
+++ soft/giet_vm/giet_fat32/fat32.c	(revision 761)
@@ -53,5 +53,5 @@
 // Fat-Descriptor
 __attribute__((section(".kdata")))
-fat_desc_t _fat __attribute__((aligned(64))); 
+fat_desc_t     _fat __attribute__((aligned(64))); 
 
 // buffer used by boot code as a simple cache when scanning FAT
@@ -180,6 +180,6 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following function introduces the inode identified by the "child" argument,
-// as a new child of the "parent" inode in the Inode-Tree.
+// The following function introduces the inode identified by the <child> argument,
+// as a new child of the <parent> inode in the Inode-Tree.
 // All checking are supposed to be done by the caller.
 // Nor the File-Cache, neither the block device are modified.
@@ -190,5 +190,5 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following function removes one inode identified by the "inode" argument 
+// The following function removes one inode identified by the <inode> argument 
 // from the Inode-Tree. All checking are supposed to be done by the caller.
 // Nor the File-Cache, neither the block device are modified.
@@ -200,6 +200,6 @@
 // This recursive function scan one File-Cache (or Fat-Cache) from root to leaves,
 // to writes all dirty clusters to block device, and reset the dirty bits.
-// The cache is identified by the "root" an "levels" arguments.
-// The "string" argument is only used for debug : inode name or Fat.
+// The cache is identified by the <root> an <levels> arguments.
+// The <string> argument is only used for debug : inode name or Fat.
 // It returns 0 on success.
 // It returns 1 on error.
@@ -223,5 +223,5 @@
 // The following function read a data field (from one to four bytes) 
 // from an unsigned char[] buffer, taking endianness into account. 
-// The analysed field is defined by the "offset" and "size" arguments.
+// The analysed field is defined by the <offset> and <size> arguments.
 //////////////////////////////////////////////////////////////////////////////
 
@@ -249,9 +249,9 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following function search in the directory identified by the "parent"
-// inode pointer a child (file or directory) identified by its "name".
-// It returns in the "inode" argument the searched child inode pointer.
+// The following function search in the directory identified by the <parent>
+// inode pointer a child (file or directory) identified by its <name>.
+// It returns in the <inode> argument the searched child inode pointer.
 // If the searched name is not found in the Inode-Tree, the function accesses
-// the "file_cache" associated to the parent directory.
+// the File-cache associated to the parent directory.
 // If the child exists on block device, the Inode-Tree is updated, and
 // a success code is returned.
@@ -356,5 +356,5 @@
 //////////////////////////////////////////////////////////////////////////////////
 // The following function releases all clusters allocated to a file or directory,
-// from the cluster index defined by the "cluster" argument, until the end 
+// from the cluster index defined by the <cluster> argument, until the end 
 // of the FAT linked list.
 // It calls _get_fat_entry() and _set_fat_entry() functions to scan the FAT,
@@ -368,7 +368,8 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// This function allocate "nb_clusters_more" new clusters to a file (or directory)
-// identified by the "inode" pointer. It allocates also the associated buffers
-// and buffer descriptors in the Cache-File.
+// This function allocate one cluster in FAT to a file (or directory) identified 
+// by the <inode> pointer. The allocated cluster index is returned in the
+// <cluster> argument.
+// It allocates also the associated buffers and buffer descriptors in Cache-File.
 // It calls _get_fat_entry() and _set_fat_entry() functions to update the
 // clusters chaining in the Cache-Fat. The FAT region on block device is updated.
@@ -377,7 +378,6 @@
 //////////////////////////////////////////////////////////////////////////////////
 
-static unsigned int _clusters_allocate( fat_inode_t* inode, 
-                                        unsigned int nb_clusters_current,
-                                        unsigned int nb_clusters_more );
+static unsigned int _cluster_allocate( fat_inode_t*   inode, 
+                                       unsigned int*  cluster );
 
 //////////////////////////////////////////////////////////////////////////////////
@@ -393,7 +393,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following function allocates and initializes a new Fat-Cache node.
+// The following function allocates and initializes a new cache node.
 // Its first child can be specified (used when adding a cache level).
-// The Fat-Cache is initialized as empty: all children set to NULL.
+// The 63 other children are set to NULL.
 // It returns a pointer to a new Fat-Cache node.
 //////////////////////////////////////////////////////////////////////////////////
@@ -404,5 +404,5 @@
 // The following function allocates and initializes a new inode, 
 // using the values defined by the arguments.
-// If the "cache_allocate" argument is true ans empty cache is allocated.
+// If the "cache_allocate" argument is true, an empty cache is allocated.
 // It returns a pointer on the new inode.
 //////////////////////////////////////////////////////////////////////////////////
@@ -417,9 +417,9 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following function allocates one 4 Kbytes buffer and associated cluster 
-// descriptor for the file (or directory) identified by the "inode" argument,
-// and updates the Cache_File slot identified by the "cluster_id" argument. 
+// The following function allocates a 4 Kbytes buffer and the associated cluster 
+// descriptor for the file (or directory) identified by the <inode> argument,
+// and updates the Cache_File slot identified by the <cluster_id> argument. 
 // The File-Cache slot must be empty.
-// It updates the cluster descriptor, using the "cluster" argument, that is 
+// It updates the buffer descriptor, using the <cluster> argument, that is 
 // the cluster index in FAT.  The cluster descriptor dirty field is set.
 // It traverse the 64-tree Cache-file from top to bottom to find the last level.
@@ -431,6 +431,6 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following function allocates one free cluster from the FAT "heap" of free 
-// clusters, and returns the cluster index in the "cluster" argument.
+// The following function allocates one free cluster from the FAT  
+// and returns the cluster index in the <cluster> argument.
 // It updates the FAT slot, and the two FAT global variables: first_free_cluster,
 // and free_clusters_number.
@@ -443,5 +443,5 @@
 /////////////////////////////////////////////////////////////////////////////
 // This function remove from the file system a file or a directory 
-// identified by the "inode" argument. 
+// identified by the <inode> argument. 
 // The remove condition must be checked by the caller.
 // The relevant lock(s) must have been taken by te caller.
@@ -483,5 +483,5 @@
 
 //////////////////////////////////////////////////////////////////////////////////
-// The following functions return the length or the size of a FAT field, 
+// The following functions return the the size (bytes) of a FAT field, 
 // identified by an (offset,length) mnemonic defined in the fat32.h file.
 //////////////////////////////////////////////////////////////////////////////////
@@ -491,4 +491,16 @@
 static inline int get_offset( int offset , int length ) { return offset; }
 
+//////////////////////////////////////////////////////////////////////////////////
+// The following function returns in the <desc> argument a pointer on a buffer 
+// descriptor contained in the Fat_Cache. 
+// The <cluster_id> argument is the buffer index in the FAT_Cache. 
+// In case of miss, a 4 Kbytesbuffer and a buffer descriptor are allocated 
+// from the local heap, and the missing cluster is loaded in the Fat_Cache.
+// It returns 0 on success.
+// It returns 1 on error.
+//////////////////////////////////////////////////////////////////////////////////
+
+static unsigned int _get_fat_cache_buffer( unsigned int        cluster_id,
+                                           fat_cache_desc_t**  desc );
 
 
@@ -855,5 +867,5 @@
 
 
-////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
 static fat_cache_node_t* _allocate_one_cache_node( fat_cache_node_t* first_child )
 {
@@ -1006,10 +1018,9 @@
     unsigned int       entry_id   = cluster & 0x3FF;
 
-    // get pointer on the relevant cluster descriptor in FAT cache
+    // get pointer on the relevant buffer descriptor in FAT cache
     fat_cache_desc_t*  pdesc;
     unsigned int*      buffer;
-    if ( _fat_buffer_from_cache( NULL,               // Fat-Cache
-                                 cluster_id,
-                                 &pdesc ) ) return 1;
+    if ( _get_fat_cache_buffer( cluster_id,
+                                &pdesc ) ) return 1;
 
     // get value from FAT slot
@@ -1031,10 +1042,9 @@
     unsigned int entry_id   = cluster & 0x3FF;
 
-    // get pointer on the relevant cluster descriptor in FAT cache
+    // get pointer on the relevant buffer descriptor in FAT cache
     fat_cache_desc_t*  pdesc;
     unsigned int*      buffer; 
-    if ( _fat_buffer_from_cache( NULL,               // Fat-Cache
-                                 cluster_id,
-                                 &pdesc ) )  return 1;           
+    if ( _get_fat_cache_buffer( cluster_id,
+                                &pdesc ) )  return 1;           
 
     // set value into FAT slot
@@ -1053,7 +1063,15 @@
                                   unsigned int  cluster )
 {
+
+#if (GIET_DEBUG_FAT & 1)
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _allocate_one_buffer(): in cache <%s> for cluster_id %d\n",
+        inode->name, cluster_id );
+#endif
+
     // add cache levels if needed
     while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
     {
+
 #if (GIET_DEBUG_FAT & 1)
 if ( _get_proctime() > GIET_DEBUG_FAT )
@@ -1077,8 +1095,11 @@
         {
             fat_cache_desc_t* pdesc = (fat_cache_desc_t*)node->children[index];
+
             if ( pdesc != NULL )      // slot not empty!!!
             {
-                _printf("\n[FAT ERROR] allocate_one buffer(): slot not empty "
-                        "in File-Cache <%s> / cluster_id = %d\n", inode->name , cluster_id );
+                _printf("\n[FAT ERROR] in _allocate_one buffer() : slot not empty "
+                        "in File-Cache <%s>\n cluster_id = %d / cache = %x / pdesc[0] = %x\n",
+                        inode->name , cluster_id , 
+                        (unsigned int)node , (unsigned int)pdesc );
                 _exit();
             }
@@ -1155,5 +1176,5 @@
 #if (GIET_DEBUG_FAT & 1)
 if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _allocate_one_cluster(): cluster = %x / first_free = %x\n",
+_printf("\n[DEBUG FAT] _allocate_one_cluster(): allocated cluster = %x / first_free = %x\n",
         free , current );
 #endif
@@ -1176,5 +1197,5 @@
     unsigned int ret = 0;
 
-    if ( levels == 1 )  // last level => children are cluster descriptors
+    if ( levels == 1 )  // last level => children are buffer descriptors
     {
         for( index = 0 ; index < 64 ; index++ )
@@ -1273,80 +1294,56 @@
 
 
-/////////////////////////////////////////////////////////////
-static unsigned int _clusters_allocate( fat_inode_t* inode, 
-                                        unsigned int nb_current_clusters,
-                                        unsigned int nb_required_clusters )
-{
-    // Check if FAT contains enough free clusters
-    if ( nb_required_clusters > _fat.free_clusters_number )
-    {
-        _printf("\n[FAT ERROR] _clusters_allocate(): required_clusters = %d"
-                " / free_clusters = %d\n", nb_required_clusters , _fat.free_clusters_number );
+////////////////////////////////////////////////////////////
+static unsigned int _cluster_allocate( fat_inode_t*   inode,
+                                       unsigned int*  cluster ) 
+{
+    // Check free cluster available
+    if ( _fat.free_clusters_number == 0 )
+    {
+        _printf("\n[FAT ERROR] in _cluster_allocate(): no more free clusters\n");
         return 1;
     }
 
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _clusters_allocate(): enters for <%s> / nb_current_clusters = %d "
-        "/ nb_required_clusters = %d\n", 
-        inode->name , nb_current_clusters , nb_required_clusters );
-#endif
- 
-    // compute last allocated cluster index when (nb_current_clusters > 0)
+    // compute number of already allocated clusters 
+    // and last allocated cluster index
+    unsigned int nb_current_clusters = 0;
     unsigned int current = inode->cluster;
-    unsigned int next;
-    unsigned int last;
-    if ( nb_current_clusters )   // clusters allocated => search last
-    {    
-        while ( current < END_OF_CHAIN_CLUSTER_MIN )
-        {
-            // get next cluster
-            if ( _get_fat_entry( current , &next ) )  return 1;
-            last    = current;
-            current = next;
-        }
+    unsigned int last    = current;
+    unsigned int next    = 0;
+    unsigned int new     = 0;
+
+    while ( current < END_OF_CHAIN_CLUSTER_MIN )
+    {
+        // get next cluster
+        if ( _get_fat_entry( current , &next ) )  return 1;
+        
+        // increment number of allocated clusters
+        nb_current_clusters++;
+
+        // update loop variables
+        last    = current;
+        current = next;
     }  
 
-    // Loop on the new clusters to be allocated
-    // if (nb_current_clusters == 0) the first new cluster index must
-    //                               be written in inode->cluster field 
-    // if (nb_current_clusters >  0) the first new cluster index must
-    //                               be written in FAT[last]
-    unsigned int      cluster_id;
-    unsigned int      new;
-    for ( cluster_id = nb_current_clusters ; 
-          cluster_id < (nb_current_clusters + nb_required_clusters) ; 
-          cluster_id ++ )
-    {
-        // allocate one cluster on block device
-        if ( _allocate_one_cluster( &new ) ) return 1;
-
-        // allocate one 4K buffer to File-Cache
-        _allocate_one_buffer( inode,
-                              cluster_id,
-                              new );
-
-        if ( cluster_id == 0 )  // update inode 
-        {
-            inode->cluster = new;
-        }
-        else                    // update FAT
-        {
-            if ( _set_fat_entry( last , new ) ) return 1;
-        }
-
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _clusters_allocate(): done for cluster_id = %d / cluster = %x\n",
-        cluster_id , new );
-#endif
-
-        // update loop variables
-        last = new;
-
-    } // end for loop
-
-    // update FAT : last slot should contain END_OF_CHAIN_CLUSTER_MAX
-    if ( _set_fat_entry( last , END_OF_CHAIN_CLUSTER_MAX ) )  return 1;
+    // allocate one free cluster from FAT
+    if ( _allocate_one_cluster( &new ) ) return 1;
+
+    // allocate one 4K buffer to File-Cache
+    _allocate_one_buffer( inode,
+                          nb_current_clusters,
+                          new );
+
+    if ( nb_current_clusters == 0 )  // first cluster : inode and directory entry
+    {
+        // update inode
+        inode->cluster = new;
+
+        // update directory entry
+        _update_dir_entry( inode );
+    }
+    else                             // update previous last cluster in FAT
+    {
+        if ( _set_fat_entry( last , new ) ) return 1;
+    }
 
     // update the FAT on block device
@@ -1354,6 +1351,16 @@
                                     _fat.fat_cache_root,
                                     "FAT" ) )              return 1;
+#if (GIET_DEBUG_FAT & 1)
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _cluster_allocate(): for <%s> / current_clusters = %d"
+        " / last_cluster = %x / new_cluster = %x\n",
+        inode->name , nb_current_clusters , last , new );
+#endif
+
+    // returns allocated cluster index 
+    *cluster = new;
+
     return 0;
-}  // end _clusters_allocate()
+}  // end _cluster_allocate()
 
 
@@ -1518,6 +1525,7 @@
     {
         // get one 4 Kytes buffer from File_Cache  
-        if ( _fat_buffer_from_cache( inode,
+        if ( _get_file_cache_buffer( inode,
                                      cluster_id,
+                                     0,          
                                      &pdesc ) )   return 1;
         buffer = pdesc->buffer;
@@ -1600,6 +1608,7 @@
     {
         // get one 4 Kytes buffer from File_Cache  
-        if ( _fat_buffer_from_cache( parent,
+        if ( _get_file_cache_buffer( parent,
                                      cluster_id,
+                                     0,
                                      &pdesc ) )   return 1;
 
@@ -1658,6 +1667,7 @@
         if ( offset >= 4096 )  // new buffer required
         {
-            if ( _fat_buffer_from_cache( parent,
+            if ( _get_file_cache_buffer( parent,
                                          cluster_id + 1,
+                                         0,
                                          &pdesc ) )      return 1;
             buffer       = pdesc->buffer;
@@ -1832,6 +1842,7 @@
     fat_cache_desc_t*  pdesc;
 
-    if ( _fat_buffer_from_cache( inode->parent,
+    if ( _get_file_cache_buffer( inode->parent,
                                  cluster_id,
+                                 0,
                                  &pdesc ) ) return 1;
     buffer       = pdesc->buffer;
@@ -1849,6 +1860,7 @@
                 break;
 
-            if ( _fat_buffer_from_cache( inode->parent,
+            if ( _get_file_cache_buffer( inode->parent,
                                          cluster_id - 1,
+                                         0,
                                          &pdesc ) )   return 1;
             buffer       = pdesc->buffer;
@@ -1885,6 +1897,7 @@
     unsigned int       offset     = (inode->dentry & 0x7F)<<5;
 
-    if ( _fat_buffer_from_cache( inode->parent,
+    if ( _get_file_cache_buffer( inode->parent,
                                  cluster_id,
+                                 0,
                                  &pdesc ) )    return 1;
     buffer       = pdesc->buffer;
@@ -1938,6 +1951,6 @@
     }
 
-    // not found in Inode-Tree => access the parent directory 
-    // file_cache.  Two embedded loops:
+    // not found in Inode-Tree => access the parent directory file_cache.
+    // Two embedded loops:
     // - scan the clusters allocated to this directory
     // - scan the directory entries in each 4 Kbytes buffer
@@ -1970,6 +1983,7 @@
         // get one 4 Kytes buffer from parent File_Cache  
         fat_cache_desc_t*  pdesc;
-        if ( _fat_buffer_from_cache( parent,
+        if ( _get_file_cache_buffer( parent,
                                      cluster_id,
+                                     0,
                                      &pdesc ) )    return 2;
         buffer = pdesc->buffer;
@@ -1978,10 +1992,4 @@
         while( (offset < 4096) && (found == 0) )
         {
-
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _get_child_from_parent(): scan buffer %d for <%s>\n",
-        cluster_id , name );
-#endif
             attr = _read_entry( DIR_ATTR , buffer + offset , 0 );   
             ord  = _read_entry( LDIR_ORD , buffer + offset , 0 );
@@ -2027,5 +2035,5 @@
                 }
                     
-                // test if extracted name == searched name
+                // get dir-entry arguments if extracted name == searched name
                 if ( _strcmp( name , cname ) == 0 )
                 {
@@ -2036,4 +2044,12 @@
                     size    = _read_entry( DIR_FILE_SIZE , buffer + offset , 1 );
                     found   = 1;
+
+                    // adjust size for a directory :
+                    // size must be non-zero and rounded to a multiple of 4 Kbytes 
+                    if ( is_dir )
+                    {
+                        if      ( size == 0 )    size = 4096;
+                        else if ( size & 0xFFF ) size = ((size>>12) + 1)<<12;  
+                    }
                 }
                 offset = offset + 32;
@@ -2449,4 +2465,94 @@
 
 
+//////////////////////////////////////////////////////////////////////////
+static unsigned int _get_fat_cache_buffer( unsigned int        cluster_id,
+                                           fat_cache_desc_t**  desc )
+{
+    // get cache pointer and number of levels
+    fat_cache_node_t*   node   = _fat.fat_cache_root;    
+    unsigned int        level  = _fat.fat_cache_levels;  
+
+    if ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > level )
+    {
+        _printf("\n[FAT ERROR] in _get_fat_cache_buffer() : "
+                "cluster_id %d too large", cluster_id );
+        return 1;
+    }
+
+    // search the 64-tree cache from top to bottom 
+    while ( level )
+    {
+        // compute child index at each level
+        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
+
+        if ( level == 1 )        // last level => children are buffer descriptors
+        {
+            fat_cache_desc_t*   pdesc = (fat_cache_desc_t*)node->children[index];
+
+            if ( pdesc == NULL )      // miss 
+            {
+
+#if (GIET_DEBUG_FAT & 1)
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _get_fat_cache_buffer(): miss for cluster_id %d\n", cluster_id );
+#endif
+                // compute missing cluster lba
+                unsigned int lba = _fat.fat_lba + (cluster_id << 3);
+
+                // allocate a 4 Kbytes buffer and a buffer descriptor
+                void* buf      = _malloc( 4096 );
+                pdesc          = _malloc( sizeof(fat_cache_desc_t) );
+                pdesc->lba     = lba;
+                pdesc->buffer  = buf;
+                pdesc->dirty   = 0;
+                node->children[index] = pdesc;
+
+                // load cluster from device
+                if ( _fat_ioc_access( 1,         // descheduling
+                                      1,         // to memory
+                                      lba,
+                                      (unsigned int)buf,
+                                      8 ) )
+                {
+                    _free( buf );
+                    _free( pdesc );
+                    _printf("\n[FAT ERROR] in _get_fat_cache_buffer() : "
+                            ": cannot access block device for lba = %x\n", lba );
+                    return 1;
+                }
+
+            }
+
+#if (GIET_DEBUG_FAT & 1)
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _get_fat_cache_buffer() : found buffer = %x\n", 
+        (unsigned int)pdesc->buffer );
+#endif
+            // return pdesc pointer
+            *desc = pdesc;
+
+            // prepare next iteration
+            level--;
+        }
+        else                      // not last level => children are 64-tree nodes
+        {
+            fat_cache_node_t* child = (fat_cache_node_t*)node->children[index];
+            if ( child == NULL )  // miss 
+            {
+                // allocate a cache node if miss
+                child = _allocate_one_cache_node( NULL );
+                node->children[index] = child;    
+            }
+
+            // prepare next iteration
+            node = child;
+            level--;
+        }
+    } // end while
+
+    return 0;
+}  // end _get_fat_cache_buffer()
+
+
 
 /////////////////////////////////////////////////////////////////////////////
@@ -2459,5 +2565,5 @@
 /////////////////////////////////////////////////////////////////////////////
 // This function initializes the FAT structures.
-// - The Fat-Descriptor is always initialized.
+// - The Fat-Descriptor is initialized in both boot and kernel modes.
 // - The dynamically allocated structures (the Inode-Tre, the Fat_Cache, 
 //   and the File-Cache for the root directory) are only allocated
@@ -2582,11 +2688,11 @@
 
         // create Inode-Tree root
-        _fat.inode_tree_root = _allocate_one_inode("/", // dir name
-                                                   1,   // directory
-                                                   2,   // cluster id
-                                                   0,   // no size
-                                                   0,   // no children
-                                                   0,   // no dentry
-                                                   1);  // allocate cache
+        _fat.inode_tree_root = _allocate_one_inode("/",   // dir name
+                                                   1,     // is directory
+                                                   2,     // cluster index
+                                                   4096,  // at least one buffer
+                                                   0,     // no children
+                                                   0,     // no dentry
+                                                   1);    // allocate cache
 
         // initialize lock
@@ -2614,11 +2720,13 @@
 ///////////////////////////////////////////////////////////////////////////////
 // This function implements the giet_fat_open() system call.
-// The semantic is similar to the UNIX open() function, but only the O_CREATE
-// and O_RDONLY flags are supported. The UNIX access rights are not supported. 
-// If the file does not exist in the specified directory, it is created.
+// The semantic is similar to the UNIX open() function, with some limitations:
+// - only the O_CREATE, O_RDONLY, and O_TRUNC flags are supported.
+// - the UNIX access rights are not supported. 
+// If the file does not exist in the specified directory, it is created when
+// the O_CREATE flag is set.
 // If the specified directory does not exist, an error is returned.
 // It allocates a file descriptor to the calling task, for the file identified 
-// by "pathname". If several tasks try to open the same file, each task  
-// obtains a private file descriptor. 
+// by the <pathname> argument. If several tasks try to open the same file, 
+// each task obtains a private file descriptor. 
 // A node name (file or directory) cannot be larger than 31 characters.
 ///////////////////////////////////////////////////////////////////////////////
@@ -2672,5 +2780,5 @@
     code = _get_inode_from_path( pathname , &inode );
 
-    if ( code == 2 )  
+    if ( code == 2 )                          // parent inode not found
     {
         _spin_lock_release( &_fat.fat_lock );
@@ -2681,5 +2789,5 @@
         return GIET_FAT32_FILE_NOT_FOUND;
     }
-    else if ( code == 3 )  
+    else if ( code == 3 )                     // illegal path name
     {
         _spin_lock_release( &_fat.fat_lock );
@@ -2690,5 +2798,5 @@
         return GIET_FAT32_NAME_TOO_LONG;
     }
-    else if ( (code == 1) && (create == 0) )   
+    else if ( (code == 1) && (create == 0) )   // inode not found
     {
         _spin_lock_release( &_fat.fat_lock );
@@ -2699,5 +2807,5 @@
         return GIET_FAT32_FILE_NOT_FOUND;
     }
-    else if ( (code == 1) && (create != 0) )   // file name not found => create 
+    else if ( (code == 1) && (create != 0) )   // inode not found => create 
     {
         // set parent inode pointer
@@ -2720,5 +2828,5 @@
                                      0,                         // size : new file is empty
                                      0,                         // count incremented later
-                                     0,                         // dentry set by add_dir_entry
+                                     0,                         // set by add_dir_entry
                                      1 );                       // cache_allocate
 
@@ -2776,6 +2884,24 @@
         // no need to truncate a new file
         truncate = 0;
-    }
-    else // code == 0
+
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+{
+    _printf("\n[DEBUG FAT] _fat_open() : new inode created for <%s>\n" 
+            " size = %x / cluster = %x / cache = %x",
+            child->name , child->size , child->cluster , child->cache );
+    if ( child->cache != NULL )
+    {
+         _printf(" / pdesc[0] = %x\n", (unsigned int)(child->cache->children[0]) );
+    }
+    else
+    {
+         _printf("\n");
+    }
+}
+#endif
+
+    }
+    else                                    // inode found
     {
         // set searched file inode pointer
@@ -2846,15 +2972,15 @@
     }
 
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] got fd = %d for <%s> / "
+        "size = %x / read_only = %d\n",
+        x , y , p , fd_id , pathname , read_only );
+#endif
+
     // releases the lock
     _spin_lock_release( &_fat.fat_lock );
     _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
 
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] got fd = %d for <%s> / "
-        "read_only = %d\n",
-        x , y , p , fd_id , pathname , read_only );
-#endif
     return fd_id;
 } // end _fat_open()
@@ -2910,13 +3036,14 @@
     fat_inode_t*  inode = _fat.fd[fd_id].inode;
 
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[FAT DEBUG] _fat_close() for file <%s> : refcount = %d"
+        " / size = %x / cluster = %x\n",
+        inode->name , inode->count , inode->size , inode->cluster );
+#endif
+
     // decrement reference count
     inode->count = inode->count - 1;
     
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[FAT DEBUG] _fat_close() for file <%s> : refcount = %d\n",
-        inode->name , inode->count );
-#endif
-
     // update block device and release File-Cache if no more references
     if ( inode->count == 0 )
@@ -2937,8 +3064,8 @@
 #if GIET_DEBUG_FAT
 if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[FAT DEBUG] _fat_close() update device for file <%s>\n", inode->name );
-#endif
-
-        // update directory dirty clusters for parent directory
+_printf("\n[FAT DEBUG] _fat_close() updated device for file <%s>\n", inode->name );
+#endif
+
+        // update dirty clusters for parent directory
         if ( inode->parent &&
              _update_device_from_cache( inode->parent->levels,
@@ -2956,5 +3083,5 @@
 #if GIET_DEBUG_FAT
 if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[FAT DEBUG] _fat_close() update device for parent directory <%s>\n",
+_printf("\n[FAT DEBUG] _fat_close() updated device for parent directory <%s>\n",
         inode->parent->name );
 #endif
@@ -3138,6 +3265,7 @@
         unsigned char*     cbuf;
         fat_cache_desc_t*  pdesc;
-        if ( _fat_buffer_from_cache( inode, 
+        if ( _get_file_cache_buffer( inode, 
                                      cluster_id,
+                                     0,
                                      &pdesc ) )
         {
@@ -3314,38 +3442,42 @@
     if ( new_size > old_size )
     {
+        // compute current and required numbers of clusters
+        unsigned old_clusters = old_size >> 12;
+        if ( old_size & 0xFFF ) old_clusters++;
+
+        unsigned new_clusters = new_size >> 12;
+        if ( new_size & 0xFFF ) new_clusters++;
+
+        // allocate new clusters from FAT if required
+        if ( new_clusters > old_clusters )
+        {
+
+#if GIET_DEBUG_FAT
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] allocates new clusters for file <%s>"
+        " / current = %d / required = %d\n",
+        x , y , p , inode->name , old_clusters , new_clusters );
+#endif
+            // allocate missing clusters
+            unsigned int cid;
+            unsigned int index;  // unused
+            for ( cid = 0 ; cid < (new_clusters - old_clusters) ; cid++ )
+            {
+                if ( _cluster_allocate( inode , &index ) )
+                {
+                    _spin_lock_release( &_fat.fat_lock );
+                    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] ,
+                                 ~LOCKS_MASK_FAT ); 
+
+                    _printf("\n[FAT ERROR] in _fat_write(): no free cluster"
+                            " for file <%s>\n", _fat.fd[fd_id].inode->name );
+                    return GIET_FAT32_NO_FREE_SPACE;
+                }
+            }
+        }
+         
         // update size in inode
         inode->size = new_size;
  
-        // compute current and required numbers of clusters
-        unsigned old_clusters = old_size >> 12;
-        if ( old_size & 0xFFF ) old_clusters++;
-
-        unsigned new_clusters = new_size >> 12;
-        if ( new_size & 0xFFF ) new_clusters++;
-
-        // allocate new clusters from FAT if required
-        if ( new_clusters > old_clusters )
-        {
-
-#if GIET_DEBUG_FAT
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] allocates new clusters for file <%s>"
-        " / current = %d / required = %d\n",
-        x , y , p , inode->name , old_clusters , new_clusters );
-#endif
-            // allocate missing clusters
-            if ( _clusters_allocate( inode,
-                                     old_clusters,
-                                     new_clusters - old_clusters ) )
-            {
-                _spin_lock_release( &_fat.fat_lock );
-                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
-
-                _printf("\n[FAT ERROR] _fat_write(): no free clusters"
-                        " for file <%s>\n", _fat.fd[fd_id].inode->name );
-                return GIET_FAT32_NO_FREE_SPACE;
-            }
-        }
-         
         // update parent directory entry (size and cluster index)
         if ( _update_dir_entry( inode ) )
@@ -3393,6 +3525,7 @@
         unsigned char*     cbuf;
         fat_cache_desc_t*  pdesc;
-        if ( _fat_buffer_from_cache( inode,   
+        if ( _get_file_cache_buffer( inode,   
                                      cluster_id,  
+                                     0,
                                      &pdesc ) )   
         {
@@ -3915,5 +4048,5 @@
                                0 );            // no cache_allocate
  
-    // give the "old" File-Cache to the "new inode
+    // attach the "old" File-Cache to the "new" inode
     new->levels = old->levels;
     new->cache  = old->cache;
@@ -4107,5 +4240,5 @@
                                      1,           // it's a directory
                                      cluster,  
-                                     0,           // size not defined
+                                     4096,        // one buffer for a directory
                                      0,           // count
                                      0,           // dentry set by _add_dir_entry()
@@ -4479,60 +4612,71 @@
 
 
-//////////////////////////////////////////////////////////////////////////////////
-// The following function returns in the "desc" argument a pointer on a buffer 
-// descriptor contained in a File_Cache, or in the Fat_Cache. 
-// The searched buffer is idenfified by the "inode" and "cluster_id" arguments.
-// If the "inode" pointer is not NULL, the searched cache is a File-Cache.
-// If the "inode" pointer is NULL, the searched cache is the Fat-Cache, 
-// The "cluster_id" argument is the buffer index in the file (or in the FAT). 
-// In case of miss, it allocate a 4 Kbytes buffer and a cluster descriptor 
-// from the local kernel heap, and calls the _fat_ioc_access() function to load 
-// the missing cluster from the block device.
+
+//////////////////////////////////////////////////////////////////////////////////
+// The following function returns in the <desc> argument a pointer on a buffer 
+// descriptor contained in a File_Cache. 
+// The searched buffer is idenfified by the <inode> and <cluster_id> arguments.
+// The <cluster_id> argument is the buffer index in the file. 
+// The <writable> argument define the behaviour in case of miss in File-Cache:
+// - if [all clusters (from 0 to cluster_id) are already allocated in FAT] 
+//   we scan the FAT to find the cluster index on device, and we load the
+//   missing cluster in the File-Cache, marked as dirty if writable is set.
+// - else if [writable is not set]  we return an error.
+// - else [writable set, but all clusters (from 0 to cluster_id) not allocated]
+//   we allocate in FAT all required clusters, we update the size in the inode 
+//   and dentry, and we allocate a buffer descriptor for the missing cluster, 
+//   marked as dirty.
+// This function can be called by the FAT functions, and by _sys_fat_mmap().
+// It does not take the FAT lock, that must be taken by the caller.
 //////////////////////////////////////////////////////////////////////////////////
 // It returns 0 on success.
 // It returns 1 on error.
 //////////////////////////////////////////////////////////////////////////////////
-int _fat_buffer_from_cache( fat_inode_t*        inode,
-                            unsigned int        cluster,
+int _get_file_cache_buffer( fat_inode_t*        inode,
+                            unsigned int        cluster_id,
+                            unsigned int        writable,
                             fat_cache_desc_t**  desc )
 {
-    // get cache pointer and levels
-    fat_cache_node_t*   node;         // pointer on a 64-tree node
-    unsigned int        level;        // cache level
-
-    if ( inode == NULL )   // searched cache is the Fat-Cache
-    {
-        node   = _fat.fat_cache_root;
-        level  = _fat.fat_cache_levels;
 
 #if (GIET_DEBUG_FAT & 1)
 if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): enters in FAT-Cache"
-        " for cluster = %d\n", cluster );
-#endif
-    }
-    else                   // searched cache is a File-Cache
-    {
-        // add cache levels if needed
-        while ( _get_levels_from_size( (cluster + 1) * 4096 ) > inode->levels )
-        {
+_printf("\n[DEBUG FAT] _get_file_cache_buffer(): enters in File-Cache <%s>"
+        " for cluster_id = %d\n size = %x / cache = %x / desc[%d] = %x\n", 
+        inode->name , cluster_id ,
+        inode->size , (unsigned int)inode->cache , cluster_id ,
+        (unsigned int)inode->cache->children[cluster_id] );
+#endif
+
+    // checking FAT initialized
+    if( _fat.initialized != FAT_INITIALIZED )
+    {
+        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : FAT not initialized\n");
+        return GIET_FAT32_NOT_INITIALIZED;
+    }
+
+    // checking arguments
+    if ( inode == NULL )   // illegal inode argument
+    {
+        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : illegal inode argument\n");
+        return GIET_FAT32_INVALID_ARG;
+    }
+
+    // add cache levels if needed
+    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
+    {
+
 #if (GIET_DEBUG_FAT & 1)
 if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): adding a File-Cache level\n" );
-#endif
-
-            inode->cache = _allocate_one_cache_node( inode->cache );
-            inode->levels++;
-        }
-
-        node   = inode->cache;
-        level  = inode->levels;
-
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): enters in File-Cache <%s>"
-        " for cluster = %d\n", inode->name , cluster );
-#endif
-    }
+_printf("\n[DEBUG FAT] _get_file_cache_buffer() : add a File-Cache level\n" );
+#endif
+
+        inode->cache = _allocate_one_cache_node( inode->cache );
+        inode->levels++;
+    }
+
+    // get File-Cache 
+    fat_cache_node_t*   node  = inode->cache;  
+    unsigned int        level = inode->levels;
+
 
     // search the 64-tree cache from top to bottom 
@@ -4540,73 +4684,120 @@
     {
         // compute child index at each level
-        unsigned int index = (cluster >> (6*(level-1))) & 0x3F;
-
-        if ( level == 1 )        // last level => children are cluster descriptors
-        {
-            fat_cache_desc_t* pdesc = (fat_cache_desc_t*)node->children[index];
-
-            if ( pdesc == NULL )      // miss 
+        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
+
+        if ( level == 1 )        // last level => children are buffer descriptors
+        {
+            fat_cache_desc_t*   pdesc = (fat_cache_desc_t*)node->children[index];
+            unsigned int        current = inode->cluster;
+            unsigned int        next    = 0;
+            unsigned int        prev    = 0;
+            unsigned int        cid;
+            unsigned int        lba;
+
+            if ( pdesc == NULL )      // miss in File-Cache
             {
-                // get missing cluster index lba
-                unsigned int lba;
-                unsigned int next;
-                unsigned int current = inode->cluster;
-                unsigned int count   = cluster;
-
-                if ( inode == NULL )      // searched cache is the Fat-Cache
+
+#if (GIET_DEBUG_FAT & 1)
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _get_file_cache_buffer() : miss in cache <%s> for cluster_id = %d\n"
+        " cluster = %x / size = %x / cache = %x / desc[%d] = %x\n",
+        inode->name , cluster_id , inode-> cluster , inode->size ,
+        (unsigned int)inode->cache , cluster_id , 
+        (unsigned int)inode->cache->children[cluster_id] );
+#endif
+                if ( inode->size > (cluster_id<<12) )  // all clusters allocated in FAT
                 {
-
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): miss in FAT-Cache for cluster %d\n",
-        cluster );
-#endif
-                    lba = _fat.fat_lba + (cluster << 3);
-                }
-                else                      // searched cache is a File-Cache
-                {
-
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): miss in File-Cache <%s> "
-        "for cluster %d\n", inode->name, cluster );
-#endif
-                    while ( count )
-                    { 
+                    // scan the FAT to find the cluster index for cluster_id
+                    for ( cid = 0 ; cid < cluster_id ; cid++ )
+                    {
+                        // get next cluster index from FAT
                         if ( _get_fat_entry( current , &next ) ) return 1;
                         current = next;
-                        count--;
                     }
+
+                    // compute lba
                     lba = _cluster_to_lba( current );
+
+                    // allocate a 4 Kbytes buffer and a buffer descriptor 
+                    // the selected heap depends on the calling thread
+                    void* buf      = _malloc( 4096 );
+                    pdesc          = _malloc( sizeof(fat_cache_desc_t) );
+
+                    // set buffer descriptor
+                    pdesc->lba     = lba;
+                    pdesc->buffer  = buf;
+                    pdesc->dirty   = writable;
+                    node->children[index] = pdesc;
+
+                    // load cluster from device
+                    if ( _fat_ioc_access( 1,         // descheduling
+                                          1,         // to memory
+                                          lba,
+                                          (unsigned int)buf,
+                                      8 ) )
+                    {
+                         
+                        _free( buf );
+                        _free( pdesc );
+                        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
+                                "cannot access block device for lba = %x\n", lba );
+                        return GIET_FAT32_IO_ERROR;
+                    }
                 }
-
-                // allocate a 4 Kbytes buffer in cluster running the calling thread
-                void* buf = _malloc( 4096 );
-
-                // load one cluster (8 blocks) from block device
-                if ( _fat_ioc_access( 1,         // descheduling
-                                      1,         // to memory
-                                      lba,
-                                      (unsigned int)buf,
-                                      8 ) )
+                else if ( writable == 0 )
                 {
-                    _free( buf );
-                    _printf("\n[FAT ERROR] _fat_buffer_from_cache()"
-                            ": cannot access block device for lba = %x\n", lba );
-                    return 1;
+                    _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
+                            " file size too small for <%s>\n"
+                            " size = %x / cluster_id = %d / procid = %x\n",
+                            inode->name , inode->size , cluster_id , _get_procid() );
+                    return GIET_FAT32_IO_ERROR;
                 }
-
-                // allocate buffer descriptor
-                pdesc          = _malloc( sizeof(fat_cache_desc_t) );
-                pdesc->lba     = lba;
-                pdesc->buffer  = buf;
-                pdesc->dirty   = 0;
-                node->children[index] = pdesc;
-
-#if (GIET_DEBUG_FAT & 1)
-if ( _get_proctime() > GIET_DEBUG_FAT )
-_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): buffer loaded from device"
-        " at vaddr = %x\n", (unsigned int)buf );
-#endif
+                else   // writable and all clusters NOT allocated in FAT
+                {
+                    // scan the FAT to allocate all required clusters 
+                    for ( cid = 0 ; cid <= cluster_id ; cid++ )
+                    {
+                        if ( current >= END_OF_CHAIN_CLUSTER_MIN ) // non allocated
+                        {
+                            // allocate one cluster on device
+                            if ( _cluster_allocate( inode , &current ) )
+                            {
+                                _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
+                                        "cannot allocate new cluster for file <%s>\n",
+                                        inode->name );
+                                return GIET_FAT32_IO_ERROR;
+                            }
+                        }
+ 
+                        // get next cluster index from FAT
+                        if ( _get_fat_entry( current , &next ) )
+                        {
+                            _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
+                                    "cannot get next cluster for file <%s>\n",
+                                    inode->name );
+                            return GIET_FAT32_IO_ERROR;
+                        }
+                        prev    = current;
+                        current = next;
+                    }
+
+                    // update size in inode and directory entry
+                    inode->size = (cluster_id + 1)<<12;
+                    _update_dir_entry( inode );
+
+                    // compute lba
+                    lba = _cluster_to_lba( current );
+
+                    // allocate a 4 Kbytes buffer and a buffer descriptor 
+                    // the selected heap depends on the calling thread
+                    void* buf      = _malloc( 4096 );
+                    pdesc          = _malloc( sizeof(fat_cache_desc_t) );
+
+                    // set buffer descriptor
+                    pdesc->lba     = lba;
+                    pdesc->buffer  = buf;
+                    pdesc->dirty   = writable;
+                    node->children[index] = pdesc;
+                }
             }
 
@@ -4614,4 +4805,10 @@
             *desc = pdesc;
 
+#if (GIET_DEBUG_FAT & 1)
+if ( _get_proctime() > GIET_DEBUG_FAT )
+_printf("\n[DEBUG FAT] _fat_buffer_from_cache(): found buffer = %x "
+        " in file <%s> for cluster_id %d\n",
+        (unsigned int)pdesc->buffer , inode->name , cluster_id );
+#endif
             // prepare next iteration
             level--;
@@ -4633,9 +4830,7 @@
     } // end while
 
-    return 0;
-}  // end _fat_buffer_from_cache()
-
-
-
+    return GIET_FAT32_OK;
+
+}  // end _get_file_cache_buffer()
 
 // Local Variables:
