source: soft/giet_vm/giet_fat32/fat32.c @ 783

Last change on this file since 783 was 783, checked in by alain, 9 years ago

Fix various bugs.

  • Property svn:executable set to *
File size: 150.6 KB
RevLine 
[773]1/////////////////////////////////////////////////////////////////////////////////
[587]2// Date     : 01/06/2015
3// Authors  : Alain Greiner
[258]4// Copyright (c) UPMC-LIP6
5//////////////////////////////////////////////////////////////////////////////////
[569]6// The fat32.h and fat32.c files define a library of access functions
[587]7// to a FAT32 disk on a block device. It is intended to be used by both
8// the boot code and the kernel code.
[258]9//////////////////////////////////////////////////////////////////////////////////
10// Implementation notes:
11// 1. the "lba" (Logical Block Address) is the physical sector index on
12//    the block device. The physical sector size is supposed to be 512 bytes.
13// 2. the "cluster" variable is actually a cluster index. A cluster contains
[587]14//    8 sectors (4K bytes) and the cluster index is a 32 bits word.
15// 3. Each file or directory referenced by the software is represented
16//    by an "inode". The set of "inodes" is organised as a tree, that is
17//    a sub-tree of the complete file system existing on the block device.
18// 4. A given file can be referenced by several software tasks, and each task
19//    will use a private handler, called a "file descriptor", allocated by the OS
20//    when the task open the file, that is organised as an indexed array.
21// 5. This FAT32 library implements (N+1) caches : one private "File_ Cache"
22//    for each referenced file or directory, and a specific "Fat_Cache" for
23//    the FAT itself. Each cache contain a variable number of clusters that are
24//    dynamically allocated when they are accessed, and organised as a 64-Tree.
[258]25//////////////////////////////////////////////////////////////////////////////////
[587]26// General Debug Policy:
27// The global variable GIET_DEBUG_FAT is defined in the giet_config.h file.
28// The debug is activated if (proctime > GIET_DEBUG_FAT) && (GIET_DEBUG_FAT != 0)
29// The GIET_DEBUG_FAT bit 0 defines the level of debug:
30//    if   (GIET_DEBUG_FAT & 0x1)    => detailed debug
31//    else                           => external functions only
32//////////////////////////////////////////////////////////////////////////////////
[258]33
34#include <giet_config.h>
[530]35#include <hard_config.h>
[258]36#include <fat32.h>
[530]37#include <utils.h>
38#include <vmem.h>
[587]39#include <kernel_malloc.h>
[709]40#include <ctx_handler.h>
[530]41#include <bdv_driver.h>
42#include <hba_driver.h>
43#include <sdc_driver.h>
44#include <rdk_driver.h>
45#include <mmc_driver.h>
[458]46#include <tty0.h>
[750]47#include <stdio.h>
[258]48
49//////////////////////////////////////////////////////////////////////////////////
[587]50//               Global variables
[258]51//////////////////////////////////////////////////////////////////////////////////
52
[587]53// Fat-Descriptor
54__attribute__((section(".kdata")))
[761]55fat_desc_t     _fat __attribute__((aligned(64))); 
[258]56
[587]57// buffer used by boot code as a simple cache when scanning FAT
58__attribute__((section(".kdata")))
59unsigned char  _fat_buffer_fat[4096] __attribute__((aligned(64)));
[530]60
[587]61// buffer used by boot code as a simple cache when scanning a directory in DATA region
62__attribute__((section(".kdata")))
63unsigned char  _fat_buffer_data[4096] __attribute__((aligned(64)));
[530]64
[587]65// lba of cluster in fat_buffer_fat
66__attribute__((section(".kdata")))
67unsigned int   _fat_buffer_fat_lba;
68
69// lba of cluster in fat_buffer_data
70__attribute__((section(".kdata")))
71unsigned int   _fat_buffer_data_lba;
72
73//////////////////////////////////////////////////////////////////////////////////
74//////////////////////////////////////////////////////////////////////////////////
75//                  Static functions declaration
76//////////////////////////////////////////////////////////////////////////////////
77//////////////////////////////////////////////////////////////////////////////////
78
79
80#if GIET_DEBUG_FAT
[530]81
[587]82static void _display_fat_descriptor();
[530]83
[773]84static void _display_clusters_list();
[530]85
[773]86#endif
[530]87
[587]88static void _get_name_from_long( unsigned char* buffer, 
89                                 char*          name );
90
91static void _get_name_from_short( unsigned char* buffer,
92                                  char*          name );
93
94static inline unsigned int _get_levels_from_size( unsigned int size );
95
96static unsigned int _get_name_from_path( char*          pathname,
97                                         char*          name,
98                                         unsigned int*  nb_read );
99
100static unsigned int _get_last_name( char*   pathname,
101                                    char*   name );
102
103static unsigned int _get_fat_entry( unsigned int  cluster,
104                                    unsigned int* value );
105
106static unsigned int _set_fat_entry( unsigned int  cluster,
107                                    unsigned int  value );
108
109static void _add_inode_in_tree( fat_inode_t*  child,
110                                fat_inode_t*  parent );
111
112static void _remove_inode_from_tree( fat_inode_t* inode );
113
114static unsigned int _update_device_from_cache( unsigned int      levels,
115                                               fat_cache_node_t* root,
116                                               char*             string );
117
[783]118static unsigned int _set_fs_info();
119
[587]120static unsigned int _update_fs_info();
121
122static unsigned int _read_entry( unsigned int    offset,
123                                 unsigned int    size,
124                                 unsigned char*  buffer,
125                                 unsigned int    little_indian );
126
127static unsigned int _cluster_to_lba( unsigned int cluster );
128
129static unsigned int _get_nb_entries( fat_inode_t*   inode,
130                                     unsigned int*  nb_entries );
131
132static unsigned int _get_child_from_parent( fat_inode_t*   parent,
133                                            char*          name,
134                                            fat_inode_t**  inode ); 
135
136static unsigned int _get_inode_from_path( char*          pathname,
137                                          fat_inode_t**  inode );
138
[638]139static unsigned int _is_ancestor( fat_inode_t* a,
140                                  fat_inode_t* b);
141
[773]142static unsigned int _get_sfn_name( char*          name,
143                                   unsigned int*  length,
144                                   unsigned int*  nb_lfn,
145                                   char*          sfn,
146                                   unsigned char* checksum );
[587]147
148static unsigned int _update_dir_entry( fat_inode_t*  inode );
149
150static unsigned int _add_dir_entry( fat_inode_t* child,
151                                    fat_inode_t* parent );
152
153static unsigned int _remove_dir_entry( fat_inode_t*  inode );
154
155static void _add_special_directories( fat_inode_t* child,
156                                      fat_inode_t* parent );
157
[783]158static unsigned int _one_cluster_allocate( fat_inode_t*   inode, 
159                                           unsigned int*  cluster );
[587]160
[783]161static unsigned int _all_clusters_release( fat_inode_t* inode );
[587]162
[651]163static void _release_cache_memory( fat_cache_node_t*  root,
164                                   unsigned int       levels );
[587]165
[639]166static fat_cache_node_t* _allocate_one_cache_node( fat_cache_node_t* first_child );
167
[587]168static fat_inode_t* _allocate_one_inode( char*        name,
169                                         unsigned int is_dir,
170                                         unsigned int cluster,
171                                         unsigned int size,
172                                         unsigned int count,
173                                         unsigned int dentry,
174                                         unsigned int cache_allocate );
175
176static void _allocate_one_buffer( fat_inode_t*    inode,
177                                  unsigned int    cluster_id,
178                                  unsigned int    cluster );
179
[783]180static unsigned int _get_free_cluster( unsigned int*  cluster );
[587]181
182static unsigned int _remove_node_from_fs( fat_inode_t* inode );
183
184static unsigned int _file_info_no_cache( char*          pathname,
185                                         unsigned int*  file_cluster,
186                                         unsigned int*  file_size );
187
188static unsigned int _next_cluster_no_cache( unsigned int   cluster,
189                                            unsigned int*  next );
190
191static inline int get_length( int offset , int length ) { return length; }
192
193static inline int get_offset( int offset , int length ) { return offset; }
194
195
196
197//////////////////////////////////////////////////////////////////////////////////
198//////////////////////////////////////////////////////////////////////////////////
199//                  Static functions definition
200//////////////////////////////////////////////////////////////////////////////////
201//////////////////////////////////////////////////////////////////////////////////
202
[258]203
[530]204#if GIET_DEBUG_FAT
[587]205/////////////////////////////////////
206static void _display_fat_descriptor()
[530]207{
[587]208    _printf("\n###############  FAT DESCRIPTOR  ################################" 
[674]209            "\nFAT initialized                  %x"
[587]210            "\nBlock Size  (bytes)              %x"
211            "\nCluster Size  (bytes)            %x"
[530]212            "\nFAT region first lba             %x"
[587]213            "\nFAT region size (blocks)         %x"
214            "\nDATA region first lba            %x"
215            "\nDATA region size (blocks)        %x"
[530]216            "\nNumber of free clusters          %x"
[587]217            "\nFirst free cluster index         %x" 
218            "\nFat_cache_levels                 %d" 
[530]219            "\n#################################################################\n",
[674]220            _fat.initialized,
[530]221            _fat.sector_size,
[587]222            _fat.cluster_size,
[530]223            _fat.fat_lba,
[587]224            _fat.fat_sectors,
[530]225            _fat.data_lba,
[587]226            _fat.data_sectors,
227            _fat.free_clusters_number,
[783]228            _fat.free_cluster_hint,
[587]229            _fat.fat_cache_levels );
230
231} // end _display_fat_descriptor()
[530]232#endif
233
[587]234
[773]235#if GIET_DEBUG_FAT
[587]236////////////////////////////////////////////////////////
237static void _display_clusters_list( fat_inode_t* inode )
[258]238{
[773]239    unsigned int next        = 0;
240    unsigned int cluster_id  = 0;
241    unsigned int current     = inode->cluster;
242
243    _printf("\n --- clusters for <%s> ---\n",
244            inode->name );
245
246    while( current < END_OF_CHAIN_CLUSTER_MIN ) 
[587]247    {
[773]248        if ( (current < 2) || (cluster_id >= 1024) ) 
249        {
250            _printf("\n[FAT ERROR] in _display_clusters_list()\n");
251            _exit();
252        }
253
[587]254        _get_fat_entry( current , &next );
255        _printf(" > %X", current );
[773]256        cluster_id++;
257        if ( (cluster_id & 0x7) == 0 ) _printf("\n");
[587]258        current = next;
259    }
260    _printf("\n");
261}  // end _display_clusters_list()
262#endif
[258]263
[587]264
265
266/////////////////////////////////////////////////////////////////////
267static inline unsigned int _get_levels_from_size( unsigned int size )
268{ 
269    if      ( size <= (1<<18) ) return 1;     // 64 clusters == 256 Kbytes
270    else if ( size <= (1<<24) ) return 2;     // 64 * 64 clusters => 16 Mbytes
271    else if ( size <= (1<<30) ) return 3;     // 64 * 64 * 64 cluster => 1 Gbytes
272    else                        return 4;     // 64 * 64 * 64 * 64 clusters
[291]273}
274
[587]275
276
277////////////////////////////////////////////////////////
278static unsigned int _read_entry( unsigned int    offset,
279                                 unsigned int    size,
280                                 unsigned char*  buffer,
281                                 unsigned int    little_endian )
[258]282{
[587]283    unsigned int n;
[258]284    unsigned int res  = 0;
285
[587]286    if ( little_endian)
[258]287    {
[587]288        for( n = size ; n > 0 ; n-- ) res = (res<<8) | buffer[offset+n-1];
[258]289    }
290    else
291    {
[587]292        for( n = 0 ; n < size ; n++ ) res = (res<<8) | buffer[offset+n];
[258]293    }
294    return res;
295
[587]296}  // end _read_entry
[258]297
298
299
[587]300//////////////////////////////////////////////////////////////////
301static inline unsigned int _cluster_to_lba( unsigned int cluster )       
[258]302{
[587]303    if ( cluster < 2 )
304    { 
[664]305        _printf("\n[FAT ERROR] _cluster_to_lba(): cluster smaller than 2\n");
[587]306        _exit();
[530]307    }
[258]308
[587]309   return  ((cluster - 2) << 3) + _fat.data_lba;
[258]310}
311
[587]312
[258]313//////////////////////////////////////////////////////
[596]314static inline unsigned char _to_lower(unsigned char c)
315{
316   if (c >= 'A' && c <= 'Z') return (c | 0x20);
317   else                      return c;
318}
319
320
321//////////////////////////////////////////////////////
[587]322static inline unsigned char _to_upper(unsigned char c)
[258]323{
324   if (c >= 'a' && c <= 'z') return (c & ~(0x20));
325   else                      return c;
326}
327
328
329
[587]330///////////////////////////////////////////////////////////////////////////
331static unsigned int _get_name_from_path( char*          pathname,  // input
332                                         char*          name,      // output
333                                         unsigned int*  nb_read )  // input & output   
[291]334{
[587]335    // skip leading "/" character
336    if ( pathname[*nb_read] == '/' ) *nb_read = *nb_read + 1;
[291]337
[587]338    // initialises current indexes
339    unsigned int i = *nb_read;
340    unsigned int j = 0;
[291]341   
[587]342    while ( (pathname[i] != '/') && (pathname[i] != 0) )
[291]343    {
[587]344        name[j++] = pathname[i++];   
345        if ( j > NAME_MAX_SIZE ) return 1;
[291]346    }
[587]347
348    // set end of string
[291]349    name[j] = 0;
350
[587]351    // skip trailing "/" character
[291]352    if ( pathname[i] == '/' ) *nb_read += j+1;
353    else                      *nb_read += j;
354
[587]355    return 0;
[291]356}
357
[587]358
359
360////////////////////////////////////////////////////////////////////
361static unsigned int _get_last_name( char*   pathname,       // input
362                                    char*   name )          // output
363{
364    unsigned int nb_read = 0;     
365    while ( pathname[nb_read] != 0 )
366    {
367        if ( _get_name_from_path( pathname, name, &nb_read ) ) return 1;
368    }
369
370    return 0;
371}   // end _get_last_name()
372
373
374
[258]375////////////////////////////////////////////////////////////////////////////////
[587]376static void _get_name_from_short( unsigned char* buffer,  // input:  SFN dir_entry
377                                  char*          name )   // output: name
[258]378{
[596]379    unsigned int i;
380    unsigned int j = 0;
[258]381
[596]382    // get name
383    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
[258]384    {
[596]385        name[j] = _to_lower( buffer[i] );
386        j++;
[258]387    }
[596]388
389    // get extension
390    for ( i = 8; i < 8 + 3 && buffer[i] != ' '; i++ )
391    {
392        // we entered the loop so there is an extension. add the dot
393        if ( i == 8 )
394        {
395            name[j] = '.';
396            j++;
397        }
398
399        name[j] = _to_lower( buffer[i] );
400        j++;
401    }
402
403    name[j] = '\0';
[258]404}
[291]405
[258]406///////////////////////////////////////////////////////////////////////////////
[587]407static void _get_name_from_long( unsigned char*  buffer, // input : LFN dir_entry
408                                 char*           name )  // output : name
[258]409{
[587]410    unsigned int   name_offset         = 0;
411    unsigned int   buffer_offset       = get_length(LDIR_ORD);
[258]412    unsigned int   l_name_1            = get_length(LDIR_NAME_1);
413    unsigned int   l_name_2            = get_length(LDIR_NAME_2);
414    unsigned int   l_name_3            = get_length(LDIR_NAME_3);
415    unsigned int   l_attr              = get_length(LDIR_ATTR);
416    unsigned int   l_type              = get_length(LDIR_TYPE);
417    unsigned int   l_chksum            = get_length(LDIR_CHKSUM);
418    unsigned int   l_rsvd              = get_length(LDIR_RSVD);
419
420    unsigned int j            = 0;
421    unsigned int eof          = 0;
422
[587]423    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
[258]424    {
425        while (j != l_name_1 && !eof )
426        {
[587]427            if ( (buffer[buffer_offset] == 0x00) || 
428                 (buffer[buffer_offset] == 0xFF) )
[258]429            {
430                eof = 1;
431                continue;
432            }
[587]433            name[name_offset] = buffer[buffer_offset];
434            buffer_offset += 2;
[258]435            j += 2;
[587]436            name_offset++;
[258]437        }
438
[587]439        buffer_offset += (l_attr + l_type + l_chksum);
[258]440        j = 0;
441
442        while (j != l_name_2 && !eof )
443        {
[587]444            if ( (buffer[buffer_offset] == 0x00) || 
445                 (buffer[buffer_offset] == 0xFF) )
[258]446            {
447                eof = 1;
448                continue;
449            }
[587]450            name[name_offset] = buffer[buffer_offset];
451            buffer_offset += 2;
[258]452            j += 2;
[587]453            name_offset++;
[258]454        }
455
[587]456        buffer_offset += l_rsvd;
[258]457        j = 0;
458
459        while (j != l_name_3 && !eof )
460        {
[587]461            if ( (buffer[buffer_offset] == 0x00) || 
462                 (buffer[buffer_offset] == 0xFF) )
[258]463            {
464                eof = 1;
465                continue;
466            }
[587]467            name[name_offset] = buffer[buffer_offset];
468            buffer_offset += 2;
[258]469            j += 2;
[587]470            name_offset++;
[258]471        }
472    }
[587]473    name[name_offset] = 0;
[258]474} // end get_name_from_long()
475
[587]476
477
[761]478//////////////////////////////////////////////////////////////////////////////////
[639]479static fat_cache_node_t* _allocate_one_cache_node( fat_cache_node_t* first_child )
480{
481    fat_cache_node_t* cnode;
482    unsigned int i;
[587]483
[639]484    cnode = _malloc( sizeof(fat_cache_node_t) );
485
486    cnode->children[0] = first_child;
487    for ( i = 1 ; i < 64 ; i++ )
488        cnode->children[i] = NULL;
489
490    return cnode;
491}   // end _allocate_one_cache_node()
492
493
494
[587]495////////////////////////////////////////////////////////////
496static fat_inode_t* _allocate_one_inode( char*        name,
497                                         unsigned int is_dir,
498                                         unsigned int cluster,
499                                         unsigned int size, 
500                                         unsigned int count,
501                                         unsigned int dentry,
502                                         unsigned int cache_allocate )
[291]503{
[587]504    fat_inode_t* new_inode  = _malloc( sizeof(fat_inode_t) );
[291]505
[587]506    new_inode->parent   = NULL;                 // set by _add_inode_in_tree()
507    new_inode->next     = NULL;                 // set by _add_inode_in_tree()
508    new_inode->child    = NULL;                 // set by _add_inode_in_tree()
509    new_inode->cluster  = cluster;
510    new_inode->size     = size; 
511    new_inode->cache    = NULL;
512    new_inode->levels   = 0;
513    new_inode->count    = count;
514    new_inode->is_dir   = (is_dir != 0);
515    new_inode->dentry   = dentry;             
[291]516
[587]517    _strcpy( new_inode->name , name ); 
518
519    if ( cache_allocate )
[291]520    {
[639]521        new_inode->cache    = _allocate_one_cache_node( NULL );
[587]522        new_inode->levels   = _get_levels_from_size( size );
[291]523    }
524
[587]525    return new_inode;
526}   // end _allocate_one_inode()
[291]527
[587]528
529
530
531////////////////////////////////////////////////////
532static void _add_inode_in_tree( fat_inode_t*  child,
533                                fat_inode_t*  parent )
534{
535    child->parent = parent;
536    child->next   = parent->child;
537    parent->child = child;
538}   // end _add_inode-in_tree()
539
540
541
542
543//////////////////////////////////////////////////////////
544static void _remove_inode_from_tree( fat_inode_t*  inode )
545{
546    fat_inode_t*  current;
547    fat_inode_t*  prev = inode->parent->child;
548
549    if ( inode == prev )  // removed inode is first in its linked list
[291]550    {
[587]551        inode->parent->child = inode->next;
[291]552    }
[587]553    else                  // removed inode is not the first
[291]554    {
[587]555        for( current = prev->next ; current ; current = current->next )
[291]556        {
[587]557            if ( current == inode )
[291]558            {
[587]559                prev->next = current->next;
[291]560            }
[587]561            prev = current;
562        }   
563    }   
564}  // end _delete_one_inode()
[291]565
566
567
[587]568/////////////////////////////////////////////////////////////////
569static inline unsigned int _get_fat_entry( unsigned int  cluster,
570                                           unsigned int* value )
[291]571{
[773]572    // compute cluster_id & entry_id in FAT from cluster index
573    // a FAT buffer is an array of 1024 unsigned int entries
[587]574    unsigned int       cluster_id = cluster >> 10;       
575    unsigned int       entry_id   = cluster & 0x3FF;
[291]576
[761]577    // get pointer on the relevant buffer descriptor in FAT cache
[587]578    fat_cache_desc_t*  pdesc;
579    unsigned int*      buffer;
[761]580    if ( _get_fat_cache_buffer( cluster_id,
581                                &pdesc ) ) return 1;
[587]582
583    // get value from FAT slot
584    buffer = (unsigned int*)pdesc->buffer;
585    *value = buffer[entry_id];
586
587    return 0;
588}  // end _get_fat_entry()
589
590
591
592////////////////////////////////////////////////////////////////
593static inline unsigned int _set_fat_entry( unsigned int cluster, 
594                                           unsigned int value  )
595{
[773]596    // compute cluster_id & entry_id in FAT from cluster index
[587]597    // a FAT cluster is an array of 1024 unsigned int entries
598    unsigned int cluster_id = cluster >> 10;
599    unsigned int entry_id   = cluster & 0x3FF;
600
[761]601    // get pointer on the relevant buffer descriptor in FAT cache
[587]602    fat_cache_desc_t*  pdesc;
603    unsigned int*      buffer; 
[761]604    if ( _get_fat_cache_buffer( cluster_id,
605                                &pdesc ) )  return 1;           
[587]606
607    // set value into FAT slot
608    buffer           = (unsigned int*)pdesc->buffer;
609    buffer[entry_id] = value;
610    pdesc->dirty     = 1;
611
612    return 0;
613} // end _set_fat_entry()
614
615
616
617//////////////////////////////////////////////////////
618static void _allocate_one_buffer( fat_inode_t*  inode,
619                                  unsigned int  cluster_id,
620                                  unsigned int  cluster )
621{
[761]622
[773]623#if GIET_DEBUG_FAT
[761]624if ( _get_proctime() > GIET_DEBUG_FAT )
625_printf("\n[DEBUG FAT] _allocate_one_buffer(): in cache <%s> for cluster_id %d\n",
626        inode->name, cluster_id );
627#endif
628
[639]629    // add cache levels if needed
630    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
631    {
[761]632
[773]633#if GIET_DEBUG_FAT
[639]634if ( _get_proctime() > GIET_DEBUG_FAT )
[664]635_printf("\n[DEBUG FAT] _allocate_one_buffer(): adding a cache level\n" );
[639]636#endif
637
638        inode->cache = _allocate_one_cache_node( inode->cache );
639        inode->levels++;
640    }
641
[587]642    // search the 64-tree cache from top to bottom
643    fat_cache_node_t*  node   = inode->cache;
[653]644    unsigned int       level;
[587]645
[653]646    for ( level = inode->levels; level != 0; level-- )
[587]647    {
648        // compute child index
649        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
650
651        if ( level == 1 )        // last level => children are cluster descriptors
652        {
653            fat_cache_desc_t* pdesc = (fat_cache_desc_t*)node->children[index];
[761]654
[587]655            if ( pdesc != NULL )      // slot not empty!!!
656            {
[761]657                _printf("\n[FAT ERROR] in _allocate_one buffer() : slot not empty "
658                        "in File-Cache <%s>\n cluster_id = %d / cache = %x / pdesc[0] = %x\n",
659                        inode->name , cluster_id , 
660                        (unsigned int)node , (unsigned int)pdesc );
[587]661                _exit();
662            }
663
[773]664#if GIET_DEBUG_FAT
[569]665if ( _get_proctime() > GIET_DEBUG_FAT )
[664]666_printf("\n[DEBUG FAT] _allocate_one_buffer(): buffer allocated to <%s> for cluster_id %d\n",
[587]667        inode->name, cluster_id );
[291]668#endif
669
[653]670            // allocate buffer descriptor
671            pdesc = _malloc( sizeof(fat_cache_desc_t) );
[587]672            pdesc->lba     = _cluster_to_lba( cluster );
[653]673            pdesc->buffer  = _malloc( 4096 );
[587]674            pdesc->dirty   = 1;
[653]675            node->children[index] = pdesc;
[587]676        }
677        else                      // not last level => children are 64-tree nodes
[291]678        {
[587]679            fat_cache_node_t* child = (fat_cache_node_t*)node->children[index];
680            if ( child == NULL )  // miss
681            {
682                // allocate a cache node if miss
[650]683                child = _allocate_one_cache_node( NULL );
[587]684                node->children[index] = child;   
685            }
686
687            // prepare next iteration
688            node  = child;
[291]689        }
[653]690    } // end for
[587]691} // end _allocate_one_buffer
[530]692
693
[587]694
695
696///////////////////////////////////////////////////////////////////
[783]697static unsigned int _get_free_cluster( unsigned int*  cluster ) 
[587]698{
699    // scan FAT to get next free cluster index
[783]700    unsigned int current = _fat.free_cluster_hint;
[587]701    unsigned int max     = (_fat.data_sectors >> 3);
702    unsigned int value;
[783]703    while ( current < max )
[530]704    {
[587]705        // get FAT entry indexed by current
706        if ( _get_fat_entry( current , &value ) ) return 1;
[773]707
[783]708        // return if free
709        if ( value == FREE_CLUSTER )
710        {
711            *cluster = current;
712            return 0;
713        }
714
715        // increment current
716        current++;
[587]717    }
718       
[783]719    // return error if not found 
720    return 1;
[530]721
[783]722}  // end _get_free_cluster()
[587]723
724
725
[291]726
[587]727//////////////////////////////////////////////////////////////////////////
728static unsigned int _update_device_from_cache( unsigned int        levels,
729                                               fat_cache_node_t*   root,
730                                               char*               string )
[291]731{
[587]732    unsigned int index;
733    unsigned int ret = 0;
[291]734
[761]735    if ( levels == 1 )  // last level => children are buffer descriptors
[291]736    {
[587]737        for( index = 0 ; index < 64 ; index++ )
738        { 
739            fat_cache_desc_t* pdesc = root->children[index];
740            if ( pdesc != NULL )
741            { 
742                // update cluster on device if dirty
743                if ( pdesc->dirty )
744                {
745                    if ( _fat_ioc_access( 1,           // descheduling
746                                          0,           // to block device
747                                          pdesc->lba,
748                                          (unsigned int)pdesc->buffer,
749                                          8 ) )
750                    {
[664]751                        _printf("\n[FAT_ERROR] _update_device from_cache(): "
[587]752                                " cannot access lba = %x\n", pdesc->lba );
753                        ret = 1;
754                    }
755                    else
756                    {
757                        pdesc->dirty = 0;
758
[773]759#if GIET_DEBUG_FAT
[587]760if ( _get_proctime() > GIET_DEBUG_FAT )
[664]761_printf("\n[DEBUG FAT] _update_device_from_cache(): cluster_id = %d for <%s>\n",
[587]762        index , string );
763#endif
764
765                    }
766                }
767            }
768        }
[291]769    }
[587]770    else               // not the last level = recursive call on each children
[291]771    {
[587]772        for( index = 0 ; index < 64 ; index++ )
773        { 
774            fat_cache_node_t* pnode = root->children[index];
775            if ( pnode != NULL )
776            {
777                if ( _update_device_from_cache( levels - 1,
778                                                root->children[index],
779                                                string ) ) ret = 1;
780            }   
781        }
[291]782    }
[587]783    return ret;
784}  // end _update_device_from_cache()
[291]785
786
[587]787
788///////////////////////////////////////////////////////////////////
[651]789static void _release_cache_memory( fat_cache_node_t*  root,
790                                   unsigned int       levels )
[587]791{
[651]792    unsigned int i;
[587]793
794    if ( levels == 1 )  // last level => children are cluster descriptors
[503]795    {
[651]796        for( i = 0 ; i < 64 ; i++ )
[587]797        { 
[651]798            fat_cache_desc_t* pdesc = root->children[i];
[587]799
800            if ( pdesc != NULL )
801            { 
802                // check dirty
803                if ( pdesc->dirty )
[664]804                    _printf("\n[FAT ERROR] _release_cache_memory(): dirty cluster\n");
[651]805
806                _free( pdesc->buffer );
807                _free( pdesc );
808                root->children[i] = NULL;
[587]809            }
810        }
[503]811    }
[587]812    else               // not the last level = recursive call on each children
813    {
[651]814        for( i = 0 ; i < 64 ; i++ )
[587]815        { 
[651]816            fat_cache_node_t* cnode = root->children[i];
[291]817
[651]818            if ( cnode != NULL )
819            {
820                _release_cache_memory( cnode, levels - 1 );
821                _free( cnode );
822                root->children[i] = NULL;
823            }
[587]824        }
825    }
826}  // end _release_cache_memory()
827
828
829
830
831
[783]832////////////////////////////////////////////////////////////////
833static unsigned int _one_cluster_allocate( fat_inode_t*   inode,
834                                           unsigned int*  cluster ) 
[587]835{
[761]836    // Check free cluster available
837    if ( _fat.free_clusters_number == 0 )
[291]838    {
[783]839        _printf("\n[FAT ERROR] in _one_cluster_allocate(): no more free clusters\n");
[587]840        return 1;
841    }
[291]842
[783]843    // scan the Fat-Cache to get last allocated cluster index
[761]844    unsigned int nb_current_clusters = 0;
[587]845    unsigned int current = inode->cluster;
[761]846    unsigned int last    = current;
847    unsigned int next    = 0;
848    unsigned int new     = 0;
849    while ( current < END_OF_CHAIN_CLUSTER_MIN )
[587]850    {
[761]851        // get next cluster
[783]852        if ( _get_fat_entry( current , &next ) )
853        {
854            _printf("\n[FAT ERROR] in _one_cluster_allocate() scanning FAT\n");
855            return 1;
856        }
[761]857       
858        // increment number of allocated clusters
859        nb_current_clusters++;
[291]860
[761]861        // update loop variables
862        last    = current;
863        current = next;
864    } 
[587]865
[761]866    // allocate one free cluster from FAT
[783]867    if ( _get_free_cluster( &new ) ) 
868    {
869        _printf("\n[FAT ERROR] in _one_cluster_allocate() : no more free clusters\n");
870        return 1;
871    }
[291]872
[761]873    // allocate one 4K buffer to File-Cache
874    _allocate_one_buffer( inode,
875                          nb_current_clusters,
876                          new );
[291]877
[783]878    // update allocated FAT slot
879    if ( _set_fat_entry( new , END_OF_CHAIN_CLUSTER_MAX ) ) 
880    {
881        _printf("\n[FAT ERROR] in _one_cluster_allocate() accessing FAT\n");
882        return 1;
883    }
884
885    // update FAT descriptor global variables
886    _fat.free_clusters_number--;
887    _fat.free_cluster_hint = new;
888
[761]889    if ( nb_current_clusters == 0 )  // first cluster : inode and directory entry
890    {
891        // update inode
892        inode->cluster = new;
[587]893
[761]894        // update directory entry
895        _update_dir_entry( inode );
896    }
897    else                             // update previous last cluster in FAT
898    {
[783]899        if ( _set_fat_entry( last , new ) ) 
900        {
901            _printf("\n[FAT ERROR] in _one_cluster_allocate() accessing FAT\n");
902            return 1;
903        }
[761]904    }
[587]905
[773]906    // update the FAT on device
[587]907    if ( _update_device_from_cache( _fat.fat_cache_levels,
908                                    _fat.fat_cache_root,
[783]909                                    "FAT" ) ) 
910    {
911        _printf("\n[FAT ERROR] in _one_cluster_allocate() updating FAT on device\n");
912        return 1;
913    }
[773]914
915    // update FS-INFO sector on device
[783]916    if ( _update_fs_info() )
917    {
918        _printf("\n[FAT ERROR] in _one_cluster_allocate() updating FS-INFO sector on device\n");
919        return 1;
920    }
[773]921
922#if GIET_DEBUG_FAT
[761]923if ( _get_proctime() > GIET_DEBUG_FAT )
[783]924_printf("\n[DEBUG FAT] _one_cluster_allocate(): for <%s>\n"
[773]925        " nb_clusters = %d / last_cluster = %x / new_cluster = %x\n",
[761]926        inode->name , nb_current_clusters , last , new );
927#endif
928
929    // returns allocated cluster index
930    *cluster = new;
[587]931    return 0;
932
[783]933}  // end _one_cluster_allocate()
[587]934
[783]935////////////////////////////////////////////////////////////
936static unsigned int _cluster_release( unsigned int cluster )
[587]937{
[783]938    if ( cluster >= END_OF_CHAIN_CLUSTER_MIN )  // terminal case : nothing to do
939    {
940        return 0;       
941    }
942    else                 // non terminal case : recursive call, then release cluster
943    {
944        // get next cluster
945        unsigned int next;
946        if ( _get_fat_entry( cluster , &next ) ) 
947        {
948            _printf("\n[FAT ERROR] in _cluster_release() accessing Fat-Cache"
949                    " for cluster %x\n", cluster );
950            return 1;
951        }
[587]952
[783]953        // call _cluster_release() on next
954        if ( _cluster_release( next ) ) return 1;
955       
956        // release current cluster
957        if ( _set_fat_entry( cluster , FREE_CLUSTER ) )
958        {
959            _printf("\n[FAT ERROR] in _cluster_release() updating Fat-Cache"
960                    " for cluster %x\n", cluster );
961            return 1;
962        }
[587]963
[783]964        // update free_cluster _hint and free_clusters_number in FAT descriptor
965        _fat.free_clusters_number++;
966        if ( cluster < _fat.free_cluster_hint ) _fat.free_cluster_hint = cluster;
[587]967
[783]968        return 0;
[291]969    }
[783]970}  // end _cluster_release()
[291]971
[783]972///////////////////////////////////////////////////////////////
973static unsigned int _all_clusters_release( fat_inode_t* inode )
974{
975    // release recursively all clusters in FAT chaining,
976    // starting from last cluster in chain, ending by first.
977    if ( _cluster_release( inode->cluster ) )
978    {
979        _printf("\n[FAT ERROR] in _all_clusters_release() releasing clusters\n");
980        return 1;
981    }
982
983    // update FAT on device
[587]984    if ( _update_device_from_cache( _fat.fat_cache_levels,
985                                    _fat.fat_cache_root,
[783]986                                    "FAT" ) )
987    {
988        _printf("\n[FAT ERROR] in _all_clusters_release() updating FAT on device\n");
989        return 1;
990    }
[773]991
992    // update FS-INFO sector on device
[783]993    if ( _update_fs_info() )
994    {
995        _printf("\n[FAT ERROR] in _all_clusters_release() updating FS_INFO sector on device\n");
996        return 1;
997    }
[773]998
999#if GIET_DEBUG_FAT
1000if ( _get_proctime() > GIET_DEBUG_FAT )
[783]1001_printf("\n[DEBUG FAT] _all_clusters_release() done for file <%s>\n", inode->name );
[773]1002#endif
1003
[291]1004    return 0;
[783]1005}  // end _all_clusters_release()
[291]1006
[587]1007
1008
1009///////////////////////////////////////////////////////////
1010static void _add_special_directories( fat_inode_t*  child, 
1011                                      fat_inode_t*  parent )
[258]1012{
[587]1013    // get first File-Cache buffer for child
1014    fat_cache_desc_t*   pdesc  = (fat_cache_desc_t*)child->cache->children[0];
1015    unsigned char*      entry;
[258]1016
[587]1017    unsigned int i;
1018    unsigned int cluster;
1019    unsigned int size;
[417]1020
[587]1021    // set "." entry (32 bytes)
1022    cluster = child->cluster;
1023    size    = child->size;
1024    entry   = pdesc->buffer;
1025   
1026    for ( i = 0 ; i < 32 ; i++ )
1027    {
1028        if      (i == 0 )     entry[i] = 0x2E;          // SFN
1029        else if (i <  11)     entry[i] = 0x20;          // SFN
1030        else if (i == 11)     entry[i] = 0x10;          // ATTR == dir
1031        else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1032        else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1033        else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1034        else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1035        else if (i == 28)     entry[i] = size>>0;       // size.B0
1036        else if (i == 29)     entry[i] = size>>8;       // size.B1
1037        else if (i == 30)     entry[i] = size>>16;      // size.B2
1038        else if (i == 31)     entry[i] = size>>24;      // size.B3
1039        else                  entry[i] = 0x00;
1040    }
[258]1041
[587]1042    // set ".." entry (32 bytes)
1043    cluster = parent->cluster;
1044    size    = parent->size;
1045    entry   = pdesc->buffer + 32;
[258]1046
[587]1047    for ( i = 0 ; i < 32 ; i++ )
[258]1048    {
[587]1049        if      (i <  2 )     entry[i] = 0x2E;          // SFN
1050        else if (i <  11)     entry[i] = 0x20;          // SFN
1051        else if (i == 11)     entry[i] = 0x10;          // ATTR == dir
1052        else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1053        else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1054        else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1055        else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1056        else if (i == 28)     entry[i] = size>>0;       // size.B0
1057        else if (i == 29)     entry[i] = size>>8;       // size.B1
1058        else if (i == 30)     entry[i] = size>>16;      // size.B2
1059        else if (i == 31)     entry[i] = size>>24;      // size.B3
1060        else                  entry[i] = 0x00;
[258]1061    }
[587]1062}  // end _add_special_directories
[258]1063
[358]1064
[587]1065
1066////////////////////////////////////////////////////////////
[638]1067static unsigned int _is_ancestor( fat_inode_t* a,
1068                                  fat_inode_t* b )
1069{
1070    while ( b )
1071    {
1072        if ( a == b )
1073            return 1;
1074
1075        b = b->parent;
1076    }
1077
1078    return 0;
1079} // _is_ancestor()
1080
1081
1082
1083////////////////////////////////////////////////////////////
[773]1084static unsigned int _get_sfn_name( char*           name,
1085                                   unsigned int*   length,
1086                                   unsigned int*   nb_lfn,
1087                                   char*           sfn,
1088                                   unsigned char*  checksum )
[587]1089{
[773]1090    // compute name length
1091    unsigned int name_length = _strlen( name );
1092
1093    // compute prefix and suffix length
1094    // only the last '.' is taken into account
1095    unsigned int suffix_length = 0;
1096    unsigned int prefix_length = 0;
1097    unsigned int dot_found     = 0;
1098    unsigned int i;
1099    for ( i=0 ; i<name_length ; i++ )
[258]1100    {
[773]1101        if (name[i] == '.' )
1102        {
1103            if ( dot_found ) 
1104            {
1105                prefix_length += suffix_length + 1;
1106                suffix_length =  0;
1107            }
1108            else
1109            {
1110                dot_found = 1;
1111            }
1112        }
1113        else
1114        { 
1115            if ( dot_found) 
1116            {
1117                suffix_length++;
1118            }
1119            else
1120            {
1121                prefix_length++;
1122            }
1123        }
1124    } 
1125
1126    // build SFN prefix (8bits)
1127    if (prefix_length <= 8)
1128    {
1129        for( i=0 ; i<8 ; i++)
1130        {
1131            if ( i<prefix_length ) sfn[i] = _to_upper( name[i] );
1132            else                   sfn[i] = 0x20;
1133        }
1134    }
1135    else
1136    {
1137        for( i=0 ; i<6 ; i++)
1138        {
1139            sfn[i] = _to_upper( name[i] );
1140        }
1141        sfn[6] = 0x7E;
1142        sfn[7] = 0x31;
1143    }
1144
1145    // build SFN suffix (3 bits)
1146    if ( suffix_length == 0 )
1147    {
1148        sfn[8]  = 0x20;
1149        sfn[9]  = 0x20;
1150        sfn[10] = 0x20;
1151    }
1152    else if ( suffix_length == 1 )
1153    {
1154        sfn[8]  = _to_upper( name[name_length-1] );
1155        sfn[9]  = 0x20;
1156        sfn[10] = 0x20;
1157    }
1158    else if ( suffix_length == 2 )
1159    {
1160        sfn[8]  = _to_upper( name[name_length-2] );
1161        sfn[9]  = _to_upper( name[name_length-1] );
1162        sfn[10] = 0x20;
1163    }
1164    else
1165    {
1166        sfn[8]  = _to_upper( name[name_length-suffix_length] );
1167        sfn[9]  = _to_upper( name[name_length-suffix_length+1] );
1168        sfn[10] = _to_upper( name[name_length-suffix_length+2] );
1169    }
1170
1171    // compute 8 bits checksum
1172    unsigned char sum = 0;
1173    for ( i=0 ; i<11 ; i++ )
1174    {
1175        sum = (((sum & 0x01)<<7) | ((sum & 0xFE)>>1)) + sfn[i];
1176    }
1177    *checksum = sum;
1178
1179    // set nb_lfn and length values
1180    if      ( name_length <= 13 )
1181    {
1182        *length  = name_length;
[587]1183        *nb_lfn  = 1;
1184        return 0;
1185    }
[773]1186    else if ( name_length <= 26 )
[587]1187    {
[773]1188        *length  = name_length;
[587]1189        *nb_lfn  = 2;
1190        return 0;
1191    }
[773]1192    else if ( name_length <= 31 )
[587]1193    {
[773]1194        *length  = name_length;
[587]1195        *nb_lfn  = 3;
1196        return 0;
1197    }
1198    else
1199    {
1200        return 1;
1201    }
[773]1202}  // _get_sfn_name()
[587]1203
1204
1205
1206
1207///////////////////////////////////////////////////////////
1208static unsigned int _get_nb_entries( fat_inode_t*   inode,
1209                                     unsigned int*  nb_entries )
1210{
1211    // scan directory until "end of directory" with two embedded loops:
1212    // - scan the clusters allocated to this directory
1213    // - scan the entries to find NO_MORE_ENTRY
1214    fat_cache_desc_t*  pdesc;                      // pointer on buffer descriptor
1215    unsigned char*     buffer;                     // 4 Kbytes buffer (one cluster)
1216    unsigned int       ord;                        // ORD field in directory entry
1217    unsigned int       attr;                       // ATTR field in directory entry
1218    unsigned int       cluster_id = 0;             // cluster index in directory
1219    unsigned int       offset     = 0;             // position in scanned buffer
1220    unsigned int       found      = 0;             // NO_MORE_ENTRY found
1221    unsigned int       count      = 0;             // number of valid NORMAL entries
1222
1223    // loop on clusters allocated to directory
1224    while ( found == 0 )
1225    {
1226        // get one 4 Kytes buffer from File_Cache 
[761]1227        if ( _get_file_cache_buffer( inode,
[587]1228                                     cluster_id,
[761]1229                                     0,         
[587]1230                                     &pdesc ) )   return 1;
1231        buffer = pdesc->buffer;
1232       
1233        // loop on directory entries in buffer
1234        while ( (offset < 4096) && (found == 0) )
[258]1235        {
[587]1236            attr = _read_entry( DIR_ATTR , buffer + offset , 0 );   
1237            ord  = _read_entry( LDIR_ORD , buffer + offset , 0 );
1238
1239            if ( ord == NO_MORE_ENTRY )
[258]1240            {
[587]1241                found = 1;
1242            } 
1243            else if ( ord == FREE_ENTRY )             // free entry => skip
1244            {
1245                offset = offset + 32;
[258]1246            }
[587]1247            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => skip
[258]1248            {
[587]1249                offset = offset + 32;
1250            }
1251            else                                      // NORMAL entry
1252            {
[620]1253                offset = offset + 32;
[587]1254                count++;
1255            }
1256        }  // end loop on directory entries
1257
1258        cluster_id++;
1259        offset = 0;
1260
1261    }  // end loop on clusters
1262
1263    // return nb_entries
1264    *nb_entries = count;
1265   
1266    return 0;
[773]1267}  // end _get_nb_entries()
[587]1268
1269
1270
[773]1271////////////////////////////////////////////////////////////
1272static unsigned int _update_dir_entry( fat_inode_t*  inode )
1273{ 
1274    // get Cache-File buffer containing the parent directory entry
1275    // 128 directories entries in one 4 Kbytes buffer
1276    fat_cache_desc_t*  pdesc;
1277    unsigned char*     buffer;   
1278    unsigned int       cluster_id = inode->dentry>>7;
1279    unsigned int       offset     = (inode->dentry & 0x7F)<<5;
1280
1281    if ( _get_file_cache_buffer( inode->parent,
1282                                 cluster_id,
1283                                 0,
1284                                 &pdesc ) )    return 1;
1285    buffer       = pdesc->buffer;
1286    pdesc->dirty = 1;
1287
1288    // update size field
1289    buffer[offset + 28] = inode->size>>0;       // size.B0
1290    buffer[offset + 29] = inode->size>>8;       // size.B1
1291    buffer[offset + 30] = inode->size>>16;      // size.B2
1292    buffer[offset + 31] = inode->size>>24;      // size.B3
1293
1294    // update cluster field
1295    buffer[offset + 26] = inode->cluster>>0;    // cluster.B0
1296    buffer[offset + 27] = inode->cluster>>8;    // cluster.B1
1297    buffer[offset + 20] = inode->cluster>>16;   // cluster.B2
1298    buffer[offset + 21] = inode->cluster>>24;   // cluster.B3
1299   
1300    return 0;
1301} // end _update_dir_entry()
1302
1303
1304
1305
[587]1306///////////////////////////////////////////////////////////
1307static unsigned int _add_dir_entry( fat_inode_t*   child,
1308                                    fat_inode_t*   parent )
1309{
1310    // get child attributes
1311    unsigned int      is_dir  = child->is_dir;     
1312    unsigned int      size    = child->size;
1313    unsigned int      cluster = child->cluster;
1314
[773]1315    // compute number of required 32 bytes entries to store
1316    // the complete child name and a legal 8.3 SFN name.
1317    unsigned int    length;
1318    unsigned int    nb_lfn;
1319    char            sfn[11];
1320    unsigned char   checksum;
1321    if ( _get_sfn_name( child->name, 
[587]1322                             &length,
[773]1323                             &nb_lfn,
1324                             sfn,
1325                             &checksum ) )  return 1;
[587]1326
[773]1327#if GIET_DEBUG_FAT
[587]1328if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1329_printf("\n[DEBUG FAT] _add_dir_entry(): try to add <%s> in <%s> / nb_lfn = %d\n", 
[587]1330        child->name , parent->name, nb_lfn );
1331#endif
1332
1333    // Find end of directory : two embedded loops:
1334    // - scan the clusters allocated to this directory
1335    // - scan the entries to find NO_MORE_ENTRY
1336    fat_cache_desc_t*  pdesc;                      // pointer on buffer descriptor
1337    unsigned char*     buffer;                     // 4 Kbytes buffer (one cluster)
1338    unsigned int       cluster_id = 0;             // cluster index in directory
1339    unsigned int       offset     = 0;             // position in scanned buffer
1340    unsigned int       found      = 0;             // NO_MORE_ENTRY found
1341
1342    // loop on clusters allocated to directory
1343    while ( found == 0 )
1344    {
[773]1345        // get the 4 Kytes buffer from File_Cache 
[761]1346        if ( _get_file_cache_buffer( parent,
[587]1347                                     cluster_id,
[761]1348                                     0,
[587]1349                                     &pdesc ) )   return 1;
1350
1351        buffer = pdesc->buffer;
1352       
1353        // loop on directory entries in buffer
1354        while ( (offset < 4096) && (found == 0) )
1355        {
1356            if ( _read_entry( LDIR_ORD , buffer + offset , 0 ) == NO_MORE_ENTRY )
[258]1357            {
[587]1358                found        = 1;
1359                pdesc->dirty = 1;
1360            } 
1361            else
1362            {
1363                offset = offset + 32;
[258]1364            }
[587]1365        }  // end loop on entries
[773]1366
[587]1367        if ( found == 0 )
1368        {
1369            cluster_id++;
1370            offset = 0;
[258]1371        }
[587]1372    }  // end loop on clusters
[258]1373
[773]1374#if GIET_DEBUG_FAT
[587]1375if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1376_printf("\n[DEBUG FAT] _add_dir_entry(): get NO_MORE directory entry : "
[587]1377        " buffer = %x / offset = %x / cluster_id = %d\n",
1378        (unsigned int)buffer , offset , cluster_id );
1379#endif
[258]1380
[587]1381    // enter FSM :
1382    // The new child requires to write 3, 4, or 5 directory entries.
1383    // To actually register the new child, we use a 5 steps FSM
1384    // (one state per entry to be written), that is traversed as:
1385    //    LFN3 -> LFN2 -> LFN1 -> NORMAL -> NOMORE
1386    // The buffer and first directory entry to be  written are identified
1387    // by the variables : buffer / cluster_id / offset
[417]1388
[587]1389    unsigned char* name  = (unsigned char*)child->name;
1390
1391    unsigned int step;          // FSM state
1392
1393    if      ( nb_lfn == 1 ) step = 3;
1394    else if ( nb_lfn == 2 ) step = 4;
1395    else if ( nb_lfn == 3 ) step = 5;
1396   
1397    unsigned int   i;           // byte index in 32 bytes directory
1398    unsigned int   c;           // character index in name
1399    unsigned char* entry;       // buffer + offset;
1400
1401    while ( step )   
1402    {
1403        // get another buffer if required
1404        if ( offset >= 4096 )  // new buffer required
[417]1405        {
[761]1406            if ( _get_file_cache_buffer( parent,
[665]1407                                         cluster_id + 1,
[761]1408                                         0,
[665]1409                                         &pdesc ) )      return 1;
1410            buffer       = pdesc->buffer;
1411            pdesc->dirty = 1;
1412            offset       = 0;
[587]1413        }
[417]1414
[587]1415        // compute directory entry address
1416        entry = buffer + offset;
[417]1417
[773]1418#if GIET_DEBUG_FAT
[587]1419if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1420_printf("\n[DEBUG FAT] _add_dir_entry(): FSM step = %d /"
[587]1421        " offset = %x / nb_lfn = %d\n", step, offset, nb_lfn );
1422#endif
1423
1424        // write one 32 bytes directory entry per iteration
1425        switch ( step )
1426        {
1427            case 5:   // write LFN3 entry
1428            {
1429                c = 26;
1430                // scan the 32 bytes in dir_entry
1431                for ( i = 0 ; i < 32 ; i++ )
[258]1432                {
[587]1433                    if (i == 0)
1434                    {
1435                        if ( nb_lfn == 3) entry[i] = 0x43;
1436                        else              entry[i] = 0x03;
1437                    }
1438                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1439                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1440                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1441                              ( c < length ) )
1442                    {
1443                                          entry[i] = name[c];
1444                                          c++;
1445                    }
1446                    else if (i == 11)     entry[i] = 0x0F;
[773]1447                    else if (i == 13)     entry[i] = checksum;
[587]1448                    else                  entry[i] = 0x00;
[258]1449                }
[587]1450                step--;
1451                break;
1452            }
1453            case 4:   // write LFN2 entry 
1454            {
1455                c = 13;
1456                // scan the 32 bytes in dir_entry
1457                for ( i = 0 ; i < 32 ; i++ )
[258]1458                {
[587]1459                    if (i == 0)
1460                    {
1461                        if ( nb_lfn == 2) entry[i] = 0x42;
1462                        else              entry[i] = 0x02;
1463                    }
1464                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1465                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1466                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1467                              ( c < length ) )
1468                    {
1469                                          entry[i] = name[c];
1470                                          c++;
1471                    }
1472                    else if (i == 11)     entry[i] = 0x0F;
[773]1473                    else if (i == 13)     entry[i] = checksum;
[587]1474                    else                  entry[i] = 0x00;
[258]1475                }
[587]1476                step--;
1477                break;
[258]1478            }
[587]1479            case 3:   // Write LFN1 entry   
[258]1480            {
[587]1481                c = 0;
1482                // scan the 32 bytes in dir_entry
1483                for ( i = 0 ; i < 32 ; i++ )
1484                {
1485                    if (i == 0)
1486                    {
1487                        if ( nb_lfn == 1) entry[i] = 0x41;
1488                        else              entry[i] = 0x01;
1489                    }
1490                    else if ( ( ((i >= 1 ) && (i<=10) && ((i&1)==1))   ||
1491                                ((i >= 14) && (i<=25) && ((i&1)==0))   ||
1492                                ((i >= 28) && (i<=31) && ((i&1)==0)) ) &&
1493                              ( c < length ) )
1494                    {
1495                                          entry[i] = name[c];
1496                                          c++;
1497                    }
1498                    else if (i == 11)     entry[i] = 0x0F;
[773]1499                    else if (i == 13)     entry[i] = checksum;
[587]1500                    else                  entry[i] = 0x00;
1501                }
1502                step--;
1503                break;
[258]1504            }
[587]1505            case 2:   // write NORMAL entry     
[258]1506            {
[587]1507                // scan the 32 bytes in dir_entry
1508                for ( i = 0 ; i < 32 ; i++ )
[258]1509                {
[773]1510                    if      ( i < 11 )                              // 8.3 SFN
[417]1511                    {
[773]1512                                          entry[i] = sfn[i];
[417]1513                    }
[587]1514                    else if (i == 11)                               // ATTR
1515                    {
1516                        if (is_dir)       entry[i] = 0x10;
1517                        else              entry[i] = 0x20;
1518                    }
1519                    else if (i == 20)     entry[i] = cluster>>16;   // cluster.B2
1520                    else if (i == 21)     entry[i] = cluster>>24;   // cluster.B3
1521                    else if (i == 26)     entry[i] = cluster>>0;    // cluster.B0
1522                    else if (i == 27)     entry[i] = cluster>>8;    // cluster.B1
1523                    else if (i == 28)     entry[i] = size>>0;       // size.B0
1524                    else if (i == 29)     entry[i] = size>>8;       // size.B1
1525                    else if (i == 30)     entry[i] = size>>16;      // size.B2
1526                    else if (i == 31)     entry[i] = size>>24;      // size.B3
1527                    else                  entry[i] = 0x00;
[258]1528                }
[587]1529
1530                // update the dentry field in child inode
1531                child->dentry = ((cluster_id<<12) + offset)>>5;
1532
1533                step--;
1534                break;
[417]1535            }
[587]1536            case 1:   // write NOMORE entry 
[417]1537            {
[587]1538                step--;
1539                entry [0] = 0x00;
1540                break;
1541            }
1542        } // end switch step
1543        offset += 32;
1544    } // exit while => exit FSM   
1545
[773]1546#if GIET_DEBUG_FAT
[587]1547if ( _get_proctime() > GIET_DEBUG_FAT )
1548{
[664]1549    _printf("\n[DEBUG FAT] _add_dir_entry(): <%s> successfully added in <%s>\n",
[587]1550            child->name , parent->name );
1551}
1552#endif
1553
1554    return 0;       
1555} // end _add_dir_entry
1556
1557
1558
1559////////////////////////////////////////////////////////////
1560static unsigned int _remove_dir_entry( fat_inode_t*  inode )
1561{
1562    // compute number of LFN entries
1563    unsigned int nb_lfn;
[773]1564    unsigned int name_length = _strlen( inode->name );
1565    if      ( name_length <= 13 ) nb_lfn  = 1;
1566    else if ( name_length <= 26 ) nb_lfn  = 2;
1567    else                          nb_lfn  = 3;
[587]1568
1569    // get cluster_id and offset in parent directory cache
1570    unsigned int  dentry     = inode->dentry;
1571    unsigned int  cluster_id = dentry >> 7;
1572    unsigned int  offset     = (dentry & 0x7F)<<5;
1573
1574    // get buffer from parent directory cache
1575    unsigned char*     buffer;
1576    fat_cache_desc_t*  pdesc;
1577
[761]1578    if ( _get_file_cache_buffer( inode->parent,
[587]1579                                 cluster_id,
[761]1580                                 0,
[587]1581                                 &pdesc ) ) return 1;
1582    buffer       = pdesc->buffer;
1583    pdesc->dirty = 1;
1584
1585    // invalidate NORMAL entry in directory cache
1586    buffer[offset] = 0xE5;
1587
1588    // invalidate LFN entries
1589    while ( nb_lfn )
1590    {
[616]1591        if (offset == 0)  // we must load buffer for (cluster_id - 1)
[587]1592        {
[636]1593            if ( cluster_id == 0 )
1594                break;
1595
[761]1596            if ( _get_file_cache_buffer( inode->parent,
[587]1597                                         cluster_id - 1,
[761]1598                                         0,
[587]1599                                         &pdesc ) )   return 1;
1600            buffer       = pdesc->buffer;
1601            pdesc->dirty = 1;
[616]1602            offset       = 4096;
[587]1603        }
1604
[616]1605        offset = offset - 32;
1606
1607        // check for LFN entry
1608        if ( _read_entry( DIR_ATTR , buffer + offset , 0 ) != ATTR_LONG_NAME_MASK )
1609            break;
1610
[587]1611        // invalidate LFN entry
1612        buffer[offset] = 0xE5;
1613
1614        nb_lfn--;
1615    }     
1616         
1617    return 0;
1618}  // end _remove_dir_entry
1619
1620
1621
1622
1623//////////////////////////////////////////////////////////////////
1624static unsigned int _get_child_from_parent( fat_inode_t*   parent,
1625                                            char*          name, 
1626                                            fat_inode_t**  inode )
1627{
1628    fat_inode_t*   current;
1629
[773]1630#if GIET_DEBUG_FAT
[587]1631if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1632_printf("\n[DEBUG FAT] _get_child_from_parent(): search <%s> in directory <%s>\n",
[587]1633        name , parent->name );
1634#endif
1635   
1636    // scan inodes in the parent directory
1637    for ( current = parent->child ; current ; current = current->next )
1638    {
[619]1639        if ( _strcmp( name , current->name ) == 0 )
[587]1640        {
1641
[773]1642#if GIET_DEBUG_FAT
[587]1643if ( _get_proctime() > GIET_DEBUG_FAT )
[773]1644_printf("\n[DEBUG FAT] _get_child_from_parent(): found inode for <%s> in <%s>\n", 
[587]1645        name , parent->name );
1646#endif
1647            *inode = current;
1648            return 0;           // name found
1649        }
1650    }
1651
[761]1652    // not found in Inode-Tree => access the parent directory file_cache.
1653    // Two embedded loops:
[587]1654    // - scan the clusters allocated to this directory
1655    // - scan the directory entries in each 4 Kbytes buffer
1656
1657    unsigned char*    buffer;           // pointer on one cache buffer
1658    char              cname[32];        // buffer for one full entry name
1659    char              lfn1[16];         // buffer for one partial name
1660    char              lfn2[16];         // buffer for one partial name
1661    char              lfn3[16];         // buffer for one partial name
1662    unsigned int      size;             // searched file/dir size (bytes)
1663    unsigned int      cluster;          // searched file/dir cluster index
1664    unsigned int      is_dir;           // searched file/dir type
1665    unsigned int      attr;             // directory entry ATTR field
1666    unsigned int      ord;              // directory entry ORD field
[597]1667    unsigned int      lfn = 0;          // LFN entries number
[587]1668    unsigned int      dentry;           // directory entry index
1669    unsigned int      offset     = 0;   // byte offset in buffer
1670    unsigned int      cluster_id = 0;   // cluster index in directory
1671    int               found      = 0;   // not found (0) / name found (1) / end of dir (-1)
1672
[773]1673#if GIET_DEBUG_FAT
[587]1674if ( _get_proctime() > GIET_DEBUG_FAT )
[773]1675_printf("\n[DEBUG FAT] _get_child_from_parent(): child <%s> in <%s> not found in Inode-Tree\n"
1676        " search in parent cache\n", name , parent->name );
[587]1677#endif
1678
1679    // scan the clusters allocated to parent directory
1680    while ( found == 0 )
1681    {
1682        // get one 4 Kytes buffer from parent File_Cache 
1683        fat_cache_desc_t*  pdesc;
[761]1684        if ( _get_file_cache_buffer( parent,
[587]1685                                     cluster_id,
[761]1686                                     0,
[587]1687                                     &pdesc ) )    return 2;
1688        buffer = pdesc->buffer;
1689
1690        // scan this buffer until end of directory, end of buffer, or name found
1691        while( (offset < 4096) && (found == 0) )
1692        {
1693            attr = _read_entry( DIR_ATTR , buffer + offset , 0 );   
1694            ord  = _read_entry( LDIR_ORD , buffer + offset , 0 );
1695
[750]1696            if (ord == NO_MORE_ENTRY)                 // no more entry => break
[587]1697            {
1698                found = -1;
1699            }
1700            else if ( ord == FREE_ENTRY )             // free entry => skip
1701            {
1702                offset = offset + 32;
1703            }
1704            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => get partial name
1705            {
1706                unsigned int seq = ord & 0x3;
1707                lfn = (seq > lfn) ? seq : lfn;   
1708                if      ( seq == 1 ) _get_name_from_long( buffer + offset, lfn1 );
1709                else if ( seq == 2 ) _get_name_from_long( buffer + offset, lfn2 );
1710                else if ( seq == 3 ) _get_name_from_long( buffer + offset, lfn3 );
1711                offset = offset + 32;
1712            }
1713            else                                 // NORMAL entry
1714            {
1715                // build the extracted name
1716                if      ( lfn == 0 )
[258]1717                {
[587]1718                    _get_name_from_short( buffer + offset , cname );
[258]1719                }
[587]1720                else if ( lfn == 1 )
[417]1721                {
[587]1722                    _strcpy( cname      , lfn1 );
1723                }   
1724                else if ( lfn == 2 ) 
1725                {
1726                    _strcpy( cname      , lfn1 );
1727                    _strcpy( cname + 13 , lfn2 );
[417]1728                }
[587]1729                else if ( lfn == 3 ) 
1730                {
1731                    _strcpy( cname      , lfn1 );
1732                    _strcpy( cname + 13 , lfn2 );
1733                    _strcpy( cname + 26 , lfn3 );
1734                }
[773]1735
1736                // get dentry arguments if extracted name == searched name
[619]1737                if ( _strcmp( name , cname ) == 0 )
[587]1738                {
1739                    cluster = (_read_entry( DIR_FST_CLUS_HI , buffer + offset , 1 ) << 16) |
1740                              (_read_entry( DIR_FST_CLUS_LO , buffer + offset , 1 )      ) ;
1741                    dentry  = ((cluster_id<<12) + offset)>>5;
1742                    is_dir  = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
1743                    size    = _read_entry( DIR_FILE_SIZE , buffer + offset , 1 );
1744                    found   = 1;
1745                }
1746                offset = offset + 32;
1747                lfn    = 0;
[258]1748            }
[587]1749        }  // end loop on directory entries
1750        cluster_id++;
1751        offset = 0;
1752    }  // end loop on buffers
1753
1754    if ( found == -1 )  // found end of directory in parent directory
1755    {
1756
[773]1757#if GIET_DEBUG_FAT
[587]1758if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1759_printf("\n[DEBUG FAT] _get_child_from_parent(): found end of directory in <%s>\n",
[587]1760        parent->name );
1761#endif
1762        *inode = NULL;
1763        return 1;
1764    }
1765    else               // found searched name in parent directory
1766    {
1767        // allocate a new inode and an empty Cache-File
1768        *inode = _allocate_one_inode( name,
1769                                      is_dir,
1770                                      cluster,
1771                                      size,
1772                                      0,             // count
1773                                      dentry,
1774                                      1 );           // cache_allocate
1775
1776        // introduce it in Inode-Tree
1777        _add_inode_in_tree( *inode , parent );
1778
[773]1779#if GIET_DEBUG_FAT
[587]1780if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1781_printf("\n[DEBUG FAT] _get_child_from_parent(): found <%s> on device\n", name );
[587]1782#endif
1783        return 0;
1784    }
1785}  // end _get_child_from_parent()
1786
1787
1788
1789
1790//////////////////////////////////////////////////////////////////
1791static unsigned int _get_inode_from_path( char*          pathname,
1792                                          fat_inode_t**  inode )
1793{
1794    char                 name[32];         // buffer for one name in pathname
1795    unsigned int         nb_read;              // number of characters written in name[]
1796    fat_inode_t*         parent;           // parent inode
1797    fat_inode_t*         child;            // child inode
1798    unsigned int         last;             // while exit condition
1799    unsigned int         code;             // return value
1800
[773]1801#if GIET_DEBUG_FAT
[587]1802if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1803_printf("\n[DEBUG FAT] _get_inode_from_path(): enters for path <%s>\n", pathname );
[587]1804#endif
1805
1806    // handle root directory case
[619]1807    if ( _strcmp( pathname , "/" ) == 0 )
[587]1808    {
1809
[773]1810#if GIET_DEBUG_FAT
[587]1811if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1812_printf("\n[DEBUG FAT] _get_inode_from_path(): found root inode for <%s>\n", 
[587]1813        pathname );
1814#endif
1815        *inode  = _fat.inode_tree_root;
1816        return 0;
1817    }
1818
1819    // If the pathname is not "/", we traverse the inode tree from the root.
1820    // We use _get_name_from_path() to scan pathname and extract inode names.
1821    // We use _get_child_from_parent() to scan each directory in the path.
1822
1823    last       = 0;
1824    nb_read    = 0;                      // number of characters analysed in path
1825    parent     = _fat.inode_tree_root;   // Inode-Tree root
1826   
[617]1827    while ( !last )
[587]1828    {
1829        // get searched file/dir name
1830        if ( _get_name_from_path( pathname, name, &nb_read ) )
1831        {
1832            return 3;   // error : name too long
[258]1833        }
1834
[587]1835        // compute last iteration condition
1836        last = (pathname[nb_read] == 0);
[258]1837
[773]1838#if GIET_DEBUG_FAT
[569]1839if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1840_printf("\n[DEBUG FAT] _get_inode_from_path(): got name <%s>\n", name );
[417]1841#endif
1842
[619]1843        if ( _strcmp( name, ".." ) == 0)
[587]1844        {
[617]1845            // found special name "..", try to go up
1846            code = 0;
1847            if ( parent->parent )
1848                child = parent->parent;
1849            else
1850                child = parent;
1851        }
[619]1852        else if ( _strcmp( name, "." ) == 0 )
[617]1853        {
1854            // found special name ".", stay on the same level
1855            code = 0;
1856            child = parent;
1857        }
1858        else
1859        {
1860            // get child inode from parent directory
1861            code = _get_child_from_parent( parent,
1862                                           name,
1863                                           &child );
[417]1864
[617]1865            // we need to find the child inode for all non terminal names
1866            if ( (code == 2) || ((code == 1 ) && !last) )
1867            {
1868
[773]1869    #if GIET_DEBUG_FAT
[617]1870    if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1871    _printf("\n[DEBUG FAT] _get_inode_from_path(): neither parent, nor child found for <%s>\n",
[617]1872            pathname );
1873    #endif
1874                return 2;  // error : parent inode not found
1875            }
[587]1876        }
[617]1877
[587]1878        // update parent if not the last iteration
[617]1879        if ( !last )
1880            parent = child;
[587]1881    } // end while
1882
1883    // returns inode pointer
1884    if (code == 0 )
1885    {
1886
[773]1887#if GIET_DEBUG_FAT
[587]1888if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1889_printf("\n[DEBUG FAT] _get_inode_from_path(): found inode for <%s>\n", 
[587]1890        pathname );
1891#endif
1892        *inode  = child;
1893    }
1894    else
1895    {
1896
[773]1897#if GIET_DEBUG_FAT
[587]1898if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1899_printf("\n[DEBUG FAT] _get_inode_from_path(): found only parent inode for <%s>\n",
[587]1900        pathname );
1901#endif
1902        *inode  = parent;
1903    }
1904
1905    return code;                 // can be 0 (found) or 1 (not found)
1906
1907}  // end _get_inode_from_path()
1908
1909
1910
1911
1912//////////////////////////////////////////////////////////////
1913static unsigned int _remove_node_from_fs( fat_inode_t* inode )
[258]1914{
[637]1915    // check for root node
1916    if ( !inode->parent ) return 1;
1917
[587]1918    // remove entry in parent directory
1919    if ( _remove_dir_entry( inode ) ) return 1;
1920
1921    // update parent directory on device
1922    if ( _update_device_from_cache( inode->parent->levels,
1923                                    inode->parent->cache,
1924                                    inode->parent->name ) ) return 1;
1925
1926    // release clusters allocated to file/dir in DATA region
[783]1927    if ( _all_clusters_release( inode ) ) return 1;
[587]1928
1929    // release File-Cache
[651]1930    _release_cache_memory( inode->cache, inode->levels );
1931    _free ( inode->cache );
[587]1932
1933    // remove inode from Inode-Tree
1934    _remove_inode_from_tree( inode );
1935
1936    // release inode
1937    _free ( inode );
1938
[258]1939    return 0;
[587]1940}  // end _remove_node_from_fs()
[258]1941
1942
[587]1943//////////////////////////////////////////////////////////////////
1944static unsigned int _next_cluster_no_cache( unsigned int   cluster,
1945                                            unsigned int*  next )
1946{
1947    // compute cluster_id and slot_id
1948    // each cluster contains 1024 slots (4 bytes per slot)
1949    unsigned int cluster_id  = cluster >> 10;
1950    unsigned int slot_id     = cluster & 0x3FF;
[258]1951
[587]1952    // compute lba of cluster identified by cluster_id
1953    unsigned int lba = _fat.fat_lba + (cluster_id << 3);
[258]1954
[587]1955    // get cluster containing the adressed FAT slot in FAT buffer
1956    if ( _fat_buffer_fat_lba != lba )
1957    {
1958        if ( _fat_ioc_access( 0,         // no descheduling
1959                              1,         // read
1960                              lba,
1961                              (unsigned int)_fat_buffer_fat,
1962                              8 ) )
1963        {
[664]1964            _printf("\n[FAT ERROR] _next_cluster_no_cache(): "
[587]1965                    "cannot load lba = %x into fat_buffer\n", lba );
1966            return 1;
1967        }
1968
1969        _fat_buffer_fat_lba = lba;
1970    }
1971
1972    // return next cluster index
1973    unsigned int* buf = (unsigned int*)_fat_buffer_fat;
1974    *next = buf[slot_id];
1975    return 0;
1976   
1977}  // end _next_cluster_no_cache()
1978
1979
1980
1981
1982/////////////////////////////////////////////////////////////////
1983static unsigned int _file_info_no_cache( char*          pathname,
1984                                         unsigned int*  file_cluster,
1985                                         unsigned int*  file_size )
[258]1986{
[587]1987   
[773]1988#if GIET_DEBUG_FAT
[587]1989if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1990_printf("\n[DEBUG FAT] _file_info_no_cache(): enters for path <%s>\n", pathname );
[587]1991#endif
[258]1992
[587]1993    char            name[32];             // buffer for one name in the analysed pathname
1994    char            lfn1[16];             // buffer for a partial name in LFN entry
1995    char            lfn2[16];             // buffer for a partial name in LFN entry
1996    char            lfn3[16];             // buffer for a partial name in LFN entry
1997    char            cname[32];            // buffer for a full name in a directory entry
1998    unsigned int    nb_read;              // number of characters analysed in path
1999    unsigned int    parent_cluster;       // cluster index for the parent directory
[597]2000    unsigned int    child_cluster = 0;    // cluster index for the searched file/dir
2001    unsigned int    child_size = 0;       // size of the searched file/dir
[587]2002    unsigned int    child_is_dir;         // type of the searched file/dir
2003    unsigned int    offset;               // offset in a 4 Kbytes buffer
2004    unsigned int    ord;                  // ORD field in a directory entry
2005    unsigned int    attr;                 // ATTR field in a directory entry
[597]2006    unsigned int    lfn = 0;              // number of lfn entries
[587]2007    unsigned char*  buf;                  // pointer on a 4 Kbytes buffer
2008    unsigned int    found;                // name found in current directory entry
2009
2010    // Three embedded loops:
2011    // - scan pathname to extract file/dir names,
2012    // - for each name, scan the clusters of the parent directory
2013    // - for each cluster, scan the 4 Kbytes buffer to find the file/dir name
2014    // The starting point is the root directory (cluster 2)
2015
2016    nb_read        = 0;
2017    parent_cluster = 2; 
2018
2019    // scan pathname 
2020    while ( pathname[nb_read] != 0 )   
2021    {
2022        // get searched file/dir name
2023        if ( _get_name_from_path( pathname, name, &nb_read ) ) return 1;
2024
[773]2025#if GIET_DEBUG_FAT
[587]2026if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2027_printf("\n[DEBUG FAT] _file_info_no_cache(): search name <%s>"
[587]2028        " in cluster %x\n", name , parent_cluster );
2029#endif
2030        found  = 0;
2031
2032        // scan clusters containing the parent directory
2033        while ( found == 0 ) 
2034        {
2035            // compute lba
2036            unsigned int lba = _cluster_to_lba( parent_cluster );
2037
2038            // load one cluster of the parent directory into data_buffer
2039            if ( _fat_buffer_data_lba != lba )
2040            {
2041                if ( _fat_ioc_access( 0,         // no descheduling
2042                                      1,         // read
2043                                      lba,
2044                                      (unsigned int)_fat_buffer_data,
2045                                      8 ) )
2046                {
[664]2047                    _printf("\n[FAT ERROR] _file_info_no_cache(): "
[587]2048                            "cannot load lba = %x into data_buffer\n", lba );
2049                    return 1;
2050                }
2051
2052                _fat_buffer_data_lba = lba;
2053            }
2054
2055            offset = 0;
2056
2057            // scan this 4 Kbytes buffer
2058            while ( (offset < 4096) && (found == 0) )
2059            {
2060                buf  = _fat_buffer_data + offset;
2061                attr = _read_entry( DIR_ATTR , buf , 0 );   
2062                ord  = _read_entry( LDIR_ORD , buf , 0 );
2063
2064                if (ord == NO_MORE_ENTRY)               // no more entry => break
2065                {
2066                    found = 2;
2067                }
2068                else if ( ord == FREE_ENTRY )           // free entry => skip
2069                {
2070                    offset = offset + 32;
2071                }
2072                else if ( attr == ATTR_LONG_NAME_MASK ) // LFN entry => get partial name
2073                {
2074                    unsigned int seq = ord & 0x3;
2075                    lfn = (seq > lfn) ? seq : lfn;   
2076                    if      ( seq == 1 ) _get_name_from_long( buf, lfn1 );
2077                    else if ( seq == 2 ) _get_name_from_long( buf, lfn2 );
2078                    else if ( seq == 3 ) _get_name_from_long( buf, lfn3 );
2079                    offset = offset + 32;
2080                }
2081                else                                    // NORMAL entry
2082                {
2083                    // build the full mame for current directory entry
2084                    if      ( lfn == 0 )
2085                    {
2086                        _get_name_from_short( buf , cname );
2087                    }
2088                    else if ( lfn == 1 )
2089                    {
2090                        _strcpy( cname      , lfn1 );
2091                    }   
2092                    else if ( lfn == 2 ) 
2093                    {
2094                        _strcpy( cname      , lfn1 );
2095                        _strcpy( cname + 13 , lfn2 );
2096                    }
2097                    else if ( lfn == 3 ) 
2098                    {
2099                        _strcpy( cname      , lfn1 );
2100                        _strcpy( cname + 13 , lfn2 );
2101                        _strcpy( cname + 26 , lfn3 );
2102                    }
2103                   
2104                    // test if extracted name == searched name
[619]2105                    if ( _strcmp( name , cname ) == 0 )
[587]2106                    {
2107                        child_cluster = (_read_entry( DIR_FST_CLUS_HI , buf , 1 ) << 16) |
2108                                        (_read_entry( DIR_FST_CLUS_LO , buf , 1 )      ) ;
2109                        child_is_dir  = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
2110                        child_size    = _read_entry( DIR_FILE_SIZE , buf , 1 );
2111                        found         = 1;
2112                    }
2113                    offset = offset + 32;
2114                    lfn = 0;
2115                }
2116            }  // en loop on directory entries
2117           
2118            // compute next cluster index
2119            unsigned int next;
2120            if ( _next_cluster_no_cache ( parent_cluster , &next ) ) return 1;
2121            parent_cluster = next;
2122        } // end loop on clusters
2123
2124        if ( found == 2 )  // found end of directory => error
2125        { 
[664]2126            _printf("\n[FAT ERROR] _file_info_no_cache(): <%s> not found\n",
[587]2127                    name );
2128            return 1;
2129        }
2130 
2131        // check type
2132        if ( ((pathname[nb_read] == 0) && (child_is_dir != 0)) ||
2133             ((pathname[nb_read] != 0) && (child_is_dir == 0)) )
2134        {
[664]2135            _printf("\n[FAT ERROR] _file_info_no_cache(): illegal type for <%s>\n", name );
[587]2136            return 1;
2137        }
2138
2139        // update parent_cluster for next name
2140        parent_cluster = child_cluster;
2141
2142    }  // end loop on names
2143
[773]2144#if GIET_DEBUG_FAT
[587]2145if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2146_printf("\n[DEBUG FAT] _file_info_no_cache(): success for <%s> / "
[587]2147        "file_size = %x / file_cluster = %x\n", pathname, child_size, child_cluster );
2148#endif
2149
2150    // return file cluster and size
2151    *file_size    = child_size;
2152    *file_cluster = child_cluster;
2153    return 0;
2154
2155}  // end _file_info_no_cache()
2156
2157
[773]2158
2159/////////////////////////////
2160unsigned int _set_fs_info()
[761]2161{
[773]2162    // load FS_INFO sector into FAT buffer
2163    if ( _fat_ioc_access( 0,                                // no descheduling
2164                          1,                                // read
2165                          _fat.fs_info_lba,                 // lba
2166                          (unsigned int)_fat.block_buffer,
2167                          1 ) )                             // one block
2168    { 
2169        _printf("\n[FAT ERROR] _set_fs_info(): cannot load FS_INFO Sector\n"); 
2170        return 1;
2171    }
2172    _fat.block_buffer_lba = _fat.fs_info_lba;
2173
2174    // get general info from FAT descriptor
2175    unsigned int  data_blocks  = _fat.data_sectors;
2176
2177    // initialise <free_clusters_number> from FS-INFO sector
2178    unsigned int free_clusters = _read_entry( FS_FREE_CLUSTERS, _fat.block_buffer, 1);
2179    if ( free_clusters >= (data_blocks>>3) )
[761]2180    {
[773]2181        _printf("\n[FAT ERROR] _set_fs_info(): illegal FS_FREE_CLUSTERS in FS-INFO\n"
2182                "  fs_free_clusters = %x / total_clusters = %x\n",
2183                free_clusters , (data_blocks>>3)  ); 
[761]2184        return 1;
2185    }
2186
[773]2187    _fat.free_clusters_number  = free_clusters;
2188
[783]2189    // initialise <free_cluster_hint> from FS_INFO sector
[773]2190    unsigned int free_cluster_hint = _read_entry( FS_FREE_CLUSTER_HINT, _fat.block_buffer, 1);     
2191    if ( free_cluster_hint > (data_blocks>>3) )
[761]2192    {
[773]2193        _printf("\n[FAT ERROR] _set_fs_info(): illegal FS_FREE_CLUSTER_HINT in FS-INFO\n" 
2194                "  fs_free_cluster_hint = %x / total_clusters = %x\n",
2195                free_cluster_hint , (data_blocks>>3)  ); 
2196        return 1;
2197    }
[761]2198
[783]2199    _fat.free_cluster_hint  = free_cluster_hint;
[773]2200
[783]2201#if GIET_DEBUG_FAT
2202if ( _get_proctime() > GIET_DEBUG_FAT )
2203_printf("\n[DEBUG FAT] _set_fs_info() : free_clusters = %x / free_cluster_hint = %x\n",
2204        free_clusters , free_cluster_hint );
2205#endif
2206
2207    return 0;
2208   
2209}  // end _set_fs_info()
2210
2211
2212
2213
2214/////////////////////////////////////
2215static unsigned int _update_fs_info()
2216{
2217    // load buffer if miss
2218    if ( _fat.fs_info_lba != _fat.block_buffer_lba )
[773]2219    {
[783]2220        if ( _fat_ioc_access( 1,                 // descheduling
2221                              1,                 // read
2222                              _fat.fs_info_lba, 
2223                              (unsigned int)_fat.block_buffer, 
2224                              1 ) )              // one block
[761]2225        {
[783]2226            _printf("\n[FAT_ERROR] _update_fs_info(): cannot read block\n");
[773]2227            return 1;
2228        }
[783]2229        _fat.block_buffer_lba = _fat.fs_info_lba;
2230    }
[761]2231
[783]2232    // update buffer
2233    unsigned int* ptr;
[773]2234
[783]2235    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTERS) );
2236    *ptr = _fat.free_clusters_number;
[761]2237
[783]2238    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTER_HINT) );
2239    *ptr = _fat.free_cluster_hint;
2240   
2241    // write bloc to FAT
2242    if ( _fat_ioc_access( 1,                // descheduling
2243                          0,                // write
2244                          _fat.fs_info_lba,
2245                          (unsigned int)_fat.block_buffer, 
2246                          1 ) )             // one block
[773]2247    {
[783]2248        _printf("\n[FAT_ERROR] _update_fs_info(): cannot write block\n");
[773]2249        return 1;
2250    }
2251
2252#if GIET_DEBUG_FAT
[761]2253if ( _get_proctime() > GIET_DEBUG_FAT )
[783]2254_printf("\n[DEBUG FAT] _update_fs_info() : free_clusters = %x / free_cluster_hint = %x\n",
2255        _fat.free_clusters_number , _fat.free_cluster_hint );
[761]2256#endif
2257
[783]2258    return 0;
2259}  // end _update_fs_info()
[761]2260
2261
[783]2262
[773]2263///////////////////////////////////////////////////////////////////////////////
2264///////////////////////////////////////////////////////////////////////////////
2265//             Extern functions                                               
2266///////////////////////////////////////////////////////////////////////////////
2267///////////////////////////////////////////////////////////////////////////////
[761]2268
[773]2269/////////////////////////////////////////////////////////////////////////////
2270int _fat_ioc_access( unsigned int use_irq,       // descheduling if non zero
2271                     unsigned int to_mem,        // read / write
2272                     unsigned int lba,           // first sector on device
2273                     unsigned int buf_vaddr,     // memory buffer vaddr
2274                     unsigned int count )        // number of sectors
2275{
2276    // compute memory buffer physical address
2277    unsigned int       flags;         // for _v2p_translate
2278    unsigned long long buf_paddr;     // buffer physical address
2279
2280    if ( ((_get_mmu_mode() & 0x4) == 0 ) || USE_IOC_RDK )  // identity
2281    { 
2282        buf_paddr = (unsigned long long)buf_vaddr;
2283    }
2284    else                                // V2P translation required
2285    {
2286        buf_paddr = _v2p_translate( buf_vaddr , &flags );
2287    }
2288
[761]2289#if (GIET_DEBUG_FAT & 1)
2290if ( _get_proctime() > GIET_DEBUG_FAT )
[773]2291_printf("\n[DEBUG FAT] _fat_ioc_access(): enters at cycle %d\n"
2292        "  to_mem = %d / vaddr = %x / paddr = %l / sectors = %d / lba = %x\n",
2293        _get_proctime(), to_mem, buf_vaddr, buf_paddr, count, lba );
[761]2294#endif
2295
2296
[773]2297#if GIET_NO_HARD_CC     // L1 cache inval (virtual addresses)
2298    if ( to_mem ) _dcache_buf_invalidate( buf_vaddr, count<<9 );
2299#endif
[761]2300
2301
[773]2302#if   ( USE_IOC_BDV )   // call the proper driver
2303    return( _bdv_access( use_irq , to_mem , lba , buf_paddr , count ) ); 
2304#elif ( USE_IOC_HBA )
2305    return( _hba_access( use_irq , to_mem , lba , buf_paddr , count ) );
2306#elif ( USE_IOC_SDC )
2307    return( _sdc_access( use_irq , to_mem , lba , buf_paddr , count ) );
2308#elif ( USE_IOC_SPI )
2309    return( _spi_access( use_irq , to_mem , lba , buf_paddr , count ) );
2310#elif ( USE_IOC_RDK )
2311    return( _rdk_access( use_irq , to_mem , lba , buf_paddr , count ) );
2312#else
2313    _printf("\n[FAT ERROR] _fat_ioc_access(): no IOC driver\n");
2314    _exit();
2315#endif
[761]2316
[773]2317}  // end _fat_ioc_access()
[761]2318
[587]2319
2320
[773]2321/////////////////////////////////////////
[587]2322int _fat_init( unsigned int kernel_mode ) 
2323{
2324
[258]2325#if GIET_DEBUG_FAT
[569]2326if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2327_printf("\n[DEBUG FAT] _fat_init(): enters at cycle %d\n", _get_proctime() );
[258]2328#endif
[458]2329
2330    // FAT initialisation should be done only once
[674]2331    if ( _fat.initialized == FAT_INITIALIZED )
[458]2332    {
[664]2333        _printf("\n[FAT WARNING] _fat_init(): FAT already initialized\n");
2334        return GIET_FAT32_OK;
[458]2335    }
2336
[587]2337    // load Boot sector (VBR) into FAT buffer
2338    if ( _fat_ioc_access( 0,                                  // no descheduling
2339                          1,                                  // read
2340                          0,                                  // block index
2341                          (unsigned int)_fat.block_buffer,
2342                          1 ) )                               // one block
[258]2343    {
[664]2344        _printf("\n[FAT ERROR] _fat_init(): cannot load VBR\n");
2345        return GIET_FAT32_IO_ERROR;
[258]2346    }
2347
[587]2348    _fat.block_buffer_lba = 0;
2349   
2350#if GIET_DEBUG_FAT
[569]2351if ( _get_proctime() > GIET_DEBUG_FAT )
[587]2352{
[664]2353    _printf("\n[DEBUG FAT] _fat_init(): Boot sector loaded\n");
[587]2354}
[258]2355#endif
2356
2357    // checking various FAT32 assuptions from boot sector
[587]2358    if( _read_entry( BPB_BYTSPERSEC, _fat.block_buffer, 1 ) != 512 )
[258]2359    {
[664]2360        _printf("\n[FAT ERROR] _fat_init(): The sector size must be 512 bytes\n");
2361        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2362    }
[587]2363    if( _read_entry( BPB_SECPERCLUS, _fat.block_buffer, 1 ) != 8 )
[258]2364    {
[664]2365        _printf("\n[FAT ERROR] _fat_init(): The cluster size must be 8 blocks\n");
2366        return GIET_FAT32_INVALID_BOOT_SECTOR;
[587]2367    }
2368    if( _read_entry( BPB_NUMFATS, _fat.block_buffer, 1 ) != 1 )
2369    {
[664]2370        _printf("\n[FAT ERROR] _fat_init(): The number of FAT copies in FAT region must be 1\n");
2371        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2372    }
[587]2373    if( (_read_entry( BPB_FAT32_FATSZ32, _fat.block_buffer, 1 ) & 0xF) != 0 )
[258]2374    {
[664]2375        _printf("\n[FAT ERROR] _fat_init(): The FAT region must be multiple of 16 sectors\n");
2376        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2377    }
[587]2378    if( _read_entry( BPB_FAT32_ROOTCLUS, _fat.block_buffer, 1 ) != 2 )
[258]2379    {
[664]2380        _printf("\n[FAT ERROR] _fat_init(): The root directory must be at cluster 2\n");
2381        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2382    }
2383
[587]2384    // initialise Fat-Descriptor from VBR
2385    _fat.sector_size         = 512;
2386    _fat.cluster_size        = 4096;
2387    _fat.fat_sectors         = _read_entry( BPB_FAT32_FATSZ32 , _fat.block_buffer , 1 );
2388    _fat.fat_lba             = _read_entry( BPB_RSVDSECCNT , _fat.block_buffer , 1 );
2389    _fat.data_sectors        = _fat.fat_sectors << 10;
[530]2390    _fat.data_lba            = _fat.fat_lba + _fat.fat_sectors;
[587]2391    _fat.fs_info_lba         = _read_entry( BPB_FAT32_FSINFO , _fat.block_buffer , 1 );
2392    _fat_buffer_fat_lba      = 0xFFFFFFFF;
2393    _fat_buffer_data_lba     = 0xFFFFFFFF;
[674]2394    _fat.initialized         = FAT_INITIALIZED;
[258]2395
[773]2396    /////////////////////////////////////////////////////////////////////
[587]2397    // This is done only when the _fat_init() is called in kernel mode
[291]2398
[587]2399    if ( kernel_mode )
2400    {
[773]2401        // initialise <free_clusters_number> and <first_free_cluster in FAT descriptor
2402        if ( _set_fs_info() ) return GIET_FAT32_IO_ERROR;
[587]2403
[652]2404        // create Inode-Tree root
[761]2405        _fat.inode_tree_root = _allocate_one_inode("/",   // dir name
2406                                                   1,     // is directory
2407                                                   2,     // cluster index
2408                                                   4096,  // at least one buffer
2409                                                   0,     // no children
2410                                                   0,     // no dentry
2411                                                   1);    // allocate cache
[587]2412
[652]2413        // initialize lock
[587]2414        _spin_lock_init( &_fat.fat_lock );
2415
[652]2416        // initialize File Descriptor Array
[773]2417        unsigned int i;
[652]2418        for( i = 0 ; i < GIET_OPEN_FILES_MAX ; i++ ) _fat.fd[i].allocated = 0;
[587]2419
[652]2420        // initialize fat_cache root
[650]2421        _fat.fat_cache_root   = _allocate_one_cache_node( NULL );
[587]2422        _fat.fat_cache_levels = _get_levels_from_size( _fat.fat_sectors << 9 );
2423    }  // end if kernel_mode
2424
[291]2425#if GIET_DEBUG_FAT
[569]2426if ( _get_proctime() > GIET_DEBUG_FAT )
[587]2427_display_fat_descriptor();
[291]2428#endif
2429
[664]2430    return GIET_FAT32_OK;
[258]2431}  // end _fat_init()
2432
[587]2433
2434
2435
[773]2436////////////////////////////////////////////////////////////////////
[587]2437int _fat_open( char*        pathname,     // absolute path from root
[772]2438               unsigned int flags )       // O_CREAT and O_RDONLY
[258]2439{
[587]2440    unsigned int         fd_id;            // index in File-Descriptor-Array
2441    unsigned int         code;             // error code
2442    fat_inode_t*         inode;            // anonymous inode pointer
2443    fat_inode_t*         child;            // pointer on searched file inode
2444    fat_inode_t*         parent;           // pointer on parent directory inode
[258]2445   
[587]2446    // get flags
[772]2447    unsigned int create    = ((flags & O_CREAT)  != 0);
[654]2448    unsigned int read_only = ((flags & O_RDONLY) != 0);
2449    unsigned int truncate  = ((flags & O_TRUNC)  != 0);
[587]2450
[258]2451#if GIET_DEBUG_FAT
[295]2452unsigned int procid  = _get_procid();
[429]2453unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
2454unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2455unsigned int p       = procid & ((1<<P_WIDTH)-1);
[569]2456if ( _get_proctime() > GIET_DEBUG_FAT )
[773]2457_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] enters for path <%s>\n"
2458        " create = %d / read_only = %d / truncate = %d\n",
2459        x, y, p, pathname , create , read_only , truncate );
[258]2460#endif
2461
[674]2462    // checking FAT initialized
2463    if( _fat.initialized != FAT_INITIALIZED )
[458]2464    {
[664]2465        _printf("\n[FAT ERROR] _fat_open(): FAT not initialized\n");
2466        return GIET_FAT32_NOT_INITIALIZED;
[458]2467    }
[587]2468
[709]2469    // takes the FAT lock and register it in thread context
2470    static_scheduler_t*  psched = _get_sched();
2471    unsigned int         ltid   = _get_thread_ltid();
[530]2472    _spin_lock_acquire( &_fat.fat_lock );
[709]2473    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[295]2474
[587]2475    // get inode pointer
2476    code = _get_inode_from_path( pathname , &inode );
2477
[761]2478    if ( code == 2 )                          // parent inode not found
[258]2479    {
[587]2480        _spin_lock_release( &_fat.fat_lock );
[709]2481        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2482
[664]2483        _printf("\n[FAT ERROR] _fat_open(): path to parent not found"
[587]2484                " for file <%s>\n", pathname );
[664]2485        return GIET_FAT32_FILE_NOT_FOUND;
[587]2486    }
[761]2487    else if ( code == 3 )                     // illegal path name
[587]2488    {
2489        _spin_lock_release( &_fat.fat_lock );
[709]2490        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2491
[664]2492        _printf("\n[FAT ERROR] _fat_open(): one name in path too long"
[587]2493                " for file <%s>\n", pathname );
[664]2494        return GIET_FAT32_NAME_TOO_LONG;
[587]2495    }
[773]2496    else if ( (code == 1) && (create == 0) )   // child inode not found
[587]2497    {
2498        _spin_lock_release( &_fat.fat_lock );
[709]2499        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2500
[664]2501        _printf("\n[FAT ERROR] _fat_open(): file not found"
[587]2502                " for file <%s>\n", pathname );
[664]2503        return GIET_FAT32_FILE_NOT_FOUND;
[587]2504    }
[773]2505    else if ( (code == 1) && (create != 0) )   // child inode not found => create
[587]2506    {
2507        // set parent inode pointer
2508        parent = inode;
[258]2509
2510#if GIET_DEBUG_FAT
[569]2511if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2512_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] create a new file <%s>\n",
[587]2513        x , y , p , pathname );
[258]2514#endif
[291]2515
[587]2516        // get new file name / error check already done by _get_inode_from_path()
2517        char name[32];       
2518        _get_last_name( pathname , name );
2519
2520        // allocate a new inode and an empty Cache-File
2521        child = _allocate_one_inode( name,
2522                                     0,                         // not a directory
2523                                     END_OF_CHAIN_CLUSTER_MAX,  // no cluster allocated
2524                                     0,                         // size : new file is empty
2525                                     0,                         // count incremented later
[761]2526                                     0,                         // set by add_dir_entry
[587]2527                                     1 );                       // cache_allocate
2528
2529        // introduce inode into Inode-Tree
2530        _add_inode_in_tree( child , parent );
2531
2532        // add an entry in the parent directory Cache_file
2533        if ( _add_dir_entry( child , parent ) )
[258]2534        {
[587]2535            _spin_lock_release( &_fat.fat_lock );
[709]2536            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2537
[664]2538            _printf("\n[FAT ERROR] _fat_open(): cannot update parent directory"
[587]2539                    " for file <%s>\n" , pathname );
[664]2540            return GIET_FAT32_IO_ERROR;
[587]2541        } 
2542
2543        // update DATA region on block device for parent directory
2544        if ( _update_device_from_cache( parent->levels,
2545                                        parent->cache,
2546                                        parent->name ) )
2547        {
2548            _spin_lock_release( &_fat.fat_lock );
[709]2549            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2550
[664]2551            _printf("\n[FAT ERROR] _fat_open(): cannot update DATA region "
[587]2552                    " for parent of file <%s>\n", pathname );
[664]2553            return GIET_FAT32_IO_ERROR;
[258]2554        }
2555
[587]2556        // update FAT region on block device
2557        if ( _update_device_from_cache( _fat.fat_cache_levels,
2558                                        _fat.fat_cache_root,
2559                                        "FAT" ) )
[258]2560        {
[587]2561            _spin_lock_release( &_fat.fat_lock );
[709]2562            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2563
[664]2564            _printf("\n[FAT ERROR] _fat_open(): cannot update FAT region"
[587]2565                    " for file <%s>\n", pathname );
[664]2566            return GIET_FAT32_IO_ERROR;
[258]2567        }
[587]2568
[654]2569        // no need to truncate a new file
2570        truncate = 0;
[761]2571
2572#if GIET_DEBUG_FAT
2573if ( _get_proctime() > GIET_DEBUG_FAT )
2574{
2575    _printf("\n[DEBUG FAT] _fat_open() : new inode created for <%s>\n" 
2576            " size = %x / cluster = %x / cache = %x",
2577            child->name , child->size , child->cluster , child->cache );
2578    if ( child->cache != NULL )
2579    {
2580         _printf(" / pdesc[0] = %x\n", (unsigned int)(child->cache->children[0]) );
[258]2581    }
[761]2582    else
[587]2583    {
[761]2584         _printf("\n");
2585    }
2586}
2587#endif
2588
2589    }
2590    else                                    // inode found
2591    {
[587]2592        // set searched file inode pointer
2593        child = inode;
[258]2594
[417]2595#if GIET_DEBUG_FAT
[569]2596if ( _get_proctime() > GIET_DEBUG_FAT )
[773]2597{
2598    _printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] found file <%s>\n"
2599            " inode = %x / size = %x\n",
2600            x , y , p , pathname , (unsigned int)child , child->size );
2601
2602    _display_clusters_list( child );
2603}
[417]2604#endif
[773]2605
[587]2606    }
[258]2607
[587]2608    // Search an empty slot in file descriptors array
2609    fd_id = 0;
2610    while ( (_fat.fd[fd_id].allocated) != 0 && (fd_id < GIET_OPEN_FILES_MAX) )
[258]2611    {
[587]2612        fd_id++;
2613    }
2614
2615    // set file descriptor if an empty slot has been found
[654]2616    if ( fd_id >= GIET_OPEN_FILES_MAX )
[587]2617    {
[654]2618        _spin_lock_release( &_fat.fat_lock );
[709]2619        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2620
[664]2621        _printf("\n[FAT ERROR] _fat_open(): File-Descriptors-Array full\n");
2622        return GIET_FAT32_TOO_MANY_OPEN_FILES;
[654]2623    }
[587]2624
[654]2625    // update file descriptor
2626    _fat.fd[fd_id].allocated  = 1;
2627    _fat.fd[fd_id].seek       = 0;
2628    _fat.fd[fd_id].read_only  = read_only;
2629    _fat.fd[fd_id].inode      = child;
[587]2630
[654]2631    // increment the refcount
2632    child->count = child->count + 1;
[587]2633
[654]2634    // truncate the file if requested
2635    if ( truncate && !read_only && !child->is_dir )
2636    {
2637        // empty file
2638        child->size = 0;
2639        child->levels = _get_levels_from_size( child->size );
2640
2641        // release File-Cache (keep root node)
2642        _release_cache_memory( child->cache, child->levels );
2643
2644        // release clusters allocated to file/dir in DATA region
[783]2645        if ( _all_clusters_release( child ) )
[654]2646        {
2647            _spin_lock_release( &_fat.fat_lock );
[709]2648            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2649
[664]2650            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2651            return GIET_FAT32_IO_ERROR;
[654]2652        }
2653
2654        // update parent directory entry (size and cluster index)
2655        if ( _update_dir_entry( child ) )
2656        {
2657            _spin_lock_release( &_fat.fat_lock );
[709]2658            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2659
[664]2660            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2661            return GIET_FAT32_IO_ERROR;
[654]2662        }
2663    }
2664
[587]2665#if GIET_DEBUG_FAT
2666if ( _get_proctime() > GIET_DEBUG_FAT )
[773]2667_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] get fd = %d for <%s>\n"
2668        " inode = %x / offset = %x / read_only = %d / size = %x / cluster = %x\n",
2669        x , y , p , fd_id , pathname , 
2670        (unsigned int)_fat.fd[fd_id].inode,
2671        _fat.fd[fd_id].seek,
2672        _fat.fd[fd_id].read_only,
2673        _fat.fd[fd_id].inode->size,
2674        _fat.fd[fd_id].inode->cluster );
[587]2675#endif
[761]2676
2677    // releases the lock
2678    _spin_lock_release( &_fat.fat_lock );
2679    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2680
[654]2681    return fd_id;
[587]2682} // end _fat_open()
2683
2684
2685
2686
[773]2687////////////////////////////////////
[587]2688int _fat_close( unsigned int fd_id )
2689{
[674]2690    // checking FAT initialized
2691    if( _fat.initialized != FAT_INITIALIZED )
[587]2692    {
[664]2693        _printf("\n[FAT ERROR] _fat_close(): FAT not initialized\n");
2694        return GIET_FAT32_NOT_INITIALIZED;
[587]2695    }
2696
2697    if( (fd_id >= GIET_OPEN_FILES_MAX) )
2698    {
[664]2699        _printf("\n[FAT ERROR] _fat_close(): illegal file descriptor index\n");
2700        return GIET_FAT32_INVALID_FD;
[587]2701    } 
2702
[709]2703    // takes the FAT lock and register it in thread context
2704    static_scheduler_t*  psched = _get_sched();
2705    unsigned int         ltid   = _get_thread_ltid();
[587]2706    _spin_lock_acquire( &_fat.fat_lock );
[709]2707    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[587]2708
[625]2709    if( _fat.fd[fd_id].allocated == 0 )
2710    {
2711        _spin_lock_release( &_fat.fat_lock );
[709]2712        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2713
[664]2714        _printf("\n[FAT ERROR] _fat_close(): file not open\n");
2715        return GIET_FAT32_NOT_OPEN;
[625]2716    }
2717
[587]2718    // get the inode pointer
2719    fat_inode_t*  inode = _fat.fd[fd_id].inode;
2720
2721#if GIET_DEBUG_FAT
2722if ( _get_proctime() > GIET_DEBUG_FAT )
[761]2723_printf("\n[FAT DEBUG] _fat_close() for file <%s> : refcount = %d"
2724        " / size = %x / cluster = %x\n",
2725        inode->name , inode->count , inode->size , inode->cluster );
[587]2726#endif
2727
[761]2728    // decrement reference count
2729    inode->count = inode->count - 1;
2730   
[587]2731    // update block device and release File-Cache if no more references
2732    if ( inode->count == 0 )
2733    {
2734        // update all dirty clusters for closed file
2735        if ( _update_device_from_cache( inode->levels, 
2736                                        inode->cache,
2737                                        inode->name ) ) 
[258]2738        {
[587]2739            _spin_lock_release( &_fat.fat_lock );
[709]2740            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2741
[664]2742            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
[587]2743                    "for file <%s>\n", inode->name );
[664]2744            return GIET_FAT32_IO_ERROR;
[258]2745        }
2746
[587]2747#if GIET_DEBUG_FAT
2748if ( _get_proctime() > GIET_DEBUG_FAT )
[761]2749_printf("\n[FAT DEBUG] _fat_close() updated device for file <%s>\n", inode->name );
[587]2750#endif
2751
[761]2752        // update dirty clusters for parent directory
[624]2753        if ( inode->parent &&
2754             _update_device_from_cache( inode->parent->levels,
[587]2755                                        inode->parent->cache,
[624]2756                                        inode->parent->name ) )
[258]2757        {
[587]2758            _spin_lock_release( &_fat.fat_lock );
[709]2759            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2760
[664]2761            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
[587]2762                    "for directory <%s>\n", inode->parent->name );
[664]2763            return GIET_FAT32_IO_ERROR;
[587]2764        }
[258]2765
2766#if GIET_DEBUG_FAT
[569]2767if ( _get_proctime() > GIET_DEBUG_FAT )
[761]2768_printf("\n[FAT DEBUG] _fat_close() updated device for parent directory <%s>\n",
[587]2769        inode->parent->name );
[258]2770#endif
2771
[651]2772        // release memory allocated to File-Cache (keep cache root node)
2773        _release_cache_memory( inode->cache, inode->levels );
[587]2774
2775#if GIET_DEBUG_FAT
2776if ( _get_proctime() > GIET_DEBUG_FAT )
2777_printf("\n[FAT DEBUG] _fat_close() release memory for File-Cache <%s>\n",
2778        inode->name );
2779#endif
2780
[773]2781    }  // end if (refcount == 0)
[587]2782
[773]2783
[587]2784    // release fd_id entry in file descriptor array
2785    _fat.fd[fd_id].allocated = 0;
2786
2787    // release lock
2788    _spin_lock_release( &_fat.fat_lock );
[709]2789    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]2790
[664]2791    return GIET_FAT32_OK;
[587]2792} // end fat_close()
2793
2794
2795
2796
[773]2797////////////////////////////////////////////
[658]2798int _fat_file_info( unsigned int     fd_id,
2799                    fat_file_info_t* info )
[587]2800{
[674]2801    if ( _fat.initialized != FAT_INITIALIZED )
[258]2802    {
[664]2803        _printf("\n[FAT ERROR] _fat_file_info(): FAT not initialized\n");
2804        return GIET_FAT32_NOT_INITIALIZED;
[258]2805    }
2806
[623]2807    if ( fd_id >= GIET_OPEN_FILES_MAX )
[587]2808    {
[664]2809        _printf("\n[FAT ERROR] _fat_file_info(): illegal file descriptor index\n");
2810        return GIET_FAT32_INVALID_FD;
[587]2811    } 
[258]2812
[587]2813    if ( _fat.fd[fd_id].allocated == 0 )
2814    {
[664]2815        _printf("\n[FAT ERROR] _fat_file_info(): file not open\n");
2816        return GIET_FAT32_NOT_OPEN;
[258]2817    }
[587]2818
[623]2819    info->size   = _fat.fd[fd_id].inode->size;
2820    info->offset = _fat.fd[fd_id].seek;
2821    info->is_dir = _fat.fd[fd_id].inode->is_dir;
2822
[664]2823    return GIET_FAT32_OK;
[587]2824} // end _fat_file_info()
2825
2826
2827
2828
[773]2829/////////////////////////////////////////////////////////////////////
[707]2830int _fat_read( unsigned int fd_id,          // file descriptor index
[709]2831               unsigned int vaddr,          // destination buffer vaddr
[707]2832               unsigned int count,          // number of bytes to read
[750]2833               unsigned int extend,         // physical address extension
2834               unsigned int offset,         // forced file offset
2835               unsigned int modes )         // special modes
[587]2836{
[709]2837
2838#if GIET_DEBUG_FAT
2839unsigned int procid  = _get_procid();
2840unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
2841unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2842unsigned int p       = procid & ((1<<P_WIDTH)-1);
2843if ( _get_proctime() > GIET_DEBUG_FAT )
2844_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] enters at cycle %d\n"
[750]2845        "  fd = %d / vaddr = %x / bytes = %x / extend = %x / forced_offset = %x\n",
[709]2846        x , y , p , _get_proctime(),
[750]2847        fd_id , vaddr , count , extend , offset );
[709]2848#endif
2849
[674]2850    // checking FAT initialized
2851    if( _fat.initialized != FAT_INITIALIZED )
[258]2852    {
[750]2853        _printf("\n[FAT ERROR] in _fat_read(): FAT not initialized\n");
[664]2854        return GIET_FAT32_NOT_INITIALIZED;
[258]2855    }
[587]2856
2857    // check fd_id overflow
2858    if ( fd_id >= GIET_OPEN_FILES_MAX )
[258]2859    {
[750]2860        _printf("\n[FAT ERROR] in _fat_read(): illegal file descriptor\n");
[664]2861        return GIET_FAT32_INVALID_FD;
[258]2862    }
[358]2863
[750]2864    // check file open
[587]2865    if ( _fat.fd[fd_id].allocated == 0 )
2866    {
[750]2867        _printf("\n[FAT ERROR] in _fat_read(): file not open\n");
[664]2868        return GIET_FAT32_NOT_OPEN;
[587]2869    }
[358]2870
[709]2871    // takes the FAT lock and register it in thread context
2872    static_scheduler_t*  psched = _get_sched();
2873    unsigned int         ltid   = _get_thread_ltid();
[587]2874    _spin_lock_acquire( &_fat.fat_lock );
[709]2875    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[587]2876           
[750]2877    // get special modes
2878    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
2879    unsigned int forced_offset       = modes & FAT_FORCED_OFFSET;
2880
[587]2881    // get file inode pointer and offset
2882    fat_inode_t* inode  = _fat.fd[fd_id].inode;
[750]2883    unsigned int seek   = forced_offset ? offset : _fat.fd[fd_id].seek;
[587]2884
[730]2885    // check seek versus file size
2886    if ( (seek >= inode->size) && !inode->is_dir )
[258]2887    {
[587]2888        _spin_lock_release( &_fat.fat_lock );
[709]2889        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2890
[750]2891        _printf("\n[FAT ERROR] in _fat_read(): offset larger than file size"
[730]2892                " / seek = %x / file_size = %x\n",
2893                seek , inode->size );
2894        return GIET_FAT32_IO_ERROR;
[258]2895    }
2896
[744]2897    // check and ajust count argument for a file
2898    if ( (count > (inode->size - seek)) && !inode->is_dir ) count = inode->size - seek;
[730]2899
[587]2900    // compute first_cluster_id and first_byte_to_move
2901    unsigned int first_cluster_id   = seek >> 12;
2902    unsigned int first_byte_to_move = seek & 0xFFF;   
[258]2903
[587]2904    // compute last_cluster and last_byte_to_move
2905    unsigned int last_cluster_id   = (seek + count - 1) >> 12;   
2906    unsigned int last_byte_to_move = (seek + count - 1) & 0xFFF;
[258]2907
2908#if GIET_DEBUG_FAT
[569]2909if ( _get_proctime() > GIET_DEBUG_FAT )
[709]2910_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] search file <%s> with seek = %x\n "
2911        " first_cluster_id = %x / first_byte_to_move = %x"
[587]2912        " / last_cluster_id = %x / last_byte_to_move = %x\n",
[709]2913        x , y , p , inode->name , seek ,
[587]2914        first_cluster_id , first_byte_to_move , last_cluster_id , last_byte_to_move );
[258]2915#endif
2916
[587]2917    // loop on all cluster covering the requested transfer
2918    unsigned int cluster_id;
2919    unsigned int done = 0;
2920    for ( cluster_id = first_cluster_id ; cluster_id <= last_cluster_id ; cluster_id++ )
[258]2921    {
[587]2922        // get pointer on the cluster_id buffer in cache
2923        unsigned char*     cbuf;
2924        fat_cache_desc_t*  pdesc;
[761]2925        if ( _get_file_cache_buffer( inode, 
[587]2926                                     cluster_id,
[761]2927                                     0,
[587]2928                                     &pdesc ) )
2929        {
2930            _spin_lock_release( &_fat.fat_lock );
[709]2931            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2932
[750]2933            _printf("\n[FAT ERROR] in _fat_read(): cannot load file <%s>\n",
[587]2934                    inode->name );
[664]2935            return GIET_FAT32_IO_ERROR;
[587]2936        }
2937        cbuf = pdesc->buffer;
2938
2939#if GIET_DEBUG_FAT
2940if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2941_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] moves cluster_id %d from Cache-File <%s>\n",
[587]2942        x , y , p , cluster_id, inode->name );
2943#endif
2944
2945        // compute memcpy arguments
2946        unsigned char*  source;
2947        unsigned int    nbytes;
[707]2948
[587]2949        if ( (cluster_id == first_cluster_id) && (cluster_id == last_cluster_id) )
2950        {
2951            source = cbuf + first_byte_to_move; 
2952            nbytes = last_byte_to_move - first_byte_to_move + 1;
2953        }
2954        else if ( cluster_id == first_cluster_id )
2955        {
2956            source = cbuf + first_byte_to_move; 
2957            nbytes = 4096 - first_byte_to_move;
2958        }
2959        else if ( cluster_id == last_cluster_id )
2960        {
2961            source = cbuf; 
2962            nbytes = last_byte_to_move + 1;
2963        }
2964        else  // not first / not last
2965        {
2966            source = cbuf; 
2967            nbytes = 4096;
2968        }
2969
[709]2970        // move data
[750]2971        if ( physical_addressing == 0 )           // no physical addressing
[707]2972        {
[709]2973            char* dest = (char*)(vaddr + done);
2974            memcpy( dest , source , nbytes );
[707]2975        }
[709]2976        else                                      // physical addressing required
[707]2977        {
2978            unsigned int flags;
[750]2979            paddr_t pdest    = (((paddr_t)extend)<<32) + vaddr + done;
[707]2980            paddr_t psource  = _v2p_translate( (unsigned int)source, &flags );
[709]2981            _physical_memcpy( pdest , psource , nbytes );
[707]2982        }
2983
[587]2984        done = done + nbytes;
[258]2985    }
2986
[587]2987#if GIET_DEBUG_FAT
2988if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2989_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] loaded file <%s> from Cache-File\n",
[587]2990        x , y , p , inode->name );
2991#endif
[258]2992
[750]2993    // update seek if required
2994    if ( forced_offset == 0 ) _fat.fd[fd_id].seek += done;
[258]2995
[587]2996    // release lock
2997    _spin_lock_release( &_fat.fat_lock );
[709]2998    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]2999
3000    return done;
3001} // end _fat_read()
3002
3003
3004
3005
[773]3006////////////////////////////////////////////////////////////////
[587]3007int _fat_write( unsigned int fd_id,    // file descriptor index
[709]3008                unsigned int vaddr,    // source buffer vaddr
3009                unsigned int count,    // number of bytes to write
[750]3010                unsigned int extend,   // physical address extension
3011                unsigned int modes )   // special modes
[587]3012{
[674]3013    // checking FAT initialized
3014    if( _fat.initialized != FAT_INITIALIZED )
[258]3015    {
[674]3016        _printf("\n[FAT ERROR] _fat_write(): FAT not initialized\n");
[664]3017        return GIET_FAT32_NOT_INITIALIZED;
[587]3018    }
[258]3019
[709]3020    // takes the FAT lock and register it in thread context
3021    static_scheduler_t*  psched = _get_sched();
3022    unsigned int         ltid   = _get_thread_ltid();
[587]3023    _spin_lock_acquire( &_fat.fat_lock );
[709]3024    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3025
[587]3026           
3027    // check fd_id overflow
3028    if ( fd_id >= GIET_OPEN_FILES_MAX )
3029    {
3030        _spin_lock_release( &_fat.fat_lock );
[709]3031        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3032
[664]3033        _printf("\n[FAT ERROR] _fat_write(): illegal file descriptor\n");
3034        return GIET_FAT32_INVALID_FD;
[587]3035    }
3036
3037    // check file open
3038    if ( _fat.fd[fd_id].allocated == 0 )
3039    {
3040        _spin_lock_release( &_fat.fat_lock );
[709]3041        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3042
[664]3043        _printf("\n[FAT ERROR] _fat_write(): file not open\n" );
3044        return GIET_FAT32_NOT_OPEN;
[587]3045    }
3046
3047    // check file writable
3048    if ( _fat.fd[fd_id].read_only )
3049    {
3050        _spin_lock_release( &_fat.fat_lock );
[709]3051        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3052
[664]3053        _printf("\n[FAT ERROR] _fat_write(): file <%s> is read-only\n",
[587]3054                _fat.fd[fd_id].inode->name );
[664]3055        return GIET_FAT32_READ_ONLY;
[587]3056    }
3057
[750]3058    // get special modes
3059    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
3060
[587]3061    // get file inode pointer and seek
3062    fat_inode_t* inode  = _fat.fd[fd_id].inode;
3063    unsigned int seek   = _fat.fd[fd_id].seek;
3064
[258]3065#if GIET_DEBUG_FAT
[587]3066unsigned int procid  = _get_procid();
3067unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3068unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3069unsigned int p       = procid & ((1<<P_WIDTH)-1);
[569]3070if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3071_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] enters for file <%s> "
[587]3072        " / bytes = %x / seek = %x\n",
3073        x , y , p , inode->name , count , seek );
[258]3074#endif
3075
[773]3076    // check if file size must be incremented
[587]3077    // and allocate new clusters from FAT if required
3078    unsigned int old_size = inode->size;
3079    unsigned int new_size = seek + count;
3080    if ( new_size > old_size )
3081    {
3082        // compute current and required numbers of clusters
3083        unsigned old_clusters = old_size >> 12;
3084        if ( old_size & 0xFFF ) old_clusters++;
3085
3086        unsigned new_clusters = new_size >> 12;
3087        if ( new_size & 0xFFF ) new_clusters++;
3088
3089        // allocate new clusters from FAT if required
3090        if ( new_clusters > old_clusters )
[258]3091        {
[587]3092
3093#if GIET_DEBUG_FAT
3094if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3095_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] allocates new clusters for file <%s>"
[587]3096        " / current = %d / required = %d\n",
3097        x , y , p , inode->name , old_clusters , new_clusters );
3098#endif
3099            // allocate missing clusters
[761]3100            unsigned int cid;
3101            unsigned int index;  // unused
3102            for ( cid = 0 ; cid < (new_clusters - old_clusters) ; cid++ )
[587]3103            {
[783]3104                if ( _one_cluster_allocate( inode , &index ) )
[761]3105                {
3106                    _spin_lock_release( &_fat.fat_lock );
3107                    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] ,
3108                                 ~LOCKS_MASK_FAT ); 
[709]3109
[761]3110                    _printf("\n[FAT ERROR] in _fat_write(): no free cluster"
3111                            " for file <%s>\n", _fat.fd[fd_id].inode->name );
3112                    return GIET_FAT32_NO_FREE_SPACE;
3113                }
[587]3114            }
[258]3115        }
3116         
[761]3117        // update size in inode
3118        inode->size = new_size;
3119 
[654]3120        // update parent directory entry (size and cluster index)
[587]3121        if ( _update_dir_entry( inode ) )
3122        {
3123            _spin_lock_release( &_fat.fat_lock );
[709]3124            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3125
[664]3126            _printf("\n[FAT ERROR] _fat_write(): cannot update parent directory entry"
[587]3127                    " for file <%s>\n", _fat.fd[fd_id].inode->name );
[664]3128            return GIET_FAT32_IO_ERROR;
[587]3129        }
3130           
3131
3132#if GIET_DEBUG_FAT
3133if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3134_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] updates size for file <%s> / size = %x\n",
[587]3135        x , y , p , inode->name , (new_size - old_size) );
3136#endif
3137
[258]3138    }
3139
[587]3140    // compute first_cluster_id and first_byte_to_move
3141    unsigned int first_cluster_id   = seek >> 12;
3142    unsigned int first_byte_to_move = seek & 0xFFF;   
[258]3143
[587]3144    // compute last_cluster and last_byte_to_move
3145    unsigned int last_cluster_id   = (seek + count - 1) >> 12;   
3146    unsigned int last_byte_to_move = (seek + count - 1) & 0xFFF;
3147
3148#if GIET_DEBUG_FAT
3149if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3150_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] starts loop on clusters for file <%s>\n"
[587]3151        "  first_cluster_id = %d / first_byte_to_move = %x"
3152        " / last_cluster_id = %d / last_byte_to_move = %x\n",
3153        x , y , p , inode->name ,
3154        first_cluster_id , first_byte_to_move , last_cluster_id , last_byte_to_move );
3155#endif
3156
3157    // loop on all clusters covering the requested transfer
3158    unsigned int cluster_id;
3159    unsigned int done = 0;
3160    for ( cluster_id = first_cluster_id ; cluster_id <= last_cluster_id ; cluster_id++ )
3161    {
3162        // get pointer on one 4K buffer in File-Cache
3163        unsigned char*     cbuf;
3164        fat_cache_desc_t*  pdesc;
[761]3165        if ( _get_file_cache_buffer( inode,   
[587]3166                                     cluster_id, 
[761]3167                                     0,
[587]3168                                     &pdesc ) )   
3169        {
3170            _spin_lock_release( &_fat.fat_lock );
[709]3171            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3172
[664]3173            _printf("\n[FAT ERROR] _fat_write(): cannot load file <%s>\n",
[587]3174                    inode->name );
[664]3175            return GIET_FAT32_IO_ERROR;
[587]3176        }
3177       
3178        cbuf         = pdesc->buffer;
3179        pdesc->dirty = 1;
3180   
3181#if GIET_DEBUG_FAT
3182if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3183_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] move cluster_id %d to Cache-file <%s>\n",
[587]3184        x , y , p , cluster_id, inode->name );
3185#endif
3186
3187        // compute memcpy arguments
3188        unsigned char* dest;
3189        unsigned int   nbytes;
3190        if ( (cluster_id == first_cluster_id) && (cluster_id == last_cluster_id) )
3191        {
3192            dest   = cbuf + first_byte_to_move; 
3193            nbytes = last_byte_to_move - first_byte_to_move + 1;
3194        }
3195        else if ( cluster_id == first_cluster_id )
3196        {
3197            dest   = cbuf + first_byte_to_move; 
3198            nbytes = 4096 - first_byte_to_move;
3199        }
3200        else if ( cluster_id == last_cluster_id )
3201        {
3202            dest   = cbuf; 
3203            nbytes = last_byte_to_move + 1;
3204        }
3205        else
3206        {
3207            dest   = cbuf; 
3208            nbytes = 4096;
3209        }
3210
[709]3211        // move data
[750]3212        if ( physical_addressing == 0 )     // no physical addressing
[709]3213        {
3214            char* source = (char*)(vaddr + done);
3215            memcpy( dest , source , nbytes ); 
3216        }
3217        else                                  // physical addressing required
3218        {
3219            unsigned int flags;
[750]3220            paddr_t      psource = (((paddr_t)extend)<<32) + vaddr + done;
[709]3221            paddr_t      pdest   = _v2p_translate( (unsigned int)dest , &flags );
3222            _physical_memcpy( pdest , psource , nbytes );
3223        }
3224
[587]3225        done = done + nbytes;
3226
3227    } // end for clusters
3228
3229    // update seek
3230    _fat.fd[fd_id].seek += done;
3231
3232#if GIET_DEBUG_FAT
3233if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3234_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] store file <%s> into Cache-File\n",
[587]3235        x , y , p , inode->name );
3236#endif
3237
3238    // release lock
3239    _spin_lock_release( &_fat.fat_lock );
[709]3240    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3241
3242    return done;
3243} // end _fat_write()
3244
3245
3246
[773]3247///////////////////////////////////
[587]3248int _fat_lseek( unsigned int fd_id,
3249                unsigned int seek,
3250                unsigned int whence )
[258]3251{
[674]3252    // checking FAT initialized
3253    if( _fat.initialized != FAT_INITIALIZED )
[587]3254    {
[664]3255        _printf("\n[FAT ERROR] _fat_lseek(): FAT not initialized\n");
3256        return GIET_FAT32_NOT_INITIALIZED;
[587]3257    }
[259]3258
[587]3259    // check fd_id overflow
3260    if ( fd_id >= GIET_OPEN_FILES_MAX )
3261    {
[664]3262        _printf("\n[FAT ERROR] _fat_lseek(): illegal file descriptor\n");
3263        return GIET_FAT32_INVALID_FD;
[587]3264    }
[259]3265
[709]3266    // takes the FAT lock and register it in thread context
3267    static_scheduler_t*  psched = _get_sched();
3268    unsigned int         ltid   = _get_thread_ltid();
[587]3269    _spin_lock_acquire( &_fat.fat_lock );
[709]3270    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[259]3271
[709]3272
[587]3273    // check file open
3274    if ( _fat.fd[fd_id].allocated == 0 )
3275    {
3276        _spin_lock_release( &_fat.fat_lock );
[709]3277        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3278
[664]3279        _printf("\n[FAT ERROR] _fat_lseek(): file not open\n");
3280        return GIET_FAT32_NOT_OPEN;
[587]3281    }
[259]3282
[587]3283    unsigned int  new_seek;
[291]3284
[587]3285    // compute new seek
3286    if      ( whence == SEEK_CUR ) new_seek = _fat.fd[fd_id].seek + seek;
3287    else if ( whence == SEEK_SET ) new_seek = seek;
[746]3288    else if ( whence == SEEK_END ) new_seek = _fat.fd[fd_id].inode->size + seek;
[587]3289    else
3290    {
3291        _spin_lock_release( &_fat.fat_lock );
[709]3292        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3293
[664]3294        _printf("\n[FAT ERROR] _fat_lseek(): illegal whence value\n");
3295        return GIET_FAT32_INVALID_ARG;
[587]3296    }
[291]3297
[587]3298    // update file descriptor offset
3299    _fat.fd[fd_id].seek = new_seek;
[291]3300
[259]3301#if GIET_DEBUG_FAT
[295]3302unsigned int procid  = _get_procid();
[429]3303unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3304unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3305unsigned int p       = procid & ((1<<P_WIDTH)-1);
[569]3306if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3307_printf("\n[DEBUG FAT] _fat_lseek(): P[%d,%d,%d] set seek = %x for file <%s>\n",
[587]3308        x , y , p , new_seek , _fat.fd[fd_id].inode->name );
[259]3309#endif
3310
[587]3311    // release lock
3312    _spin_lock_release( &_fat.fat_lock );
[709]3313    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3314
3315    return new_seek;
3316}  // end _fat_lseek()
3317
3318
3319
[773]3320///////////////////////////////////////
[587]3321int _fat_remove( char*        pathname,
3322                 unsigned int should_be_dir )
3323{
3324    fat_inode_t*  inode;            // searched file inode pointer
3325
3326#if GIET_DEBUG_FAT
3327unsigned int procid  = _get_procid();
3328unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3329unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3330unsigned int p       = procid & ((1<<P_WIDTH)-1);
3331if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3332_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] enters for path <%s>\n",
[587]3333        x, y, p, pathname );
3334#endif
3335
[674]3336    // checking FAT initialized
3337    if( _fat.initialized != FAT_INITIALIZED )
[587]3338    {
[664]3339        _printf("\n[FAT ERROR] _fat_remove(): FAT not initialized\n");
3340        return GIET_FAT32_NOT_INITIALIZED;
[259]3341    }
[587]3342
[709]3343    // takes the FAT lock and register it in thread context
3344    static_scheduler_t*  psched = _get_sched();
3345    unsigned int         ltid   = _get_thread_ltid();
[587]3346    _spin_lock_acquire( &_fat.fat_lock );
[709]3347    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[587]3348
[709]3349
[587]3350    // get searched file inode
3351    unsigned int code = _get_inode_from_path( pathname , &inode );
3352
3353#if GIET_DEBUG_FAT
3354if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3355_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] found inode %x for <%s> / code = %d\n",
[587]3356        x , y , p , (unsigned int)inode , pathname , code );
3357#endif
3358
3359    if ( (code == 1) || (code == 2) )
[259]3360    {
[587]3361        _spin_lock_release( &_fat.fat_lock );
[709]3362        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3363
[664]3364        _printf("\n[FAT ERROR] _fat_remove(): file <%s> not found\n", 
[587]3365                pathname );
[664]3366        return GIET_FAT32_FILE_NOT_FOUND;
[259]3367    }
[587]3368    else if ( code == 3 )
[259]3369    {
[587]3370        _spin_lock_release( &_fat.fat_lock );
[709]3371        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3372
[664]3373        _printf("\n[FAT ERROR] _fat_remove(): name too long in <%s>\n",
[587]3374                pathname );
[664]3375        return GIET_FAT32_NAME_TOO_LONG;
[259]3376    }
3377
[587]3378    // check inode type
3379    if ( (inode->is_dir != 0) && (should_be_dir == 0) ) 
[291]3380    {
[587]3381        _spin_lock_release( &_fat.fat_lock );
[709]3382        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3383
[664]3384        _printf("\n[FAT ERROR] _fat_remove(): <%s> is a directory\n",
[587]3385                pathname );
[664]3386        return GIET_FAT32_IS_DIRECTORY;
[587]3387    }
3388    if ( (inode->is_dir == 0) && (should_be_dir != 0) )
3389    {
3390        _spin_lock_release( &_fat.fat_lock );
[709]3391        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3392
[664]3393        _printf("\n[FAT ERROR] _fat_remove(): <%s> is not a directory\n", 
[587]3394                pathname );
[664]3395        return GIET_FAT32_NOT_A_DIRECTORY;
[587]3396    }
3397
3398#if GIET_DEBUG_FAT
3399if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3400_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked inode type for <%s>\n",
[587]3401        x , y , p , pathname );
3402#endif
3403   
3404    // check references count for a file
3405    if ( (inode->is_dir == 0) && (inode->count != 0) )
3406    {
3407        _spin_lock_release( &_fat.fat_lock );
[709]3408        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3409
[664]3410        _printf("\n[FAT ERROR] _fat_remove(): file <%s> still referenced\n",
[587]3411                pathname );
[664]3412        return GIET_FAT32_IS_OPEN;
[587]3413    }
3414
3415    //  check empty for a directory
3416    if ( inode->is_dir )
3417    {
3418        unsigned int entries;
3419        if ( _get_nb_entries( inode , &entries ) )
[291]3420        {
[587]3421            _spin_lock_release( &_fat.fat_lock );
[709]3422            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3423
[664]3424            _printf("\n[FAT ERROR] _fat_remove(): cannot scan directory <%s>\n", 
[587]3425                    pathname );
[664]3426            return GIET_FAT32_IO_ERROR;
[291]3427        }
[587]3428        else if ( entries > 2 )
3429        {
3430            _spin_lock_release( &_fat.fat_lock );
[709]3431            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3432
[664]3433            _printf("\n[FAT ERROR] _fat_remove(): directory <%s> not empty\n", 
[587]3434                    pathname );
[664]3435            return GIET_FAT32_DIRECTORY_NOT_EMPTY;
[587]3436        }
[291]3437    }
3438
[587]3439#if GIET_DEBUG_FAT
3440if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3441_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked remove condition OK for <%s>\n",
[587]3442        x , y , p , pathname );
3443#endif
[259]3444   
[587]3445    // remove the file or directory from the file system
3446    if ( _remove_node_from_fs( inode ) )
3447    {
3448        _spin_lock_release( &_fat.fat_lock );
[709]3449        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3450
[664]3451        _printf("\n[FAT ERROR] _fat_remove(): cannot remove <%s> from FS\n",
[587]3452                pathname );
[664]3453        return GIET_FAT32_IO_ERROR;
[587]3454    }
[259]3455
[587]3456    // release lock and return success
3457    _spin_lock_release( &_fat.fat_lock );
[709]3458    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3459
[259]3460#if GIET_DEBUG_FAT
[569]3461if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3462_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] removed  <%s> from FS\n",
[587]3463        x, y, p, pathname );
[259]3464#endif
[587]3465   
[664]3466    return GIET_FAT32_OK;
[587]3467       
3468}  // end _fat_remove()
[259]3469
[587]3470
3471
3472
3473
[773]3474/////////////////////////////////
[587]3475int _fat_rename( char*  old_path,
3476                 char*  new_path )
3477{
3478    fat_inode_t*  inode;        // anonymous inode pointer
3479    fat_inode_t*  old;          // inode identified by old_path      => to be deleted
3480    fat_inode_t*  new;          // inode identified by new_path      => to be created
3481    fat_inode_t*  old_parent;   // parent inode  in old_path         => to be modified
3482    fat_inode_t*  new_parent;   // parent inode  in new_path         => to be modified
3483    fat_inode_t*  to_remove;    // previouly identified by new_path  => to be removed
3484    unsigned int  code;
3485
3486#if GIET_DEBUG_FAT
3487unsigned int procid  = _get_procid();
3488unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3489unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3490unsigned int p       = procid & ((1<<P_WIDTH)-1);
3491if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3492_printf("\n[DEBUG FAT] _fat_rename(): P[%d,%d,%d] enters to move <%s> to <%s>\n",
[587]3493        x , y , p , old_path , new_path );
3494#endif
3495
[674]3496    // checking FAT initialized
3497    if( _fat.initialized != FAT_INITIALIZED )
[259]3498    {
[664]3499        _printf("\n[FAT ERROR] _fat_rename(): FAT not initialized\n");
3500        return GIET_FAT32_NOT_INITIALIZED;
[259]3501    }
3502
[709]3503    // takes the FAT lock and register it in thread context
3504    static_scheduler_t*  psched = _get_sched();
3505    unsigned int         ltid   = _get_thread_ltid();
[587]3506    _spin_lock_acquire( &_fat.fat_lock );
[709]3507    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[259]3508
[709]3509
[587]3510    // get "old" and "old_parent" inode pointers
3511    if ( _get_inode_from_path( old_path , &inode ) )
3512    {
3513        _spin_lock_release( &_fat.fat_lock );
[709]3514        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3515
[664]3516        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", old_path );
3517        return GIET_FAT32_FILE_NOT_FOUND;
[587]3518    }
3519    else
3520    {
3521        old        = inode;
3522        old_parent = inode->parent;
3523    }
[259]3524
[587]3525    // get "to_removed" and "new_parent" inode pointers
3526    code = _get_inode_from_path( new_path , &inode );
3527
3528    if ( code == 0 )       // new_path inode already exist
[259]3529    {
[621]3530        if ( inode == old )  // the file will replace itself, do nothing
3531        {
3532            _spin_lock_release( &_fat.fat_lock );
[709]3533            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3534
[664]3535            return GIET_FAT32_OK;
[621]3536        }
3537
[587]3538        to_remove        = inode;
[621]3539        new_parent       = inode->parent;
[587]3540    }
3541    else if ( code == 1 )  // to_remove does not exist but parent exist
3542    {
3543        to_remove        = NULL;
3544        new_parent       = inode;
3545    }
3546    else                   // parent directory in new_path not found
3547    {
3548        _spin_lock_release( &_fat.fat_lock );
[709]3549        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3550
[664]3551        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", new_path );
3552        return GIET_FAT32_FILE_NOT_FOUND;
[587]3553    }
[259]3554
[638]3555    // check for move into own subdirectory
3556    if ( _is_ancestor( old, new_parent ) )
3557    {
3558        _spin_lock_release( &_fat.fat_lock );
[709]3559        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3560
3561        _printf("\n[FAT ERROR] _fat_rename(): can't move %s into  own directory\n", old_path );
[664]3562        return GIET_FAT32_MOVE_INTO_SUBDIR;
[638]3563    }
3564
[259]3565#if GIET_DEBUG_FAT
[569]3566if ( _get_proctime() > GIET_DEBUG_FAT )
[587]3567{
3568if ( to_remove )
[664]3569_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
[587]3570        "/ to_remove = %s\n",
3571        old_parent->name , old->name , new_parent->name , to_remove->name );
3572else
[664]3573_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
[587]3574        "/ no remove\n", 
3575        old_parent->name , old->name , new_parent->name );
3576}
[259]3577#endif
3578
[587]3579    // check remove condition for "to_remove" inode
3580    if ( to_remove )
3581    {
3582        if ( to_remove->is_dir )   // it's a directory
[259]3583        {
[587]3584            unsigned int entries;
3585            if ( _get_nb_entries( to_remove , &entries ) )
3586            {
3587                _spin_lock_release( &_fat.fat_lock );
[709]3588                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3589
[664]3590                _printf("\n[FAT ERROR] _fat_rename(): cannot scan directory <%s>\n", 
[587]3591                        to_remove->name );
[664]3592                return GIET_FAT32_IO_ERROR;
[587]3593            }
3594            else if ( entries > 2 )
3595            {
3596                _spin_lock_release( &_fat.fat_lock );
[709]3597                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3598
[664]3599                _printf("\n[FAT ERROR] _fat_rename(): directory <%s> not empty\n", 
[587]3600                        to_remove->name );
[664]3601                return GIET_FAT32_DIRECTORY_NOT_EMPTY;
[587]3602            }
[259]3603        }
[587]3604        else                       // it's a file
3605        {
3606            if ( to_remove->count ) 
3607            {
3608                _spin_lock_release( &_fat.fat_lock );
[709]3609                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3610
[664]3611                _printf("\n[FAT ERROR] _fat_rename(): file <%s> still referenced\n", 
[587]3612                        to_remove->name );
[664]3613                return GIET_FAT32_IS_OPEN;
[587]3614            }
3615        }
[259]3616    }
[291]3617
[587]3618#if GIET_DEBUG_FAT
3619if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3620_printf("\n[FAT DEBUG] _fat_rename(): P[%d,%d,%d] checked remove condition OK\n",
[587]3621        x , y , p );
3622#endif
3623
3624    // get new last name / error checking already done by _get_inode_from_path()
3625    char  new_name[32];
3626    _get_last_name( new_path , new_name );
3627
3628    // allocate "new" inode
3629    new = _allocate_one_inode( new_name,
3630                               old->is_dir,
3631                               old->cluster,
3632                               old->size,
3633                               0,              // count
3634                               0,              // dentry
3635                               0 );            // no cache_allocate
3636 
[761]3637    // attach the "old" File-Cache to the "new" inode
[587]3638    new->levels = old->levels;
3639    new->cache  = old->cache;
3640
3641    // add "new" to "new_parent" directory File-Cache
3642    if ( _add_dir_entry( new , new_parent ) )
[291]3643    {
[587]3644        _spin_lock_release( &_fat.fat_lock );
[709]3645        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3646
[664]3647        _printf("\n[FAT ERROR] _fat_rename(): cannot add <%s> into <%s>\n",
[587]3648                new->name , new_parent->name );
[664]3649        return GIET_FAT32_IO_ERROR;
[291]3650    }
3651
[587]3652    // add "new" to "new_parent" directory in Inode-Tree
3653    _add_inode_in_tree( new , new_parent );
3654   
3655    // updates "new_parent" directory on device
3656    if ( _update_device_from_cache( new_parent->levels,
3657                                    new_parent->cache,
3658                                    new_parent->name ) )
[291]3659    {
[587]3660        _spin_lock_release( &_fat.fat_lock );
[709]3661        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3662
[664]3663        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
[587]3664                    new_parent->name );
[664]3665        return GIET_FAT32_IO_ERROR;
[291]3666    }
[258]3667
[587]3668    // remove "old" from "old_parent" File-Cache
3669    if ( _remove_dir_entry( old ) )
3670    {
3671        _spin_lock_release( &_fat.fat_lock );
[709]3672        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3673
[664]3674        _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from <%s>\n",
[587]3675                old->name , old_parent->name );
[664]3676        return GIET_FAT32_IO_ERROR;
[587]3677    }
3678 
3679    // remove "old" inode from Inode-Tree
3680    _remove_inode_from_tree( old );
3681
[622]3682    // release "old" inode
3683    _free( old );
3684
[587]3685    // updates "old_parent" directory on device
3686    if ( _update_device_from_cache( old_parent->levels,
3687                                    old_parent->cache,
3688                                    old_parent->name ) )
3689    {
3690        _spin_lock_release( &_fat.fat_lock );
[709]3691        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3692
[664]3693        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
[587]3694                    old_parent->name );
[664]3695        return GIET_FAT32_IO_ERROR;
[587]3696    }
3697
3698    // remove "to_remove" from File System (if required)
3699    if ( to_remove )
3700    {
3701        if ( _remove_node_from_fs( to_remove ) )
3702        {
3703            _spin_lock_release( &_fat.fat_lock );
[709]3704            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3705
[664]3706            _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from FS\n",
[587]3707                    to_remove->name );
[664]3708            return GIET_FAT32_IO_ERROR;
[587]3709        }
3710    }
3711
3712    // release lock
3713    _spin_lock_release( &_fat.fat_lock );
[709]3714    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3715
[664]3716    return GIET_FAT32_OK;
[587]3717}  // end _fat_rename()
3718
3719
3720
3721
[773]3722////////////////////////////////
[587]3723int _fat_mkdir( char* pathname )
[260]3724{
[587]3725    fat_inode_t*         inode;            // anonymous inode pointer
3726    fat_inode_t*         child;            // searched directory inode pointer
3727    fat_inode_t*         parent;           // parent directory inode pointer
[260]3728
[587]3729#if GIET_DEBUG_FAT
3730unsigned int procid  = _get_procid();
3731unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3732unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3733unsigned int p       = procid & ((1<<P_WIDTH)-1);
3734if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3735_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] enters for path <%s>\n",
[587]3736        x, y, p, pathname );
3737#endif
3738
[674]3739    // checking FAT initialized
3740    if( _fat.initialized != FAT_INITIALIZED )
[260]3741    {
[664]3742        _printf("\n[FAT ERROR] _fat_mkdir(): FAT not initialized\n");
3743        return GIET_FAT32_NOT_INITIALIZED;
[587]3744    }
[260]3745
[709]3746    // takes the FAT lock and register it in thread context
3747    static_scheduler_t*  psched = _get_sched();
3748    unsigned int         ltid   = _get_thread_ltid();
[587]3749    _spin_lock_acquire( &_fat.fat_lock );
[709]3750    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3751
[587]3752    // get inode
3753    unsigned int code = _get_inode_from_path( pathname , &inode );
[260]3754
[587]3755    if ( code == 2 ) 
3756    {
3757        _spin_lock_release( &_fat.fat_lock );
[709]3758        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3759
[664]3760        _printf("\n[FAT ERROR] _fat_mkdir(): path to parent not found"
[587]3761                " for directory <%s>\n", pathname );
[664]3762        return GIET_FAT32_FILE_NOT_FOUND;
[260]3763    }
[587]3764    else if ( code == 3 ) 
[260]3765    {
[587]3766        _spin_lock_release( &_fat.fat_lock );
[709]3767        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3768
[664]3769        _printf("\n[FAT ERROR] _fat_mkdir(): one name in path too long"
[587]3770                " for directory  <%s>\n", pathname );
[664]3771        return GIET_FAT32_NAME_TOO_LONG;
[587]3772    }
3773    else if ( code == 0 )
3774    {
3775        _spin_lock_release( &_fat.fat_lock );
[709]3776        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3777
[664]3778        _printf("\n[FAT ERROR] _fat_mkdir(): directory <%s> already exist\n",
[587]3779                pathname );
[664]3780        return GIET_FAT32_FILE_EXISTS;
[587]3781    }
3782    else if ( code == 1 )   // directory not found => create
3783    {
3784        parent = inode;
[260]3785
[587]3786#if GIET_DEBUG_FAT
3787if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3788_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] create new directory <%s>\n",
[587]3789        x , y , p , pathname );
3790#endif
3791
3792        // get directory name / error check already done by _get_inode_from_path()
3793        char name[32];       
3794        _get_last_name( pathname , name );
3795
[783]3796        // allocate a new inode and an empty Cache-File
3797        child = _allocate_one_inode( name,
3798                                     1,           // it's a directory
3799                                     0xFFFFFFFF,  // cluster index not defined yet
3800                                     0,           // size = 0 for a directory
3801                                     0,           // count
3802                                     0,           // dentry set by _add_dir_entry()
3803                                     1 );         // cache_allocate
3804
3805        // introduce inode in Inode-Tree
3806        _add_inode_in_tree( child , parent );
3807 
3808        // allocate cluster from FAT
[587]3809        unsigned int cluster;
[783]3810        if ( _one_cluster_allocate( inode , &cluster ) )
[587]3811        {
3812            _spin_lock_release( &_fat.fat_lock );
[709]3813            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3814
[664]3815            _printf("\n[FAT ERROR] _fat_mkdir(): no free cluster"
[587]3816                    " for directory <%s>\n" , pathname );
[664]3817            return GIET_FAT32_NO_FREE_SPACE;
[587]3818        }
3819
[783]3820        // update cluster index in inode
3821        child->cluster = cluster;
[587]3822
3823        // allocate and initialise one 4 Kbytes buffer and associated descriptor
3824        _allocate_one_buffer( child,
3825                              0,            // cluster_id,
3826                              cluster );
3827
3828        _add_special_directories( child, 
3829                                  parent );
3830
3831        // add an entry in the parent directory Cache_file
3832        if ( _add_dir_entry( child , parent ) )
3833        { 
3834            _spin_lock_release( &_fat.fat_lock );
[709]3835            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3836
[664]3837            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update parent directory"
[587]3838                    " for directory <%s>\n" , pathname );
[664]3839            return GIET_FAT32_IO_ERROR;
[587]3840        } 
3841
3842        // update DATA region on block device for parent directory
3843        if ( _update_device_from_cache( parent->levels,
3844                                        parent->cache,
3845                                        parent->name ) )
3846        {
3847            _spin_lock_release( &_fat.fat_lock );
[709]3848            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3849
[664]3850            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region "
[587]3851                    " for parent of directory <%s>\n", pathname );
[664]3852            return GIET_FAT32_IO_ERROR;
[587]3853        }
3854
3855        // update FAT region on block device
3856        if ( _update_device_from_cache( _fat.fat_cache_levels,
3857                                        _fat.fat_cache_root,
3858                                        "FAT" ) )
3859        {
3860            _spin_lock_release( &_fat.fat_lock );
[709]3861            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3862
[664]3863            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update FAT region"
[587]3864                    " for directory <%s>\n", pathname );
[664]3865            return GIET_FAT32_IO_ERROR;
[587]3866        }
3867
3868        // update DATA region on block device for the new directory
3869        if ( _update_device_from_cache( child->levels,   
3870                                        child->cache,
3871                                        child->name ) )
3872        {
3873            _spin_lock_release( &_fat.fat_lock );
[709]3874            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3875
[664]3876            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region"
[587]3877                    " for directory <%s>\n", pathname );
[664]3878            return GIET_FAT32_IO_ERROR;
[587]3879        }
3880    }  // end create directory
3881
[606]3882    // release lock
3883    _spin_lock_release( &_fat.fat_lock );
[709]3884    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[606]3885
[664]3886    return GIET_FAT32_OK;
[587]3887}  // end _fat_mkdir()
3888
3889
3890
3891
[773]3892/////////////////////////////////////////
[658]3893extern int _fat_opendir( char* pathname )
3894{
3895    int fd_id = _fat_open( pathname, O_RDONLY );
[587]3896
[658]3897    if ( fd_id < 0 )
3898        return fd_id;
3899
3900    if ( !_fat.fd[fd_id].inode->is_dir )
3901    {
[664]3902        _printf("\n[FAT ERROR] _fat_opendir(): <%s> is not a directory\n",
[658]3903                pathname );
[664]3904        return GIET_FAT32_NOT_A_DIRECTORY;
[658]3905    }
3906
3907    return fd_id;
3908}
3909
3910
3911
3912
[773]3913//////////////////////////////////////////////
[658]3914extern int _fat_closedir( unsigned int fd_id )
3915{
3916    return _fat_close( fd_id );
3917}
3918
3919
3920
3921
[773]3922/////////////////////////////////////////////
[658]3923extern int _fat_readdir( unsigned int  fd_id,
3924                         fat_dirent_t* entry )
3925{
3926    unsigned int  lfn   = 0;            // lfn entries count
3927    unsigned int  attr;                 // ATTR field value
3928    unsigned int  ord;                  // ORD field value
3929    char          lfn1[16];             // temporary buffer for string in LFN1
3930    char          lfn2[16];             // temporary buffer for string in LFN2
3931    char          lfn3[16];             // temporary buffer for string in LFN3
3932    unsigned char buf[DIR_ENTRY_SIZE];  // raw entry buffer
3933    fat_file_info_t info;
3934
3935    // check for directory
3936    int ret = _fat_file_info( fd_id, &info );
3937    if (ret < 0)
3938    {
3939        return ret;
3940    }
3941    else if ( !info.is_dir )
3942    {
[750]3943        _printf("\n[FAT ERROR] in _fat_readdir(): not a directory\n" );
[664]3944        return GIET_FAT32_NOT_A_DIRECTORY;
[658]3945    }
3946
[744]3947
3948#if GIET_DEBUG_FAT
3949unsigned int procid  = _get_procid();
3950unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3951unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3952unsigned int p       = procid & ((1<<P_WIDTH)-1);
3953if ( _get_proctime() > GIET_DEBUG_FAT )
3954_printf("\n[DEBUG FAT] _fat_readdir(): P[%d,%d,%d] enter for <%s>\n",
3955        x , y , p , _fat.fd[fd_id].inode->name );
3956#endif
3957
[658]3958    while ( 1 )
3959    {
[750]3960        if ( _fat_read( fd_id, 
3961                        (unsigned int)&buf, 
3962                        DIR_ENTRY_SIZE,
3963                        0, 0, 0 )  != sizeof(buf) )
[658]3964        {
[750]3965            _printf("\n[FAT ERROR] in _fat_readdir(): can't read entry\n" );
[664]3966            return GIET_FAT32_IO_ERROR;
[658]3967        }
3968
3969        attr = _read_entry( DIR_ATTR, buf, 0 );
3970        ord  = _read_entry( LDIR_ORD, buf, 0 );
3971
3972        if (ord == NO_MORE_ENTRY)               // no more entry in directory => stop
3973        {
3974            // seek back to this entry
[709]3975            _atomic_increment( &_fat.fd[fd_id].seek , -DIR_ENTRY_SIZE );
[658]3976
[664]3977            return GIET_FAT32_NO_MORE_ENTRIES;
[658]3978        }
3979        else if ( ord == FREE_ENTRY )           // free entry => skip
3980        {
3981            continue;
3982        }
3983        else if ( attr == ATTR_LONG_NAME_MASK ) // LFN entry => get partial names
3984        {
3985            unsigned int seq = ord & 0x3;
3986            lfn = (seq > lfn) ? seq : lfn;
3987            if      ( seq == 1 ) _get_name_from_long( buf, lfn1 );
3988            else if ( seq == 2 ) _get_name_from_long( buf, lfn2 );
3989            else if ( seq == 3 ) _get_name_from_long( buf, lfn3 );
3990            continue;
3991        }
3992        else                                    // NORMAL entry => stop
3993        {
3994            break;
3995        }
3996    }
3997
3998    // TODO handle is_vid
3999    entry->cluster = (_read_entry( DIR_FST_CLUS_HI, buf, 1 ) << 16) |
4000                     (_read_entry( DIR_FST_CLUS_LO, buf, 1 )      ) ;
4001    entry->size    = (_read_entry( DIR_FILE_SIZE  , buf, 1 )      ) ;
4002    entry->is_dir  = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
4003
4004    if      ( lfn == 0 )
4005    {
4006        _get_name_from_short( buf, entry->name );
4007    }
4008    else if ( lfn == 1 )
4009    {
4010        _strcpy( entry->name     , lfn1 );
4011    }
4012    else if ( lfn == 2 )
4013    {
4014        _strcpy( entry->name     , lfn1 );
4015        _strcpy( entry->name + 13, lfn2 );
4016    }
4017    else if ( lfn == 3 )
4018    {
4019        _strcpy( entry->name     , lfn1 );
4020        _strcpy( entry->name + 13, lfn2 );
4021        _strcpy( entry->name + 26, lfn3 );
4022    }
4023
[664]4024    return GIET_FAT32_OK;
[750]4025}  // end _fat_readdir()
[658]4026
4027
4028
4029
[773]4030///////////////////////////////////////////////
[587]4031int _fat_load_no_cache( char*        pathname,
4032                        unsigned int buffer_vbase, 
4033                        unsigned int buffer_size ) 
[258]4034{
[674]4035    // checking FAT initialized
4036    if( _fat.initialized != FAT_INITIALIZED )
[587]4037    {
[664]4038        _printf("\n[FAT ERROR] _fat_load_no_cache(): FAT not initialized\n");
4039        return GIET_FAT32_NOT_INITIALIZED;
[587]4040    }
[258]4041
[587]4042    unsigned int  file_size;
4043    unsigned int  cluster;
4044
4045#if GIET_DEBUG_FAT
4046unsigned int procid  = _get_procid();
4047unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
4048unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
4049unsigned int p       = procid & ((1<<P_WIDTH)-1);
4050if ( _get_proctime() > GIET_DEBUG_FAT )
[664]4051_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] enters for file <%s>\n",
[587]4052        x , y , p , pathname );
4053#endif
4054
4055    // get file size, and cluster index in FAT
4056    if ( _file_info_no_cache( pathname,
4057                              &cluster,
4058                              &file_size ) )
4059    {
[664]4060        _printf("\n[FAT ERROR] _fat_load_no_cache(): file <%s> not found\n",
[587]4061        pathname );
[664]4062        return GIET_FAT32_FILE_NOT_FOUND;
[587]4063    }
4064
4065    // check buffer size
4066    if ( file_size > buffer_size )
4067    {
[664]4068        _printf("\n[FAT ERROR] _fat_load_no_cache(): buffer too small : "
[587]4069                "file_size = %x / buffer_size = %x", file_size , buffer_size );
[664]4070        return GIET_FAT32_BUFFER_TOO_SMALL;
[587]4071    }
4072
4073    // compute total number of clusters to read
4074    unsigned int nb_clusters = file_size >> 12;
4075    if ( file_size & 0xFFF ) nb_clusters++;
4076
4077    // initialise buffer address
4078    unsigned int dst = buffer_vbase;
4079
4080    // loop on the clusters containing the file
4081    while ( nb_clusters > 0 )
4082    {
4083        unsigned int lba = _cluster_to_lba( cluster );
4084
4085        if( _fat_ioc_access( 0,         // no descheduling
4086                             1,         // read
4087                             lba, 
4088                             dst, 
4089                             8 ) )      // 8 blocks
4090        {
[664]4091            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot load lba %x", lba );
4092            return GIET_FAT32_IO_ERROR;
[587]4093        }
4094         
4095
4096        // compute next cluster index
4097        unsigned int next;
4098        if ( _next_cluster_no_cache( cluster , &next ) )
4099        {
[664]4100            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot get next cluster "
[587]4101                    " for cluster = %x\n", cluster );
[664]4102            return GIET_FAT32_IO_ERROR;
[587]4103        }
4104       
4105        // update variables for next iteration
4106        nb_clusters = nb_clusters - 1;
4107        dst         = dst + 4096;
4108        cluster     = next;
4109    }
4110         
4111#if GIET_DEBUG_FAT
4112if ( _get_proctime() > GIET_DEBUG_FAT )
[664]4113_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] loaded <%s> at vaddr = %x"
[587]4114        " / size = %x\n", x , y , p , pathname , buffer_vbase , file_size );
4115#endif
4116
[664]4117    return GIET_FAT32_OK;
[587]4118}  // end _fat_load_no_cache()
[258]4119
4120
[587]4121
[761]4122
[773]4123//////////////////////////////////////////////////////////
4124int _get_fat_cache_buffer( unsigned int        cluster_id,
4125                           fat_cache_desc_t**  desc )
4126{
4127    // get cache pointer and number of levels
4128    fat_cache_node_t*   node   = _fat.fat_cache_root;   
4129    unsigned int        level  = _fat.fat_cache_levels; 
4130
4131    if ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > level )
4132    {
4133        _printf("\n[FAT ERROR] in _get_fat_cache_buffer() : "
4134                "cluster_id %d too large", cluster_id );
4135        return GIET_FAT32_IO_ERROR;
4136    }
4137
4138    // search the 64-tree cache from top to bottom
4139    while ( level )
4140    {
4141        // compute child index at each level
4142        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
4143
4144        if ( level == 1 )        // last level => children are buffer descriptors
4145        {
4146            fat_cache_desc_t*   pdesc = (fat_cache_desc_t*)node->children[index];
4147
4148            if ( pdesc == NULL )      // miss
4149            {
4150
4151#if GIET_DEBUG_FAT
4152if ( _get_proctime() > GIET_DEBUG_FAT )
4153_printf("\n[DEBUG FAT] _get_fat_cache_buffer(): miss for cluster_id %d\n", cluster_id );
4154#endif
4155                // compute missing cluster lba
4156                unsigned int lba = _fat.fat_lba + (cluster_id << 3);
4157
4158                // allocate a 4 Kbytes buffer and a buffer descriptor
4159                void* buf      = _malloc( 4096 );
4160                pdesc          = _malloc( sizeof(fat_cache_desc_t) );
4161                pdesc->lba     = lba;
4162                pdesc->buffer  = buf;
4163                pdesc->dirty   = 0;
4164                node->children[index] = pdesc;
4165
4166                // load cluster from device
4167                if ( _fat_ioc_access( 1,         // descheduling
4168                                      1,         // to memory
4169                                      lba,
4170                                      (unsigned int)buf,
4171                                      8 ) )
4172                {
4173                    _free( buf );
4174                    _free( pdesc );
4175                    _printf("\n[FAT ERROR] in _get_fat_cache_buffer() : "
4176                            ": cannot access block device for lba = %x\n", lba );
4177                    return GIET_FAT32_IO_ERROR;
4178                }
4179
4180            }
4181
4182            // return pdesc pointer
4183            *desc = pdesc;
4184
4185            // prepare next iteration
4186            level--;
4187        }
4188        else                      // not last level => children are 64-tree nodes
4189        {
4190            fat_cache_node_t* child = (fat_cache_node_t*)node->children[index];
4191            if ( child == NULL )  // miss
4192            {
4193                // allocate a cache node if miss
4194                child = _allocate_one_cache_node( NULL );
4195                node->children[index] = child;   
4196            }
4197
4198            // prepare next iteration
4199            node = child;
4200            level--;
4201        }
4202    } // end while
4203
4204    return 0;
4205}  // end _get_fat_cache_buffer()
4206
4207
4208
4209
4210//////////////////////////////////////////////////////
[761]4211int _get_file_cache_buffer( fat_inode_t*        inode,
4212                            unsigned int        cluster_id,
4213                            unsigned int        writable,
[750]4214                            fat_cache_desc_t**  desc )
4215{
4216
[773]4217#if GIET_DEBUG_FAT
[750]4218if ( _get_proctime() > GIET_DEBUG_FAT )
[773]4219_printf("\n[DEBUG FAT] _get_file_cache_buffer() : enters in File-Cache <%s>"
[761]4220        " for cluster_id = %d\n size = %x / cache = %x / desc[%d] = %x\n", 
4221        inode->name , cluster_id ,
4222        inode->size , (unsigned int)inode->cache , cluster_id ,
4223        (unsigned int)inode->cache->children[cluster_id] );
[750]4224#endif
[761]4225
4226    // checking FAT initialized
4227    if( _fat.initialized != FAT_INITIALIZED )
4228    {
4229        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : FAT not initialized\n");
4230        return GIET_FAT32_NOT_INITIALIZED;
[750]4231    }
[761]4232
4233    // checking arguments
4234    if ( inode == NULL )   // illegal inode argument
[750]4235    {
[761]4236        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : illegal inode argument\n");
4237        return GIET_FAT32_INVALID_ARG;
4238    }
[750]4239
[761]4240    // add cache levels if needed
4241    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
4242    {
[750]4243
[773]4244#if GIET_DEBUG_FAT
[750]4245if ( _get_proctime() > GIET_DEBUG_FAT )
[761]4246_printf("\n[DEBUG FAT] _get_file_cache_buffer() : add a File-Cache level\n" );
[750]4247#endif
[761]4248
4249        inode->cache = _allocate_one_cache_node( inode->cache );
4250        inode->levels++;
[750]4251    }
4252
[773]4253    // get inode type, size, and File-Cache
4254    unsigned int       size   = inode->size;
4255    unsigned int       is_dir = inode->is_dir;
4256    fat_cache_node_t*  node   = inode->cache; 
4257    unsigned int       level  = inode->levels;
[761]4258
[750]4259    // search the 64-tree cache from top to bottom
4260    while ( level )
4261    {
4262        // compute child index at each level
[761]4263        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
[750]4264
[761]4265        if ( level == 1 )        // last level => children are buffer descriptors
[750]4266        {
[773]4267            fat_cache_desc_t*   pdesc   = (fat_cache_desc_t*)node->children[index];
[761]4268            unsigned int        next    = 0;
4269            unsigned int        prev    = 0;
[773]4270            unsigned int        current;
[761]4271            unsigned int        cid;
4272            unsigned int        lba;
[783]4273            unsigned int        one_cluster_allocated;
[750]4274
[773]4275            // File-Cache miss handling:
4276            // In case of miss, the missing buffer is allocated,
4277            // and the missing cluster is loaded from block device.
4278            // A new cluster is allocated from FAT if required, when
4279            // the writable argument is set.
4280            if ( pdesc == NULL )   
[750]4281            {
4282
[773]4283#if GIET_DEBUG_FAT
[750]4284if ( _get_proctime() > GIET_DEBUG_FAT )
[773]4285_printf("\n[DEBUG FAT] _get_file_cache_buffer() : miss in File-Cache <%s> "
4286        " for cluster_id = %d\n"
4287        " cluster = %x / size = %x / is_dir = %d / cache = %x / desc[%d] = %x\n",
4288        inode->name , cluster_id , inode->cluster , inode->size , inode->is_dir ,
[761]4289        (unsigned int)inode->cache , cluster_id , 
4290        (unsigned int)inode->cache->children[cluster_id] );
[750]4291#endif
[783]4292                // compute one_cluster_allocated condition, depending on file / dir type
4293                if ( is_dir )  one_cluster_allocated = ( cluster_id < is_dir );
4294                else           one_cluster_allocated = ( (cluster_id<<12) < size );
[773]4295
[783]4296                if ( one_cluster_allocated )  // cluster already allocated => allocate buffer
[750]4297                {
[761]4298                    // scan the FAT to find the cluster index for cluster_id
[773]4299                    current = inode->cluster;
[761]4300                    for ( cid = 0 ; cid < cluster_id ; cid++ )
4301                    {
4302                        // get next cluster index from FAT
[750]4303                        if ( _get_fat_entry( current , &next ) ) return 1;
4304                        current = next;
4305                    }
[761]4306
4307                    // compute lba
[750]4308                    lba = _cluster_to_lba( current );
4309
[761]4310                    // allocate a 4 Kbytes buffer and a buffer descriptor
4311                    // the selected heap depends on the calling thread
4312                    void* buf      = _malloc( 4096 );
4313                    pdesc          = _malloc( sizeof(fat_cache_desc_t) );
[750]4314
[761]4315                    // set buffer descriptor
4316                    pdesc->lba     = lba;
4317                    pdesc->buffer  = buf;
4318                    pdesc->dirty   = writable;
4319                    node->children[index] = pdesc;
4320
4321                    // load cluster from device
4322                    if ( _fat_ioc_access( 1,         // descheduling
4323                                          1,         // to memory
4324                                          lba,
4325                                          (unsigned int)buf,
[750]4326                                      8 ) )
[761]4327                    {
4328                         
4329                        _free( buf );
4330                        _free( pdesc );
4331                        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4332                                "cannot access block device for lba = %x\n", lba );
4333                        return GIET_FAT32_IO_ERROR;
4334                    }
4335                }
[773]4336                else if ( writable == 0 ) // not writable and cluster not allocated in FAT
[750]4337                {
[761]4338                    _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4339                            " file size too small for <%s>\n"
4340                            " size = %x / cluster_id = %d / procid = %x\n",
4341                            inode->name , inode->size , cluster_id , _get_procid() );
4342                    return GIET_FAT32_IO_ERROR;
[750]4343                }
[773]4344                else   // writable and cluster NOT allocated in FAT => allocate cluster & buffer
[761]4345                {
4346                    // scan the FAT to allocate all required clusters
[773]4347                    current = inode->cluster;
[761]4348                    for ( cid = 0 ; cid <= cluster_id ; cid++ )
4349                    {
4350                        if ( current >= END_OF_CHAIN_CLUSTER_MIN ) // non allocated
4351                        {
4352                            // allocate one cluster on device
[783]4353                            if ( _one_cluster_allocate( inode , &current ) )
[761]4354                            {
4355                                _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4356                                        "cannot allocate new cluster for file <%s>\n",
4357                                        inode->name );
4358                                return GIET_FAT32_IO_ERROR;
4359                            }
4360                        }
4361 
4362                        // get next cluster index from FAT
4363                        if ( _get_fat_entry( current , &next ) )
4364                        {
4365                            _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4366                                    "cannot get next cluster for file <%s>\n",
4367                                    inode->name );
4368                            return GIET_FAT32_IO_ERROR;
4369                        }
4370                        prev    = current;
4371                        current = next;
4372                    }
[750]4373
[773]4374                    // update size or is_dir attributes in inode
4375                    if ( is_dir )    inode->is_dir = cluster_id;
4376                    else             inode->size   = (cluster_id + 1)<<12;
4377
4378                    // update directory entry from inode
[761]4379                    _update_dir_entry( inode );
[750]4380
[761]4381                    // compute lba
4382                    lba = _cluster_to_lba( current );
4383
4384                    // allocate a 4 Kbytes buffer and a buffer descriptor
4385                    // the selected heap depends on the calling thread
4386                    void* buf      = _malloc( 4096 );
4387                    pdesc          = _malloc( sizeof(fat_cache_desc_t) );
4388
4389                    // set buffer descriptor
4390                    pdesc->lba     = lba;
4391                    pdesc->buffer  = buf;
4392                    pdesc->dirty   = writable;
4393                    node->children[index] = pdesc;
4394                }
[773]4395            }  // end File-Cache miss handling
[750]4396
4397            // return pdesc pointer
4398            *desc = pdesc;
4399
[773]4400#if GIET_DEBUG_FAT
[761]4401if ( _get_proctime() > GIET_DEBUG_FAT )
[773]4402_printf("\n[DEBUG FAT] _get_file_cache_buffer(): found buffer = %x "
[761]4403        " in file <%s> for cluster_id %d\n",
4404        (unsigned int)pdesc->buffer , inode->name , cluster_id );
4405#endif
[750]4406            // prepare next iteration
4407            level--;
4408        }
4409        else                      // not last level => children are 64-tree nodes
4410        {
4411            fat_cache_node_t* child = (fat_cache_node_t*)node->children[index];
4412            if ( child == NULL )  // miss
4413            {
4414                // allocate a cache node if miss
4415                child = _allocate_one_cache_node( NULL );
4416                node->children[index] = child;   
4417            }
4418
4419            // prepare next iteration
4420            node = child;
4421            level--;
4422        }
4423    } // end while
4424
[761]4425    return GIET_FAT32_OK;
[750]4426
[761]4427}  // end _get_file_cache_buffer()
[750]4428
[773]4429
4430
4431
4432
4433
[258]4434// Local Variables:
4435// tab-width: 4
4436// c-basic-offset: 4
4437// c-file-offsets:((innamespace . 0)(inline-open . 0))
4438// indent-tabs-mode: nil
4439// End:
4440// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
4441
Note: See TracBrowser for help on using the repository browser.