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

Last change on this file since 797 was 797, checked in by alain, 8 years ago

Fix a bug in _all_clusters_allocate()

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