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

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

Fix various bugs.

  • Property svn:executable set to *
File size: 150.6 KB
Line 
1/////////////////////////////////////////////////////////////////////////////////
2// Date     : 01/06/2015
3// Authors  : Alain Greiner
4// Copyright (c) UPMC-LIP6
5//////////////////////////////////////////////////////////////////////////////////
6// The fat32.h and fat32.c files define a library of access functions
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.
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
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.
25//////////////////////////////////////////////////////////////////////////////////
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//////////////////////////////////////////////////////////////////////////////////
33
34#include <giet_config.h>
35#include <hard_config.h>
36#include <fat32.h>
37#include <utils.h>
38#include <vmem.h>
39#include <kernel_malloc.h>
40#include <ctx_handler.h>
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>
46#include <tty0.h>
47#include <stdio.h>
48
49//////////////////////////////////////////////////////////////////////////////////
50//               Global variables
51//////////////////////////////////////////////////////////////////////////////////
52
53// Fat-Descriptor
54__attribute__((section(".kdata")))
55fat_desc_t     _fat __attribute__((aligned(64))); 
56
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)));
60
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)));
64
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
81
82static void _display_fat_descriptor();
83
84static void _display_clusters_list();
85
86#endif
87
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
118static unsigned int _set_fs_info();
119
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
139static unsigned int _is_ancestor( fat_inode_t* a,
140                                  fat_inode_t* b);
141
142static unsigned int _get_sfn_name( char*          name,
143                                   unsigned int*  length,
144                                   unsigned int*  nb_lfn,
145                                   char*          sfn,
146                                   unsigned char* checksum );
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
158static unsigned int _one_cluster_allocate( fat_inode_t*   inode, 
159                                           unsigned int*  cluster );
160
161static unsigned int _all_clusters_release( fat_inode_t* inode );
162
163static void _release_cache_memory( fat_cache_node_t*  root,
164                                   unsigned int       levels );
165
166static fat_cache_node_t* _allocate_one_cache_node( fat_cache_node_t* first_child );
167
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
180static unsigned int _get_free_cluster( unsigned int*  cluster );
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
203
204#if GIET_DEBUG_FAT
205/////////////////////////////////////
206static void _display_fat_descriptor()
207{
208    _printf("\n###############  FAT DESCRIPTOR  ################################" 
209            "\nFAT initialized                  %x"
210            "\nBlock Size  (bytes)              %x"
211            "\nCluster Size  (bytes)            %x"
212            "\nFAT region first lba             %x"
213            "\nFAT region size (blocks)         %x"
214            "\nDATA region first lba            %x"
215            "\nDATA region size (blocks)        %x"
216            "\nNumber of free clusters          %x"
217            "\nFirst free cluster index         %x" 
218            "\nFat_cache_levels                 %d" 
219            "\n#################################################################\n",
220            _fat.initialized,
221            _fat.sector_size,
222            _fat.cluster_size,
223            _fat.fat_lba,
224            _fat.fat_sectors,
225            _fat.data_lba,
226            _fat.data_sectors,
227            _fat.free_clusters_number,
228            _fat.free_cluster_hint,
229            _fat.fat_cache_levels );
230
231} // end _display_fat_descriptor()
232#endif
233
234
235#if GIET_DEBUG_FAT
236////////////////////////////////////////////////////////
237static void _display_clusters_list( fat_inode_t* inode )
238{
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 ) 
247    {
248        if ( (current < 2) || (cluster_id >= 1024) ) 
249        {
250            _printf("\n[FAT ERROR] in _display_clusters_list()\n");
251            _exit();
252        }
253
254        _get_fat_entry( current , &next );
255        _printf(" > %X", current );
256        cluster_id++;
257        if ( (cluster_id & 0x7) == 0 ) _printf("\n");
258        current = next;
259    }
260    _printf("\n");
261}  // end _display_clusters_list()
262#endif
263
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
273}
274
275
276
277////////////////////////////////////////////////////////
278static unsigned int _read_entry( unsigned int    offset,
279                                 unsigned int    size,
280                                 unsigned char*  buffer,
281                                 unsigned int    little_endian )
282{
283    unsigned int n;
284    unsigned int res  = 0;
285
286    if ( little_endian)
287    {
288        for( n = size ; n > 0 ; n-- ) res = (res<<8) | buffer[offset+n-1];
289    }
290    else
291    {
292        for( n = 0 ; n < size ; n++ ) res = (res<<8) | buffer[offset+n];
293    }
294    return res;
295
296}  // end _read_entry
297
298
299
300//////////////////////////////////////////////////////////////////
301static inline unsigned int _cluster_to_lba( unsigned int cluster )       
302{
303    if ( cluster < 2 )
304    { 
305        _printf("\n[FAT ERROR] _cluster_to_lba(): cluster smaller than 2\n");
306        _exit();
307    }
308
309   return  ((cluster - 2) << 3) + _fat.data_lba;
310}
311
312
313//////////////////////////////////////////////////////
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//////////////////////////////////////////////////////
322static inline unsigned char _to_upper(unsigned char c)
323{
324   if (c >= 'a' && c <= 'z') return (c & ~(0x20));
325   else                      return c;
326}
327
328
329
330///////////////////////////////////////////////////////////////////////////
331static unsigned int _get_name_from_path( char*          pathname,  // input
332                                         char*          name,      // output
333                                         unsigned int*  nb_read )  // input & output   
334{
335    // skip leading "/" character
336    if ( pathname[*nb_read] == '/' ) *nb_read = *nb_read + 1;
337
338    // initialises current indexes
339    unsigned int i = *nb_read;
340    unsigned int j = 0;
341   
342    while ( (pathname[i] != '/') && (pathname[i] != 0) )
343    {
344        name[j++] = pathname[i++];   
345        if ( j > NAME_MAX_SIZE ) return 1;
346    }
347
348    // set end of string
349    name[j] = 0;
350
351    // skip trailing "/" character
352    if ( pathname[i] == '/' ) *nb_read += j+1;
353    else                      *nb_read += j;
354
355    return 0;
356}
357
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
375////////////////////////////////////////////////////////////////////////////////
376static void _get_name_from_short( unsigned char* buffer,  // input:  SFN dir_entry
377                                  char*          name )   // output: name
378{
379    unsigned int i;
380    unsigned int j = 0;
381
382    // get name
383    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
384    {
385        name[j] = _to_lower( buffer[i] );
386        j++;
387    }
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';
404}
405
406///////////////////////////////////////////////////////////////////////////////
407static void _get_name_from_long( unsigned char*  buffer, // input : LFN dir_entry
408                                 char*           name )  // output : name
409{
410    unsigned int   name_offset         = 0;
411    unsigned int   buffer_offset       = get_length(LDIR_ORD);
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
423    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
424    {
425        while (j != l_name_1 && !eof )
426        {
427            if ( (buffer[buffer_offset] == 0x00) || 
428                 (buffer[buffer_offset] == 0xFF) )
429            {
430                eof = 1;
431                continue;
432            }
433            name[name_offset] = buffer[buffer_offset];
434            buffer_offset += 2;
435            j += 2;
436            name_offset++;
437        }
438
439        buffer_offset += (l_attr + l_type + l_chksum);
440        j = 0;
441
442        while (j != l_name_2 && !eof )
443        {
444            if ( (buffer[buffer_offset] == 0x00) || 
445                 (buffer[buffer_offset] == 0xFF) )
446            {
447                eof = 1;
448                continue;
449            }
450            name[name_offset] = buffer[buffer_offset];
451            buffer_offset += 2;
452            j += 2;
453            name_offset++;
454        }
455
456        buffer_offset += l_rsvd;
457        j = 0;
458
459        while (j != l_name_3 && !eof )
460        {
461            if ( (buffer[buffer_offset] == 0x00) || 
462                 (buffer[buffer_offset] == 0xFF) )
463            {
464                eof = 1;
465                continue;
466            }
467            name[name_offset] = buffer[buffer_offset];
468            buffer_offset += 2;
469            j += 2;
470            name_offset++;
471        }
472    }
473    name[name_offset] = 0;
474} // end get_name_from_long()
475
476
477
478//////////////////////////////////////////////////////////////////////////////////
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;
483
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
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 )
503{
504    fat_inode_t* new_inode  = _malloc( sizeof(fat_inode_t) );
505
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;             
516
517    _strcpy( new_inode->name , name ); 
518
519    if ( cache_allocate )
520    {
521        new_inode->cache    = _allocate_one_cache_node( NULL );
522        new_inode->levels   = _get_levels_from_size( size );
523    }
524
525    return new_inode;
526}   // end _allocate_one_inode()
527
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
550    {
551        inode->parent->child = inode->next;
552    }
553    else                  // removed inode is not the first
554    {
555        for( current = prev->next ; current ; current = current->next )
556        {
557            if ( current == inode )
558            {
559                prev->next = current->next;
560            }
561            prev = current;
562        }   
563    }   
564}  // end _delete_one_inode()
565
566
567
568/////////////////////////////////////////////////////////////////
569static inline unsigned int _get_fat_entry( unsigned int  cluster,
570                                           unsigned int* value )
571{
572    // compute cluster_id & entry_id in FAT from cluster index
573    // a FAT buffer is an array of 1024 unsigned int entries
574    unsigned int       cluster_id = cluster >> 10;       
575    unsigned int       entry_id   = cluster & 0x3FF;
576
577    // get pointer on the relevant buffer descriptor in FAT cache
578    fat_cache_desc_t*  pdesc;
579    unsigned int*      buffer;
580    if ( _get_fat_cache_buffer( cluster_id,
581                                &pdesc ) ) return 1;
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{
596    // compute cluster_id & entry_id in FAT from cluster index
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
601    // get pointer on the relevant buffer descriptor in FAT cache
602    fat_cache_desc_t*  pdesc;
603    unsigned int*      buffer; 
604    if ( _get_fat_cache_buffer( cluster_id,
605                                &pdesc ) )  return 1;           
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{
622
623#if GIET_DEBUG_FAT
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
629    // add cache levels if needed
630    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
631    {
632
633#if GIET_DEBUG_FAT
634if ( _get_proctime() > GIET_DEBUG_FAT )
635_printf("\n[DEBUG FAT] _allocate_one_buffer(): adding a cache level\n" );
636#endif
637
638        inode->cache = _allocate_one_cache_node( inode->cache );
639        inode->levels++;
640    }
641
642    // search the 64-tree cache from top to bottom
643    fat_cache_node_t*  node   = inode->cache;
644    unsigned int       level;
645
646    for ( level = inode->levels; level != 0; level-- )
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];
654
655            if ( pdesc != NULL )      // slot not empty!!!
656            {
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 );
661                _exit();
662            }
663
664#if GIET_DEBUG_FAT
665if ( _get_proctime() > GIET_DEBUG_FAT )
666_printf("\n[DEBUG FAT] _allocate_one_buffer(): buffer allocated to <%s> for cluster_id %d\n",
667        inode->name, cluster_id );
668#endif
669
670            // allocate buffer descriptor
671            pdesc = _malloc( sizeof(fat_cache_desc_t) );
672            pdesc->lba     = _cluster_to_lba( cluster );
673            pdesc->buffer  = _malloc( 4096 );
674            pdesc->dirty   = 1;
675            node->children[index] = pdesc;
676        }
677        else                      // not last level => children are 64-tree nodes
678        {
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
683                child = _allocate_one_cache_node( NULL );
684                node->children[index] = child;   
685            }
686
687            // prepare next iteration
688            node  = child;
689        }
690    } // end for
691} // end _allocate_one_buffer
692
693
694
695
696///////////////////////////////////////////////////////////////////
697static unsigned int _get_free_cluster( unsigned int*  cluster ) 
698{
699    // scan FAT to get next free cluster index
700    unsigned int current = _fat.free_cluster_hint;
701    unsigned int max     = (_fat.data_sectors >> 3);
702    unsigned int value;
703    while ( current < max )
704    {
705        // get FAT entry indexed by current
706        if ( _get_fat_entry( current , &value ) ) return 1;
707
708        // return if free
709        if ( value == FREE_CLUSTER )
710        {
711            *cluster = current;
712            return 0;
713        }
714
715        // increment current
716        current++;
717    }
718       
719    // return error if not found 
720    return 1;
721
722}  // end _get_free_cluster()
723
724
725
726
727//////////////////////////////////////////////////////////////////////////
728static unsigned int _update_device_from_cache( unsigned int        levels,
729                                               fat_cache_node_t*   root,
730                                               char*               string )
731{
732    unsigned int index;
733    unsigned int ret = 0;
734
735    if ( levels == 1 )  // last level => children are buffer descriptors
736    {
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                    {
751                        _printf("\n[FAT_ERROR] _update_device from_cache(): "
752                                " cannot access lba = %x\n", pdesc->lba );
753                        ret = 1;
754                    }
755                    else
756                    {
757                        pdesc->dirty = 0;
758
759#if GIET_DEBUG_FAT
760if ( _get_proctime() > GIET_DEBUG_FAT )
761_printf("\n[DEBUG FAT] _update_device_from_cache(): cluster_id = %d for <%s>\n",
762        index , string );
763#endif
764
765                    }
766                }
767            }
768        }
769    }
770    else               // not the last level = recursive call on each children
771    {
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        }
782    }
783    return ret;
784}  // end _update_device_from_cache()
785
786
787
788///////////////////////////////////////////////////////////////////
789static void _release_cache_memory( fat_cache_node_t*  root,
790                                   unsigned int       levels )
791{
792    unsigned int i;
793
794    if ( levels == 1 )  // last level => children are cluster descriptors
795    {
796        for( i = 0 ; i < 64 ; i++ )
797        { 
798            fat_cache_desc_t* pdesc = root->children[i];
799
800            if ( pdesc != NULL )
801            { 
802                // check dirty
803                if ( pdesc->dirty )
804                    _printf("\n[FAT ERROR] _release_cache_memory(): dirty cluster\n");
805
806                _free( pdesc->buffer );
807                _free( pdesc );
808                root->children[i] = NULL;
809            }
810        }
811    }
812    else               // not the last level = recursive call on each children
813    {
814        for( i = 0 ; i < 64 ; i++ )
815        { 
816            fat_cache_node_t* cnode = root->children[i];
817
818            if ( cnode != NULL )
819            {
820                _release_cache_memory( cnode, levels - 1 );
821                _free( cnode );
822                root->children[i] = NULL;
823            }
824        }
825    }
826}  // end _release_cache_memory()
827
828
829
830
831
832////////////////////////////////////////////////////////////////
833static unsigned int _one_cluster_allocate( fat_inode_t*   inode,
834                                           unsigned int*  cluster ) 
835{
836    // Check free cluster available
837    if ( _fat.free_clusters_number == 0 )
838    {
839        _printf("\n[FAT ERROR] in _one_cluster_allocate(): no more free clusters\n");
840        return 1;
841    }
842
843    // scan the Fat-Cache to get last allocated cluster index
844    unsigned int nb_current_clusters = 0;
845    unsigned int current = inode->cluster;
846    unsigned int last    = current;
847    unsigned int next    = 0;
848    unsigned int new     = 0;
849    while ( current < END_OF_CHAIN_CLUSTER_MIN )
850    {
851        // get next cluster
852        if ( _get_fat_entry( current , &next ) )
853        {
854            _printf("\n[FAT ERROR] in _one_cluster_allocate() scanning FAT\n");
855            return 1;
856        }
857       
858        // increment number of allocated clusters
859        nb_current_clusters++;
860
861        // update loop variables
862        last    = current;
863        current = next;
864    } 
865
866    // allocate one free cluster from FAT
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    }
872
873    // allocate one 4K buffer to File-Cache
874    _allocate_one_buffer( inode,
875                          nb_current_clusters,
876                          new );
877
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
889    if ( nb_current_clusters == 0 )  // first cluster : inode and directory entry
890    {
891        // update inode
892        inode->cluster = new;
893
894        // update directory entry
895        _update_dir_entry( inode );
896    }
897    else                             // update previous last cluster in FAT
898    {
899        if ( _set_fat_entry( last , new ) ) 
900        {
901            _printf("\n[FAT ERROR] in _one_cluster_allocate() accessing FAT\n");
902            return 1;
903        }
904    }
905
906    // update the FAT on device
907    if ( _update_device_from_cache( _fat.fat_cache_levels,
908                                    _fat.fat_cache_root,
909                                    "FAT" ) ) 
910    {
911        _printf("\n[FAT ERROR] in _one_cluster_allocate() updating FAT on device\n");
912        return 1;
913    }
914
915    // update FS-INFO sector on device
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    }
921
922#if GIET_DEBUG_FAT
923if ( _get_proctime() > GIET_DEBUG_FAT )
924_printf("\n[DEBUG FAT] _one_cluster_allocate(): for <%s>\n"
925        " nb_clusters = %d / last_cluster = %x / new_cluster = %x\n",
926        inode->name , nb_current_clusters , last , new );
927#endif
928
929    // returns allocated cluster index
930    *cluster = new;
931    return 0;
932
933}  // end _one_cluster_allocate()
934
935////////////////////////////////////////////////////////////
936static unsigned int _cluster_release( unsigned int cluster )
937{
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        }
952
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        }
963
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;
967
968        return 0;
969    }
970}  // end _cluster_release()
971
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
984    if ( _update_device_from_cache( _fat.fat_cache_levels,
985                                    _fat.fat_cache_root,
986                                    "FAT" ) )
987    {
988        _printf("\n[FAT ERROR] in _all_clusters_release() updating FAT on device\n");
989        return 1;
990    }
991
992    // update FS-INFO sector on device
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    }
998
999#if GIET_DEBUG_FAT
1000if ( _get_proctime() > GIET_DEBUG_FAT )
1001_printf("\n[DEBUG FAT] _all_clusters_release() done for file <%s>\n", inode->name );
1002#endif
1003
1004    return 0;
1005}  // end _all_clusters_release()
1006
1007
1008
1009///////////////////////////////////////////////////////////
1010static void _add_special_directories( fat_inode_t*  child, 
1011                                      fat_inode_t*  parent )
1012{
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;
1016
1017    unsigned int i;
1018    unsigned int cluster;
1019    unsigned int size;
1020
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    }
1041
1042    // set ".." entry (32 bytes)
1043    cluster = parent->cluster;
1044    size    = parent->size;
1045    entry   = pdesc->buffer + 32;
1046
1047    for ( i = 0 ; i < 32 ; i++ )
1048    {
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;
1061    }
1062}  // end _add_special_directories
1063
1064
1065
1066////////////////////////////////////////////////////////////
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////////////////////////////////////////////////////////////
1084static unsigned int _get_sfn_name( char*           name,
1085                                   unsigned int*   length,
1086                                   unsigned int*   nb_lfn,
1087                                   char*           sfn,
1088                                   unsigned char*  checksum )
1089{
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++ )
1100    {
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;
1183        *nb_lfn  = 1;
1184        return 0;
1185    }
1186    else if ( name_length <= 26 )
1187    {
1188        *length  = name_length;
1189        *nb_lfn  = 2;
1190        return 0;
1191    }
1192    else if ( name_length <= 31 )
1193    {
1194        *length  = name_length;
1195        *nb_lfn  = 3;
1196        return 0;
1197    }
1198    else
1199    {
1200        return 1;
1201    }
1202}  // _get_sfn_name()
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 
1227        if ( _get_file_cache_buffer( inode,
1228                                     cluster_id,
1229                                     0,         
1230                                     &pdesc ) )   return 1;
1231        buffer = pdesc->buffer;
1232       
1233        // loop on directory entries in buffer
1234        while ( (offset < 4096) && (found == 0) )
1235        {
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 )
1240            {
1241                found = 1;
1242            } 
1243            else if ( ord == FREE_ENTRY )             // free entry => skip
1244            {
1245                offset = offset + 32;
1246            }
1247            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => skip
1248            {
1249                offset = offset + 32;
1250            }
1251            else                                      // NORMAL entry
1252            {
1253                offset = offset + 32;
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;
1267}  // end _get_nb_entries()
1268
1269
1270
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
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
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, 
1322                             &length,
1323                             &nb_lfn,
1324                             sfn,
1325                             &checksum ) )  return 1;
1326
1327#if GIET_DEBUG_FAT
1328if ( _get_proctime() > GIET_DEBUG_FAT )
1329_printf("\n[DEBUG FAT] _add_dir_entry(): try to add <%s> in <%s> / nb_lfn = %d\n", 
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    {
1345        // get the 4 Kytes buffer from File_Cache 
1346        if ( _get_file_cache_buffer( parent,
1347                                     cluster_id,
1348                                     0,
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 )
1357            {
1358                found        = 1;
1359                pdesc->dirty = 1;
1360            } 
1361            else
1362            {
1363                offset = offset + 32;
1364            }
1365        }  // end loop on entries
1366
1367        if ( found == 0 )
1368        {
1369            cluster_id++;
1370            offset = 0;
1371        }
1372    }  // end loop on clusters
1373
1374#if GIET_DEBUG_FAT
1375if ( _get_proctime() > GIET_DEBUG_FAT )
1376_printf("\n[DEBUG FAT] _add_dir_entry(): get NO_MORE directory entry : "
1377        " buffer = %x / offset = %x / cluster_id = %d\n",
1378        (unsigned int)buffer , offset , cluster_id );
1379#endif
1380
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
1388
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
1405        {
1406            if ( _get_file_cache_buffer( parent,
1407                                         cluster_id + 1,
1408                                         0,
1409                                         &pdesc ) )      return 1;
1410            buffer       = pdesc->buffer;
1411            pdesc->dirty = 1;
1412            offset       = 0;
1413        }
1414
1415        // compute directory entry address
1416        entry = buffer + offset;
1417
1418#if GIET_DEBUG_FAT
1419if ( _get_proctime() > GIET_DEBUG_FAT )
1420_printf("\n[DEBUG FAT] _add_dir_entry(): FSM step = %d /"
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++ )
1432                {
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;
1447                    else if (i == 13)     entry[i] = checksum;
1448                    else                  entry[i] = 0x00;
1449                }
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++ )
1458                {
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;
1473                    else if (i == 13)     entry[i] = checksum;
1474                    else                  entry[i] = 0x00;
1475                }
1476                step--;
1477                break;
1478            }
1479            case 3:   // Write LFN1 entry   
1480            {
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;
1499                    else if (i == 13)     entry[i] = checksum;
1500                    else                  entry[i] = 0x00;
1501                }
1502                step--;
1503                break;
1504            }
1505            case 2:   // write NORMAL entry     
1506            {
1507                // scan the 32 bytes in dir_entry
1508                for ( i = 0 ; i < 32 ; i++ )
1509                {
1510                    if      ( i < 11 )                              // 8.3 SFN
1511                    {
1512                                          entry[i] = sfn[i];
1513                    }
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;
1528                }
1529
1530                // update the dentry field in child inode
1531                child->dentry = ((cluster_id<<12) + offset)>>5;
1532
1533                step--;
1534                break;
1535            }
1536            case 1:   // write NOMORE entry 
1537            {
1538                step--;
1539                entry [0] = 0x00;
1540                break;
1541            }
1542        } // end switch step
1543        offset += 32;
1544    } // exit while => exit FSM   
1545
1546#if GIET_DEBUG_FAT
1547if ( _get_proctime() > GIET_DEBUG_FAT )
1548{
1549    _printf("\n[DEBUG FAT] _add_dir_entry(): <%s> successfully added in <%s>\n",
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;
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;
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
1578    if ( _get_file_cache_buffer( inode->parent,
1579                                 cluster_id,
1580                                 0,
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    {
1591        if (offset == 0)  // we must load buffer for (cluster_id - 1)
1592        {
1593            if ( cluster_id == 0 )
1594                break;
1595
1596            if ( _get_file_cache_buffer( inode->parent,
1597                                         cluster_id - 1,
1598                                         0,
1599                                         &pdesc ) )   return 1;
1600            buffer       = pdesc->buffer;
1601            pdesc->dirty = 1;
1602            offset       = 4096;
1603        }
1604
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
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
1630#if GIET_DEBUG_FAT
1631if ( _get_proctime() > GIET_DEBUG_FAT )
1632_printf("\n[DEBUG FAT] _get_child_from_parent(): search <%s> in directory <%s>\n",
1633        name , parent->name );
1634#endif
1635   
1636    // scan inodes in the parent directory
1637    for ( current = parent->child ; current ; current = current->next )
1638    {
1639        if ( _strcmp( name , current->name ) == 0 )
1640        {
1641
1642#if GIET_DEBUG_FAT
1643if ( _get_proctime() > GIET_DEBUG_FAT )
1644_printf("\n[DEBUG FAT] _get_child_from_parent(): found inode for <%s> in <%s>\n", 
1645        name , parent->name );
1646#endif
1647            *inode = current;
1648            return 0;           // name found
1649        }
1650    }
1651
1652    // not found in Inode-Tree => access the parent directory file_cache.
1653    // Two embedded loops:
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
1667    unsigned int      lfn = 0;          // LFN entries number
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
1673#if GIET_DEBUG_FAT
1674if ( _get_proctime() > GIET_DEBUG_FAT )
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 );
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;
1684        if ( _get_file_cache_buffer( parent,
1685                                     cluster_id,
1686                                     0,
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
1696            if (ord == NO_MORE_ENTRY)                 // no more entry => break
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 )
1717                {
1718                    _get_name_from_short( buffer + offset , cname );
1719                }
1720                else if ( lfn == 1 )
1721                {
1722                    _strcpy( cname      , lfn1 );
1723                }   
1724                else if ( lfn == 2 ) 
1725                {
1726                    _strcpy( cname      , lfn1 );
1727                    _strcpy( cname + 13 , lfn2 );
1728                }
1729                else if ( lfn == 3 ) 
1730                {
1731                    _strcpy( cname      , lfn1 );
1732                    _strcpy( cname + 13 , lfn2 );
1733                    _strcpy( cname + 26 , lfn3 );
1734                }
1735
1736                // get dentry arguments if extracted name == searched name
1737                if ( _strcmp( name , cname ) == 0 )
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;
1748            }
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
1757#if GIET_DEBUG_FAT
1758if ( _get_proctime() > GIET_DEBUG_FAT )
1759_printf("\n[DEBUG FAT] _get_child_from_parent(): found end of directory in <%s>\n",
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
1779#if GIET_DEBUG_FAT
1780if ( _get_proctime() > GIET_DEBUG_FAT )
1781_printf("\n[DEBUG FAT] _get_child_from_parent(): found <%s> on device\n", name );
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
1801#if GIET_DEBUG_FAT
1802if ( _get_proctime() > GIET_DEBUG_FAT )
1803_printf("\n[DEBUG FAT] _get_inode_from_path(): enters for path <%s>\n", pathname );
1804#endif
1805
1806    // handle root directory case
1807    if ( _strcmp( pathname , "/" ) == 0 )
1808    {
1809
1810#if GIET_DEBUG_FAT
1811if ( _get_proctime() > GIET_DEBUG_FAT )
1812_printf("\n[DEBUG FAT] _get_inode_from_path(): found root inode for <%s>\n", 
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   
1827    while ( !last )
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
1833        }
1834
1835        // compute last iteration condition
1836        last = (pathname[nb_read] == 0);
1837
1838#if GIET_DEBUG_FAT
1839if ( _get_proctime() > GIET_DEBUG_FAT )
1840_printf("\n[DEBUG FAT] _get_inode_from_path(): got name <%s>\n", name );
1841#endif
1842
1843        if ( _strcmp( name, ".." ) == 0)
1844        {
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        }
1852        else if ( _strcmp( name, "." ) == 0 )
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 );
1864
1865            // we need to find the child inode for all non terminal names
1866            if ( (code == 2) || ((code == 1 ) && !last) )
1867            {
1868
1869    #if GIET_DEBUG_FAT
1870    if ( _get_proctime() > GIET_DEBUG_FAT )
1871    _printf("\n[DEBUG FAT] _get_inode_from_path(): neither parent, nor child found for <%s>\n",
1872            pathname );
1873    #endif
1874                return 2;  // error : parent inode not found
1875            }
1876        }
1877
1878        // update parent if not the last iteration
1879        if ( !last )
1880            parent = child;
1881    } // end while
1882
1883    // returns inode pointer
1884    if (code == 0 )
1885    {
1886
1887#if GIET_DEBUG_FAT
1888if ( _get_proctime() > GIET_DEBUG_FAT )
1889_printf("\n[DEBUG FAT] _get_inode_from_path(): found inode for <%s>\n", 
1890        pathname );
1891#endif
1892        *inode  = child;
1893    }
1894    else
1895    {
1896
1897#if GIET_DEBUG_FAT
1898if ( _get_proctime() > GIET_DEBUG_FAT )
1899_printf("\n[DEBUG FAT] _get_inode_from_path(): found only parent inode for <%s>\n",
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 )
1914{
1915    // check for root node
1916    if ( !inode->parent ) return 1;
1917
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
1927    if ( _all_clusters_release( inode ) ) return 1;
1928
1929    // release File-Cache
1930    _release_cache_memory( inode->cache, inode->levels );
1931    _free ( inode->cache );
1932
1933    // remove inode from Inode-Tree
1934    _remove_inode_from_tree( inode );
1935
1936    // release inode
1937    _free ( inode );
1938
1939    return 0;
1940}  // end _remove_node_from_fs()
1941
1942
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;
1951
1952    // compute lba of cluster identified by cluster_id
1953    unsigned int lba = _fat.fat_lba + (cluster_id << 3);
1954
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        {
1964            _printf("\n[FAT ERROR] _next_cluster_no_cache(): "
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 )
1986{
1987   
1988#if GIET_DEBUG_FAT
1989if ( _get_proctime() > GIET_DEBUG_FAT )
1990_printf("\n[DEBUG FAT] _file_info_no_cache(): enters for path <%s>\n", pathname );
1991#endif
1992
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
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
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
2006    unsigned int    lfn = 0;              // number of lfn entries
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
2025#if GIET_DEBUG_FAT
2026if ( _get_proctime() > GIET_DEBUG_FAT )
2027_printf("\n[DEBUG FAT] _file_info_no_cache(): search name <%s>"
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                {
2047                    _printf("\n[FAT ERROR] _file_info_no_cache(): "
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
2105                    if ( _strcmp( name , cname ) == 0 )
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        { 
2126            _printf("\n[FAT ERROR] _file_info_no_cache(): <%s> not found\n",
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        {
2135            _printf("\n[FAT ERROR] _file_info_no_cache(): illegal type for <%s>\n", name );
2136            return 1;
2137        }
2138
2139        // update parent_cluster for next name
2140        parent_cluster = child_cluster;
2141
2142    }  // end loop on names
2143
2144#if GIET_DEBUG_FAT
2145if ( _get_proctime() > GIET_DEBUG_FAT )
2146_printf("\n[DEBUG FAT] _file_info_no_cache(): success for <%s> / "
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
2158
2159/////////////////////////////
2160unsigned int _set_fs_info()
2161{
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) )
2180    {
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)  ); 
2184        return 1;
2185    }
2186
2187    _fat.free_clusters_number  = free_clusters;
2188
2189    // initialise <free_cluster_hint> from FS_INFO sector
2190    unsigned int free_cluster_hint = _read_entry( FS_FREE_CLUSTER_HINT, _fat.block_buffer, 1);     
2191    if ( free_cluster_hint > (data_blocks>>3) )
2192    {
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    }
2198
2199    _fat.free_cluster_hint  = free_cluster_hint;
2200
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 )
2219    {
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
2225        {
2226            _printf("\n[FAT_ERROR] _update_fs_info(): cannot read block\n");
2227            return 1;
2228        }
2229        _fat.block_buffer_lba = _fat.fs_info_lba;
2230    }
2231
2232    // update buffer
2233    unsigned int* ptr;
2234
2235    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTERS) );
2236    *ptr = _fat.free_clusters_number;
2237
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
2247    {
2248        _printf("\n[FAT_ERROR] _update_fs_info(): cannot write block\n");
2249        return 1;
2250    }
2251
2252#if GIET_DEBUG_FAT
2253if ( _get_proctime() > GIET_DEBUG_FAT )
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 );
2256#endif
2257
2258    return 0;
2259}  // end _update_fs_info()
2260
2261
2262
2263///////////////////////////////////////////////////////////////////////////////
2264///////////////////////////////////////////////////////////////////////////////
2265//             Extern functions                                               
2266///////////////////////////////////////////////////////////////////////////////
2267///////////////////////////////////////////////////////////////////////////////
2268
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
2289#if (GIET_DEBUG_FAT & 1)
2290if ( _get_proctime() > GIET_DEBUG_FAT )
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 );
2294#endif
2295
2296
2297#if GIET_NO_HARD_CC     // L1 cache inval (virtual addresses)
2298    if ( to_mem ) _dcache_buf_invalidate( buf_vaddr, count<<9 );
2299#endif
2300
2301
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
2316
2317}  // end _fat_ioc_access()
2318
2319
2320
2321/////////////////////////////////////////
2322int _fat_init( unsigned int kernel_mode ) 
2323{
2324
2325#if GIET_DEBUG_FAT
2326if ( _get_proctime() > GIET_DEBUG_FAT )
2327_printf("\n[DEBUG FAT] _fat_init(): enters at cycle %d\n", _get_proctime() );
2328#endif
2329
2330    // FAT initialisation should be done only once
2331    if ( _fat.initialized == FAT_INITIALIZED )
2332    {
2333        _printf("\n[FAT WARNING] _fat_init(): FAT already initialized\n");
2334        return GIET_FAT32_OK;
2335    }
2336
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
2343    {
2344        _printf("\n[FAT ERROR] _fat_init(): cannot load VBR\n");
2345        return GIET_FAT32_IO_ERROR;
2346    }
2347
2348    _fat.block_buffer_lba = 0;
2349   
2350#if GIET_DEBUG_FAT
2351if ( _get_proctime() > GIET_DEBUG_FAT )
2352{
2353    _printf("\n[DEBUG FAT] _fat_init(): Boot sector loaded\n");
2354}
2355#endif
2356
2357    // checking various FAT32 assuptions from boot sector
2358    if( _read_entry( BPB_BYTSPERSEC, _fat.block_buffer, 1 ) != 512 )
2359    {
2360        _printf("\n[FAT ERROR] _fat_init(): The sector size must be 512 bytes\n");
2361        return GIET_FAT32_INVALID_BOOT_SECTOR;
2362    }
2363    if( _read_entry( BPB_SECPERCLUS, _fat.block_buffer, 1 ) != 8 )
2364    {
2365        _printf("\n[FAT ERROR] _fat_init(): The cluster size must be 8 blocks\n");
2366        return GIET_FAT32_INVALID_BOOT_SECTOR;
2367    }
2368    if( _read_entry( BPB_NUMFATS, _fat.block_buffer, 1 ) != 1 )
2369    {
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;
2372    }
2373    if( (_read_entry( BPB_FAT32_FATSZ32, _fat.block_buffer, 1 ) & 0xF) != 0 )
2374    {
2375        _printf("\n[FAT ERROR] _fat_init(): The FAT region must be multiple of 16 sectors\n");
2376        return GIET_FAT32_INVALID_BOOT_SECTOR;
2377    }
2378    if( _read_entry( BPB_FAT32_ROOTCLUS, _fat.block_buffer, 1 ) != 2 )
2379    {
2380        _printf("\n[FAT ERROR] _fat_init(): The root directory must be at cluster 2\n");
2381        return GIET_FAT32_INVALID_BOOT_SECTOR;
2382    }
2383
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;
2390    _fat.data_lba            = _fat.fat_lba + _fat.fat_sectors;
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;
2394    _fat.initialized         = FAT_INITIALIZED;
2395
2396    /////////////////////////////////////////////////////////////////////
2397    // This is done only when the _fat_init() is called in kernel mode
2398
2399    if ( kernel_mode )
2400    {
2401        // initialise <free_clusters_number> and <first_free_cluster in FAT descriptor
2402        if ( _set_fs_info() ) return GIET_FAT32_IO_ERROR;
2403
2404        // create Inode-Tree root
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
2412
2413        // initialize lock
2414        _spin_lock_init( &_fat.fat_lock );
2415
2416        // initialize File Descriptor Array
2417        unsigned int i;
2418        for( i = 0 ; i < GIET_OPEN_FILES_MAX ; i++ ) _fat.fd[i].allocated = 0;
2419
2420        // initialize fat_cache root
2421        _fat.fat_cache_root   = _allocate_one_cache_node( NULL );
2422        _fat.fat_cache_levels = _get_levels_from_size( _fat.fat_sectors << 9 );
2423    }  // end if kernel_mode
2424
2425#if GIET_DEBUG_FAT
2426if ( _get_proctime() > GIET_DEBUG_FAT )
2427_display_fat_descriptor();
2428#endif
2429
2430    return GIET_FAT32_OK;
2431}  // end _fat_init()
2432
2433
2434
2435
2436////////////////////////////////////////////////////////////////////
2437int _fat_open( char*        pathname,     // absolute path from root
2438               unsigned int flags )       // O_CREAT and O_RDONLY
2439{
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
2445   
2446    // get flags
2447    unsigned int create    = ((flags & O_CREAT)  != 0);
2448    unsigned int read_only = ((flags & O_RDONLY) != 0);
2449    unsigned int truncate  = ((flags & O_TRUNC)  != 0);
2450
2451#if GIET_DEBUG_FAT
2452unsigned int procid  = _get_procid();
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);
2456if ( _get_proctime() > GIET_DEBUG_FAT )
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 );
2460#endif
2461
2462    // checking FAT initialized
2463    if( _fat.initialized != FAT_INITIALIZED )
2464    {
2465        _printf("\n[FAT ERROR] _fat_open(): FAT not initialized\n");
2466        return GIET_FAT32_NOT_INITIALIZED;
2467    }
2468
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();
2472    _spin_lock_acquire( &_fat.fat_lock );
2473    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
2474
2475    // get inode pointer
2476    code = _get_inode_from_path( pathname , &inode );
2477
2478    if ( code == 2 )                          // parent inode not found
2479    {
2480        _spin_lock_release( &_fat.fat_lock );
2481        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2482
2483        _printf("\n[FAT ERROR] _fat_open(): path to parent not found"
2484                " for file <%s>\n", pathname );
2485        return GIET_FAT32_FILE_NOT_FOUND;
2486    }
2487    else if ( code == 3 )                     // illegal path name
2488    {
2489        _spin_lock_release( &_fat.fat_lock );
2490        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2491
2492        _printf("\n[FAT ERROR] _fat_open(): one name in path too long"
2493                " for file <%s>\n", pathname );
2494        return GIET_FAT32_NAME_TOO_LONG;
2495    }
2496    else if ( (code == 1) && (create == 0) )   // child inode not found
2497    {
2498        _spin_lock_release( &_fat.fat_lock );
2499        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2500
2501        _printf("\n[FAT ERROR] _fat_open(): file not found"
2502                " for file <%s>\n", pathname );
2503        return GIET_FAT32_FILE_NOT_FOUND;
2504    }
2505    else if ( (code == 1) && (create != 0) )   // child inode not found => create
2506    {
2507        // set parent inode pointer
2508        parent = inode;
2509
2510#if GIET_DEBUG_FAT
2511if ( _get_proctime() > GIET_DEBUG_FAT )
2512_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] create a new file <%s>\n",
2513        x , y , p , pathname );
2514#endif
2515
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
2526                                     0,                         // set by add_dir_entry
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 ) )
2534        {
2535            _spin_lock_release( &_fat.fat_lock );
2536            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2537
2538            _printf("\n[FAT ERROR] _fat_open(): cannot update parent directory"
2539                    " for file <%s>\n" , pathname );
2540            return GIET_FAT32_IO_ERROR;
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 );
2549            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2550
2551            _printf("\n[FAT ERROR] _fat_open(): cannot update DATA region "
2552                    " for parent of file <%s>\n", pathname );
2553            return GIET_FAT32_IO_ERROR;
2554        }
2555
2556        // update FAT region on block device
2557        if ( _update_device_from_cache( _fat.fat_cache_levels,
2558                                        _fat.fat_cache_root,
2559                                        "FAT" ) )
2560        {
2561            _spin_lock_release( &_fat.fat_lock );
2562            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2563
2564            _printf("\n[FAT ERROR] _fat_open(): cannot update FAT region"
2565                    " for file <%s>\n", pathname );
2566            return GIET_FAT32_IO_ERROR;
2567        }
2568
2569        // no need to truncate a new file
2570        truncate = 0;
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]) );
2581    }
2582    else
2583    {
2584         _printf("\n");
2585    }
2586}
2587#endif
2588
2589    }
2590    else                                    // inode found
2591    {
2592        // set searched file inode pointer
2593        child = inode;
2594
2595#if GIET_DEBUG_FAT
2596if ( _get_proctime() > GIET_DEBUG_FAT )
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}
2604#endif
2605
2606    }
2607
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) )
2611    {
2612        fd_id++;
2613    }
2614
2615    // set file descriptor if an empty slot has been found
2616    if ( fd_id >= GIET_OPEN_FILES_MAX )
2617    {
2618        _spin_lock_release( &_fat.fat_lock );
2619        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2620
2621        _printf("\n[FAT ERROR] _fat_open(): File-Descriptors-Array full\n");
2622        return GIET_FAT32_TOO_MANY_OPEN_FILES;
2623    }
2624
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;
2630
2631    // increment the refcount
2632    child->count = child->count + 1;
2633
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
2645        if ( _all_clusters_release( child ) )
2646        {
2647            _spin_lock_release( &_fat.fat_lock );
2648            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2649
2650            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2651            return GIET_FAT32_IO_ERROR;
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 );
2658            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2659
2660            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2661            return GIET_FAT32_IO_ERROR;
2662        }
2663    }
2664
2665#if GIET_DEBUG_FAT
2666if ( _get_proctime() > GIET_DEBUG_FAT )
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 );
2675#endif
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
2681    return fd_id;
2682} // end _fat_open()
2683
2684
2685
2686
2687////////////////////////////////////
2688int _fat_close( unsigned int fd_id )
2689{
2690    // checking FAT initialized
2691    if( _fat.initialized != FAT_INITIALIZED )
2692    {
2693        _printf("\n[FAT ERROR] _fat_close(): FAT not initialized\n");
2694        return GIET_FAT32_NOT_INITIALIZED;
2695    }
2696
2697    if( (fd_id >= GIET_OPEN_FILES_MAX) )
2698    {
2699        _printf("\n[FAT ERROR] _fat_close(): illegal file descriptor index\n");
2700        return GIET_FAT32_INVALID_FD;
2701    } 
2702
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();
2706    _spin_lock_acquire( &_fat.fat_lock );
2707    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
2708
2709    if( _fat.fd[fd_id].allocated == 0 )
2710    {
2711        _spin_lock_release( &_fat.fat_lock );
2712        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2713
2714        _printf("\n[FAT ERROR] _fat_close(): file not open\n");
2715        return GIET_FAT32_NOT_OPEN;
2716    }
2717
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 )
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 );
2726#endif
2727
2728    // decrement reference count
2729    inode->count = inode->count - 1;
2730   
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 ) ) 
2738        {
2739            _spin_lock_release( &_fat.fat_lock );
2740            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2741
2742            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
2743                    "for file <%s>\n", inode->name );
2744            return GIET_FAT32_IO_ERROR;
2745        }
2746
2747#if GIET_DEBUG_FAT
2748if ( _get_proctime() > GIET_DEBUG_FAT )
2749_printf("\n[FAT DEBUG] _fat_close() updated device for file <%s>\n", inode->name );
2750#endif
2751
2752        // update dirty clusters for parent directory
2753        if ( inode->parent &&
2754             _update_device_from_cache( inode->parent->levels,
2755                                        inode->parent->cache,
2756                                        inode->parent->name ) )
2757        {
2758            _spin_lock_release( &_fat.fat_lock );
2759            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2760
2761            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
2762                    "for directory <%s>\n", inode->parent->name );
2763            return GIET_FAT32_IO_ERROR;
2764        }
2765
2766#if GIET_DEBUG_FAT
2767if ( _get_proctime() > GIET_DEBUG_FAT )
2768_printf("\n[FAT DEBUG] _fat_close() updated device for parent directory <%s>\n",
2769        inode->parent->name );
2770#endif
2771
2772        // release memory allocated to File-Cache (keep cache root node)
2773        _release_cache_memory( inode->cache, inode->levels );
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
2781    }  // end if (refcount == 0)
2782
2783
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 );
2789    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2790
2791    return GIET_FAT32_OK;
2792} // end fat_close()
2793
2794
2795
2796
2797////////////////////////////////////////////
2798int _fat_file_info( unsigned int     fd_id,
2799                    fat_file_info_t* info )
2800{
2801    if ( _fat.initialized != FAT_INITIALIZED )
2802    {
2803        _printf("\n[FAT ERROR] _fat_file_info(): FAT not initialized\n");
2804        return GIET_FAT32_NOT_INITIALIZED;
2805    }
2806
2807    if ( fd_id >= GIET_OPEN_FILES_MAX )
2808    {
2809        _printf("\n[FAT ERROR] _fat_file_info(): illegal file descriptor index\n");
2810        return GIET_FAT32_INVALID_FD;
2811    } 
2812
2813    if ( _fat.fd[fd_id].allocated == 0 )
2814    {
2815        _printf("\n[FAT ERROR] _fat_file_info(): file not open\n");
2816        return GIET_FAT32_NOT_OPEN;
2817    }
2818
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
2823    return GIET_FAT32_OK;
2824} // end _fat_file_info()
2825
2826
2827
2828
2829/////////////////////////////////////////////////////////////////////
2830int _fat_read( unsigned int fd_id,          // file descriptor index
2831               unsigned int vaddr,          // destination buffer vaddr
2832               unsigned int count,          // number of bytes to read
2833               unsigned int extend,         // physical address extension
2834               unsigned int offset,         // forced file offset
2835               unsigned int modes )         // special modes
2836{
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"
2845        "  fd = %d / vaddr = %x / bytes = %x / extend = %x / forced_offset = %x\n",
2846        x , y , p , _get_proctime(),
2847        fd_id , vaddr , count , extend , offset );
2848#endif
2849
2850    // checking FAT initialized
2851    if( _fat.initialized != FAT_INITIALIZED )
2852    {
2853        _printf("\n[FAT ERROR] in _fat_read(): FAT not initialized\n");
2854        return GIET_FAT32_NOT_INITIALIZED;
2855    }
2856
2857    // check fd_id overflow
2858    if ( fd_id >= GIET_OPEN_FILES_MAX )
2859    {
2860        _printf("\n[FAT ERROR] in _fat_read(): illegal file descriptor\n");
2861        return GIET_FAT32_INVALID_FD;
2862    }
2863
2864    // check file open
2865    if ( _fat.fd[fd_id].allocated == 0 )
2866    {
2867        _printf("\n[FAT ERROR] in _fat_read(): file not open\n");
2868        return GIET_FAT32_NOT_OPEN;
2869    }
2870
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();
2874    _spin_lock_acquire( &_fat.fat_lock );
2875    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
2876           
2877    // get special modes
2878    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
2879    unsigned int forced_offset       = modes & FAT_FORCED_OFFSET;
2880
2881    // get file inode pointer and offset
2882    fat_inode_t* inode  = _fat.fd[fd_id].inode;
2883    unsigned int seek   = forced_offset ? offset : _fat.fd[fd_id].seek;
2884
2885    // check seek versus file size
2886    if ( (seek >= inode->size) && !inode->is_dir )
2887    {
2888        _spin_lock_release( &_fat.fat_lock );
2889        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2890
2891        _printf("\n[FAT ERROR] in _fat_read(): offset larger than file size"
2892                " / seek = %x / file_size = %x\n",
2893                seek , inode->size );
2894        return GIET_FAT32_IO_ERROR;
2895    }
2896
2897    // check and ajust count argument for a file
2898    if ( (count > (inode->size - seek)) && !inode->is_dir ) count = inode->size - seek;
2899
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;   
2903
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;
2907
2908#if GIET_DEBUG_FAT
2909if ( _get_proctime() > GIET_DEBUG_FAT )
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"
2912        " / last_cluster_id = %x / last_byte_to_move = %x\n",
2913        x , y , p , inode->name , seek ,
2914        first_cluster_id , first_byte_to_move , last_cluster_id , last_byte_to_move );
2915#endif
2916
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++ )
2921    {
2922        // get pointer on the cluster_id buffer in cache
2923        unsigned char*     cbuf;
2924        fat_cache_desc_t*  pdesc;
2925        if ( _get_file_cache_buffer( inode, 
2926                                     cluster_id,
2927                                     0,
2928                                     &pdesc ) )
2929        {
2930            _spin_lock_release( &_fat.fat_lock );
2931            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2932
2933            _printf("\n[FAT ERROR] in _fat_read(): cannot load file <%s>\n",
2934                    inode->name );
2935            return GIET_FAT32_IO_ERROR;
2936        }
2937        cbuf = pdesc->buffer;
2938
2939#if GIET_DEBUG_FAT
2940if ( _get_proctime() > GIET_DEBUG_FAT )
2941_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] moves cluster_id %d from Cache-File <%s>\n",
2942        x , y , p , cluster_id, inode->name );
2943#endif
2944
2945        // compute memcpy arguments
2946        unsigned char*  source;
2947        unsigned int    nbytes;
2948
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
2970        // move data
2971        if ( physical_addressing == 0 )           // no physical addressing
2972        {
2973            char* dest = (char*)(vaddr + done);
2974            memcpy( dest , source , nbytes );
2975        }
2976        else                                      // physical addressing required
2977        {
2978            unsigned int flags;
2979            paddr_t pdest    = (((paddr_t)extend)<<32) + vaddr + done;
2980            paddr_t psource  = _v2p_translate( (unsigned int)source, &flags );
2981            _physical_memcpy( pdest , psource , nbytes );
2982        }
2983
2984        done = done + nbytes;
2985    }
2986
2987#if GIET_DEBUG_FAT
2988if ( _get_proctime() > GIET_DEBUG_FAT )
2989_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] loaded file <%s> from Cache-File\n",
2990        x , y , p , inode->name );
2991#endif
2992
2993    // update seek if required
2994    if ( forced_offset == 0 ) _fat.fd[fd_id].seek += done;
2995
2996    // release lock
2997    _spin_lock_release( &_fat.fat_lock );
2998    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2999
3000    return done;
3001} // end _fat_read()
3002
3003
3004
3005
3006////////////////////////////////////////////////////////////////
3007int _fat_write( unsigned int fd_id,    // file descriptor index
3008                unsigned int vaddr,    // source buffer vaddr
3009                unsigned int count,    // number of bytes to write
3010                unsigned int extend,   // physical address extension
3011                unsigned int modes )   // special modes
3012{
3013    // checking FAT initialized
3014    if( _fat.initialized != FAT_INITIALIZED )
3015    {
3016        _printf("\n[FAT ERROR] _fat_write(): FAT not initialized\n");
3017        return GIET_FAT32_NOT_INITIALIZED;
3018    }
3019
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();
3023    _spin_lock_acquire( &_fat.fat_lock );
3024    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3025
3026           
3027    // check fd_id overflow
3028    if ( fd_id >= GIET_OPEN_FILES_MAX )
3029    {
3030        _spin_lock_release( &_fat.fat_lock );
3031        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3032
3033        _printf("\n[FAT ERROR] _fat_write(): illegal file descriptor\n");
3034        return GIET_FAT32_INVALID_FD;
3035    }
3036
3037    // check file open
3038    if ( _fat.fd[fd_id].allocated == 0 )
3039    {
3040        _spin_lock_release( &_fat.fat_lock );
3041        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3042
3043        _printf("\n[FAT ERROR] _fat_write(): file not open\n" );
3044        return GIET_FAT32_NOT_OPEN;
3045    }
3046
3047    // check file writable
3048    if ( _fat.fd[fd_id].read_only )
3049    {
3050        _spin_lock_release( &_fat.fat_lock );
3051        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3052
3053        _printf("\n[FAT ERROR] _fat_write(): file <%s> is read-only\n",
3054                _fat.fd[fd_id].inode->name );
3055        return GIET_FAT32_READ_ONLY;
3056    }
3057
3058    // get special modes
3059    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
3060
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
3065#if GIET_DEBUG_FAT
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);
3070if ( _get_proctime() > GIET_DEBUG_FAT )
3071_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] enters for file <%s> "
3072        " / bytes = %x / seek = %x\n",
3073        x , y , p , inode->name , count , seek );
3074#endif
3075
3076    // check if file size must be incremented
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 )
3091        {
3092
3093#if GIET_DEBUG_FAT
3094if ( _get_proctime() > GIET_DEBUG_FAT )
3095_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] allocates new clusters for file <%s>"
3096        " / current = %d / required = %d\n",
3097        x , y , p , inode->name , old_clusters , new_clusters );
3098#endif
3099            // allocate missing clusters
3100            unsigned int cid;
3101            unsigned int index;  // unused
3102            for ( cid = 0 ; cid < (new_clusters - old_clusters) ; cid++ )
3103            {
3104                if ( _one_cluster_allocate( inode , &index ) )
3105                {
3106                    _spin_lock_release( &_fat.fat_lock );
3107                    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] ,
3108                                 ~LOCKS_MASK_FAT ); 
3109
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                }
3114            }
3115        }
3116         
3117        // update size in inode
3118        inode->size = new_size;
3119 
3120        // update parent directory entry (size and cluster index)
3121        if ( _update_dir_entry( inode ) )
3122        {
3123            _spin_lock_release( &_fat.fat_lock );
3124            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3125
3126            _printf("\n[FAT ERROR] _fat_write(): cannot update parent directory entry"
3127                    " for file <%s>\n", _fat.fd[fd_id].inode->name );
3128            return GIET_FAT32_IO_ERROR;
3129        }
3130           
3131
3132#if GIET_DEBUG_FAT
3133if ( _get_proctime() > GIET_DEBUG_FAT )
3134_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] updates size for file <%s> / size = %x\n",
3135        x , y , p , inode->name , (new_size - old_size) );
3136#endif
3137
3138    }
3139
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;   
3143
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 )
3150_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] starts loop on clusters for file <%s>\n"
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;
3165        if ( _get_file_cache_buffer( inode,   
3166                                     cluster_id, 
3167                                     0,
3168                                     &pdesc ) )   
3169        {
3170            _spin_lock_release( &_fat.fat_lock );
3171            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3172
3173            _printf("\n[FAT ERROR] _fat_write(): cannot load file <%s>\n",
3174                    inode->name );
3175            return GIET_FAT32_IO_ERROR;
3176        }
3177       
3178        cbuf         = pdesc->buffer;
3179        pdesc->dirty = 1;
3180   
3181#if GIET_DEBUG_FAT
3182if ( _get_proctime() > GIET_DEBUG_FAT )
3183_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] move cluster_id %d to Cache-file <%s>\n",
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
3211        // move data
3212        if ( physical_addressing == 0 )     // no physical addressing
3213        {
3214            char* source = (char*)(vaddr + done);
3215            memcpy( dest , source , nbytes ); 
3216        }
3217        else                                  // physical addressing required
3218        {
3219            unsigned int flags;
3220            paddr_t      psource = (((paddr_t)extend)<<32) + vaddr + done;
3221            paddr_t      pdest   = _v2p_translate( (unsigned int)dest , &flags );
3222            _physical_memcpy( pdest , psource , nbytes );
3223        }
3224
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 )
3234_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] store file <%s> into Cache-File\n",
3235        x , y , p , inode->name );
3236#endif
3237
3238    // release lock
3239    _spin_lock_release( &_fat.fat_lock );
3240    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3241
3242    return done;
3243} // end _fat_write()
3244
3245
3246
3247///////////////////////////////////
3248int _fat_lseek( unsigned int fd_id,
3249                unsigned int seek,
3250                unsigned int whence )
3251{
3252    // checking FAT initialized
3253    if( _fat.initialized != FAT_INITIALIZED )
3254    {
3255        _printf("\n[FAT ERROR] _fat_lseek(): FAT not initialized\n");
3256        return GIET_FAT32_NOT_INITIALIZED;
3257    }
3258
3259    // check fd_id overflow
3260    if ( fd_id >= GIET_OPEN_FILES_MAX )
3261    {
3262        _printf("\n[FAT ERROR] _fat_lseek(): illegal file descriptor\n");
3263        return GIET_FAT32_INVALID_FD;
3264    }
3265
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();
3269    _spin_lock_acquire( &_fat.fat_lock );
3270    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3271
3272
3273    // check file open
3274    if ( _fat.fd[fd_id].allocated == 0 )
3275    {
3276        _spin_lock_release( &_fat.fat_lock );
3277        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3278
3279        _printf("\n[FAT ERROR] _fat_lseek(): file not open\n");
3280        return GIET_FAT32_NOT_OPEN;
3281    }
3282
3283    unsigned int  new_seek;
3284
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;
3288    else if ( whence == SEEK_END ) new_seek = _fat.fd[fd_id].inode->size + seek;
3289    else
3290    {
3291        _spin_lock_release( &_fat.fat_lock );
3292        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3293
3294        _printf("\n[FAT ERROR] _fat_lseek(): illegal whence value\n");
3295        return GIET_FAT32_INVALID_ARG;
3296    }
3297
3298    // update file descriptor offset
3299    _fat.fd[fd_id].seek = new_seek;
3300
3301#if GIET_DEBUG_FAT
3302unsigned int procid  = _get_procid();
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);
3306if ( _get_proctime() > GIET_DEBUG_FAT )
3307_printf("\n[DEBUG FAT] _fat_lseek(): P[%d,%d,%d] set seek = %x for file <%s>\n",
3308        x , y , p , new_seek , _fat.fd[fd_id].inode->name );
3309#endif
3310
3311    // release lock
3312    _spin_lock_release( &_fat.fat_lock );
3313    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3314
3315    return new_seek;
3316}  // end _fat_lseek()
3317
3318
3319
3320///////////////////////////////////////
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 )
3332_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] enters for path <%s>\n",
3333        x, y, p, pathname );
3334#endif
3335
3336    // checking FAT initialized
3337    if( _fat.initialized != FAT_INITIALIZED )
3338    {
3339        _printf("\n[FAT ERROR] _fat_remove(): FAT not initialized\n");
3340        return GIET_FAT32_NOT_INITIALIZED;
3341    }
3342
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();
3346    _spin_lock_acquire( &_fat.fat_lock );
3347    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3348
3349
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 )
3355_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] found inode %x for <%s> / code = %d\n",
3356        x , y , p , (unsigned int)inode , pathname , code );
3357#endif
3358
3359    if ( (code == 1) || (code == 2) )
3360    {
3361        _spin_lock_release( &_fat.fat_lock );
3362        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3363
3364        _printf("\n[FAT ERROR] _fat_remove(): file <%s> not found\n", 
3365                pathname );
3366        return GIET_FAT32_FILE_NOT_FOUND;
3367    }
3368    else if ( code == 3 )
3369    {
3370        _spin_lock_release( &_fat.fat_lock );
3371        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3372
3373        _printf("\n[FAT ERROR] _fat_remove(): name too long in <%s>\n",
3374                pathname );
3375        return GIET_FAT32_NAME_TOO_LONG;
3376    }
3377
3378    // check inode type
3379    if ( (inode->is_dir != 0) && (should_be_dir == 0) ) 
3380    {
3381        _spin_lock_release( &_fat.fat_lock );
3382        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3383
3384        _printf("\n[FAT ERROR] _fat_remove(): <%s> is a directory\n",
3385                pathname );
3386        return GIET_FAT32_IS_DIRECTORY;
3387    }
3388    if ( (inode->is_dir == 0) && (should_be_dir != 0) )
3389    {
3390        _spin_lock_release( &_fat.fat_lock );
3391        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3392
3393        _printf("\n[FAT ERROR] _fat_remove(): <%s> is not a directory\n", 
3394                pathname );
3395        return GIET_FAT32_NOT_A_DIRECTORY;
3396    }
3397
3398#if GIET_DEBUG_FAT
3399if ( _get_proctime() > GIET_DEBUG_FAT )
3400_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked inode type for <%s>\n",
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 );
3408        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3409
3410        _printf("\n[FAT ERROR] _fat_remove(): file <%s> still referenced\n",
3411                pathname );
3412        return GIET_FAT32_IS_OPEN;
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 ) )
3420        {
3421            _spin_lock_release( &_fat.fat_lock );
3422            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3423
3424            _printf("\n[FAT ERROR] _fat_remove(): cannot scan directory <%s>\n", 
3425                    pathname );
3426            return GIET_FAT32_IO_ERROR;
3427        }
3428        else if ( entries > 2 )
3429        {
3430            _spin_lock_release( &_fat.fat_lock );
3431            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3432
3433            _printf("\n[FAT ERROR] _fat_remove(): directory <%s> not empty\n", 
3434                    pathname );
3435            return GIET_FAT32_DIRECTORY_NOT_EMPTY;
3436        }
3437    }
3438
3439#if GIET_DEBUG_FAT
3440if ( _get_proctime() > GIET_DEBUG_FAT )
3441_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked remove condition OK for <%s>\n",
3442        x , y , p , pathname );
3443#endif
3444   
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 );
3449        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3450
3451        _printf("\n[FAT ERROR] _fat_remove(): cannot remove <%s> from FS\n",
3452                pathname );
3453        return GIET_FAT32_IO_ERROR;
3454    }
3455
3456    // release lock and return success
3457    _spin_lock_release( &_fat.fat_lock );
3458    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3459
3460#if GIET_DEBUG_FAT
3461if ( _get_proctime() > GIET_DEBUG_FAT )
3462_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] removed  <%s> from FS\n",
3463        x, y, p, pathname );
3464#endif
3465   
3466    return GIET_FAT32_OK;
3467       
3468}  // end _fat_remove()
3469
3470
3471
3472
3473
3474/////////////////////////////////
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 )
3492_printf("\n[DEBUG FAT] _fat_rename(): P[%d,%d,%d] enters to move <%s> to <%s>\n",
3493        x , y , p , old_path , new_path );
3494#endif
3495
3496    // checking FAT initialized
3497    if( _fat.initialized != FAT_INITIALIZED )
3498    {
3499        _printf("\n[FAT ERROR] _fat_rename(): FAT not initialized\n");
3500        return GIET_FAT32_NOT_INITIALIZED;
3501    }
3502
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();
3506    _spin_lock_acquire( &_fat.fat_lock );
3507    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3508
3509
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 );
3514        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3515
3516        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", old_path );
3517        return GIET_FAT32_FILE_NOT_FOUND;
3518    }
3519    else
3520    {
3521        old        = inode;
3522        old_parent = inode->parent;
3523    }
3524
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
3529    {
3530        if ( inode == old )  // the file will replace itself, do nothing
3531        {
3532            _spin_lock_release( &_fat.fat_lock );
3533            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3534
3535            return GIET_FAT32_OK;
3536        }
3537
3538        to_remove        = inode;
3539        new_parent       = inode->parent;
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 );
3549        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3550
3551        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", new_path );
3552        return GIET_FAT32_FILE_NOT_FOUND;
3553    }
3554
3555    // check for move into own subdirectory
3556    if ( _is_ancestor( old, new_parent ) )
3557    {
3558        _spin_lock_release( &_fat.fat_lock );
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 );
3562        return GIET_FAT32_MOVE_INTO_SUBDIR;
3563    }
3564
3565#if GIET_DEBUG_FAT
3566if ( _get_proctime() > GIET_DEBUG_FAT )
3567{
3568if ( to_remove )
3569_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
3570        "/ to_remove = %s\n",
3571        old_parent->name , old->name , new_parent->name , to_remove->name );
3572else
3573_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
3574        "/ no remove\n", 
3575        old_parent->name , old->name , new_parent->name );
3576}
3577#endif
3578
3579    // check remove condition for "to_remove" inode
3580    if ( to_remove )
3581    {
3582        if ( to_remove->is_dir )   // it's a directory
3583        {
3584            unsigned int entries;
3585            if ( _get_nb_entries( to_remove , &entries ) )
3586            {
3587                _spin_lock_release( &_fat.fat_lock );
3588                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3589
3590                _printf("\n[FAT ERROR] _fat_rename(): cannot scan directory <%s>\n", 
3591                        to_remove->name );
3592                return GIET_FAT32_IO_ERROR;
3593            }
3594            else if ( entries > 2 )
3595            {
3596                _spin_lock_release( &_fat.fat_lock );
3597                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3598
3599                _printf("\n[FAT ERROR] _fat_rename(): directory <%s> not empty\n", 
3600                        to_remove->name );
3601                return GIET_FAT32_DIRECTORY_NOT_EMPTY;
3602            }
3603        }
3604        else                       // it's a file
3605        {
3606            if ( to_remove->count ) 
3607            {
3608                _spin_lock_release( &_fat.fat_lock );
3609                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3610
3611                _printf("\n[FAT ERROR] _fat_rename(): file <%s> still referenced\n", 
3612                        to_remove->name );
3613                return GIET_FAT32_IS_OPEN;
3614            }
3615        }
3616    }
3617
3618#if GIET_DEBUG_FAT
3619if ( _get_proctime() > GIET_DEBUG_FAT )
3620_printf("\n[FAT DEBUG] _fat_rename(): P[%d,%d,%d] checked remove condition OK\n",
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 
3637    // attach the "old" File-Cache to the "new" inode
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 ) )
3643    {
3644        _spin_lock_release( &_fat.fat_lock );
3645        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3646
3647        _printf("\n[FAT ERROR] _fat_rename(): cannot add <%s> into <%s>\n",
3648                new->name , new_parent->name );
3649        return GIET_FAT32_IO_ERROR;
3650    }
3651
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 ) )
3659    {
3660        _spin_lock_release( &_fat.fat_lock );
3661        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3662
3663        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
3664                    new_parent->name );
3665        return GIET_FAT32_IO_ERROR;
3666    }
3667
3668    // remove "old" from "old_parent" File-Cache
3669    if ( _remove_dir_entry( old ) )
3670    {
3671        _spin_lock_release( &_fat.fat_lock );
3672        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3673
3674        _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from <%s>\n",
3675                old->name , old_parent->name );
3676        return GIET_FAT32_IO_ERROR;
3677    }
3678 
3679    // remove "old" inode from Inode-Tree
3680    _remove_inode_from_tree( old );
3681
3682    // release "old" inode
3683    _free( old );
3684
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 );
3691        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3692
3693        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
3694                    old_parent->name );
3695        return GIET_FAT32_IO_ERROR;
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 );
3704            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3705
3706            _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from FS\n",
3707                    to_remove->name );
3708            return GIET_FAT32_IO_ERROR;
3709        }
3710    }
3711
3712    // release lock
3713    _spin_lock_release( &_fat.fat_lock );
3714    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3715
3716    return GIET_FAT32_OK;
3717}  // end _fat_rename()
3718
3719
3720
3721
3722////////////////////////////////
3723int _fat_mkdir( char* pathname )
3724{
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
3728
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 )
3735_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] enters for path <%s>\n",
3736        x, y, p, pathname );
3737#endif
3738
3739    // checking FAT initialized
3740    if( _fat.initialized != FAT_INITIALIZED )
3741    {
3742        _printf("\n[FAT ERROR] _fat_mkdir(): FAT not initialized\n");
3743        return GIET_FAT32_NOT_INITIALIZED;
3744    }
3745
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();
3749    _spin_lock_acquire( &_fat.fat_lock );
3750    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3751
3752    // get inode
3753    unsigned int code = _get_inode_from_path( pathname , &inode );
3754
3755    if ( code == 2 ) 
3756    {
3757        _spin_lock_release( &_fat.fat_lock );
3758        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3759
3760        _printf("\n[FAT ERROR] _fat_mkdir(): path to parent not found"
3761                " for directory <%s>\n", pathname );
3762        return GIET_FAT32_FILE_NOT_FOUND;
3763    }
3764    else if ( code == 3 ) 
3765    {
3766        _spin_lock_release( &_fat.fat_lock );
3767        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3768
3769        _printf("\n[FAT ERROR] _fat_mkdir(): one name in path too long"
3770                " for directory  <%s>\n", pathname );
3771        return GIET_FAT32_NAME_TOO_LONG;
3772    }
3773    else if ( code == 0 )
3774    {
3775        _spin_lock_release( &_fat.fat_lock );
3776        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3777
3778        _printf("\n[FAT ERROR] _fat_mkdir(): directory <%s> already exist\n",
3779                pathname );
3780        return GIET_FAT32_FILE_EXISTS;
3781    }
3782    else if ( code == 1 )   // directory not found => create
3783    {
3784        parent = inode;
3785
3786#if GIET_DEBUG_FAT
3787if ( _get_proctime() > GIET_DEBUG_FAT )
3788_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] create new directory <%s>\n",
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
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
3809        unsigned int cluster;
3810        if ( _one_cluster_allocate( inode , &cluster ) )
3811        {
3812            _spin_lock_release( &_fat.fat_lock );
3813            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3814
3815            _printf("\n[FAT ERROR] _fat_mkdir(): no free cluster"
3816                    " for directory <%s>\n" , pathname );
3817            return GIET_FAT32_NO_FREE_SPACE;
3818        }
3819
3820        // update cluster index in inode
3821        child->cluster = cluster;
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 );
3835            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3836
3837            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update parent directory"
3838                    " for directory <%s>\n" , pathname );
3839            return GIET_FAT32_IO_ERROR;
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 );
3848            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3849
3850            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region "
3851                    " for parent of directory <%s>\n", pathname );
3852            return GIET_FAT32_IO_ERROR;
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 );
3861            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3862
3863            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update FAT region"
3864                    " for directory <%s>\n", pathname );
3865            return GIET_FAT32_IO_ERROR;
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 );
3874            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3875
3876            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region"
3877                    " for directory <%s>\n", pathname );
3878            return GIET_FAT32_IO_ERROR;
3879        }
3880    }  // end create directory
3881
3882    // release lock
3883    _spin_lock_release( &_fat.fat_lock );
3884    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3885
3886    return GIET_FAT32_OK;
3887}  // end _fat_mkdir()
3888
3889
3890
3891
3892/////////////////////////////////////////
3893extern int _fat_opendir( char* pathname )
3894{
3895    int fd_id = _fat_open( pathname, O_RDONLY );
3896
3897    if ( fd_id < 0 )
3898        return fd_id;
3899
3900    if ( !_fat.fd[fd_id].inode->is_dir )
3901    {
3902        _printf("\n[FAT ERROR] _fat_opendir(): <%s> is not a directory\n",
3903                pathname );
3904        return GIET_FAT32_NOT_A_DIRECTORY;
3905    }
3906
3907    return fd_id;
3908}
3909
3910
3911
3912
3913//////////////////////////////////////////////
3914extern int _fat_closedir( unsigned int fd_id )
3915{
3916    return _fat_close( fd_id );
3917}
3918
3919
3920
3921
3922/////////////////////////////////////////////
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    {
3943        _printf("\n[FAT ERROR] in _fat_readdir(): not a directory\n" );
3944        return GIET_FAT32_NOT_A_DIRECTORY;
3945    }
3946
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
3958    while ( 1 )
3959    {
3960        if ( _fat_read( fd_id, 
3961                        (unsigned int)&buf, 
3962                        DIR_ENTRY_SIZE,
3963                        0, 0, 0 )  != sizeof(buf) )
3964        {
3965            _printf("\n[FAT ERROR] in _fat_readdir(): can't read entry\n" );
3966            return GIET_FAT32_IO_ERROR;
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
3975            _atomic_increment( &_fat.fd[fd_id].seek , -DIR_ENTRY_SIZE );
3976
3977            return GIET_FAT32_NO_MORE_ENTRIES;
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
4024    return GIET_FAT32_OK;
4025}  // end _fat_readdir()
4026
4027
4028
4029
4030///////////////////////////////////////////////
4031int _fat_load_no_cache( char*        pathname,
4032                        unsigned int buffer_vbase, 
4033                        unsigned int buffer_size ) 
4034{
4035    // checking FAT initialized
4036    if( _fat.initialized != FAT_INITIALIZED )
4037    {
4038        _printf("\n[FAT ERROR] _fat_load_no_cache(): FAT not initialized\n");
4039        return GIET_FAT32_NOT_INITIALIZED;
4040    }
4041
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 )
4051_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] enters for file <%s>\n",
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    {
4060        _printf("\n[FAT ERROR] _fat_load_no_cache(): file <%s> not found\n",
4061        pathname );
4062        return GIET_FAT32_FILE_NOT_FOUND;
4063    }
4064
4065    // check buffer size
4066    if ( file_size > buffer_size )
4067    {
4068        _printf("\n[FAT ERROR] _fat_load_no_cache(): buffer too small : "
4069                "file_size = %x / buffer_size = %x", file_size , buffer_size );
4070        return GIET_FAT32_BUFFER_TOO_SMALL;
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        {
4091            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot load lba %x", lba );
4092            return GIET_FAT32_IO_ERROR;
4093        }
4094         
4095
4096        // compute next cluster index
4097        unsigned int next;
4098        if ( _next_cluster_no_cache( cluster , &next ) )
4099        {
4100            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot get next cluster "
4101                    " for cluster = %x\n", cluster );
4102            return GIET_FAT32_IO_ERROR;
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 )
4113_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] loaded <%s> at vaddr = %x"
4114        " / size = %x\n", x , y , p , pathname , buffer_vbase , file_size );
4115#endif
4116
4117    return GIET_FAT32_OK;
4118}  // end _fat_load_no_cache()
4119
4120
4121
4122
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//////////////////////////////////////////////////////
4211int _get_file_cache_buffer( fat_inode_t*        inode,
4212                            unsigned int        cluster_id,
4213                            unsigned int        writable,
4214                            fat_cache_desc_t**  desc )
4215{
4216
4217#if GIET_DEBUG_FAT
4218if ( _get_proctime() > GIET_DEBUG_FAT )
4219_printf("\n[DEBUG FAT] _get_file_cache_buffer() : enters in File-Cache <%s>"
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] );
4224#endif
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;
4231    }
4232
4233    // checking arguments
4234    if ( inode == NULL )   // illegal inode argument
4235    {
4236        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : illegal inode argument\n");
4237        return GIET_FAT32_INVALID_ARG;
4238    }
4239
4240    // add cache levels if needed
4241    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
4242    {
4243
4244#if GIET_DEBUG_FAT
4245if ( _get_proctime() > GIET_DEBUG_FAT )
4246_printf("\n[DEBUG FAT] _get_file_cache_buffer() : add a File-Cache level\n" );
4247#endif
4248
4249        inode->cache = _allocate_one_cache_node( inode->cache );
4250        inode->levels++;
4251    }
4252
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;
4258
4259    // search the 64-tree cache from top to bottom
4260    while ( level )
4261    {
4262        // compute child index at each level
4263        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
4264
4265        if ( level == 1 )        // last level => children are buffer descriptors
4266        {
4267            fat_cache_desc_t*   pdesc   = (fat_cache_desc_t*)node->children[index];
4268            unsigned int        next    = 0;
4269            unsigned int        prev    = 0;
4270            unsigned int        current;
4271            unsigned int        cid;
4272            unsigned int        lba;
4273            unsigned int        one_cluster_allocated;
4274
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 )   
4281            {
4282
4283#if GIET_DEBUG_FAT
4284if ( _get_proctime() > GIET_DEBUG_FAT )
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 ,
4289        (unsigned int)inode->cache , cluster_id , 
4290        (unsigned int)inode->cache->children[cluster_id] );
4291#endif
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 );
4295
4296                if ( one_cluster_allocated )  // cluster already allocated => allocate buffer
4297                {
4298                    // scan the FAT to find the cluster index for cluster_id
4299                    current = inode->cluster;
4300                    for ( cid = 0 ; cid < cluster_id ; cid++ )
4301                    {
4302                        // get next cluster index from FAT
4303                        if ( _get_fat_entry( current , &next ) ) return 1;
4304                        current = next;
4305                    }
4306
4307                    // compute lba
4308                    lba = _cluster_to_lba( current );
4309
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) );
4314
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,
4326                                      8 ) )
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                }
4336                else if ( writable == 0 ) // not writable and cluster not allocated in FAT
4337                {
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;
4343                }
4344                else   // writable and cluster NOT allocated in FAT => allocate cluster & buffer
4345                {
4346                    // scan the FAT to allocate all required clusters
4347                    current = inode->cluster;
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
4353                            if ( _one_cluster_allocate( inode , &current ) )
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                    }
4373
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
4379                    _update_dir_entry( inode );
4380
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                }
4395            }  // end File-Cache miss handling
4396
4397            // return pdesc pointer
4398            *desc = pdesc;
4399
4400#if GIET_DEBUG_FAT
4401if ( _get_proctime() > GIET_DEBUG_FAT )
4402_printf("\n[DEBUG FAT] _get_file_cache_buffer(): found buffer = %x "
4403        " in file <%s> for cluster_id %d\n",
4404        (unsigned int)pdesc->buffer , inode->name , cluster_id );
4405#endif
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
4425    return GIET_FAT32_OK;
4426
4427}  // end _get_file_cache_buffer()
4428
4429
4430
4431
4432
4433
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.