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

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

Bug fix in mkdir.

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