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

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

Fix a bug in the O_TRUNC flag used by the giet_fat_open() system call.
Introduce support for the O_APPEND flag for the same system call.

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