source: soft/giet_vm/giet_fat32/fat32.c

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

Introduce the O_WRONLY and O_RDWR flags for the giet_fat_open system call.

  • Property svn:executable set to *
File size: 150.2 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 write_only = ((flags & O_WRONLY) != 0);
2414    unsigned int truncate   = ((flags & O_TRUNC)  != 0);
2415    unsigned int append     = ((flags & O_APPEND) != 0);
2416
2417#if GIET_DEBUG_FAT
2418    unsigned int procid  = _get_procid();
2419    unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
2420    unsigned int y       = (procid >> P_WIDTH) & ((1 << Y_WIDTH) - 1);
2421    unsigned int p       = procid & ((1 << P_WIDTH) - 1);
2422    if ( _get_proctime() > GIET_DEBUG_FAT )
2423        _printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] enters for path <%s>\n"
2424                " create = %d / read_only = %d / truncate = %d\n",
2425                x, y, p, pathname , create , read_only , truncate );
2426#endif
2427
2428    // checking FAT initialized
2429    if ( _fat.initialized != FAT_INITIALIZED )
2430    {
2431        _printf("\n[FAT ERROR] _fat_open(): FAT not initialized\n");
2432        return GIET_FAT32_NOT_INITIALIZED;
2433    }
2434
2435    // takes the FAT lock and register it in thread context
2436    static_scheduler_t*  psched = _get_sched();
2437    unsigned int         ltid   = _get_thread_ltid();
2438    _spin_lock_acquire( &_fat.fat_lock );
2439    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
2440
2441    // get inode pointer
2442    code = _get_inode_from_path( pathname , &inode );
2443
2444    if ( code == 2 )                          // parent inode not found
2445    {
2446        _spin_lock_release( &_fat.fat_lock );
2447        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2448
2449        _printf("\n[FAT ERROR] _fat_open(): path to parent not found"
2450                " for file <%s>\n", pathname );
2451        return GIET_FAT32_FILE_NOT_FOUND;
2452    }
2453    else if ( code == 3 )                     // illegal path name
2454    {
2455        _spin_lock_release( &_fat.fat_lock );
2456        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2457
2458        _printf("\n[FAT ERROR] _fat_open(): one name in path too long"
2459                " for file <%s>\n", pathname );
2460        return GIET_FAT32_NAME_TOO_LONG;
2461    }
2462    else if ( (code == 1) && (create == 0) )   // child inode not found
2463    {
2464        _spin_lock_release( &_fat.fat_lock );
2465        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2466
2467        _printf("\n[FAT ERROR] _fat_open(): file not found"
2468                " for file <%s>\n", pathname );
2469        return GIET_FAT32_FILE_NOT_FOUND;
2470    }
2471    else if ( (code == 1) && (create != 0) )   // child inode not found => create
2472    {
2473        // set parent inode pointer
2474        parent = inode;
2475
2476#if GIET_DEBUG_FAT
2477        if ( _get_proctime() > GIET_DEBUG_FAT )
2478            _printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] create a new file <%s>\n",
2479                    x , y , p , pathname );
2480#endif
2481
2482        // get new file name / error check already done by _get_inode_from_path()
2483        char name[32];       
2484        _get_last_name( pathname , name );
2485
2486        // allocate a new inode and an empty Cache-File
2487        child = _allocate_one_inode( name,
2488                                     0,                         // not a directory
2489                                     END_OF_CHAIN_CLUSTER_MAX,  // no cluster allocated
2490                                     0,                         // size : new file is empty
2491                                     0,                         // count incremented later
2492                                     0,                         // set by add_dir_entry
2493                                     1 );                       // cache_allocate
2494
2495        // introduce inode into Inode-Tree
2496        _add_inode_in_tree( child , parent );
2497
2498        // add an entry in the parent directory Cache_file
2499        // and update the dentry field in child inode
2500        if ( _add_dir_entry( child ) )
2501        {
2502            _spin_lock_release( &_fat.fat_lock );
2503            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2504
2505            _printf("\n[FAT ERROR] _fat_open(): cannot update parent directory"
2506                    " for file <%s>\n" , pathname );
2507            return GIET_FAT32_IO_ERROR;
2508        } 
2509
2510        // update DATA region on block device for parent directory
2511        if ( _update_device_from_cache( parent->levels,
2512                                        parent->cache,
2513                                        parent->name ) )
2514        {
2515            _spin_lock_release( &_fat.fat_lock );
2516            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2517
2518            _printf("\n[FAT ERROR] _fat_open(): cannot update DATA region "
2519                    " for parent of file <%s>\n", pathname );
2520            return GIET_FAT32_IO_ERROR;
2521        }
2522
2523        // update FAT region on block device
2524        if ( _update_device_from_cache( _fat.fat_cache_levels,
2525                                        _fat.fat_cache_root,
2526                                        "FAT" ) )
2527        {
2528            _spin_lock_release( &_fat.fat_lock );
2529            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2530
2531            _printf("\n[FAT ERROR] _fat_open(): cannot update FAT region"
2532                    " for file <%s>\n", pathname );
2533            return GIET_FAT32_IO_ERROR;
2534        }
2535
2536        // no need to truncate a new file
2537        truncate = 0;
2538
2539#if GIET_DEBUG_FAT
2540        if ( _get_proctime() > GIET_DEBUG_FAT )
2541        {
2542            _printf("\n[DEBUG FAT] _fat_open() : new inode created for <%s>\n" 
2543                    " size = %x / cluster = %x / cache = %x",
2544                    child->name , child->size , child->cluster , child->cache );
2545            if ( child->cache != NULL )
2546            {
2547                _printf(" / pdesc[0] = %x\n", (unsigned int)(child->cache->children[0]) );
2548            }
2549            else
2550            {
2551                _printf("\n");
2552            }
2553        }
2554#endif
2555
2556    }
2557    else                                    // inode found
2558    {
2559        // set searched file inode pointer
2560        child = inode;
2561
2562#if GIET_DEBUG_FAT
2563        if ( _get_proctime() > GIET_DEBUG_FAT )
2564        {
2565            _printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] found file <%s>\n"
2566                    " inode = %x / size = %x\n",
2567                    x , y , p , pathname , (unsigned int)child , child->size );
2568
2569            _display_clusters_list( child );
2570        }
2571#endif
2572
2573    }
2574
2575    // Search an empty slot in file descriptors array
2576    fd_id = 0;
2577    while ( (_fat.fd[fd_id].allocated) != 0 && (fd_id < GIET_OPEN_FILES_MAX) )
2578    {
2579        fd_id++;
2580    }
2581
2582    // check if an empty slot has been found
2583    if ( fd_id >= GIET_OPEN_FILES_MAX )
2584    {
2585        _spin_lock_release( &_fat.fat_lock );
2586        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2587
2588        _printf("\n[FAT ERROR] _fat_open(): File-Descriptors-Array full\n");
2589        return GIET_FAT32_TOO_MANY_OPEN_FILES;
2590    }
2591
2592    // truncate the file if requested
2593    if ( truncate && !read_only && !child->is_dir && child->size != 0 )
2594    {
2595        // release File-Cache (keep root node)
2596        _release_cache_memory( child->cache, child->levels );
2597
2598        // release clusters allocated to file/dir in DATA region
2599        if ( _all_clusters_release( child ) )
2600        {
2601            _spin_lock_release( &_fat.fat_lock );
2602            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2603
2604            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2605            return GIET_FAT32_IO_ERROR;
2606        }
2607
2608        // update parent directory entry (size and cluster index)
2609        if ( _update_dir_entry( child ) )
2610        {
2611            _spin_lock_release( &_fat.fat_lock );
2612            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2613
2614            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2615            return GIET_FAT32_IO_ERROR;
2616        }
2617
2618        // update inode
2619        child->size   = 0;
2620        child->levels = 1;
2621    }
2622
2623    // update file descriptor
2624    _fat.fd[fd_id].allocated  = 1;
2625    _fat.fd[fd_id].read_only  = read_only;
2626    _fat.fd[fd_id].write_only = write_only;
2627    _fat.fd[fd_id].inode      = child;
2628    _fat.fd[fd_id].seek       = ( append ) ? child->size : 0;
2629
2630    // increment the refcount
2631    child->count = child->count + 1;
2632
2633#if GIET_DEBUG_FAT
2634    if ( _get_proctime() > GIET_DEBUG_FAT )
2635        _printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] get fd = %d for <%s>\n"
2636                " inode = %x / offset = %x / read_only = %d / size = %x / cluster = %x\n",
2637                x , y , p , fd_id , pathname , 
2638                (unsigned int)_fat.fd[fd_id].inode,
2639                _fat.fd[fd_id].seek,
2640                _fat.fd[fd_id].read_only,
2641                _fat.fd[fd_id].inode->size,
2642                _fat.fd[fd_id].inode->cluster );
2643#endif
2644
2645    // releases the lock
2646    _spin_lock_release( &_fat.fat_lock );
2647    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2648
2649    return fd_id;
2650} // end _fat_open()
2651
2652
2653
2654
2655////////////////////////////////////
2656int _fat_close( unsigned int fd_id )
2657{
2658    // checking FAT initialized
2659    if( _fat.initialized != FAT_INITIALIZED )
2660    {
2661        _printf("\n[FAT ERROR] _fat_close(): FAT not initialized\n");
2662        return GIET_FAT32_NOT_INITIALIZED;
2663    }
2664
2665    if( (fd_id >= GIET_OPEN_FILES_MAX) )
2666    {
2667        _printf("\n[FAT ERROR] _fat_close(): illegal file descriptor index\n");
2668        return GIET_FAT32_INVALID_FD;
2669    } 
2670
2671    // takes the FAT lock and register it in thread context
2672    static_scheduler_t*  psched = _get_sched();
2673    unsigned int         ltid   = _get_thread_ltid();
2674    _spin_lock_acquire( &_fat.fat_lock );
2675    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
2676
2677    if( _fat.fd[fd_id].allocated == 0 )
2678    {
2679        _spin_lock_release( &_fat.fat_lock );
2680        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2681
2682        _printf("\n[FAT ERROR] _fat_close(): file not open\n");
2683        return GIET_FAT32_NOT_OPEN;
2684    }
2685
2686    // get the inode pointer
2687    fat_inode_t*  inode = _fat.fd[fd_id].inode;
2688
2689#if GIET_DEBUG_FAT
2690if ( _get_proctime() > GIET_DEBUG_FAT )
2691_printf("\n[FAT DEBUG] _fat_close() for file <%s> : refcount = %d"
2692        " / size = %x / cluster = %x\n",
2693        inode->name , inode->count , inode->size , inode->cluster );
2694#endif
2695
2696    // decrement reference count
2697    inode->count = inode->count - 1;
2698   
2699    // update block device and release File-Cache if no more references
2700    if ( inode->count == 0 )
2701    {
2702        // update all dirty clusters for closed file
2703        if ( _update_device_from_cache( inode->levels, 
2704                                        inode->cache,
2705                                        inode->name ) ) 
2706        {
2707            _spin_lock_release( &_fat.fat_lock );
2708            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2709
2710            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
2711                    "for file <%s>\n", inode->name );
2712            return GIET_FAT32_IO_ERROR;
2713        }
2714
2715#if GIET_DEBUG_FAT
2716if ( _get_proctime() > GIET_DEBUG_FAT )
2717_printf("\n[FAT DEBUG] _fat_close() updated device for file <%s>\n", inode->name );
2718#endif
2719
2720        // update dirty clusters for parent directory
2721        if ( inode->parent &&
2722             _update_device_from_cache( inode->parent->levels,
2723                                        inode->parent->cache,
2724                                        inode->parent->name ) )
2725        {
2726            _spin_lock_release( &_fat.fat_lock );
2727            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2728
2729            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
2730                    "for directory <%s>\n", inode->parent->name );
2731            return GIET_FAT32_IO_ERROR;
2732        }
2733
2734#if GIET_DEBUG_FAT
2735if ( _get_proctime() > GIET_DEBUG_FAT )
2736_printf("\n[FAT DEBUG] _fat_close() updated device for parent directory <%s>\n",
2737        inode->parent->name );
2738#endif
2739
2740        // release memory allocated to File-Cache (keep cache root node)
2741        _release_cache_memory( inode->cache, inode->levels );
2742
2743#if GIET_DEBUG_FAT
2744if ( _get_proctime() > GIET_DEBUG_FAT )
2745_printf("\n[FAT DEBUG] _fat_close() release memory for File-Cache <%s>\n",
2746        inode->name );
2747#endif
2748
2749    }  // end if (refcount == 0)
2750
2751
2752    // release fd_id entry in file descriptor array
2753    _fat.fd[fd_id].allocated = 0;
2754
2755    // release lock
2756    _spin_lock_release( &_fat.fat_lock );
2757    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2758
2759    return GIET_FAT32_OK;
2760} // end fat_close()
2761
2762
2763
2764
2765////////////////////////////////////////////
2766int _fat_file_info( unsigned int     fd_id,
2767                    fat_file_info_t* info )
2768{
2769    if ( _fat.initialized != FAT_INITIALIZED )
2770    {
2771        _printf("\n[FAT ERROR] _fat_file_info(): FAT not initialized\n");
2772        return GIET_FAT32_NOT_INITIALIZED;
2773    }
2774
2775    if ( fd_id >= GIET_OPEN_FILES_MAX )
2776    {
2777        _printf("\n[FAT ERROR] _fat_file_info(): illegal file descriptor index\n");
2778        return GIET_FAT32_INVALID_FD;
2779    } 
2780
2781    if ( _fat.fd[fd_id].allocated == 0 )
2782    {
2783        _printf("\n[FAT ERROR] _fat_file_info(): file not open\n");
2784        return GIET_FAT32_NOT_OPEN;
2785    }
2786
2787    info->size   = _fat.fd[fd_id].inode->size;
2788    info->offset = _fat.fd[fd_id].seek;
2789    info->is_dir = _fat.fd[fd_id].inode->is_dir;
2790
2791    return GIET_FAT32_OK;
2792} // end _fat_file_info()
2793
2794
2795
2796
2797/////////////////////////////////////////////////////////////////////
2798int _fat_read( unsigned int fd_id,          // file descriptor index
2799               unsigned int vaddr,          // destination buffer vaddr
2800               unsigned int count,          // number of bytes to read
2801               unsigned int extend,         // physical address extension
2802               unsigned int offset,         // forced file offset
2803               unsigned int modes )         // special modes
2804{
2805
2806#if GIET_DEBUG_FAT
2807unsigned int procid  = _get_procid();
2808unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
2809unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
2810unsigned int p       = procid & ((1<<P_WIDTH)-1);
2811if ( _get_proctime() > GIET_DEBUG_FAT )
2812_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] enters at cycle %d\n"
2813        "  fd = %d / vaddr = %x / bytes = %x / extend = %x / forced_offset = %x\n",
2814        x , y , p , _get_proctime(),
2815        fd_id , vaddr , count , extend , offset );
2816#endif
2817
2818    // checking FAT initialized
2819    if( _fat.initialized != FAT_INITIALIZED )
2820    {
2821        _printf("\n[FAT ERROR] in _fat_read(): FAT not initialized\n");
2822        return GIET_FAT32_NOT_INITIALIZED;
2823    }
2824
2825    // takes the FAT lock and register it in thread context
2826    static_scheduler_t*  psched = _get_sched();
2827    unsigned int         ltid   = _get_thread_ltid();
2828    _spin_lock_acquire( &_fat.fat_lock );
2829    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
2830           
2831    // check fd_id overflow
2832    if ( fd_id >= GIET_OPEN_FILES_MAX )
2833    {
2834        _spin_lock_release( &_fat.fat_lock );
2835        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2836
2837        _printf("\n[FAT ERROR] in _fat_read(): illegal file descriptor\n");
2838        return GIET_FAT32_INVALID_FD;
2839    }
2840
2841    // check file open
2842    if ( _fat.fd[fd_id].allocated == 0 )
2843    {
2844        _spin_lock_release( &_fat.fat_lock );
2845        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2846
2847        _printf("\n[FAT ERROR] in _fat_read(): file not open\n");
2848        return GIET_FAT32_NOT_OPEN;
2849    }
2850
2851    // check file readable
2852    if ( _fat.fd[fd_id].write_only )
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] _fat_read(): file <%s> is write-only\n",
2858                _fat.fd[fd_id].inode->name );
2859        return GIET_FAT32_WRITE_ONLY;
2860    }
2861
2862    // get special modes
2863    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
2864    unsigned int forced_offset       = modes & FAT_FORCED_OFFSET;
2865
2866    // get file inode pointer and offset
2867    fat_inode_t* inode  = _fat.fd[fd_id].inode;
2868    unsigned int seek   = forced_offset ? offset : _fat.fd[fd_id].seek;
2869
2870    // check seek versus file size
2871    if ( (seek >= inode->size) && !inode->is_dir )
2872    {
2873        _spin_lock_release( &_fat.fat_lock );
2874        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2875
2876        _printf("\n[FAT ERROR] in _fat_read(): offset larger than file size"
2877                " / seek = %x / file_size = %x\n",
2878                seek , inode->size );
2879        return GIET_FAT32_IO_ERROR;
2880    }
2881
2882    // check and ajust count argument for a file
2883    if ( (count > (inode->size - seek)) && !inode->is_dir ) count = inode->size - seek;
2884
2885    // compute first_cluster_id and first_byte_to_move
2886    unsigned int first_cluster_id   = seek >> 12;
2887    unsigned int first_byte_to_move = seek & 0xFFF;   
2888
2889    // compute last_cluster and last_byte_to_move
2890    unsigned int last_cluster_id   = (seek + count - 1) >> 12;   
2891    unsigned int last_byte_to_move = (seek + count - 1) & 0xFFF;
2892
2893#if GIET_DEBUG_FAT
2894if ( _get_proctime() > GIET_DEBUG_FAT )
2895_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] search file <%s> with seek = %x\n "
2896        " first_cluster_id = %x / first_byte_to_move = %x"
2897        " / last_cluster_id = %x / last_byte_to_move = %x\n",
2898        x , y , p , inode->name , seek ,
2899        first_cluster_id , first_byte_to_move , last_cluster_id , last_byte_to_move );
2900#endif
2901
2902    // loop on all cluster covering the requested transfer
2903    unsigned int cluster_id;
2904    unsigned int done = 0;
2905    for ( cluster_id = first_cluster_id ; cluster_id <= last_cluster_id ; cluster_id++ )
2906    {
2907        // get pointer on the cluster_id buffer in cache
2908        unsigned char*     cbuf;
2909        fat_cache_desc_t*  pdesc;
2910        if ( _get_file_cache_buffer( inode, 
2911                                     cluster_id,
2912                                     0,
2913                                     &pdesc ) )
2914        {
2915            _spin_lock_release( &_fat.fat_lock );
2916            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2917
2918            _printf("\n[FAT ERROR] in _fat_read(): cannot load file <%s>\n",
2919                    inode->name );
2920            return GIET_FAT32_IO_ERROR;
2921        }
2922        cbuf = pdesc->buffer;
2923
2924#if GIET_DEBUG_FAT
2925if ( _get_proctime() > GIET_DEBUG_FAT )
2926_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] moves cluster_id %d from Cache-File <%s>\n",
2927        x , y , p , cluster_id, inode->name );
2928#endif
2929
2930        // compute memcpy arguments
2931        unsigned char*  source;
2932        unsigned int    nbytes;
2933
2934        if ( (cluster_id == first_cluster_id) && (cluster_id == last_cluster_id) )
2935        {
2936            source = cbuf + first_byte_to_move; 
2937            nbytes = last_byte_to_move - first_byte_to_move + 1;
2938        }
2939        else if ( cluster_id == first_cluster_id )
2940        {
2941            source = cbuf + first_byte_to_move; 
2942            nbytes = 4096 - first_byte_to_move;
2943        }
2944        else if ( cluster_id == last_cluster_id )
2945        {
2946            source = cbuf; 
2947            nbytes = last_byte_to_move + 1;
2948        }
2949        else  // not first / not last
2950        {
2951            source = cbuf; 
2952            nbytes = 4096;
2953        }
2954
2955        // move data
2956        if ( physical_addressing == 0 )           // no physical addressing
2957        {
2958            char* dest = (char*)(vaddr + done);
2959            memcpy( dest , source , nbytes );
2960        }
2961        else                                      // physical addressing required
2962        {
2963            unsigned int flags;
2964            paddr_t pdest    = (((paddr_t)extend)<<32) + vaddr + done;
2965            paddr_t psource  = _v2p_translate( (unsigned int)source, &flags );
2966            _physical_memcpy( pdest , psource , nbytes );
2967        }
2968
2969        done = done + nbytes;
2970    }
2971
2972#if GIET_DEBUG_FAT
2973if ( _get_proctime() > GIET_DEBUG_FAT )
2974_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] loaded file <%s> from Cache-File\n",
2975        x , y , p , inode->name );
2976#endif
2977
2978    // update seek if required
2979    if ( forced_offset == 0 ) _fat.fd[fd_id].seek += done;
2980
2981    // release lock
2982    _spin_lock_release( &_fat.fat_lock );
2983    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2984
2985    return done;
2986} // end _fat_read()
2987
2988
2989
2990
2991////////////////////////////////////////////////////////////////
2992int _fat_write( unsigned int fd_id,    // file descriptor index
2993                unsigned int vaddr,    // source buffer vaddr
2994                unsigned int count,    // number of bytes to write
2995                unsigned int extend,   // physical address extension
2996                unsigned int modes )   // special modes
2997{
2998    // checking FAT initialized
2999    if( _fat.initialized != FAT_INITIALIZED )
3000    {
3001        _printf("\n[FAT ERROR] _fat_write(): FAT not initialized\n");
3002        return GIET_FAT32_NOT_INITIALIZED;
3003    }
3004
3005    // takes the FAT lock and register it in thread context
3006    static_scheduler_t*  psched = _get_sched();
3007    unsigned int         ltid   = _get_thread_ltid();
3008    _spin_lock_acquire( &_fat.fat_lock );
3009    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3010
3011           
3012    // check fd_id overflow
3013    if ( fd_id >= GIET_OPEN_FILES_MAX )
3014    {
3015        _spin_lock_release( &_fat.fat_lock );
3016        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3017
3018        _printf("\n[FAT ERROR] _fat_write(): illegal file descriptor\n");
3019        return GIET_FAT32_INVALID_FD;
3020    }
3021
3022    // check file open
3023    if ( _fat.fd[fd_id].allocated == 0 )
3024    {
3025        _spin_lock_release( &_fat.fat_lock );
3026        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3027
3028        _printf("\n[FAT ERROR] _fat_write(): file not open\n" );
3029        return GIET_FAT32_NOT_OPEN;
3030    }
3031
3032    // check file writable
3033    if ( _fat.fd[fd_id].read_only )
3034    {
3035        _spin_lock_release( &_fat.fat_lock );
3036        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3037
3038        _printf("\n[FAT ERROR] _fat_write(): file <%s> is read-only\n",
3039                _fat.fd[fd_id].inode->name );
3040        return GIET_FAT32_READ_ONLY;
3041    }
3042
3043    // get special modes
3044    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
3045
3046    // get file inode pointer and seek
3047    fat_inode_t* inode  = _fat.fd[fd_id].inode;
3048    unsigned int seek   = _fat.fd[fd_id].seek;
3049
3050#if GIET_DEBUG_FAT
3051unsigned int procid  = _get_procid();
3052unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3053unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3054unsigned int p       = procid & ((1<<P_WIDTH)-1);
3055if ( _get_proctime() > GIET_DEBUG_FAT )
3056_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] enters for file <%s> "
3057        " / bytes = %x / seek = %x\n",
3058        x , y , p , inode->name , count , seek );
3059#endif
3060
3061    // check if file size must be incremented
3062    // and allocate new clusters from FAT if required
3063    unsigned int old_size = inode->size;
3064    unsigned int new_size = seek + count;
3065    if ( new_size > old_size )
3066    {
3067        // compute current and required numbers of clusters
3068        unsigned old_clusters = old_size >> 12;
3069        if ( old_size & 0xFFF ) old_clusters++;
3070
3071        unsigned new_clusters = new_size >> 12;
3072        if ( new_size & 0xFFF ) new_clusters++;
3073
3074        // allocate new clusters from FAT if required
3075        if ( new_clusters > old_clusters )
3076        {
3077
3078#if GIET_DEBUG_FAT
3079if ( _get_proctime() > GIET_DEBUG_FAT )
3080_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] allocates new clusters for file <%s>"
3081        " / current = %d / required = %d\n",
3082        x , y , p , inode->name , old_clusters , new_clusters );
3083#endif
3084            // allocate missing clusters
3085            unsigned int cid;
3086            unsigned int index;  // unused
3087            for ( cid = 0 ; cid < (new_clusters - old_clusters) ; cid++ )
3088            {
3089                if ( _one_cluster_allocate( inode , &index ) )
3090                {
3091                    _spin_lock_release( &_fat.fat_lock );
3092                    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] ,
3093                                 ~LOCKS_MASK_FAT ); 
3094
3095                    _printf("\n[FAT ERROR] in _fat_write(): no free cluster"
3096                            " for file <%s>\n", _fat.fd[fd_id].inode->name );
3097                    return GIET_FAT32_NO_FREE_SPACE;
3098                }
3099            }
3100        }
3101         
3102        // update size in inode
3103        inode->size = new_size;
3104 
3105        // update parent directory entry (size and cluster index)
3106        if ( _update_dir_entry( inode ) )
3107        {
3108            _spin_lock_release( &_fat.fat_lock );
3109            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3110
3111            _printf("\n[FAT ERROR] _fat_write(): cannot update parent directory entry"
3112                    " for file <%s>\n", _fat.fd[fd_id].inode->name );
3113            return GIET_FAT32_IO_ERROR;
3114        }
3115           
3116
3117#if GIET_DEBUG_FAT
3118if ( _get_proctime() > GIET_DEBUG_FAT )
3119_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] updates size for file <%s> / size = %x\n",
3120        x , y , p , inode->name , (new_size - old_size) );
3121#endif
3122
3123    }
3124
3125    // compute first_cluster_id and first_byte_to_move
3126    unsigned int first_cluster_id   = seek >> 12;
3127    unsigned int first_byte_to_move = seek & 0xFFF;   
3128
3129    // compute last_cluster and last_byte_to_move
3130    unsigned int last_cluster_id   = (seek + count - 1) >> 12;   
3131    unsigned int last_byte_to_move = (seek + count - 1) & 0xFFF;
3132
3133#if GIET_DEBUG_FAT
3134if ( _get_proctime() > GIET_DEBUG_FAT )
3135_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] starts loop on clusters for file <%s>\n"
3136        "  first_cluster_id = %d / first_byte_to_move = %x"
3137        " / last_cluster_id = %d / last_byte_to_move = %x\n",
3138        x , y , p , inode->name ,
3139        first_cluster_id , first_byte_to_move , last_cluster_id , last_byte_to_move );
3140#endif
3141
3142    // loop on all clusters covering the requested transfer
3143    unsigned int cluster_id;
3144    unsigned int done = 0;
3145    for ( cluster_id = first_cluster_id ; cluster_id <= last_cluster_id ; cluster_id++ )
3146    {
3147        // get pointer on one 4K buffer in File-Cache
3148        unsigned char*     cbuf;
3149        fat_cache_desc_t*  pdesc;
3150        if ( _get_file_cache_buffer( inode,   
3151                                     cluster_id, 
3152                                     0,
3153                                     &pdesc ) )   
3154        {
3155            _spin_lock_release( &_fat.fat_lock );
3156            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3157
3158            _printf("\n[FAT ERROR] _fat_write(): cannot load file <%s>\n",
3159                    inode->name );
3160            return GIET_FAT32_IO_ERROR;
3161        }
3162       
3163        cbuf         = pdesc->buffer;
3164        pdesc->dirty = 1;
3165   
3166#if GIET_DEBUG_FAT
3167if ( _get_proctime() > GIET_DEBUG_FAT )
3168_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] move cluster_id %d to Cache-file <%s>\n",
3169        x , y , p , cluster_id, inode->name );
3170#endif
3171
3172        // compute memcpy arguments
3173        unsigned char* dest;
3174        unsigned int   nbytes;
3175        if ( (cluster_id == first_cluster_id) && (cluster_id == last_cluster_id) )
3176        {
3177            dest   = cbuf + first_byte_to_move; 
3178            nbytes = last_byte_to_move - first_byte_to_move + 1;
3179        }
3180        else if ( cluster_id == first_cluster_id )
3181        {
3182            dest   = cbuf + first_byte_to_move; 
3183            nbytes = 4096 - first_byte_to_move;
3184        }
3185        else if ( cluster_id == last_cluster_id )
3186        {
3187            dest   = cbuf; 
3188            nbytes = last_byte_to_move + 1;
3189        }
3190        else
3191        {
3192            dest   = cbuf; 
3193            nbytes = 4096;
3194        }
3195
3196        // move data
3197        if ( physical_addressing == 0 )     // no physical addressing
3198        {
3199            char* source = (char*)(vaddr + done);
3200            memcpy( dest , source , nbytes ); 
3201        }
3202        else                                  // physical addressing required
3203        {
3204            unsigned int flags;
3205            paddr_t      psource = (((paddr_t)extend)<<32) + vaddr + done;
3206            paddr_t      pdest   = _v2p_translate( (unsigned int)dest , &flags );
3207            _physical_memcpy( pdest , psource , nbytes );
3208        }
3209
3210        done = done + nbytes;
3211
3212    } // end for clusters
3213
3214    // update seek
3215    _fat.fd[fd_id].seek += done;
3216
3217#if GIET_DEBUG_FAT
3218if ( _get_proctime() > GIET_DEBUG_FAT )
3219_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] store file <%s> into Cache-File\n",
3220        x , y , p , inode->name );
3221#endif
3222
3223    // release lock
3224    _spin_lock_release( &_fat.fat_lock );
3225    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3226
3227    return done;
3228} // end _fat_write()
3229
3230
3231
3232///////////////////////////////////
3233int _fat_lseek( unsigned int fd_id,
3234                unsigned int seek,
3235                unsigned int whence )
3236{
3237    // checking FAT initialized
3238    if( _fat.initialized != FAT_INITIALIZED )
3239    {
3240        _printf("\n[FAT ERROR] _fat_lseek(): FAT not initialized\n");
3241        return GIET_FAT32_NOT_INITIALIZED;
3242    }
3243
3244    // check fd_id overflow
3245    if ( fd_id >= GIET_OPEN_FILES_MAX )
3246    {
3247        _printf("\n[FAT ERROR] _fat_lseek(): illegal file descriptor\n");
3248        return GIET_FAT32_INVALID_FD;
3249    }
3250
3251    // takes the FAT lock and register it in thread context
3252    static_scheduler_t*  psched = _get_sched();
3253    unsigned int         ltid   = _get_thread_ltid();
3254    _spin_lock_acquire( &_fat.fat_lock );
3255    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3256
3257
3258    // check file open
3259    if ( _fat.fd[fd_id].allocated == 0 )
3260    {
3261        _spin_lock_release( &_fat.fat_lock );
3262        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3263
3264        _printf("\n[FAT ERROR] _fat_lseek(): file not open\n");
3265        return GIET_FAT32_NOT_OPEN;
3266    }
3267
3268    unsigned int  new_seek;
3269
3270    // compute new seek
3271    if      ( whence == SEEK_CUR ) new_seek = _fat.fd[fd_id].seek + seek;
3272    else if ( whence == SEEK_SET ) new_seek = seek;
3273    else if ( whence == SEEK_END ) new_seek = _fat.fd[fd_id].inode->size + seek;
3274    else
3275    {
3276        _spin_lock_release( &_fat.fat_lock );
3277        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3278
3279        _printf("\n[FAT ERROR] _fat_lseek(): illegal whence value\n");
3280        return GIET_FAT32_INVALID_ARG;
3281    }
3282
3283    // update file descriptor offset
3284    _fat.fd[fd_id].seek = new_seek;
3285
3286#if GIET_DEBUG_FAT
3287unsigned int procid  = _get_procid();
3288unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3289unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3290unsigned int p       = procid & ((1<<P_WIDTH)-1);
3291if ( _get_proctime() > GIET_DEBUG_FAT )
3292_printf("\n[DEBUG FAT] _fat_lseek(): P[%d,%d,%d] set seek = %x for file <%s>\n",
3293        x , y , p , new_seek , _fat.fd[fd_id].inode->name );
3294#endif
3295
3296    // release lock
3297    _spin_lock_release( &_fat.fat_lock );
3298    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3299
3300    return new_seek;
3301}  // end _fat_lseek()
3302
3303
3304
3305///////////////////////////////////////
3306int _fat_remove( char*        pathname,
3307                 unsigned int should_be_dir )
3308{
3309    fat_inode_t*  inode;            // searched file inode pointer
3310
3311#if GIET_DEBUG_FAT
3312unsigned int procid  = _get_procid();
3313unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3314unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3315unsigned int p       = procid & ((1<<P_WIDTH)-1);
3316if ( _get_proctime() > GIET_DEBUG_FAT )
3317_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] enters for path <%s>\n",
3318        x, y, p, pathname );
3319#endif
3320
3321    // checking FAT initialized
3322    if( _fat.initialized != FAT_INITIALIZED )
3323    {
3324        _printf("\n[FAT ERROR] _fat_remove(): FAT not initialized\n");
3325        return GIET_FAT32_NOT_INITIALIZED;
3326    }
3327
3328    // takes the FAT lock and register it in thread context
3329    static_scheduler_t*  psched = _get_sched();
3330    unsigned int         ltid   = _get_thread_ltid();
3331    _spin_lock_acquire( &_fat.fat_lock );
3332    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3333
3334
3335    // get searched file inode
3336    unsigned int code = _get_inode_from_path( pathname , &inode );
3337
3338#if GIET_DEBUG_FAT
3339if ( _get_proctime() > GIET_DEBUG_FAT )
3340_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] found inode %x for <%s> / code = %d\n",
3341        x , y , p , (unsigned int)inode , pathname , code );
3342#endif
3343
3344    if ( (code == 1) || (code == 2) )
3345    {
3346        _spin_lock_release( &_fat.fat_lock );
3347        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3348
3349        _printf("\n[FAT ERROR] _fat_remove(): file <%s> not found\n", 
3350                pathname );
3351        return GIET_FAT32_FILE_NOT_FOUND;
3352    }
3353    else if ( code == 3 )
3354    {
3355        _spin_lock_release( &_fat.fat_lock );
3356        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3357
3358        _printf("\n[FAT ERROR] _fat_remove(): name too long in <%s>\n",
3359                pathname );
3360        return GIET_FAT32_NAME_TOO_LONG;
3361    }
3362
3363    // check inode type
3364    if ( (inode->is_dir != 0) && (should_be_dir == 0) ) 
3365    {
3366        _spin_lock_release( &_fat.fat_lock );
3367        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3368
3369        _printf("\n[FAT ERROR] _fat_remove(): <%s> is a directory\n",
3370                pathname );
3371        return GIET_FAT32_IS_DIRECTORY;
3372    }
3373    if ( (inode->is_dir == 0) && (should_be_dir != 0) )
3374    {
3375        _spin_lock_release( &_fat.fat_lock );
3376        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3377
3378        _printf("\n[FAT ERROR] _fat_remove(): <%s> is not a directory\n", 
3379                pathname );
3380        return GIET_FAT32_NOT_A_DIRECTORY;
3381    }
3382
3383#if GIET_DEBUG_FAT
3384if ( _get_proctime() > GIET_DEBUG_FAT )
3385_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked inode type for <%s>\n",
3386        x , y , p , pathname );
3387#endif
3388   
3389    // check references count for a file
3390    if ( (inode->is_dir == 0) && (inode->count != 0) )
3391    {
3392        _spin_lock_release( &_fat.fat_lock );
3393        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3394
3395        _printf("\n[FAT ERROR] _fat_remove(): file <%s> still referenced\n",
3396                pathname );
3397        return GIET_FAT32_IS_OPEN;
3398    }
3399
3400    //  check empty for a directory
3401    if ( inode->is_dir )
3402    {
3403        unsigned int entries;
3404        if ( _get_nb_entries( inode , &entries ) )
3405        {
3406            _spin_lock_release( &_fat.fat_lock );
3407            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3408
3409            _printf("\n[FAT ERROR] _fat_remove(): cannot scan directory <%s>\n", 
3410                    pathname );
3411            return GIET_FAT32_IO_ERROR;
3412        }
3413        else if ( entries > 2 )
3414        {
3415            _spin_lock_release( &_fat.fat_lock );
3416            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3417
3418            _printf("\n[FAT ERROR] _fat_remove(): directory <%s> not empty\n", 
3419                    pathname );
3420            return GIET_FAT32_DIRECTORY_NOT_EMPTY;
3421        }
3422    }
3423
3424#if GIET_DEBUG_FAT
3425if ( _get_proctime() > GIET_DEBUG_FAT )
3426_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked remove condition OK for <%s>\n",
3427        x , y , p , pathname );
3428#endif
3429   
3430    // remove the file or directory from the file system
3431    if ( _remove_node_from_fs( inode ) )
3432    {
3433        _spin_lock_release( &_fat.fat_lock );
3434        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3435
3436        _printf("\n[FAT ERROR] _fat_remove(): cannot remove <%s> from FS\n",
3437                pathname );
3438        return GIET_FAT32_IO_ERROR;
3439    }
3440
3441    // release lock and return success
3442    _spin_lock_release( &_fat.fat_lock );
3443    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3444
3445#if GIET_DEBUG_FAT
3446if ( _get_proctime() > GIET_DEBUG_FAT )
3447_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] removed  <%s> from FS\n",
3448        x, y, p, pathname );
3449#endif
3450   
3451    return GIET_FAT32_OK;
3452       
3453}  // end _fat_remove()
3454
3455
3456
3457
3458
3459/////////////////////////////////
3460int _fat_rename( char*  old_path,
3461                 char*  new_path )
3462{
3463    fat_inode_t*  inode;        // anonymous inode pointer
3464    fat_inode_t*  old;          // inode identified by old_path      => to be deleted
3465    fat_inode_t*  new;          // inode identified by new_path      => to be created
3466    fat_inode_t*  old_parent;   // parent inode  in old_path         => to be modified
3467    fat_inode_t*  new_parent;   // parent inode  in new_path         => to be modified
3468    fat_inode_t*  to_remove;    // previouly identified by new_path  => to be removed
3469    unsigned int  code;
3470
3471#if GIET_DEBUG_FAT
3472unsigned int procid  = _get_procid();
3473unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3474unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3475unsigned int p       = procid & ((1<<P_WIDTH)-1);
3476if ( _get_proctime() > GIET_DEBUG_FAT )
3477_printf("\n[DEBUG FAT] _fat_rename(): P[%d,%d,%d] enters to move <%s> to <%s>\n",
3478        x , y , p , old_path , new_path );
3479#endif
3480
3481    // checking FAT initialized
3482    if( _fat.initialized != FAT_INITIALIZED )
3483    {
3484        _printf("\n[FAT ERROR] _fat_rename(): FAT not initialized\n");
3485        return GIET_FAT32_NOT_INITIALIZED;
3486    }
3487
3488    // takes the FAT lock and register it in thread context
3489    static_scheduler_t*  psched = _get_sched();
3490    unsigned int         ltid   = _get_thread_ltid();
3491    _spin_lock_acquire( &_fat.fat_lock );
3492    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3493
3494
3495    // get "old" and "old_parent" inode pointers
3496    if ( _get_inode_from_path( old_path , &inode ) )
3497    {
3498        _spin_lock_release( &_fat.fat_lock );
3499        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3500
3501        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", old_path );
3502        return GIET_FAT32_FILE_NOT_FOUND;
3503    }
3504    else
3505    {
3506        old        = inode;
3507        old_parent = inode->parent;
3508    }
3509
3510    // get "to_removed" and "new_parent" inode pointers
3511    code = _get_inode_from_path( new_path , &inode );
3512
3513    if ( code == 0 )       // new_path inode already exist
3514    {
3515        if ( inode == old )  // the file will replace itself, do nothing
3516        {
3517            _spin_lock_release( &_fat.fat_lock );
3518            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3519
3520            return GIET_FAT32_OK;
3521        }
3522
3523        to_remove        = inode;
3524        new_parent       = inode->parent;
3525    }
3526    else if ( code == 1 )  // to_remove does not exist but parent exist
3527    {
3528        to_remove        = NULL;
3529        new_parent       = inode;
3530    }
3531    else                   // parent directory in new_path not found
3532    {
3533        _spin_lock_release( &_fat.fat_lock );
3534        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3535
3536        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", new_path );
3537        return GIET_FAT32_FILE_NOT_FOUND;
3538    }
3539
3540    // check for move into own subdirectory
3541    if ( _is_ancestor( old, new_parent ) )
3542    {
3543        _spin_lock_release( &_fat.fat_lock );
3544        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3545
3546        _printf("\n[FAT ERROR] _fat_rename(): can't move %s into  own directory\n", old_path );
3547        return GIET_FAT32_MOVE_INTO_SUBDIR;
3548    }
3549
3550#if GIET_DEBUG_FAT
3551if ( _get_proctime() > GIET_DEBUG_FAT )
3552{
3553if ( to_remove )
3554_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
3555        "/ to_remove = %s\n",
3556        old_parent->name , old->name , new_parent->name , to_remove->name );
3557else
3558_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
3559        "/ no remove\n", 
3560        old_parent->name , old->name , new_parent->name );
3561}
3562#endif
3563
3564    // check remove condition for "to_remove" inode
3565    if ( to_remove )
3566    {
3567        if ( to_remove->is_dir )   // it's a directory
3568        {
3569            unsigned int entries;
3570            if ( _get_nb_entries( to_remove , &entries ) )
3571            {
3572                _spin_lock_release( &_fat.fat_lock );
3573                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3574
3575                _printf("\n[FAT ERROR] _fat_rename(): cannot scan directory <%s>\n", 
3576                        to_remove->name );
3577                return GIET_FAT32_IO_ERROR;
3578            }
3579            else if ( entries > 2 )
3580            {
3581                _spin_lock_release( &_fat.fat_lock );
3582                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3583
3584                _printf("\n[FAT ERROR] _fat_rename(): directory <%s> not empty\n", 
3585                        to_remove->name );
3586                return GIET_FAT32_DIRECTORY_NOT_EMPTY;
3587            }
3588        }
3589        else                       // it's a file
3590        {
3591            if ( to_remove->count ) 
3592            {
3593                _spin_lock_release( &_fat.fat_lock );
3594                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3595
3596                _printf("\n[FAT ERROR] _fat_rename(): file <%s> still referenced\n", 
3597                        to_remove->name );
3598                return GIET_FAT32_IS_OPEN;
3599            }
3600        }
3601    }
3602
3603#if GIET_DEBUG_FAT
3604if ( _get_proctime() > GIET_DEBUG_FAT )
3605_printf("\n[FAT DEBUG] _fat_rename(): P[%d,%d,%d] checked remove condition OK\n",
3606        x , y , p );
3607#endif
3608
3609    // get new last name / error checking already done by _get_inode_from_path()
3610    char  new_name[32];
3611    _get_last_name( new_path , new_name );
3612
3613    // allocate "new" inode
3614    new = _allocate_one_inode( new_name,
3615                               old->is_dir,
3616                               old->cluster,
3617                               old->size,
3618                               0,              // count
3619                               0,              // dentry set by _add_dir_entry()
3620                               0 );            // no cache_allocate
3621 
3622    // attach the "old" File-Cache to the "new" inode
3623    new->levels = old->levels;
3624    new->cache  = old->cache;
3625
3626    // add "new" to "new_parent" directory in Inode-Tree
3627    _add_inode_in_tree( new , new_parent );
3628   
3629    // add "new" to "new_parent" directory File-Cache
3630    // and update the dentry field in new inode
3631    if ( _add_dir_entry( new ) )
3632    {
3633        _spin_lock_release( &_fat.fat_lock );
3634        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3635
3636        _printf("\n[FAT ERROR] _fat_rename(): cannot add <%s> into <%s>\n",
3637                new->name , new_parent->name );
3638        return GIET_FAT32_IO_ERROR;
3639    }
3640
3641    // updates "new_parent" directory on device
3642    if ( _update_device_from_cache( new_parent->levels,
3643                                    new_parent->cache,
3644                                    new_parent->name ) )
3645    {
3646        _spin_lock_release( &_fat.fat_lock );
3647        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3648
3649        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
3650                    new_parent->name );
3651        return GIET_FAT32_IO_ERROR;
3652    }
3653
3654    // remove "old" from "old_parent" File-Cache
3655    if ( _remove_dir_entry( old ) )
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 remove <%s> from <%s>\n",
3661                old->name , old_parent->name );
3662        return GIET_FAT32_IO_ERROR;
3663    }
3664 
3665    // remove "old" inode from Inode-Tree
3666    _remove_inode_from_tree( old );
3667
3668    // release "old" inode
3669    _free( old );
3670
3671    // updates "old_parent" directory on device
3672    if ( _update_device_from_cache( old_parent->levels,
3673                                    old_parent->cache,
3674                                    old_parent->name ) )
3675    {
3676        _spin_lock_release( &_fat.fat_lock );
3677        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3678
3679        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
3680                    old_parent->name );
3681        return GIET_FAT32_IO_ERROR;
3682    }
3683
3684    // remove "to_remove" from File System (if required)
3685    if ( to_remove )
3686    {
3687        if ( _remove_node_from_fs( to_remove ) )
3688        {
3689            _spin_lock_release( &_fat.fat_lock );
3690            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3691
3692            _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from FS\n",
3693                    to_remove->name );
3694            return GIET_FAT32_IO_ERROR;
3695        }
3696    }
3697
3698    // release lock
3699    _spin_lock_release( &_fat.fat_lock );
3700    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3701
3702    return GIET_FAT32_OK;
3703}  // end _fat_rename()
3704
3705
3706
3707
3708////////////////////////////////
3709int _fat_mkdir( char* pathname )
3710{
3711    fat_inode_t*         inode;            // anonymous inode pointer
3712    fat_inode_t*         child;            // searched directory inode pointer
3713    fat_inode_t*         parent;           // parent directory inode pointer
3714
3715#if GIET_DEBUG_FAT
3716unsigned int procid  = _get_procid();
3717unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3718unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3719unsigned int p       = procid & ((1<<P_WIDTH)-1);
3720if ( _get_proctime() > GIET_DEBUG_FAT )
3721_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] enters for path <%s>\n",
3722        x, y, p, pathname );
3723#endif
3724
3725    // checking FAT initialized
3726    if( _fat.initialized != FAT_INITIALIZED )
3727    {
3728        _printf("\n[FAT ERROR] _fat_mkdir(): FAT not initialized\n");
3729        return GIET_FAT32_NOT_INITIALIZED;
3730    }
3731
3732    // takes the FAT lock and register it in thread context
3733    static_scheduler_t*  psched = _get_sched();
3734    unsigned int         ltid   = _get_thread_ltid();
3735    _spin_lock_acquire( &_fat.fat_lock );
3736    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3737
3738    // get inode
3739    unsigned int code = _get_inode_from_path( pathname , &inode );
3740
3741    if ( code == 2 ) 
3742    {
3743        _spin_lock_release( &_fat.fat_lock );
3744        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3745
3746        _printf("\n[FAT ERROR] _fat_mkdir(): path to parent not found"
3747                " for directory <%s>\n", pathname );
3748        return GIET_FAT32_FILE_NOT_FOUND;
3749    }
3750    else if ( code == 3 ) 
3751    {
3752        _spin_lock_release( &_fat.fat_lock );
3753        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3754
3755        _printf("\n[FAT ERROR] _fat_mkdir(): one name in path too long"
3756                " for directory  <%s>\n", pathname );
3757        return GIET_FAT32_NAME_TOO_LONG;
3758    }
3759    else if ( code == 0 )
3760    {
3761        _spin_lock_release( &_fat.fat_lock );
3762        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3763
3764        _printf("\n[FAT ERROR] _fat_mkdir(): directory <%s> already exist\n",
3765                pathname );
3766        return GIET_FAT32_FILE_EXISTS;
3767    }
3768    else if ( code == 1 )   // directory not found => create
3769    {
3770        parent = inode;
3771
3772#if GIET_DEBUG_FAT
3773if ( _get_proctime() > GIET_DEBUG_FAT )
3774_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] create new directory <%s>\n",
3775        x , y , p , pathname );
3776#endif
3777
3778        // get directory name / error check already done by _get_inode_from_path()
3779        char name[32];       
3780        _get_last_name( pathname , name );
3781
3782        // allocate a new inode and an empty Cache-File
3783        child = _allocate_one_inode( name,
3784                                     1,                         // it's a directory
3785                                     END_OF_CHAIN_CLUSTER_MAX,  // cluster set later
3786                                     0,                         // size = 0 for directory
3787                                     0,                         // count
3788                                     0,                         // dentry set later
3789                                     1 );                       // cache_allocate
3790
3791        // introduce inode in Inode-Tree
3792        _add_inode_in_tree( child , parent );
3793 
3794        // allocate one cluster from FAT for child
3795        unsigned int cluster;
3796        if ( _one_cluster_allocate( child , &cluster ) )
3797        {
3798            _spin_lock_release( &_fat.fat_lock );
3799            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3800
3801            _printf("\n[FAT ERROR] _fat_mkdir(): no free cluster"
3802                    " for directory <%s>\n" , pathname );
3803            return GIET_FAT32_NO_FREE_SPACE;
3804        }
3805
3806        // update cluster index in inode
3807        child->cluster = cluster;
3808
3809        // add new entry in parent directory File-Cache
3810        // and update dentry field in child inode
3811        if ( _add_dir_entry( child ) )
3812        {
3813            _spin_lock_release( &_fat.fat_lock );
3814            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3815
3816            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update parent directory"
3817                    " for directory <%s>\n" , pathname );
3818            return GIET_FAT32_IO_ERROR;
3819        } 
3820
3821        // add "." and ".." directories in child directory
3822        _add_special_directories( child );
3823
3824        // update DATA region on block device for parent directory
3825        if ( _update_device_from_cache( parent->levels,
3826                                        parent->cache,
3827                                        parent->name ) )
3828        {
3829            _spin_lock_release( &_fat.fat_lock );
3830            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3831
3832            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region "
3833                    " for parent of directory <%s>\n", pathname );
3834            return GIET_FAT32_IO_ERROR;
3835        }
3836
3837        // update FAT region on block device
3838        if ( _update_device_from_cache( _fat.fat_cache_levels,
3839                                        _fat.fat_cache_root,
3840                                        "FAT" ) )
3841        {
3842            _spin_lock_release( &_fat.fat_lock );
3843            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3844
3845            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update FAT region"
3846                    " for directory <%s>\n", pathname );
3847            return GIET_FAT32_IO_ERROR;
3848        }
3849
3850        // update DATA region on block device for the new directory
3851        if ( _update_device_from_cache( child->levels,   
3852                                        child->cache,
3853                                        child->name ) )
3854        {
3855            _spin_lock_release( &_fat.fat_lock );
3856            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3857
3858            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region"
3859                    " for directory <%s>\n", pathname );
3860            return GIET_FAT32_IO_ERROR;
3861        }
3862    }  // end create directory
3863
3864    // release lock
3865    _spin_lock_release( &_fat.fat_lock );
3866    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3867
3868    return GIET_FAT32_OK;
3869}  // end _fat_mkdir()
3870
3871
3872
3873
3874/////////////////////////////////////////
3875extern int _fat_opendir( char* pathname )
3876{
3877    int fd_id = _fat_open( pathname, O_RDONLY );
3878
3879    if ( fd_id < 0 )
3880        return fd_id;
3881
3882    if ( !_fat.fd[fd_id].inode->is_dir )
3883    {
3884        _printf("\n[FAT ERROR] _fat_opendir(): <%s> is not a directory\n",
3885                pathname );
3886        return GIET_FAT32_NOT_A_DIRECTORY;
3887    }
3888
3889    return fd_id;
3890}
3891
3892
3893
3894
3895//////////////////////////////////////////////
3896extern int _fat_closedir( unsigned int fd_id )
3897{
3898    return _fat_close( fd_id );
3899}
3900
3901
3902
3903
3904/////////////////////////////////////////////
3905extern int _fat_readdir( unsigned int  fd_id,
3906                         fat_dirent_t* entry )
3907{
3908    unsigned int  lfn   = 0;            // lfn entries count
3909    unsigned int  attr;                 // ATTR field value
3910    unsigned int  ord;                  // ORD field value
3911    char          lfn1[16];             // temporary buffer for string in LFN1
3912    char          lfn2[16];             // temporary buffer for string in LFN2
3913    char          lfn3[16];             // temporary buffer for string in LFN3
3914    unsigned char buf[DIR_ENTRY_SIZE];  // raw entry buffer
3915    fat_file_info_t info;
3916
3917    // check for directory
3918    int ret = _fat_file_info( fd_id, &info );
3919    if (ret < 0)
3920    {
3921        return ret;
3922    }
3923    else if ( !info.is_dir )
3924    {
3925        _printf("\n[FAT ERROR] in _fat_readdir(): not a directory\n" );
3926        return GIET_FAT32_NOT_A_DIRECTORY;
3927    }
3928
3929
3930#if GIET_DEBUG_FAT
3931unsigned int procid  = _get_procid();
3932unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
3933unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
3934unsigned int p       = procid & ((1<<P_WIDTH)-1);
3935if ( _get_proctime() > GIET_DEBUG_FAT )
3936_printf("\n[DEBUG FAT] _fat_readdir(): P[%d,%d,%d] enter for <%s>\n",
3937        x , y , p , _fat.fd[fd_id].inode->name );
3938#endif
3939
3940    while ( 1 )
3941    {
3942        if ( _fat_read( fd_id, 
3943                        (unsigned int)&buf, 
3944                        DIR_ENTRY_SIZE,
3945                        0, 0, 0 )  != sizeof(buf) )
3946        {
3947            _printf("\n[FAT ERROR] in _fat_readdir(): can't read entry\n" );
3948            return GIET_FAT32_IO_ERROR;
3949        }
3950
3951        attr = _read_entry( DIR_ATTR, buf, 0 );
3952        ord  = _read_entry( LDIR_ORD, buf, 0 );
3953
3954        if (ord == NO_MORE_ENTRY)               // no more entry in directory => stop
3955        {
3956            // seek back to this entry
3957            _atomic_increment( &_fat.fd[fd_id].seek , -DIR_ENTRY_SIZE );
3958
3959            return GIET_FAT32_NO_MORE_ENTRIES;
3960        }
3961        else if ( ord == FREE_ENTRY )           // free entry => skip
3962        {
3963            continue;
3964        }
3965        else if ( attr == ATTR_LONG_NAME_MASK ) // LFN entry => get partial names
3966        {
3967            unsigned int seq = ord & 0x3;
3968            lfn = (seq > lfn) ? seq : lfn;
3969            if      ( seq == 1 ) _get_name_from_long( buf, lfn1 );
3970            else if ( seq == 2 ) _get_name_from_long( buf, lfn2 );
3971            else if ( seq == 3 ) _get_name_from_long( buf, lfn3 );
3972            continue;
3973        }
3974        else                                    // NORMAL entry => stop
3975        {
3976            break;
3977        }
3978    }
3979
3980    // TODO handle is_vid
3981    entry->cluster = (_read_entry( DIR_FST_CLUS_HI, buf, 1 ) << 16) |
3982                     (_read_entry( DIR_FST_CLUS_LO, buf, 1 )      ) ;
3983    entry->size    = (_read_entry( DIR_FILE_SIZE  , buf, 1 )      ) ;
3984    entry->is_dir  = ((attr & ATTR_DIRECTORY) == ATTR_DIRECTORY);
3985
3986    if      ( lfn == 0 )
3987    {
3988        _get_name_from_short( buf, entry->name );
3989    }
3990    else if ( lfn == 1 )
3991    {
3992        _strcpy( entry->name     , lfn1 );
3993    }
3994    else if ( lfn == 2 )
3995    {
3996        _strcpy( entry->name     , lfn1 );
3997        _strcpy( entry->name + 13, lfn2 );
3998    }
3999    else if ( lfn == 3 )
4000    {
4001        _strcpy( entry->name     , lfn1 );
4002        _strcpy( entry->name + 13, lfn2 );
4003        _strcpy( entry->name + 26, lfn3 );
4004    }
4005
4006    return GIET_FAT32_OK;
4007}  // end _fat_readdir()
4008
4009
4010
4011
4012///////////////////////////////////////////////
4013int _fat_load_no_cache( char*        pathname,
4014                        unsigned int buffer_vbase, 
4015                        unsigned int buffer_size ) 
4016{
4017    // checking FAT initialized
4018    if( _fat.initialized != FAT_INITIALIZED )
4019    {
4020        _printf("\n[FAT ERROR] _fat_load_no_cache(): FAT not initialized\n");
4021        return GIET_FAT32_NOT_INITIALIZED;
4022    }
4023
4024    unsigned int  file_size;
4025    unsigned int  cluster;
4026
4027#if GIET_DEBUG_FAT
4028unsigned int procid  = _get_procid();
4029unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
4030unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
4031unsigned int p       = procid & ((1<<P_WIDTH)-1);
4032if ( _get_proctime() > GIET_DEBUG_FAT )
4033_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] enters for file <%s>\n",
4034        x , y , p , pathname );
4035#endif
4036
4037    // get file size, and cluster index in FAT
4038    if ( _file_info_no_cache( pathname,
4039                              &cluster,
4040                              &file_size ) )
4041    {
4042        _printf("\n[FAT ERROR] _fat_load_no_cache(): file <%s> not found\n",
4043        pathname );
4044        return GIET_FAT32_FILE_NOT_FOUND;
4045    }
4046
4047    // check buffer size
4048    if ( file_size > buffer_size )
4049    {
4050        _printf("\n[FAT ERROR] _fat_load_no_cache(): buffer too small : "
4051                "file_size = %x / buffer_size = %x", file_size , buffer_size );
4052        return GIET_FAT32_BUFFER_TOO_SMALL;
4053    }
4054
4055    // compute total number of clusters to read
4056    unsigned int nb_clusters = file_size >> 12;
4057    if ( file_size & 0xFFF ) nb_clusters++;
4058
4059    // initialise buffer address
4060    unsigned int dst = buffer_vbase;
4061
4062    // loop on the clusters containing the file
4063    while ( nb_clusters > 0 )
4064    {
4065        unsigned int lba = _cluster_to_lba( cluster );
4066
4067        if( _fat_ioc_access( 0,         // no descheduling
4068                             1,         // read
4069                             lba, 
4070                             dst, 
4071                             8 ) )      // 8 blocks
4072        {
4073            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot load lba %x", lba );
4074            return GIET_FAT32_IO_ERROR;
4075        }
4076         
4077
4078        // compute next cluster index
4079        unsigned int next;
4080        if ( _next_cluster_no_cache( cluster , &next ) )
4081        {
4082            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot get next cluster "
4083                    " for cluster = %x\n", cluster );
4084            return GIET_FAT32_IO_ERROR;
4085        }
4086       
4087        // update variables for next iteration
4088        nb_clusters = nb_clusters - 1;
4089        dst         = dst + 4096;
4090        cluster     = next;
4091    }
4092         
4093#if GIET_DEBUG_FAT
4094if ( _get_proctime() > GIET_DEBUG_FAT )
4095_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] loaded <%s> at vaddr = %x"
4096        " / size = %x\n", x , y , p , pathname , buffer_vbase , file_size );
4097#endif
4098
4099    return GIET_FAT32_OK;
4100}  // end _fat_load_no_cache()
4101
4102
4103
4104
4105//////////////////////////////////////////////////////////
4106int _get_fat_cache_buffer( unsigned int        cluster_id,
4107                           fat_cache_desc_t**  desc )
4108{
4109    // get cache pointer and number of levels
4110    fat_cache_node_t*   node   = _fat.fat_cache_root;   
4111    unsigned int        level  = _fat.fat_cache_levels; 
4112
4113    if ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > level )
4114    {
4115        _printf("\n[FAT ERROR] in _get_fat_cache_buffer() : "
4116                "cluster_id %d too large\n", cluster_id );
4117        return GIET_FAT32_IO_ERROR;
4118    }
4119
4120    // search the 64-tree cache from top to bottom
4121    while ( level )
4122    {
4123        // compute child index at each level
4124        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
4125
4126        if ( level == 1 )        // last level => children are buffer descriptors
4127        {
4128            fat_cache_desc_t*   pdesc = (fat_cache_desc_t*)node->children[index];
4129
4130            if ( pdesc == NULL )      // miss
4131            {
4132
4133#if GIET_DEBUG_FAT
4134if ( _get_proctime() > GIET_DEBUG_FAT )
4135_printf("\n[DEBUG FAT] _get_fat_cache_buffer(): miss for cluster_id %d\n", cluster_id );
4136#endif
4137                // compute missing cluster lba
4138                unsigned int lba = _fat.fat_lba + (cluster_id << 3);
4139
4140                // allocate a 4 Kbytes buffer and a buffer descriptor
4141                void* buf      = _malloc( 4096 );
4142                pdesc          = _malloc( sizeof(fat_cache_desc_t) );
4143                pdesc->lba     = lba;
4144                pdesc->buffer  = buf;
4145                pdesc->dirty   = 0;
4146                node->children[index] = pdesc;
4147
4148                // load cluster from device
4149                if ( _fat_ioc_access( 1,         // descheduling
4150                                      1,         // to memory
4151                                      lba,
4152                                      (unsigned int)buf,
4153                                      8 ) )
4154                {
4155                    _free( buf );
4156                    _free( pdesc );
4157                    _printf("\n[FAT ERROR] in _get_fat_cache_buffer() : "
4158                            ": cannot access block device for lba = %x\n", lba );
4159                    return GIET_FAT32_IO_ERROR;
4160                }
4161
4162            }
4163
4164            // return pdesc pointer
4165            *desc = pdesc;
4166
4167            // prepare next iteration
4168            level--;
4169        }
4170        else                      // not last level => children are 64-tree nodes
4171        {
4172            fat_cache_node_t* child = (fat_cache_node_t*)node->children[index];
4173            if ( child == NULL )  // miss
4174            {
4175                // allocate a cache node if miss
4176                child = _allocate_one_cache_node( NULL );
4177                node->children[index] = child;   
4178            }
4179
4180            // prepare next iteration
4181            node = child;
4182            level--;
4183        }
4184    } // end while
4185
4186    return 0;
4187}  // end _get_fat_cache_buffer()
4188
4189
4190
4191
4192//////////////////////////////////////////////////////
4193int _get_file_cache_buffer( fat_inode_t*        inode,
4194                            unsigned int        cluster_id,
4195                            unsigned int        writable,
4196                            fat_cache_desc_t**  desc )
4197{
4198
4199#if GIET_DEBUG_FAT
4200if ( _get_proctime() > GIET_DEBUG_FAT )
4201_printf("\n[DEBUG FAT] _get_file_cache_buffer() : enters in File-Cache <%s>"
4202        " for cluster_id = %d\n size = %x / cache = %x / desc[%d] = %x\n", 
4203        inode->name , cluster_id ,
4204        inode->size , (unsigned int)inode->cache , cluster_id ,
4205        (unsigned int)inode->cache->children[cluster_id] );
4206#endif
4207
4208    // checking FAT initialized
4209    if( _fat.initialized != FAT_INITIALIZED )
4210    {
4211        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : FAT not initialized\n");
4212        return GIET_FAT32_NOT_INITIALIZED;
4213    }
4214
4215    // checking arguments
4216    if ( inode == NULL )   // illegal inode argument
4217    {
4218        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : illegal inode argument\n");
4219        return GIET_FAT32_INVALID_ARG;
4220    }
4221
4222    // add cache levels if needed
4223    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
4224    {
4225
4226#if GIET_DEBUG_FAT
4227if ( _get_proctime() > GIET_DEBUG_FAT )
4228_printf("\n[DEBUG FAT] _get_file_cache_buffer() : add a File-Cache level\n" );
4229#endif
4230
4231        inode->cache = _allocate_one_cache_node( inode->cache );
4232        inode->levels++;
4233    }
4234
4235    // get inode type, size, and File-Cache
4236    unsigned int       size   = inode->size;
4237    unsigned int       is_dir = inode->is_dir;
4238    fat_cache_node_t*  node   = inode->cache; 
4239    unsigned int       level  = inode->levels;
4240
4241    // search the 64-tree cache from top to bottom
4242    while ( level )
4243    {
4244        // compute child index at each level
4245        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
4246
4247        if ( level == 1 )        // last level => children are buffer descriptors
4248        {
4249            fat_cache_desc_t*   pdesc   = (fat_cache_desc_t*)node->children[index];
4250            unsigned int        next    = 0;
4251            unsigned int        prev    = 0;
4252            unsigned int        current;
4253            unsigned int        cid;
4254            unsigned int        lba;
4255            unsigned int        one_cluster_allocated;
4256
4257            // File-Cache miss handling:
4258            // In case of miss, the missing buffer is allocated,
4259            // and the missing cluster is loaded from block device.
4260            // A new cluster is allocated from FAT if required, when
4261            // the writable argument is set.
4262            if ( pdesc == NULL )   
4263            {
4264
4265#if GIET_DEBUG_FAT
4266if ( _get_proctime() > GIET_DEBUG_FAT )
4267_printf("\n[DEBUG FAT] _get_file_cache_buffer() : miss in File-Cache <%s> "
4268        " for cluster_id = %d\n"
4269        " cluster = %x / size = %x / is_dir = %d / cache = %x / desc[%d] = %x\n",
4270        inode->name , cluster_id , inode->cluster , inode->size , inode->is_dir ,
4271        (unsigned int)inode->cache , cluster_id , 
4272        (unsigned int)inode->cache->children[cluster_id] );
4273#endif
4274                // compute one_cluster_allocated condition, depending on file / dir type
4275                if ( is_dir )  one_cluster_allocated = ( cluster_id < is_dir );
4276                else           one_cluster_allocated = ( (cluster_id<<12) < size );
4277
4278                if ( one_cluster_allocated )  // cluster already allocated => allocate buffer
4279                {
4280                    // scan the FAT to find the cluster index for cluster_id
4281                    current = inode->cluster;
4282                    for ( cid = 0 ; cid < cluster_id ; cid++ )
4283                    {
4284                        // get next cluster index from FAT
4285                        if ( _get_fat_entry( current , &next ) ) return 1;
4286                        current = next;
4287                    }
4288
4289                    // compute lba
4290                    lba = _cluster_to_lba( current );
4291
4292                    // allocate a 4 Kbytes buffer and a buffer descriptor
4293                    // the selected heap depends on the calling thread
4294                    void* buf      = _malloc( 4096 );
4295                    pdesc          = _malloc( sizeof(fat_cache_desc_t) );
4296
4297                    // set buffer descriptor
4298                    pdesc->lba     = lba;
4299                    pdesc->buffer  = buf;
4300                    pdesc->dirty   = writable;
4301                    node->children[index] = pdesc;
4302
4303                    // load cluster from device
4304                    if ( _fat_ioc_access( 1,         // descheduling
4305                                          1,         // to memory
4306                                          lba,
4307                                          (unsigned int)buf,
4308                                      8 ) )
4309                    {
4310                         
4311                        _free( buf );
4312                        _free( pdesc );
4313                        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4314                                "cannot access block device for lba = %x\n", lba );
4315                        return GIET_FAT32_IO_ERROR;
4316                    }
4317                }
4318                else if ( writable == 0 ) // not writable and cluster not allocated in FAT
4319                {
4320                    _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4321                            " file size too small for <%s>\n"
4322                            " size = %x / cluster_id = %d / procid = %x\n",
4323                            inode->name , inode->size , cluster_id , _get_procid() );
4324                    return GIET_FAT32_IO_ERROR;
4325                }
4326                else   // writable and cluster NOT allocated in FAT => allocate cluster & buffer
4327                {
4328                    // scan the FAT to allocate all required clusters
4329                    current = inode->cluster;
4330                    for ( cid = 0 ; cid <= cluster_id ; cid++ )
4331                    {
4332                        if ( current >= END_OF_CHAIN_CLUSTER_MIN ) // non allocated
4333                        {
4334                            // allocate one cluster on device
4335                            if ( _one_cluster_allocate( inode , &current ) )
4336                            {
4337                                _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4338                                        "cannot allocate new cluster for file <%s>\n",
4339                                        inode->name );
4340                                return GIET_FAT32_IO_ERROR;
4341                            }
4342                        }
4343 
4344                        // get next cluster index from FAT
4345                        if ( _get_fat_entry( current , &next ) )
4346                        {
4347                            _printf("\n[FAT ERROR] in _get_file_cache_buffer() : "
4348                                    "cannot get next cluster for file <%s>\n",
4349                                    inode->name );
4350                            return GIET_FAT32_IO_ERROR;
4351                        }
4352                        prev    = current;
4353                        current = next;
4354                    }
4355
4356                    // update size or is_dir attributes in inode
4357                    if ( is_dir )    inode->is_dir = cluster_id;
4358                    else             inode->size   = (cluster_id + 1)<<12;
4359
4360                    // update directory entry from inode
4361                    _update_dir_entry( inode );
4362
4363                    // compute lba
4364                    lba = _cluster_to_lba( current );
4365
4366                    // allocate a 4 Kbytes buffer and a buffer descriptor
4367                    // the selected heap depends on the calling thread
4368                    void* buf      = _malloc( 4096 );
4369                    pdesc          = _malloc( sizeof(fat_cache_desc_t) );
4370
4371                    // set buffer descriptor
4372                    pdesc->lba     = lba;
4373                    pdesc->buffer  = buf;
4374                    pdesc->dirty   = writable;
4375                    node->children[index] = pdesc;
4376                }
4377            }  // end File-Cache miss handling
4378
4379            // return pdesc pointer
4380            *desc = pdesc;
4381
4382#if GIET_DEBUG_FAT
4383if ( _get_proctime() > GIET_DEBUG_FAT )
4384_printf("\n[DEBUG FAT] _get_file_cache_buffer(): found buffer = %x "
4385        " in file <%s> for cluster_id %d\n",
4386        (unsigned int)pdesc->buffer , inode->name , cluster_id );
4387#endif
4388            // prepare next iteration
4389            level--;
4390        }
4391        else                      // not last level => children are 64-tree nodes
4392        {
4393            fat_cache_node_t* child = (fat_cache_node_t*)node->children[index];
4394            if ( child == NULL )  // miss
4395            {
4396                // allocate a cache node if miss
4397                child = _allocate_one_cache_node( NULL );
4398                node->children[index] = child;   
4399            }
4400
4401            // prepare next iteration
4402            node = child;
4403            level--;
4404        }
4405    } // end while
4406
4407    return GIET_FAT32_OK;
4408
4409}  // end _get_file_cache_buffer()
4410
4411
4412
4413
4414
4415
4416// Local Variables:
4417// tab-width: 4
4418// c-basic-offset: 4
4419// c-file-offsets:((innamespace . 0)(inline-open . 0))
4420// indent-tabs-mode: nil
4421// End:
4422// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
4423
Note: See TracBrowser for help on using the repository browser.