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

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

Fix several bugs related to new files or directories creation:

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