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
RevLine 
[787]1//////////////////////////////////////////////////////////////////////////////////
[587]2// Date     : 01/06/2015
3// Authors  : Alain Greiner
[258]4// Copyright (c) UPMC-LIP6
5//////////////////////////////////////////////////////////////////////////////////
[569]6// The fat32.h and fat32.c files define a library of access functions
[587]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.
[258]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
[587]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.
[258]25//////////////////////////////////////////////////////////////////////////////////
[587]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//////////////////////////////////////////////////////////////////////////////////
[258]33
34#include <giet_config.h>
[530]35#include <hard_config.h>
[258]36#include <fat32.h>
[530]37#include <utils.h>
38#include <vmem.h>
[587]39#include <kernel_malloc.h>
[709]40#include <ctx_handler.h>
[530]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>
[458]46#include <tty0.h>
[750]47#include <stdio.h>
[258]48
49//////////////////////////////////////////////////////////////////////////////////
[587]50//               Global variables
[258]51//////////////////////////////////////////////////////////////////////////////////
52
[587]53// Fat-Descriptor
54__attribute__((section(".kdata")))
[761]55fat_desc_t     _fat __attribute__((aligned(64))); 
[258]56
[587]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)));
[530]60
[587]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)));
[530]64
[587]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
[530]81
[587]82static void _display_fat_descriptor();
[530]83
[773]84static void _display_clusters_list();
[530]85
[773]86#endif
[530]87
[587]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
[783]118static unsigned int _set_fs_info();
119
[587]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
[638]139static unsigned int _is_ancestor( fat_inode_t* a,
140                                  fat_inode_t* b);
141
[773]142static unsigned int _get_sfn_name( char*          name,
143                                   unsigned int*  length,
144                                   unsigned int*  nb_lfn,
145                                   char*          sfn,
146                                   unsigned char* checksum );
[587]147
148static unsigned int _update_dir_entry( fat_inode_t*  inode );
149
[787]150static unsigned int _add_dir_entry( fat_inode_t* child );
[587]151
152static unsigned int _remove_dir_entry( fat_inode_t*  inode );
153
[787]154static void _add_special_directories( fat_inode_t* child );
[587]155
[783]156static unsigned int _one_cluster_allocate( fat_inode_t*   inode, 
157                                           unsigned int*  cluster );
[587]158
[783]159static unsigned int _all_clusters_release( fat_inode_t* inode );
[587]160
[651]161static void _release_cache_memory( fat_cache_node_t*  root,
162                                   unsigned int       levels );
[587]163
[639]164static fat_cache_node_t* _allocate_one_cache_node( fat_cache_node_t* first_child );
165
[587]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
[783]178static unsigned int _get_free_cluster( unsigned int*  cluster );
[587]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
[258]201
[530]202#if GIET_DEBUG_FAT
[587]203/////////////////////////////////////
204static void _display_fat_descriptor()
[530]205{
[587]206    _printf("\n###############  FAT DESCRIPTOR  ################################" 
[674]207            "\nFAT initialized                  %x"
[587]208            "\nBlock Size  (bytes)              %x"
209            "\nCluster Size  (bytes)            %x"
[530]210            "\nFAT region first lba             %x"
[587]211            "\nFAT region size (blocks)         %x"
212            "\nDATA region first lba            %x"
213            "\nDATA region size (blocks)        %x"
[530]214            "\nNumber of free clusters          %x"
[587]215            "\nFirst free cluster index         %x" 
216            "\nFat_cache_levels                 %d" 
[530]217            "\n#################################################################\n",
[674]218            _fat.initialized,
[530]219            _fat.sector_size,
[587]220            _fat.cluster_size,
[530]221            _fat.fat_lba,
[587]222            _fat.fat_sectors,
[530]223            _fat.data_lba,
[587]224            _fat.data_sectors,
225            _fat.free_clusters_number,
[783]226            _fat.free_cluster_hint,
[587]227            _fat.fat_cache_levels );
228
229} // end _display_fat_descriptor()
[530]230#endif
231
[587]232
[773]233#if GIET_DEBUG_FAT
[587]234////////////////////////////////////////////////////////
235static void _display_clusters_list( fat_inode_t* inode )
[258]236{
[773]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 ) 
[587]245    {
[773]246        if ( (current < 2) || (cluster_id >= 1024) ) 
247        {
248            _printf("\n[FAT ERROR] in _display_clusters_list()\n");
249            _exit();
250        }
251
[587]252        _get_fat_entry( current , &next );
253        _printf(" > %X", current );
[773]254        cluster_id++;
255        if ( (cluster_id & 0x7) == 0 ) _printf("\n");
[587]256        current = next;
257    }
258    _printf("\n");
259}  // end _display_clusters_list()
260#endif
[258]261
[587]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
[291]271}
272
[587]273
274
275////////////////////////////////////////////////////////
276static unsigned int _read_entry( unsigned int    offset,
277                                 unsigned int    size,
278                                 unsigned char*  buffer,
279                                 unsigned int    little_endian )
[258]280{
[587]281    unsigned int n;
[258]282    unsigned int res  = 0;
283
[587]284    if ( little_endian)
[258]285    {
[587]286        for( n = size ; n > 0 ; n-- ) res = (res<<8) | buffer[offset+n-1];
[258]287    }
288    else
289    {
[587]290        for( n = 0 ; n < size ; n++ ) res = (res<<8) | buffer[offset+n];
[258]291    }
292    return res;
293
[587]294}  // end _read_entry
[258]295
296
297
[587]298//////////////////////////////////////////////////////////////////
299static inline unsigned int _cluster_to_lba( unsigned int cluster )       
[258]300{
[587]301    if ( cluster < 2 )
302    { 
[664]303        _printf("\n[FAT ERROR] _cluster_to_lba(): cluster smaller than 2\n");
[587]304        _exit();
[530]305    }
[258]306
[587]307   return  ((cluster - 2) << 3) + _fat.data_lba;
[258]308}
309
[587]310
[258]311//////////////////////////////////////////////////////
[596]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//////////////////////////////////////////////////////
[587]320static inline unsigned char _to_upper(unsigned char c)
[258]321{
322   if (c >= 'a' && c <= 'z') return (c & ~(0x20));
323   else                      return c;
324}
325
326
327
[587]328///////////////////////////////////////////////////////////////////////////
329static unsigned int _get_name_from_path( char*          pathname,  // input
330                                         char*          name,      // output
331                                         unsigned int*  nb_read )  // input & output   
[291]332{
[587]333    // skip leading "/" character
334    if ( pathname[*nb_read] == '/' ) *nb_read = *nb_read + 1;
[291]335
[587]336    // initialises current indexes
337    unsigned int i = *nb_read;
338    unsigned int j = 0;
[291]339   
[587]340    while ( (pathname[i] != '/') && (pathname[i] != 0) )
[291]341    {
[587]342        name[j++] = pathname[i++];   
343        if ( j > NAME_MAX_SIZE ) return 1;
[291]344    }
[587]345
346    // set end of string
[291]347    name[j] = 0;
348
[587]349    // skip trailing "/" character
[291]350    if ( pathname[i] == '/' ) *nb_read += j+1;
351    else                      *nb_read += j;
352
[587]353    return 0;
[291]354}
355
[587]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
[258]373////////////////////////////////////////////////////////////////////////////////
[587]374static void _get_name_from_short( unsigned char* buffer,  // input:  SFN dir_entry
375                                  char*          name )   // output: name
[258]376{
[596]377    unsigned int i;
378    unsigned int j = 0;
[258]379
[596]380    // get name
381    for ( i = 0; i < 8 && buffer[i] != ' '; i++ )
[258]382    {
[596]383        name[j] = _to_lower( buffer[i] );
384        j++;
[258]385    }
[596]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';
[258]402}
[291]403
[258]404///////////////////////////////////////////////////////////////////////////////
[587]405static void _get_name_from_long( unsigned char*  buffer, // input : LFN dir_entry
406                                 char*           name )  // output : name
[258]407{
[587]408    unsigned int   name_offset         = 0;
409    unsigned int   buffer_offset       = get_length(LDIR_ORD);
[258]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
[587]421    while ( (buffer_offset != DIR_ENTRY_SIZE)  && (!eof) )
[258]422    {
423        while (j != l_name_1 && !eof )
424        {
[587]425            if ( (buffer[buffer_offset] == 0x00) || 
426                 (buffer[buffer_offset] == 0xFF) )
[258]427            {
428                eof = 1;
429                continue;
430            }
[587]431            name[name_offset] = buffer[buffer_offset];
432            buffer_offset += 2;
[258]433            j += 2;
[587]434            name_offset++;
[258]435        }
436
[587]437        buffer_offset += (l_attr + l_type + l_chksum);
[258]438        j = 0;
439
440        while (j != l_name_2 && !eof )
441        {
[587]442            if ( (buffer[buffer_offset] == 0x00) || 
443                 (buffer[buffer_offset] == 0xFF) )
[258]444            {
445                eof = 1;
446                continue;
447            }
[587]448            name[name_offset] = buffer[buffer_offset];
449            buffer_offset += 2;
[258]450            j += 2;
[587]451            name_offset++;
[258]452        }
453
[587]454        buffer_offset += l_rsvd;
[258]455        j = 0;
456
457        while (j != l_name_3 && !eof )
458        {
[587]459            if ( (buffer[buffer_offset] == 0x00) || 
460                 (buffer[buffer_offset] == 0xFF) )
[258]461            {
462                eof = 1;
463                continue;
464            }
[587]465            name[name_offset] = buffer[buffer_offset];
466            buffer_offset += 2;
[258]467            j += 2;
[587]468            name_offset++;
[258]469        }
470    }
[587]471    name[name_offset] = 0;
[258]472} // end get_name_from_long()
473
[587]474
475
[761]476//////////////////////////////////////////////////////////////////////////////////
[639]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;
[587]481
[639]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
[587]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 )
[291]501{
[587]502    fat_inode_t* new_inode  = _malloc( sizeof(fat_inode_t) );
[291]503
[587]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;             
[291]514
[587]515    _strcpy( new_inode->name , name ); 
516
517    if ( cache_allocate )
[291]518    {
[639]519        new_inode->cache    = _allocate_one_cache_node( NULL );
[587]520        new_inode->levels   = _get_levels_from_size( size );
[291]521    }
522
[587]523    return new_inode;
524}   // end _allocate_one_inode()
[291]525
[587]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
[291]548    {
[587]549        inode->parent->child = inode->next;
[291]550    }
[587]551    else                  // removed inode is not the first
[291]552    {
[587]553        for( current = prev->next ; current ; current = current->next )
[291]554        {
[587]555            if ( current == inode )
[291]556            {
[587]557                prev->next = current->next;
[291]558            }
[587]559            prev = current;
560        }   
561    }   
562}  // end _delete_one_inode()
[291]563
564
565
[587]566/////////////////////////////////////////////////////////////////
567static inline unsigned int _get_fat_entry( unsigned int  cluster,
568                                           unsigned int* value )
[291]569{
[773]570    // compute cluster_id & entry_id in FAT from cluster index
571    // a FAT buffer is an array of 1024 unsigned int entries
[587]572    unsigned int       cluster_id = cluster >> 10;       
573    unsigned int       entry_id   = cluster & 0x3FF;
[291]574
[761]575    // get pointer on the relevant buffer descriptor in FAT cache
[587]576    fat_cache_desc_t*  pdesc;
577    unsigned int*      buffer;
[761]578    if ( _get_fat_cache_buffer( cluster_id,
579                                &pdesc ) ) return 1;
[587]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{
[773]594    // compute cluster_id & entry_id in FAT from cluster index
[587]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
[761]599    // get pointer on the relevant buffer descriptor in FAT cache
[587]600    fat_cache_desc_t*  pdesc;
601    unsigned int*      buffer; 
[761]602    if ( _get_fat_cache_buffer( cluster_id,
603                                &pdesc ) )  return 1;           
[587]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{
[639]620    // add cache levels if needed
621    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
622    {
[761]623
[773]624#if GIET_DEBUG_FAT
[639]625if ( _get_proctime() > GIET_DEBUG_FAT )
[787]626_printf("\n[DEBUG FAT] _allocate_one_buffer(): adding a cache level for %s\n",
627        inode->name );
[639]628#endif
629
630        inode->cache = _allocate_one_cache_node( inode->cache );
631        inode->levels++;
632    }
633
[587]634    // search the 64-tree cache from top to bottom
635    fat_cache_node_t*  node   = inode->cache;
[653]636    unsigned int       level;
[587]637
[653]638    for ( level = inode->levels; level != 0; level-- )
[587]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];
[761]646
[587]647            if ( pdesc != NULL )      // slot not empty!!!
648            {
[761]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 );
[587]653                _exit();
654            }
655
[773]656#if GIET_DEBUG_FAT
[569]657if ( _get_proctime() > GIET_DEBUG_FAT )
[664]658_printf("\n[DEBUG FAT] _allocate_one_buffer(): buffer allocated to <%s> for cluster_id %d\n",
[587]659        inode->name, cluster_id );
[291]660#endif
661
[653]662            // allocate buffer descriptor
663            pdesc = _malloc( sizeof(fat_cache_desc_t) );
[587]664            pdesc->lba     = _cluster_to_lba( cluster );
[653]665            pdesc->buffer  = _malloc( 4096 );
[587]666            pdesc->dirty   = 1;
[653]667            node->children[index] = pdesc;
[587]668        }
669        else                      // not last level => children are 64-tree nodes
[291]670        {
[587]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
[650]675                child = _allocate_one_cache_node( NULL );
[587]676                node->children[index] = child;   
677            }
678
679            // prepare next iteration
680            node  = child;
[291]681        }
[653]682    } // end for
[587]683} // end _allocate_one_buffer
[530]684
685
[587]686
687
688///////////////////////////////////////////////////////////////////
[783]689static unsigned int _get_free_cluster( unsigned int*  cluster ) 
[587]690{
691    // scan FAT to get next free cluster index
[783]692    unsigned int current = _fat.free_cluster_hint;
[587]693    unsigned int max     = (_fat.data_sectors >> 3);
694    unsigned int value;
[783]695    while ( current < max )
[530]696    {
[587]697        // get FAT entry indexed by current
698        if ( _get_fat_entry( current , &value ) ) return 1;
[773]699
[783]700        // return if free
701        if ( value == FREE_CLUSTER )
702        {
703            *cluster = current;
704            return 0;
705        }
706
707        // increment current
708        current++;
[587]709    }
710       
[783]711    // return error if not found 
712    return 1;
[530]713
[783]714}  // end _get_free_cluster()
[587]715
716
717
[291]718
[587]719//////////////////////////////////////////////////////////////////////////
720static unsigned int _update_device_from_cache( unsigned int        levels,
721                                               fat_cache_node_t*   root,
722                                               char*               string )
[291]723{
[587]724    unsigned int index;
725    unsigned int ret = 0;
[291]726
[761]727    if ( levels == 1 )  // last level => children are buffer descriptors
[291]728    {
[587]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                    {
[664]743                        _printf("\n[FAT_ERROR] _update_device from_cache(): "
[587]744                                " cannot access lba = %x\n", pdesc->lba );
745                        ret = 1;
746                    }
747                    else
748                    {
749                        pdesc->dirty = 0;
750
[773]751#if GIET_DEBUG_FAT
[587]752if ( _get_proctime() > GIET_DEBUG_FAT )
[664]753_printf("\n[DEBUG FAT] _update_device_from_cache(): cluster_id = %d for <%s>\n",
[587]754        index , string );
755#endif
756
757                    }
758                }
759            }
760        }
[291]761    }
[587]762    else               // not the last level = recursive call on each children
[291]763    {
[587]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        }
[291]774    }
[587]775    return ret;
776}  // end _update_device_from_cache()
[291]777
778
[587]779
780///////////////////////////////////////////////////////////////////
[651]781static void _release_cache_memory( fat_cache_node_t*  root,
782                                   unsigned int       levels )
[587]783{
[651]784    unsigned int i;
[587]785
786    if ( levels == 1 )  // last level => children are cluster descriptors
[503]787    {
[651]788        for( i = 0 ; i < 64 ; i++ )
[587]789        { 
[651]790            fat_cache_desc_t* pdesc = root->children[i];
[587]791
792            if ( pdesc != NULL )
793            { 
794                // check dirty
795                if ( pdesc->dirty )
[664]796                    _printf("\n[FAT ERROR] _release_cache_memory(): dirty cluster\n");
[651]797
798                _free( pdesc->buffer );
799                _free( pdesc );
800                root->children[i] = NULL;
[587]801            }
802        }
[503]803    }
[587]804    else               // not the last level = recursive call on each children
805    {
[651]806        for( i = 0 ; i < 64 ; i++ )
[587]807        { 
[651]808            fat_cache_node_t* cnode = root->children[i];
[291]809
[651]810            if ( cnode != NULL )
811            {
812                _release_cache_memory( cnode, levels - 1 );
813                _free( cnode );
814                root->children[i] = NULL;
815            }
[587]816        }
817    }
818}  // end _release_cache_memory()
819
820
821
822
823
[783]824////////////////////////////////////////////////////////////////
825static unsigned int _one_cluster_allocate( fat_inode_t*   inode,
826                                           unsigned int*  cluster ) 
[587]827{
[787]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
[761]834    // Check free cluster available
835    if ( _fat.free_clusters_number == 0 )
[291]836    {
[783]837        _printf("\n[FAT ERROR] in _one_cluster_allocate(): no more free clusters\n");
[587]838        return 1;
839    }
[291]840
[783]841    // scan the Fat-Cache to get last allocated cluster index
[761]842    unsigned int nb_current_clusters = 0;
[587]843    unsigned int current = inode->cluster;
[761]844    unsigned int last    = current;
845    unsigned int next    = 0;
846    unsigned int new     = 0;
847    while ( current < END_OF_CHAIN_CLUSTER_MIN )
[587]848    {
[761]849        // get next cluster
[783]850        if ( _get_fat_entry( current , &next ) )
851        {
852            _printf("\n[FAT ERROR] in _one_cluster_allocate() scanning FAT\n");
853            return 1;
854        }
[761]855       
856        // increment number of allocated clusters
857        nb_current_clusters++;
[291]858
[761]859        // update loop variables
860        last    = current;
861        current = next;
862    } 
[587]863
[761]864    // allocate one free cluster from FAT
[783]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    }
[291]870
[761]871    // allocate one 4K buffer to File-Cache
872    _allocate_one_buffer( inode,
873                          nb_current_clusters,
874                          new );
[291]875
[783]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
[787]887    // update cluster chaining
888    if ( nb_current_clusters == 0 )  // first cluster : update cluster field in inode
[761]889    {
890        inode->cluster = new;
891    }
[787]892    else                             // not the last : update previous last cluster in FAT
[761]893    {
[783]894        if ( _set_fat_entry( last , new ) ) 
895        {
896            _printf("\n[FAT ERROR] in _one_cluster_allocate() accessing FAT\n");
897            return 1;
898        }
[761]899    }
[587]900
[773]901    // update the FAT on device
[587]902    if ( _update_device_from_cache( _fat.fat_cache_levels,
903                                    _fat.fat_cache_root,
[783]904                                    "FAT" ) ) 
905    {
906        _printf("\n[FAT ERROR] in _one_cluster_allocate() updating FAT on device\n");
907        return 1;
908    }
[773]909
910    // update FS-INFO sector on device
[783]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    }
[773]916
917#if GIET_DEBUG_FAT
[761]918if ( _get_proctime() > GIET_DEBUG_FAT )
[787]919_printf("\n[DEBUG FAT] _one_cluster_allocate(): for <%s> cluster = %x\n",
920        inode->name , new );
[761]921#endif
922
923    // returns allocated cluster index
924    *cluster = new;
[587]925    return 0;
926
[783]927}  // end _one_cluster_allocate()
[587]928
[783]929////////////////////////////////////////////////////////////
[787]930// recursive function called by _all_clusters_release()
931////////////////////////////////////////////////////////////
[783]932static unsigned int _cluster_release( unsigned int cluster )
[587]933{
[783]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        }
[587]948
[783]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        }
[587]959
[783]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;
[587]963
[783]964        return 0;
[291]965    }
[783]966}  // end _cluster_release()
[291]967
[783]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
[587]980    if ( _update_device_from_cache( _fat.fat_cache_levels,
981                                    _fat.fat_cache_root,
[783]982                                    "FAT" ) )
983    {
984        _printf("\n[FAT ERROR] in _all_clusters_release() updating FAT on device\n");
985        return 1;
986    }
[773]987
988    // update FS-INFO sector on device
[783]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    }
[773]994
995#if GIET_DEBUG_FAT
996if ( _get_proctime() > GIET_DEBUG_FAT )
[783]997_printf("\n[DEBUG FAT] _all_clusters_release() done for file <%s>\n", inode->name );
[773]998#endif
999
[291]1000    return 0;
[783]1001}  // end _all_clusters_release()
[291]1002
[587]1003
1004
1005///////////////////////////////////////////////////////////
[787]1006static void _add_special_directories( fat_inode_t*  child )
[258]1007{
[787]1008    // get File-Cache buffer for child and cluster_id = 0
[587]1009    fat_cache_desc_t*   pdesc  = (fat_cache_desc_t*)child->cache->children[0];
1010    unsigned char*      entry;
[258]1011
[587]1012    unsigned int i;
1013    unsigned int cluster;
[417]1014
[587]1015    // set "." entry (32 bytes)
[787]1016    entry   = pdesc->buffer;
[587]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    }
[258]1030
[587]1031    // set ".." entry (32 bytes)
1032    entry   = pdesc->buffer + 32;
[787]1033    cluster = child->parent->cluster;
[258]1034
[787]1035    // handling special case when parent is root directory
1036    if ( cluster == 2 ) cluster = 0;
1037
[587]1038    for ( i = 0 ; i < 32 ; i++ )
[258]1039    {
[587]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;
[258]1048    }
[587]1049}  // end _add_special_directories
[258]1050
[358]1051
[587]1052
1053////////////////////////////////////////////////////////////
[638]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////////////////////////////////////////////////////////////
[773]1071static unsigned int _get_sfn_name( char*           name,
1072                                   unsigned int*   length,
1073                                   unsigned int*   nb_lfn,
1074                                   char*           sfn,
1075                                   unsigned char*  checksum )
[587]1076{
[773]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++ )
[258]1087    {
[773]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;
[587]1170        *nb_lfn  = 1;
1171        return 0;
1172    }
[773]1173    else if ( name_length <= 26 )
[587]1174    {
[773]1175        *length  = name_length;
[587]1176        *nb_lfn  = 2;
1177        return 0;
1178    }
[773]1179    else if ( name_length <= 31 )
[587]1180    {
[773]1181        *length  = name_length;
[587]1182        *nb_lfn  = 3;
1183        return 0;
1184    }
1185    else
1186    {
1187        return 1;
1188    }
[773]1189}  // _get_sfn_name()
[587]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 
[761]1214        if ( _get_file_cache_buffer( inode,
[587]1215                                     cluster_id,
[761]1216                                     0,         
[587]1217                                     &pdesc ) )   return 1;
1218        buffer = pdesc->buffer;
1219       
1220        // loop on directory entries in buffer
1221        while ( (offset < 4096) && (found == 0) )
[258]1222        {
[587]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 )
[258]1227            {
[587]1228                found = 1;
1229            } 
1230            else if ( ord == FREE_ENTRY )             // free entry => skip
1231            {
1232                offset = offset + 32;
[258]1233            }
[587]1234            else if ( attr == ATTR_LONG_NAME_MASK )   // LFN entry => skip
[258]1235            {
[587]1236                offset = offset + 32;
1237            }
1238            else                                      // NORMAL entry
1239            {
[620]1240                offset = offset + 32;
[587]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;
[773]1254}  // end _get_nb_entries()
[587]1255
1256
1257
[773]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
[787]1293//////////////////////////////////////////////////////////
1294static unsigned int _add_dir_entry( fat_inode_t*   child )
[587]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;
[787]1300    fat_inode_t*      parent  = child->parent;
[587]1301
[787]1302    if ( parent == NULL ) return 1;
1303
[773]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, 
[787]1311                        &length,
1312                        &nb_lfn,
1313                        sfn,
1314                        &checksum ) )  return 1;
[587]1315
[773]1316#if GIET_DEBUG_FAT
[587]1317if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1318_printf("\n[DEBUG FAT] _add_dir_entry(): try to add <%s> in <%s> / nb_lfn = %d\n", 
[587]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    {
[773]1334        // get the 4 Kytes buffer from File_Cache 
[761]1335        if ( _get_file_cache_buffer( parent,
[587]1336                                     cluster_id,
[761]1337                                     0,
[587]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 )
[258]1346            {
[587]1347                found        = 1;
1348                pdesc->dirty = 1;
1349            } 
1350            else
1351            {
1352                offset = offset + 32;
[258]1353            }
[587]1354        }  // end loop on entries
[773]1355
[587]1356        if ( found == 0 )
1357        {
1358            cluster_id++;
1359            offset = 0;
[258]1360        }
[587]1361    }  // end loop on clusters
[258]1362
[773]1363#if GIET_DEBUG_FAT
[587]1364if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1365_printf("\n[DEBUG FAT] _add_dir_entry(): get NO_MORE directory entry : "
[587]1366        " buffer = %x / offset = %x / cluster_id = %d\n",
1367        (unsigned int)buffer , offset , cluster_id );
1368#endif
[258]1369
[787]1370    // enter FSM to modify parent directory:
[587]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
[417]1377
[587]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
[417]1394        {
[761]1395            if ( _get_file_cache_buffer( parent,
[665]1396                                         cluster_id + 1,
[761]1397                                         0,
[665]1398                                         &pdesc ) )      return 1;
1399            buffer       = pdesc->buffer;
1400            pdesc->dirty = 1;
1401            offset       = 0;
[587]1402        }
[417]1403
[587]1404        // compute directory entry address
1405        entry = buffer + offset;
[417]1406
[773]1407#if GIET_DEBUG_FAT
[587]1408if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1409_printf("\n[DEBUG FAT] _add_dir_entry(): FSM step = %d /"
[587]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++ )
[258]1421                {
[587]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;
[773]1436                    else if (i == 13)     entry[i] = checksum;
[587]1437                    else                  entry[i] = 0x00;
[258]1438                }
[587]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++ )
[258]1447                {
[587]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;
[773]1462                    else if (i == 13)     entry[i] = checksum;
[587]1463                    else                  entry[i] = 0x00;
[258]1464                }
[587]1465                step--;
1466                break;
[258]1467            }
[587]1468            case 3:   // Write LFN1 entry   
[258]1469            {
[587]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;
[773]1488                    else if (i == 13)     entry[i] = checksum;
[587]1489                    else                  entry[i] = 0x00;
1490                }
1491                step--;
1492                break;
[258]1493            }
[587]1494            case 2:   // write NORMAL entry     
[258]1495            {
[587]1496                // scan the 32 bytes in dir_entry
1497                for ( i = 0 ; i < 32 ; i++ )
[258]1498                {
[773]1499                    if      ( i < 11 )                              // 8.3 SFN
[417]1500                    {
[773]1501                                          entry[i] = sfn[i];
[417]1502                    }
[587]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;
[258]1517                }
[587]1518
1519                // update the dentry field in child inode
1520                child->dentry = ((cluster_id<<12) + offset)>>5;
1521
1522                step--;
1523                break;
[417]1524            }
[587]1525            case 1:   // write NOMORE entry 
[417]1526            {
[787]1527                entry [0] = 0x00;
[587]1528                step--;
1529                break;
1530            }
1531        } // end switch step
1532        offset += 32;
1533    } // exit while => exit FSM   
1534
[773]1535#if GIET_DEBUG_FAT
[587]1536if ( _get_proctime() > GIET_DEBUG_FAT )
1537{
[664]1538    _printf("\n[DEBUG FAT] _add_dir_entry(): <%s> successfully added in <%s>\n",
[587]1539            child->name , parent->name );
1540}
1541#endif
1542
1543    return 0;       
[787]1544} // end _add_dir_entry()
[587]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;
[773]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;
[587]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
[761]1567    if ( _get_file_cache_buffer( inode->parent,
[587]1568                                 cluster_id,
[761]1569                                 0,
[587]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    {
[616]1580        if (offset == 0)  // we must load buffer for (cluster_id - 1)
[587]1581        {
[636]1582            if ( cluster_id == 0 )
1583                break;
1584
[761]1585            if ( _get_file_cache_buffer( inode->parent,
[587]1586                                         cluster_id - 1,
[761]1587                                         0,
[587]1588                                         &pdesc ) )   return 1;
1589            buffer       = pdesc->buffer;
1590            pdesc->dirty = 1;
[616]1591            offset       = 4096;
[587]1592        }
1593
[616]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
[587]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
[773]1619#if GIET_DEBUG_FAT
[587]1620if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1621_printf("\n[DEBUG FAT] _get_child_from_parent(): search <%s> in directory <%s>\n",
[587]1622        name , parent->name );
1623#endif
1624   
1625    // scan inodes in the parent directory
1626    for ( current = parent->child ; current ; current = current->next )
1627    {
[619]1628        if ( _strcmp( name , current->name ) == 0 )
[587]1629        {
1630
[773]1631#if GIET_DEBUG_FAT
[587]1632if ( _get_proctime() > GIET_DEBUG_FAT )
[773]1633_printf("\n[DEBUG FAT] _get_child_from_parent(): found inode for <%s> in <%s>\n", 
[587]1634        name , parent->name );
1635#endif
1636            *inode = current;
1637            return 0;           // name found
1638        }
1639    }
1640
[761]1641    // not found in Inode-Tree => access the parent directory file_cache.
1642    // Two embedded loops:
[587]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
[597]1656    unsigned int      lfn = 0;          // LFN entries number
[587]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
[773]1662#if GIET_DEBUG_FAT
[587]1663if ( _get_proctime() > GIET_DEBUG_FAT )
[773]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 );
[587]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;
[761]1673        if ( _get_file_cache_buffer( parent,
[587]1674                                     cluster_id,
[761]1675                                     0,
[587]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
[750]1685            if (ord == NO_MORE_ENTRY)                 // no more entry => break
[587]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 )
[258]1706                {
[587]1707                    _get_name_from_short( buffer + offset , cname );
[258]1708                }
[587]1709                else if ( lfn == 1 )
[417]1710                {
[587]1711                    _strcpy( cname      , lfn1 );
1712                }   
1713                else if ( lfn == 2 ) 
1714                {
1715                    _strcpy( cname      , lfn1 );
1716                    _strcpy( cname + 13 , lfn2 );
[417]1717                }
[587]1718                else if ( lfn == 3 ) 
1719                {
1720                    _strcpy( cname      , lfn1 );
1721                    _strcpy( cname + 13 , lfn2 );
1722                    _strcpy( cname + 26 , lfn3 );
1723                }
[773]1724
1725                // get dentry arguments if extracted name == searched name
[619]1726                if ( _strcmp( name , cname ) == 0 )
[587]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;
[258]1737            }
[587]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
[773]1746#if GIET_DEBUG_FAT
[587]1747if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1748_printf("\n[DEBUG FAT] _get_child_from_parent(): found end of directory in <%s>\n",
[587]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
[773]1768#if GIET_DEBUG_FAT
[587]1769if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1770_printf("\n[DEBUG FAT] _get_child_from_parent(): found <%s> on device\n", name );
[587]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
[773]1790#if GIET_DEBUG_FAT
[587]1791if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1792_printf("\n[DEBUG FAT] _get_inode_from_path(): enters for path <%s>\n", pathname );
[587]1793#endif
1794
1795    // handle root directory case
[619]1796    if ( _strcmp( pathname , "/" ) == 0 )
[587]1797    {
1798
[773]1799#if GIET_DEBUG_FAT
[587]1800if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1801_printf("\n[DEBUG FAT] _get_inode_from_path(): found root inode for <%s>\n", 
[587]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   
[617]1816    while ( !last )
[587]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
[258]1822        }
1823
[587]1824        // compute last iteration condition
1825        last = (pathname[nb_read] == 0);
[258]1826
[773]1827#if GIET_DEBUG_FAT
[569]1828if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1829_printf("\n[DEBUG FAT] _get_inode_from_path(): got name <%s>\n", name );
[417]1830#endif
1831
[619]1832        if ( _strcmp( name, ".." ) == 0)
[587]1833        {
[617]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        }
[619]1841        else if ( _strcmp( name, "." ) == 0 )
[617]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 );
[417]1853
[617]1854            // we need to find the child inode for all non terminal names
1855            if ( (code == 2) || ((code == 1 ) && !last) )
1856            {
1857
[773]1858    #if GIET_DEBUG_FAT
[617]1859    if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1860    _printf("\n[DEBUG FAT] _get_inode_from_path(): neither parent, nor child found for <%s>\n",
[617]1861            pathname );
1862    #endif
1863                return 2;  // error : parent inode not found
1864            }
[587]1865        }
[617]1866
[587]1867        // update parent if not the last iteration
[617]1868        if ( !last )
1869            parent = child;
[587]1870    } // end while
1871
1872    // returns inode pointer
1873    if (code == 0 )
1874    {
1875
[773]1876#if GIET_DEBUG_FAT
[587]1877if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1878_printf("\n[DEBUG FAT] _get_inode_from_path(): found inode for <%s>\n", 
[587]1879        pathname );
1880#endif
1881        *inode  = child;
1882    }
1883    else
1884    {
1885
[773]1886#if GIET_DEBUG_FAT
[587]1887if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1888_printf("\n[DEBUG FAT] _get_inode_from_path(): found only parent inode for <%s>\n",
[587]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 )
[258]1903{
[637]1904    // check for root node
1905    if ( !inode->parent ) return 1;
1906
[587]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
[783]1916    if ( _all_clusters_release( inode ) ) return 1;
[587]1917
1918    // release File-Cache
[651]1919    _release_cache_memory( inode->cache, inode->levels );
1920    _free ( inode->cache );
[587]1921
1922    // remove inode from Inode-Tree
1923    _remove_inode_from_tree( inode );
1924
1925    // release inode
1926    _free ( inode );
1927
[258]1928    return 0;
[587]1929}  // end _remove_node_from_fs()
[258]1930
1931
[587]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;
[258]1940
[587]1941    // compute lba of cluster identified by cluster_id
1942    unsigned int lba = _fat.fat_lba + (cluster_id << 3);
[258]1943
[587]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        {
[664]1953            _printf("\n[FAT ERROR] _next_cluster_no_cache(): "
[587]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 )
[258]1975{
[587]1976   
[773]1977#if GIET_DEBUG_FAT
[587]1978if ( _get_proctime() > GIET_DEBUG_FAT )
[664]1979_printf("\n[DEBUG FAT] _file_info_no_cache(): enters for path <%s>\n", pathname );
[587]1980#endif
[258]1981
[587]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
[597]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
[587]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
[597]1995    unsigned int    lfn = 0;              // number of lfn entries
[587]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
[773]2014#if GIET_DEBUG_FAT
[587]2015if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2016_printf("\n[DEBUG FAT] _file_info_no_cache(): search name <%s>"
[587]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                {
[664]2036                    _printf("\n[FAT ERROR] _file_info_no_cache(): "
[587]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
[619]2094                    if ( _strcmp( name , cname ) == 0 )
[587]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        { 
[664]2115            _printf("\n[FAT ERROR] _file_info_no_cache(): <%s> not found\n",
[587]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        {
[664]2124            _printf("\n[FAT ERROR] _file_info_no_cache(): illegal type for <%s>\n", name );
[587]2125            return 1;
2126        }
2127
2128        // update parent_cluster for next name
2129        parent_cluster = child_cluster;
2130
2131    }  // end loop on names
2132
[773]2133#if GIET_DEBUG_FAT
[587]2134if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2135_printf("\n[DEBUG FAT] _file_info_no_cache(): success for <%s> / "
[587]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
[773]2147
2148/////////////////////////////
2149unsigned int _set_fs_info()
[761]2150{
[773]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) )
[761]2169    {
[773]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)  ); 
[761]2173        return 1;
2174    }
2175
[773]2176    _fat.free_clusters_number  = free_clusters;
2177
[783]2178    // initialise <free_cluster_hint> from FS_INFO sector
[773]2179    unsigned int free_cluster_hint = _read_entry( FS_FREE_CLUSTER_HINT, _fat.block_buffer, 1);     
2180    if ( free_cluster_hint > (data_blocks>>3) )
[761]2181    {
[773]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    }
[761]2187
[783]2188    _fat.free_cluster_hint  = free_cluster_hint;
[773]2189
[783]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 )
[773]2208    {
[783]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
[761]2214        {
[783]2215            _printf("\n[FAT_ERROR] _update_fs_info(): cannot read block\n");
[773]2216            return 1;
2217        }
[783]2218        _fat.block_buffer_lba = _fat.fs_info_lba;
2219    }
[761]2220
[783]2221    // update buffer
2222    unsigned int* ptr;
[773]2223
[783]2224    ptr  = (unsigned int*)(_fat.block_buffer + get_offset(FS_FREE_CLUSTERS) );
2225    *ptr = _fat.free_clusters_number;
[761]2226
[783]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
[773]2236    {
[783]2237        _printf("\n[FAT_ERROR] _update_fs_info(): cannot write block\n");
[773]2238        return 1;
2239    }
2240
2241#if GIET_DEBUG_FAT
[761]2242if ( _get_proctime() > GIET_DEBUG_FAT )
[783]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 );
[761]2245#endif
2246
[783]2247    return 0;
2248}  // end _update_fs_info()
[761]2249
2250
[783]2251
[773]2252///////////////////////////////////////////////////////////////////////////////
2253///////////////////////////////////////////////////////////////////////////////
2254//             Extern functions                                               
2255///////////////////////////////////////////////////////////////////////////////
2256///////////////////////////////////////////////////////////////////////////////
[761]2257
[773]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
[761]2278#if (GIET_DEBUG_FAT & 1)
2279if ( _get_proctime() > GIET_DEBUG_FAT )
[773]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 );
[761]2283#endif
2284
2285
[773]2286#if GIET_NO_HARD_CC     // L1 cache inval (virtual addresses)
2287    if ( to_mem ) _dcache_buf_invalidate( buf_vaddr, count<<9 );
2288#endif
[761]2289
2290
[773]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
[761]2305
[773]2306}  // end _fat_ioc_access()
[761]2307
[587]2308
2309
[773]2310/////////////////////////////////////////
[587]2311int _fat_init( unsigned int kernel_mode ) 
2312{
2313
[258]2314#if GIET_DEBUG_FAT
[569]2315if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2316_printf("\n[DEBUG FAT] _fat_init(): enters at cycle %d\n", _get_proctime() );
[258]2317#endif
[458]2318
2319    // FAT initialisation should be done only once
[674]2320    if ( _fat.initialized == FAT_INITIALIZED )
[458]2321    {
[664]2322        _printf("\n[FAT WARNING] _fat_init(): FAT already initialized\n");
2323        return GIET_FAT32_OK;
[458]2324    }
2325
[587]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
[258]2332    {
[664]2333        _printf("\n[FAT ERROR] _fat_init(): cannot load VBR\n");
2334        return GIET_FAT32_IO_ERROR;
[258]2335    }
2336
[587]2337    _fat.block_buffer_lba = 0;
2338   
2339#if GIET_DEBUG_FAT
[569]2340if ( _get_proctime() > GIET_DEBUG_FAT )
[587]2341{
[664]2342    _printf("\n[DEBUG FAT] _fat_init(): Boot sector loaded\n");
[587]2343}
[258]2344#endif
2345
2346    // checking various FAT32 assuptions from boot sector
[587]2347    if( _read_entry( BPB_BYTSPERSEC, _fat.block_buffer, 1 ) != 512 )
[258]2348    {
[664]2349        _printf("\n[FAT ERROR] _fat_init(): The sector size must be 512 bytes\n");
2350        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2351    }
[587]2352    if( _read_entry( BPB_SECPERCLUS, _fat.block_buffer, 1 ) != 8 )
[258]2353    {
[664]2354        _printf("\n[FAT ERROR] _fat_init(): The cluster size must be 8 blocks\n");
2355        return GIET_FAT32_INVALID_BOOT_SECTOR;
[587]2356    }
2357    if( _read_entry( BPB_NUMFATS, _fat.block_buffer, 1 ) != 1 )
2358    {
[664]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;
[258]2361    }
[587]2362    if( (_read_entry( BPB_FAT32_FATSZ32, _fat.block_buffer, 1 ) & 0xF) != 0 )
[258]2363    {
[664]2364        _printf("\n[FAT ERROR] _fat_init(): The FAT region must be multiple of 16 sectors\n");
2365        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2366    }
[587]2367    if( _read_entry( BPB_FAT32_ROOTCLUS, _fat.block_buffer, 1 ) != 2 )
[258]2368    {
[664]2369        _printf("\n[FAT ERROR] _fat_init(): The root directory must be at cluster 2\n");
2370        return GIET_FAT32_INVALID_BOOT_SECTOR;
[258]2371    }
2372
[587]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;
[530]2379    _fat.data_lba            = _fat.fat_lba + _fat.fat_sectors;
[587]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;
[674]2383    _fat.initialized         = FAT_INITIALIZED;
[258]2384
[773]2385    /////////////////////////////////////////////////////////////////////
[587]2386    // This is done only when the _fat_init() is called in kernel mode
[291]2387
[587]2388    if ( kernel_mode )
2389    {
[773]2390        // initialise <free_clusters_number> and <first_free_cluster in FAT descriptor
2391        if ( _set_fs_info() ) return GIET_FAT32_IO_ERROR;
[587]2392
[652]2393        // create Inode-Tree root
[761]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
[587]2401
[652]2402        // initialize lock
[587]2403        _spin_lock_init( &_fat.fat_lock );
2404
[652]2405        // initialize File Descriptor Array
[773]2406        unsigned int i;
[652]2407        for( i = 0 ; i < GIET_OPEN_FILES_MAX ; i++ ) _fat.fd[i].allocated = 0;
[587]2408
[652]2409        // initialize fat_cache root
[650]2410        _fat.fat_cache_root   = _allocate_one_cache_node( NULL );
[587]2411        _fat.fat_cache_levels = _get_levels_from_size( _fat.fat_sectors << 9 );
2412    }  // end if kernel_mode
2413
[291]2414#if GIET_DEBUG_FAT
[569]2415if ( _get_proctime() > GIET_DEBUG_FAT )
[587]2416_display_fat_descriptor();
[291]2417#endif
2418
[664]2419    return GIET_FAT32_OK;
[258]2420}  // end _fat_init()
2421
[587]2422
2423
2424
[773]2425////////////////////////////////////////////////////////////////////
[587]2426int _fat_open( char*        pathname,     // absolute path from root
[772]2427               unsigned int flags )       // O_CREAT and O_RDONLY
[258]2428{
[587]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
[258]2434   
[587]2435    // get flags
[772]2436    unsigned int create    = ((flags & O_CREAT)  != 0);
[654]2437    unsigned int read_only = ((flags & O_RDONLY) != 0);
2438    unsigned int truncate  = ((flags & O_TRUNC)  != 0);
[587]2439
[258]2440#if GIET_DEBUG_FAT
[295]2441unsigned int procid  = _get_procid();
[429]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);
[569]2445if ( _get_proctime() > GIET_DEBUG_FAT )
[773]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 );
[258]2449#endif
2450
[674]2451    // checking FAT initialized
2452    if( _fat.initialized != FAT_INITIALIZED )
[458]2453    {
[664]2454        _printf("\n[FAT ERROR] _fat_open(): FAT not initialized\n");
2455        return GIET_FAT32_NOT_INITIALIZED;
[458]2456    }
[587]2457
[709]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();
[530]2461    _spin_lock_acquire( &_fat.fat_lock );
[709]2462    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[295]2463
[587]2464    // get inode pointer
2465    code = _get_inode_from_path( pathname , &inode );
2466
[761]2467    if ( code == 2 )                          // parent inode not found
[258]2468    {
[587]2469        _spin_lock_release( &_fat.fat_lock );
[709]2470        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2471
[664]2472        _printf("\n[FAT ERROR] _fat_open(): path to parent not found"
[587]2473                " for file <%s>\n", pathname );
[664]2474        return GIET_FAT32_FILE_NOT_FOUND;
[587]2475    }
[761]2476    else if ( code == 3 )                     // illegal path name
[587]2477    {
2478        _spin_lock_release( &_fat.fat_lock );
[709]2479        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2480
[664]2481        _printf("\n[FAT ERROR] _fat_open(): one name in path too long"
[587]2482                " for file <%s>\n", pathname );
[664]2483        return GIET_FAT32_NAME_TOO_LONG;
[587]2484    }
[773]2485    else if ( (code == 1) && (create == 0) )   // child inode not found
[587]2486    {
2487        _spin_lock_release( &_fat.fat_lock );
[709]2488        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2489
[664]2490        _printf("\n[FAT ERROR] _fat_open(): file not found"
[587]2491                " for file <%s>\n", pathname );
[664]2492        return GIET_FAT32_FILE_NOT_FOUND;
[587]2493    }
[773]2494    else if ( (code == 1) && (create != 0) )   // child inode not found => create
[587]2495    {
2496        // set parent inode pointer
2497        parent = inode;
[258]2498
2499#if GIET_DEBUG_FAT
[569]2500if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2501_printf("\n[DEBUG FAT] _fat_open(): P[%d,%d,%d] create a new file <%s>\n",
[587]2502        x , y , p , pathname );
[258]2503#endif
[291]2504
[587]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
[761]2515                                     0,                         // set by add_dir_entry
[587]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
[787]2522        // and update the dentry field in child inode
2523        if ( _add_dir_entry( child ) )
[258]2524        {
[587]2525            _spin_lock_release( &_fat.fat_lock );
[709]2526            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2527
[664]2528            _printf("\n[FAT ERROR] _fat_open(): cannot update parent directory"
[587]2529                    " for file <%s>\n" , pathname );
[664]2530            return GIET_FAT32_IO_ERROR;
[587]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 );
[709]2539            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2540
[664]2541            _printf("\n[FAT ERROR] _fat_open(): cannot update DATA region "
[587]2542                    " for parent of file <%s>\n", pathname );
[664]2543            return GIET_FAT32_IO_ERROR;
[258]2544        }
2545
[587]2546        // update FAT region on block device
2547        if ( _update_device_from_cache( _fat.fat_cache_levels,
2548                                        _fat.fat_cache_root,
2549                                        "FAT" ) )
[258]2550        {
[587]2551            _spin_lock_release( &_fat.fat_lock );
[709]2552            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2553
[664]2554            _printf("\n[FAT ERROR] _fat_open(): cannot update FAT region"
[587]2555                    " for file <%s>\n", pathname );
[664]2556            return GIET_FAT32_IO_ERROR;
[258]2557        }
[587]2558
[654]2559        // no need to truncate a new file
2560        truncate = 0;
[761]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]) );
[258]2571    }
[761]2572    else
[587]2573    {
[761]2574         _printf("\n");
2575    }
2576}
2577#endif
2578
2579    }
2580    else                                    // inode found
2581    {
[587]2582        // set searched file inode pointer
2583        child = inode;
[258]2584
[417]2585#if GIET_DEBUG_FAT
[569]2586if ( _get_proctime() > GIET_DEBUG_FAT )
[773]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}
[417]2594#endif
[773]2595
[587]2596    }
[258]2597
[587]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) )
[258]2601    {
[587]2602        fd_id++;
2603    }
2604
2605    // set file descriptor if an empty slot has been found
[654]2606    if ( fd_id >= GIET_OPEN_FILES_MAX )
[587]2607    {
[654]2608        _spin_lock_release( &_fat.fat_lock );
[709]2609        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2610
[664]2611        _printf("\n[FAT ERROR] _fat_open(): File-Descriptors-Array full\n");
2612        return GIET_FAT32_TOO_MANY_OPEN_FILES;
[654]2613    }
[587]2614
[654]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;
[587]2620
[654]2621    // increment the refcount
2622    child->count = child->count + 1;
[587]2623
[654]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
[783]2635        if ( _all_clusters_release( child ) )
[654]2636        {
2637            _spin_lock_release( &_fat.fat_lock );
[709]2638            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2639
[664]2640            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2641            return GIET_FAT32_IO_ERROR;
[654]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 );
[709]2648            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2649
[664]2650            _printf("\n[FAT ERROR] _fat_open(): can't truncate file\n");
2651            return GIET_FAT32_IO_ERROR;
[654]2652        }
2653    }
2654
[587]2655#if GIET_DEBUG_FAT
2656if ( _get_proctime() > GIET_DEBUG_FAT )
[773]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 );
[587]2665#endif
[761]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
[654]2671    return fd_id;
[587]2672} // end _fat_open()
2673
2674
2675
2676
[773]2677////////////////////////////////////
[587]2678int _fat_close( unsigned int fd_id )
2679{
[674]2680    // checking FAT initialized
2681    if( _fat.initialized != FAT_INITIALIZED )
[587]2682    {
[664]2683        _printf("\n[FAT ERROR] _fat_close(): FAT not initialized\n");
2684        return GIET_FAT32_NOT_INITIALIZED;
[587]2685    }
2686
2687    if( (fd_id >= GIET_OPEN_FILES_MAX) )
2688    {
[664]2689        _printf("\n[FAT ERROR] _fat_close(): illegal file descriptor index\n");
2690        return GIET_FAT32_INVALID_FD;
[587]2691    } 
2692
[709]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();
[587]2696    _spin_lock_acquire( &_fat.fat_lock );
[709]2697    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[587]2698
[625]2699    if( _fat.fd[fd_id].allocated == 0 )
2700    {
2701        _spin_lock_release( &_fat.fat_lock );
[709]2702        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2703
[664]2704        _printf("\n[FAT ERROR] _fat_close(): file not open\n");
2705        return GIET_FAT32_NOT_OPEN;
[625]2706    }
2707
[587]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 )
[761]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 );
[587]2716#endif
2717
[761]2718    // decrement reference count
2719    inode->count = inode->count - 1;
2720   
[587]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 ) ) 
[258]2728        {
[587]2729            _spin_lock_release( &_fat.fat_lock );
[709]2730            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2731
[664]2732            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
[587]2733                    "for file <%s>\n", inode->name );
[664]2734            return GIET_FAT32_IO_ERROR;
[258]2735        }
2736
[587]2737#if GIET_DEBUG_FAT
2738if ( _get_proctime() > GIET_DEBUG_FAT )
[761]2739_printf("\n[FAT DEBUG] _fat_close() updated device for file <%s>\n", inode->name );
[587]2740#endif
2741
[761]2742        // update dirty clusters for parent directory
[624]2743        if ( inode->parent &&
2744             _update_device_from_cache( inode->parent->levels,
[587]2745                                        inode->parent->cache,
[624]2746                                        inode->parent->name ) )
[258]2747        {
[587]2748            _spin_lock_release( &_fat.fat_lock );
[709]2749            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2750
[664]2751            _printf("\n[FAT ERROR] _fat_close(): cannot write dirty clusters "
[587]2752                    "for directory <%s>\n", inode->parent->name );
[664]2753            return GIET_FAT32_IO_ERROR;
[587]2754        }
[258]2755
2756#if GIET_DEBUG_FAT
[569]2757if ( _get_proctime() > GIET_DEBUG_FAT )
[761]2758_printf("\n[FAT DEBUG] _fat_close() updated device for parent directory <%s>\n",
[587]2759        inode->parent->name );
[258]2760#endif
2761
[651]2762        // release memory allocated to File-Cache (keep cache root node)
2763        _release_cache_memory( inode->cache, inode->levels );
[587]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
[773]2771    }  // end if (refcount == 0)
[587]2772
[773]2773
[587]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 );
[709]2779    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]2780
[664]2781    return GIET_FAT32_OK;
[587]2782} // end fat_close()
2783
2784
2785
2786
[773]2787////////////////////////////////////////////
[658]2788int _fat_file_info( unsigned int     fd_id,
2789                    fat_file_info_t* info )
[587]2790{
[674]2791    if ( _fat.initialized != FAT_INITIALIZED )
[258]2792    {
[664]2793        _printf("\n[FAT ERROR] _fat_file_info(): FAT not initialized\n");
2794        return GIET_FAT32_NOT_INITIALIZED;
[258]2795    }
2796
[623]2797    if ( fd_id >= GIET_OPEN_FILES_MAX )
[587]2798    {
[664]2799        _printf("\n[FAT ERROR] _fat_file_info(): illegal file descriptor index\n");
2800        return GIET_FAT32_INVALID_FD;
[587]2801    } 
[258]2802
[587]2803    if ( _fat.fd[fd_id].allocated == 0 )
2804    {
[664]2805        _printf("\n[FAT ERROR] _fat_file_info(): file not open\n");
2806        return GIET_FAT32_NOT_OPEN;
[258]2807    }
[587]2808
[623]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
[664]2813    return GIET_FAT32_OK;
[587]2814} // end _fat_file_info()
2815
2816
2817
2818
[773]2819/////////////////////////////////////////////////////////////////////
[707]2820int _fat_read( unsigned int fd_id,          // file descriptor index
[709]2821               unsigned int vaddr,          // destination buffer vaddr
[707]2822               unsigned int count,          // number of bytes to read
[750]2823               unsigned int extend,         // physical address extension
2824               unsigned int offset,         // forced file offset
2825               unsigned int modes )         // special modes
[587]2826{
[709]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"
[750]2835        "  fd = %d / vaddr = %x / bytes = %x / extend = %x / forced_offset = %x\n",
[709]2836        x , y , p , _get_proctime(),
[750]2837        fd_id , vaddr , count , extend , offset );
[709]2838#endif
2839
[674]2840    // checking FAT initialized
2841    if( _fat.initialized != FAT_INITIALIZED )
[258]2842    {
[750]2843        _printf("\n[FAT ERROR] in _fat_read(): FAT not initialized\n");
[664]2844        return GIET_FAT32_NOT_INITIALIZED;
[258]2845    }
[587]2846
2847    // check fd_id overflow
2848    if ( fd_id >= GIET_OPEN_FILES_MAX )
[258]2849    {
[750]2850        _printf("\n[FAT ERROR] in _fat_read(): illegal file descriptor\n");
[664]2851        return GIET_FAT32_INVALID_FD;
[258]2852    }
[358]2853
[750]2854    // check file open
[587]2855    if ( _fat.fd[fd_id].allocated == 0 )
2856    {
[750]2857        _printf("\n[FAT ERROR] in _fat_read(): file not open\n");
[664]2858        return GIET_FAT32_NOT_OPEN;
[587]2859    }
[358]2860
[709]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();
[587]2864    _spin_lock_acquire( &_fat.fat_lock );
[709]2865    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[587]2866           
[750]2867    // get special modes
2868    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
2869    unsigned int forced_offset       = modes & FAT_FORCED_OFFSET;
2870
[587]2871    // get file inode pointer and offset
2872    fat_inode_t* inode  = _fat.fd[fd_id].inode;
[750]2873    unsigned int seek   = forced_offset ? offset : _fat.fd[fd_id].seek;
[587]2874
[730]2875    // check seek versus file size
2876    if ( (seek >= inode->size) && !inode->is_dir )
[258]2877    {
[587]2878        _spin_lock_release( &_fat.fat_lock );
[709]2879        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2880
[750]2881        _printf("\n[FAT ERROR] in _fat_read(): offset larger than file size"
[730]2882                " / seek = %x / file_size = %x\n",
2883                seek , inode->size );
2884        return GIET_FAT32_IO_ERROR;
[258]2885    }
2886
[744]2887    // check and ajust count argument for a file
2888    if ( (count > (inode->size - seek)) && !inode->is_dir ) count = inode->size - seek;
[730]2889
[587]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;   
[258]2893
[587]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;
[258]2897
2898#if GIET_DEBUG_FAT
[569]2899if ( _get_proctime() > GIET_DEBUG_FAT )
[709]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"
[587]2902        " / last_cluster_id = %x / last_byte_to_move = %x\n",
[709]2903        x , y , p , inode->name , seek ,
[587]2904        first_cluster_id , first_byte_to_move , last_cluster_id , last_byte_to_move );
[258]2905#endif
2906
[587]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++ )
[258]2911    {
[587]2912        // get pointer on the cluster_id buffer in cache
2913        unsigned char*     cbuf;
2914        fat_cache_desc_t*  pdesc;
[761]2915        if ( _get_file_cache_buffer( inode, 
[587]2916                                     cluster_id,
[761]2917                                     0,
[587]2918                                     &pdesc ) )
2919        {
2920            _spin_lock_release( &_fat.fat_lock );
[709]2921            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
2922
[750]2923            _printf("\n[FAT ERROR] in _fat_read(): cannot load file <%s>\n",
[587]2924                    inode->name );
[664]2925            return GIET_FAT32_IO_ERROR;
[587]2926        }
2927        cbuf = pdesc->buffer;
2928
2929#if GIET_DEBUG_FAT
2930if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2931_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] moves cluster_id %d from Cache-File <%s>\n",
[587]2932        x , y , p , cluster_id, inode->name );
2933#endif
2934
2935        // compute memcpy arguments
2936        unsigned char*  source;
2937        unsigned int    nbytes;
[707]2938
[587]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
[709]2960        // move data
[750]2961        if ( physical_addressing == 0 )           // no physical addressing
[707]2962        {
[709]2963            char* dest = (char*)(vaddr + done);
2964            memcpy( dest , source , nbytes );
[707]2965        }
[709]2966        else                                      // physical addressing required
[707]2967        {
2968            unsigned int flags;
[750]2969            paddr_t pdest    = (((paddr_t)extend)<<32) + vaddr + done;
[707]2970            paddr_t psource  = _v2p_translate( (unsigned int)source, &flags );
[709]2971            _physical_memcpy( pdest , psource , nbytes );
[707]2972        }
2973
[587]2974        done = done + nbytes;
[258]2975    }
2976
[587]2977#if GIET_DEBUG_FAT
2978if ( _get_proctime() > GIET_DEBUG_FAT )
[664]2979_printf("\n[DEBUG FAT] _fat_read(): P[%d,%d,%d] loaded file <%s> from Cache-File\n",
[587]2980        x , y , p , inode->name );
2981#endif
[258]2982
[750]2983    // update seek if required
2984    if ( forced_offset == 0 ) _fat.fd[fd_id].seek += done;
[258]2985
[587]2986    // release lock
2987    _spin_lock_release( &_fat.fat_lock );
[709]2988    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]2989
2990    return done;
2991} // end _fat_read()
2992
2993
2994
2995
[773]2996////////////////////////////////////////////////////////////////
[587]2997int _fat_write( unsigned int fd_id,    // file descriptor index
[709]2998                unsigned int vaddr,    // source buffer vaddr
2999                unsigned int count,    // number of bytes to write
[750]3000                unsigned int extend,   // physical address extension
3001                unsigned int modes )   // special modes
[587]3002{
[674]3003    // checking FAT initialized
3004    if( _fat.initialized != FAT_INITIALIZED )
[258]3005    {
[674]3006        _printf("\n[FAT ERROR] _fat_write(): FAT not initialized\n");
[664]3007        return GIET_FAT32_NOT_INITIALIZED;
[587]3008    }
[258]3009
[709]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();
[587]3013    _spin_lock_acquire( &_fat.fat_lock );
[709]3014    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3015
[587]3016           
3017    // check fd_id overflow
3018    if ( fd_id >= GIET_OPEN_FILES_MAX )
3019    {
3020        _spin_lock_release( &_fat.fat_lock );
[709]3021        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3022
[664]3023        _printf("\n[FAT ERROR] _fat_write(): illegal file descriptor\n");
3024        return GIET_FAT32_INVALID_FD;
[587]3025    }
3026
3027    // check file open
3028    if ( _fat.fd[fd_id].allocated == 0 )
3029    {
3030        _spin_lock_release( &_fat.fat_lock );
[709]3031        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3032
[664]3033        _printf("\n[FAT ERROR] _fat_write(): file not open\n" );
3034        return GIET_FAT32_NOT_OPEN;
[587]3035    }
3036
3037    // check file writable
3038    if ( _fat.fd[fd_id].read_only )
3039    {
3040        _spin_lock_release( &_fat.fat_lock );
[709]3041        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3042
[664]3043        _printf("\n[FAT ERROR] _fat_write(): file <%s> is read-only\n",
[587]3044                _fat.fd[fd_id].inode->name );
[664]3045        return GIET_FAT32_READ_ONLY;
[587]3046    }
3047
[750]3048    // get special modes
3049    unsigned int physical_addressing = modes & FAT_PADDR_MODE;
3050
[587]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
[258]3055#if GIET_DEBUG_FAT
[587]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);
[569]3060if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3061_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] enters for file <%s> "
[587]3062        " / bytes = %x / seek = %x\n",
3063        x , y , p , inode->name , count , seek );
[258]3064#endif
3065
[773]3066    // check if file size must be incremented
[587]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 )
[258]3081        {
[587]3082
3083#if GIET_DEBUG_FAT
3084if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3085_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] allocates new clusters for file <%s>"
[587]3086        " / current = %d / required = %d\n",
3087        x , y , p , inode->name , old_clusters , new_clusters );
3088#endif
3089            // allocate missing clusters
[761]3090            unsigned int cid;
3091            unsigned int index;  // unused
3092            for ( cid = 0 ; cid < (new_clusters - old_clusters) ; cid++ )
[587]3093            {
[783]3094                if ( _one_cluster_allocate( inode , &index ) )
[761]3095                {
3096                    _spin_lock_release( &_fat.fat_lock );
3097                    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] ,
3098                                 ~LOCKS_MASK_FAT ); 
[709]3099
[761]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                }
[587]3104            }
[258]3105        }
3106         
[761]3107        // update size in inode
3108        inode->size = new_size;
3109 
[654]3110        // update parent directory entry (size and cluster index)
[587]3111        if ( _update_dir_entry( inode ) )
3112        {
3113            _spin_lock_release( &_fat.fat_lock );
[709]3114            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3115
[664]3116            _printf("\n[FAT ERROR] _fat_write(): cannot update parent directory entry"
[587]3117                    " for file <%s>\n", _fat.fd[fd_id].inode->name );
[664]3118            return GIET_FAT32_IO_ERROR;
[587]3119        }
3120           
3121
3122#if GIET_DEBUG_FAT
3123if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3124_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] updates size for file <%s> / size = %x\n",
[587]3125        x , y , p , inode->name , (new_size - old_size) );
3126#endif
3127
[258]3128    }
3129
[587]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;   
[258]3133
[587]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 )
[664]3140_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] starts loop on clusters for file <%s>\n"
[587]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;
[761]3155        if ( _get_file_cache_buffer( inode,   
[587]3156                                     cluster_id, 
[761]3157                                     0,
[587]3158                                     &pdesc ) )   
3159        {
3160            _spin_lock_release( &_fat.fat_lock );
[709]3161            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3162
[664]3163            _printf("\n[FAT ERROR] _fat_write(): cannot load file <%s>\n",
[587]3164                    inode->name );
[664]3165            return GIET_FAT32_IO_ERROR;
[587]3166        }
3167       
3168        cbuf         = pdesc->buffer;
3169        pdesc->dirty = 1;
3170   
3171#if GIET_DEBUG_FAT
3172if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3173_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] move cluster_id %d to Cache-file <%s>\n",
[587]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
[709]3201        // move data
[750]3202        if ( physical_addressing == 0 )     // no physical addressing
[709]3203        {
3204            char* source = (char*)(vaddr + done);
3205            memcpy( dest , source , nbytes ); 
3206        }
3207        else                                  // physical addressing required
3208        {
3209            unsigned int flags;
[750]3210            paddr_t      psource = (((paddr_t)extend)<<32) + vaddr + done;
[709]3211            paddr_t      pdest   = _v2p_translate( (unsigned int)dest , &flags );
3212            _physical_memcpy( pdest , psource , nbytes );
3213        }
3214
[587]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 )
[664]3224_printf("\n[DEBUG FAT] _fat_write(): P[%d,%d,%d] store file <%s> into Cache-File\n",
[587]3225        x , y , p , inode->name );
3226#endif
3227
3228    // release lock
3229    _spin_lock_release( &_fat.fat_lock );
[709]3230    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3231
3232    return done;
3233} // end _fat_write()
3234
3235
3236
[773]3237///////////////////////////////////
[587]3238int _fat_lseek( unsigned int fd_id,
3239                unsigned int seek,
3240                unsigned int whence )
[258]3241{
[674]3242    // checking FAT initialized
3243    if( _fat.initialized != FAT_INITIALIZED )
[587]3244    {
[664]3245        _printf("\n[FAT ERROR] _fat_lseek(): FAT not initialized\n");
3246        return GIET_FAT32_NOT_INITIALIZED;
[587]3247    }
[259]3248
[587]3249    // check fd_id overflow
3250    if ( fd_id >= GIET_OPEN_FILES_MAX )
3251    {
[664]3252        _printf("\n[FAT ERROR] _fat_lseek(): illegal file descriptor\n");
3253        return GIET_FAT32_INVALID_FD;
[587]3254    }
[259]3255
[709]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();
[587]3259    _spin_lock_acquire( &_fat.fat_lock );
[709]3260    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[259]3261
[709]3262
[587]3263    // check file open
3264    if ( _fat.fd[fd_id].allocated == 0 )
3265    {
3266        _spin_lock_release( &_fat.fat_lock );
[709]3267        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3268
[664]3269        _printf("\n[FAT ERROR] _fat_lseek(): file not open\n");
3270        return GIET_FAT32_NOT_OPEN;
[587]3271    }
[259]3272
[587]3273    unsigned int  new_seek;
[291]3274
[587]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;
[746]3278    else if ( whence == SEEK_END ) new_seek = _fat.fd[fd_id].inode->size + seek;
[587]3279    else
3280    {
3281        _spin_lock_release( &_fat.fat_lock );
[709]3282        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3283
[664]3284        _printf("\n[FAT ERROR] _fat_lseek(): illegal whence value\n");
3285        return GIET_FAT32_INVALID_ARG;
[587]3286    }
[291]3287
[587]3288    // update file descriptor offset
3289    _fat.fd[fd_id].seek = new_seek;
[291]3290
[259]3291#if GIET_DEBUG_FAT
[295]3292unsigned int procid  = _get_procid();
[429]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);
[569]3296if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3297_printf("\n[DEBUG FAT] _fat_lseek(): P[%d,%d,%d] set seek = %x for file <%s>\n",
[587]3298        x , y , p , new_seek , _fat.fd[fd_id].inode->name );
[259]3299#endif
3300
[587]3301    // release lock
3302    _spin_lock_release( &_fat.fat_lock );
[709]3303    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3304
3305    return new_seek;
3306}  // end _fat_lseek()
3307
3308
3309
[773]3310///////////////////////////////////////
[587]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 )
[664]3322_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] enters for path <%s>\n",
[587]3323        x, y, p, pathname );
3324#endif
3325
[674]3326    // checking FAT initialized
3327    if( _fat.initialized != FAT_INITIALIZED )
[587]3328    {
[664]3329        _printf("\n[FAT ERROR] _fat_remove(): FAT not initialized\n");
3330        return GIET_FAT32_NOT_INITIALIZED;
[259]3331    }
[587]3332
[709]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();
[587]3336    _spin_lock_acquire( &_fat.fat_lock );
[709]3337    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[587]3338
[709]3339
[587]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 )
[664]3345_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] found inode %x for <%s> / code = %d\n",
[587]3346        x , y , p , (unsigned int)inode , pathname , code );
3347#endif
3348
3349    if ( (code == 1) || (code == 2) )
[259]3350    {
[587]3351        _spin_lock_release( &_fat.fat_lock );
[709]3352        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3353
[664]3354        _printf("\n[FAT ERROR] _fat_remove(): file <%s> not found\n", 
[587]3355                pathname );
[664]3356        return GIET_FAT32_FILE_NOT_FOUND;
[259]3357    }
[587]3358    else if ( code == 3 )
[259]3359    {
[587]3360        _spin_lock_release( &_fat.fat_lock );
[709]3361        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3362
[664]3363        _printf("\n[FAT ERROR] _fat_remove(): name too long in <%s>\n",
[587]3364                pathname );
[664]3365        return GIET_FAT32_NAME_TOO_LONG;
[259]3366    }
3367
[587]3368    // check inode type
3369    if ( (inode->is_dir != 0) && (should_be_dir == 0) ) 
[291]3370    {
[587]3371        _spin_lock_release( &_fat.fat_lock );
[709]3372        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3373
[664]3374        _printf("\n[FAT ERROR] _fat_remove(): <%s> is a directory\n",
[587]3375                pathname );
[664]3376        return GIET_FAT32_IS_DIRECTORY;
[587]3377    }
3378    if ( (inode->is_dir == 0) && (should_be_dir != 0) )
3379    {
3380        _spin_lock_release( &_fat.fat_lock );
[709]3381        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3382
[664]3383        _printf("\n[FAT ERROR] _fat_remove(): <%s> is not a directory\n", 
[587]3384                pathname );
[664]3385        return GIET_FAT32_NOT_A_DIRECTORY;
[587]3386    }
3387
3388#if GIET_DEBUG_FAT
3389if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3390_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked inode type for <%s>\n",
[587]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 );
[709]3398        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3399
[664]3400        _printf("\n[FAT ERROR] _fat_remove(): file <%s> still referenced\n",
[587]3401                pathname );
[664]3402        return GIET_FAT32_IS_OPEN;
[587]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 ) )
[291]3410        {
[587]3411            _spin_lock_release( &_fat.fat_lock );
[709]3412            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3413
[664]3414            _printf("\n[FAT ERROR] _fat_remove(): cannot scan directory <%s>\n", 
[587]3415                    pathname );
[664]3416            return GIET_FAT32_IO_ERROR;
[291]3417        }
[587]3418        else if ( entries > 2 )
3419        {
3420            _spin_lock_release( &_fat.fat_lock );
[709]3421            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3422
[664]3423            _printf("\n[FAT ERROR] _fat_remove(): directory <%s> not empty\n", 
[587]3424                    pathname );
[664]3425            return GIET_FAT32_DIRECTORY_NOT_EMPTY;
[587]3426        }
[291]3427    }
3428
[587]3429#if GIET_DEBUG_FAT
3430if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3431_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] checked remove condition OK for <%s>\n",
[587]3432        x , y , p , pathname );
3433#endif
[259]3434   
[587]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 );
[709]3439        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3440
[664]3441        _printf("\n[FAT ERROR] _fat_remove(): cannot remove <%s> from FS\n",
[587]3442                pathname );
[664]3443        return GIET_FAT32_IO_ERROR;
[587]3444    }
[259]3445
[587]3446    // release lock and return success
3447    _spin_lock_release( &_fat.fat_lock );
[709]3448    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3449
[259]3450#if GIET_DEBUG_FAT
[569]3451if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3452_printf("\n[DEBUG FAT] _fat_remove(): P[%d,%d,%d] removed  <%s> from FS\n",
[587]3453        x, y, p, pathname );
[259]3454#endif
[587]3455   
[664]3456    return GIET_FAT32_OK;
[587]3457       
3458}  // end _fat_remove()
[259]3459
[587]3460
3461
3462
3463
[773]3464/////////////////////////////////
[587]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 )
[664]3482_printf("\n[DEBUG FAT] _fat_rename(): P[%d,%d,%d] enters to move <%s> to <%s>\n",
[587]3483        x , y , p , old_path , new_path );
3484#endif
3485
[674]3486    // checking FAT initialized
3487    if( _fat.initialized != FAT_INITIALIZED )
[259]3488    {
[664]3489        _printf("\n[FAT ERROR] _fat_rename(): FAT not initialized\n");
3490        return GIET_FAT32_NOT_INITIALIZED;
[259]3491    }
3492
[709]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();
[587]3496    _spin_lock_acquire( &_fat.fat_lock );
[709]3497    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
[259]3498
[709]3499
[587]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 );
[709]3504        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3505
[664]3506        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", old_path );
3507        return GIET_FAT32_FILE_NOT_FOUND;
[587]3508    }
3509    else
3510    {
3511        old        = inode;
3512        old_parent = inode->parent;
3513    }
[259]3514
[587]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
[259]3519    {
[621]3520        if ( inode == old )  // the file will replace itself, do nothing
3521        {
3522            _spin_lock_release( &_fat.fat_lock );
[709]3523            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3524
[664]3525            return GIET_FAT32_OK;
[621]3526        }
3527
[587]3528        to_remove        = inode;
[621]3529        new_parent       = inode->parent;
[587]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 );
[709]3539        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3540
[664]3541        _printf("\n[FAT ERROR] _fat_rename(): <%s> not found\n", new_path );
3542        return GIET_FAT32_FILE_NOT_FOUND;
[587]3543    }
[259]3544
[638]3545    // check for move into own subdirectory
3546    if ( _is_ancestor( old, new_parent ) )
3547    {
3548        _spin_lock_release( &_fat.fat_lock );
[709]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 );
[664]3552        return GIET_FAT32_MOVE_INTO_SUBDIR;
[638]3553    }
3554
[259]3555#if GIET_DEBUG_FAT
[569]3556if ( _get_proctime() > GIET_DEBUG_FAT )
[587]3557{
3558if ( to_remove )
[664]3559_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
[587]3560        "/ to_remove = %s\n",
3561        old_parent->name , old->name , new_parent->name , to_remove->name );
3562else
[664]3563_printf("\n[DEBUG FAT] _fat_rename(): old_parent = %s / old = %s / new_parent = %s "
[587]3564        "/ no remove\n", 
3565        old_parent->name , old->name , new_parent->name );
3566}
[259]3567#endif
3568
[587]3569    // check remove condition for "to_remove" inode
3570    if ( to_remove )
3571    {
3572        if ( to_remove->is_dir )   // it's a directory
[259]3573        {
[587]3574            unsigned int entries;
3575            if ( _get_nb_entries( to_remove , &entries ) )
3576            {
3577                _spin_lock_release( &_fat.fat_lock );
[709]3578                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3579
[664]3580                _printf("\n[FAT ERROR] _fat_rename(): cannot scan directory <%s>\n", 
[587]3581                        to_remove->name );
[664]3582                return GIET_FAT32_IO_ERROR;
[587]3583            }
3584            else if ( entries > 2 )
3585            {
3586                _spin_lock_release( &_fat.fat_lock );
[709]3587                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3588
[664]3589                _printf("\n[FAT ERROR] _fat_rename(): directory <%s> not empty\n", 
[587]3590                        to_remove->name );
[664]3591                return GIET_FAT32_DIRECTORY_NOT_EMPTY;
[587]3592            }
[259]3593        }
[587]3594        else                       // it's a file
3595        {
3596            if ( to_remove->count ) 
3597            {
3598                _spin_lock_release( &_fat.fat_lock );
[709]3599                _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3600
[664]3601                _printf("\n[FAT ERROR] _fat_rename(): file <%s> still referenced\n", 
[587]3602                        to_remove->name );
[664]3603                return GIET_FAT32_IS_OPEN;
[587]3604            }
3605        }
[259]3606    }
[291]3607
[587]3608#if GIET_DEBUG_FAT
3609if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3610_printf("\n[FAT DEBUG] _fat_rename(): P[%d,%d,%d] checked remove condition OK\n",
[587]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
[787]3624                               0,              // dentry set by _add_dir_entry()
[587]3625                               0 );            // no cache_allocate
3626 
[761]3627    // attach the "old" File-Cache to the "new" inode
[587]3628    new->levels = old->levels;
3629    new->cache  = old->cache;
3630
[787]3631    // add "new" to "new_parent" directory in Inode-Tree
3632    _add_inode_in_tree( new , new_parent );
3633   
[587]3634    // add "new" to "new_parent" directory File-Cache
[787]3635    // and update the dentry field in new inode
3636    if ( _add_dir_entry( new ) )
[291]3637    {
[587]3638        _spin_lock_release( &_fat.fat_lock );
[709]3639        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3640
[664]3641        _printf("\n[FAT ERROR] _fat_rename(): cannot add <%s> into <%s>\n",
[587]3642                new->name , new_parent->name );
[664]3643        return GIET_FAT32_IO_ERROR;
[291]3644    }
3645
[587]3646    // updates "new_parent" directory on device
3647    if ( _update_device_from_cache( new_parent->levels,
3648                                    new_parent->cache,
3649                                    new_parent->name ) )
[291]3650    {
[587]3651        _spin_lock_release( &_fat.fat_lock );
[709]3652        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3653
[664]3654        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
[587]3655                    new_parent->name );
[664]3656        return GIET_FAT32_IO_ERROR;
[291]3657    }
[258]3658
[587]3659    // remove "old" from "old_parent" File-Cache
3660    if ( _remove_dir_entry( old ) )
3661    {
3662        _spin_lock_release( &_fat.fat_lock );
[709]3663        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3664
[664]3665        _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from <%s>\n",
[587]3666                old->name , old_parent->name );
[664]3667        return GIET_FAT32_IO_ERROR;
[587]3668    }
3669 
3670    // remove "old" inode from Inode-Tree
3671    _remove_inode_from_tree( old );
3672
[622]3673    // release "old" inode
3674    _free( old );
3675
[587]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 );
[709]3682        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3683
[664]3684        _printf("\n[FAT ERROR] _fat_rename(): cannot update <%s> on device\n",
[587]3685                    old_parent->name );
[664]3686        return GIET_FAT32_IO_ERROR;
[587]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 );
[709]3695            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3696
[664]3697            _printf("\n[FAT ERROR] _fat_rename(): cannot remove <%s> from FS\n",
[587]3698                    to_remove->name );
[664]3699            return GIET_FAT32_IO_ERROR;
[587]3700        }
3701    }
3702
3703    // release lock
3704    _spin_lock_release( &_fat.fat_lock );
[709]3705    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[587]3706
[664]3707    return GIET_FAT32_OK;
[587]3708}  // end _fat_rename()
3709
3710
3711
3712
[773]3713////////////////////////////////
[587]3714int _fat_mkdir( char* pathname )
[260]3715{
[587]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
[260]3719
[587]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 )
[664]3726_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] enters for path <%s>\n",
[587]3727        x, y, p, pathname );
3728#endif
3729
[674]3730    // checking FAT initialized
3731    if( _fat.initialized != FAT_INITIALIZED )
[260]3732    {
[664]3733        _printf("\n[FAT ERROR] _fat_mkdir(): FAT not initialized\n");
3734        return GIET_FAT32_NOT_INITIALIZED;
[587]3735    }
[260]3736
[709]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();
[587]3740    _spin_lock_acquire( &_fat.fat_lock );
[709]3741    _atomic_or( &psched->context[ltid].slot[CTX_LOCKS_ID] , LOCKS_MASK_FAT ); 
3742
[587]3743    // get inode
3744    unsigned int code = _get_inode_from_path( pathname , &inode );
[260]3745
[587]3746    if ( code == 2 ) 
3747    {
3748        _spin_lock_release( &_fat.fat_lock );
[709]3749        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3750
[664]3751        _printf("\n[FAT ERROR] _fat_mkdir(): path to parent not found"
[587]3752                " for directory <%s>\n", pathname );
[664]3753        return GIET_FAT32_FILE_NOT_FOUND;
[260]3754    }
[587]3755    else if ( code == 3 ) 
[260]3756    {
[587]3757        _spin_lock_release( &_fat.fat_lock );
[709]3758        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3759
[664]3760        _printf("\n[FAT ERROR] _fat_mkdir(): one name in path too long"
[587]3761                " for directory  <%s>\n", pathname );
[664]3762        return GIET_FAT32_NAME_TOO_LONG;
[587]3763    }
3764    else if ( code == 0 )
3765    {
3766        _spin_lock_release( &_fat.fat_lock );
[709]3767        _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3768
[664]3769        _printf("\n[FAT ERROR] _fat_mkdir(): directory <%s> already exist\n",
[587]3770                pathname );
[664]3771        return GIET_FAT32_FILE_EXISTS;
[587]3772    }
3773    else if ( code == 1 )   // directory not found => create
3774    {
3775        parent = inode;
[260]3776
[587]3777#if GIET_DEBUG_FAT
3778if ( _get_proctime() > GIET_DEBUG_FAT )
[664]3779_printf("\n[DEBUG FAT] _fat_mkdir(): P[%d,%d,%d] create new directory <%s>\n",
[587]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
[783]3787        // allocate a new inode and an empty Cache-File
3788        child = _allocate_one_inode( name,
[787]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
[783]3795
3796        // introduce inode in Inode-Tree
3797        _add_inode_in_tree( child , parent );
3798 
[787]3799        // allocate one cluster from FAT for child
[587]3800        unsigned int cluster;
[787]3801        if ( _one_cluster_allocate( child , &cluster ) )
[587]3802        {
3803            _spin_lock_release( &_fat.fat_lock );
[709]3804            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3805
[664]3806            _printf("\n[FAT ERROR] _fat_mkdir(): no free cluster"
[587]3807                    " for directory <%s>\n" , pathname );
[664]3808            return GIET_FAT32_NO_FREE_SPACE;
[587]3809        }
3810
[783]3811        // update cluster index in inode
3812        child->cluster = cluster;
[587]3813
[787]3814        // add new entry in parent directory File-Cache
3815        // and update dentry field in child inode
3816        if ( _add_dir_entry( child ) )
3817        {
[587]3818            _spin_lock_release( &_fat.fat_lock );
[709]3819            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3820
[664]3821            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update parent directory"
[587]3822                    " for directory <%s>\n" , pathname );
[664]3823            return GIET_FAT32_IO_ERROR;
[587]3824        } 
3825
[787]3826        // add "." and ".." directories in child directory
3827        _add_special_directories( child );
3828
[587]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 );
[709]3835            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3836
[664]3837            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region "
[587]3838                    " for parent of directory <%s>\n", pathname );
[664]3839            return GIET_FAT32_IO_ERROR;
[587]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 );
[709]3848            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3849
[664]3850            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update FAT region"
[587]3851                    " for directory <%s>\n", pathname );
[664]3852            return GIET_FAT32_IO_ERROR;
[587]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 );
[709]3861            _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
3862
[664]3863            _printf("\n[FAT ERROR] _fat_mkdir(): cannot update DATA region"
[587]3864                    " for directory <%s>\n", pathname );
[664]3865            return GIET_FAT32_IO_ERROR;
[587]3866        }
3867    }  // end create directory
3868
[606]3869    // release lock
3870    _spin_lock_release( &_fat.fat_lock );
[709]3871    _atomic_and( &psched->context[ltid].slot[CTX_LOCKS_ID] , ~LOCKS_MASK_FAT ); 
[606]3872
[664]3873    return GIET_FAT32_OK;
[587]3874}  // end _fat_mkdir()
3875
3876
3877
3878
[773]3879/////////////////////////////////////////
[658]3880extern int _fat_opendir( char* pathname )
3881{
3882    int fd_id = _fat_open( pathname, O_RDONLY );
[587]3883
[658]3884    if ( fd_id < 0 )
3885        return fd_id;
3886
3887    if ( !_fat.fd[fd_id].inode->is_dir )
3888    {
[664]3889        _printf("\n[FAT ERROR] _fat_opendir(): <%s> is not a directory\n",
[658]3890                pathname );
[664]3891        return GIET_FAT32_NOT_A_DIRECTORY;
[658]3892    }
3893
3894    return fd_id;
3895}
3896
3897
3898
3899
[773]3900//////////////////////////////////////////////
[658]3901extern int _fat_closedir( unsigned int fd_id )
3902{
3903    return _fat_close( fd_id );
3904}
3905
3906
3907
3908
[773]3909/////////////////////////////////////////////
[658]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    {
[750]3930        _printf("\n[FAT ERROR] in _fat_readdir(): not a directory\n" );
[664]3931        return GIET_FAT32_NOT_A_DIRECTORY;
[658]3932    }
3933
[744]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
[658]3945    while ( 1 )
3946    {
[750]3947        if ( _fat_read( fd_id, 
3948                        (unsigned int)&buf, 
3949                        DIR_ENTRY_SIZE,
3950                        0, 0, 0 )  != sizeof(buf) )
[658]3951        {
[750]3952            _printf("\n[FAT ERROR] in _fat_readdir(): can't read entry\n" );
[664]3953            return GIET_FAT32_IO_ERROR;
[658]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
[709]3962            _atomic_increment( &_fat.fd[fd_id].seek , -DIR_ENTRY_SIZE );
[658]3963
[664]3964            return GIET_FAT32_NO_MORE_ENTRIES;
[658]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
[664]4011    return GIET_FAT32_OK;
[750]4012}  // end _fat_readdir()
[658]4013
4014
4015
4016
[773]4017///////////////////////////////////////////////
[587]4018int _fat_load_no_cache( char*        pathname,
4019                        unsigned int buffer_vbase, 
4020                        unsigned int buffer_size ) 
[258]4021{
[674]4022    // checking FAT initialized
4023    if( _fat.initialized != FAT_INITIALIZED )
[587]4024    {
[664]4025        _printf("\n[FAT ERROR] _fat_load_no_cache(): FAT not initialized\n");
4026        return GIET_FAT32_NOT_INITIALIZED;
[587]4027    }
[258]4028
[587]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 )
[664]4038_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] enters for file <%s>\n",
[587]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    {
[664]4047        _printf("\n[FAT ERROR] _fat_load_no_cache(): file <%s> not found\n",
[587]4048        pathname );
[664]4049        return GIET_FAT32_FILE_NOT_FOUND;
[587]4050    }
4051
4052    // check buffer size
4053    if ( file_size > buffer_size )
4054    {
[664]4055        _printf("\n[FAT ERROR] _fat_load_no_cache(): buffer too small : "
[587]4056                "file_size = %x / buffer_size = %x", file_size , buffer_size );
[664]4057        return GIET_FAT32_BUFFER_TOO_SMALL;
[587]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        {
[664]4078            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot load lba %x", lba );
4079            return GIET_FAT32_IO_ERROR;
[587]4080        }
4081         
4082
4083        // compute next cluster index
4084        unsigned int next;
4085        if ( _next_cluster_no_cache( cluster , &next ) )
4086        {
[664]4087            _printf("\n[FAT ERROR] _fat_load_no_cache(): cannot get next cluster "
[587]4088                    " for cluster = %x\n", cluster );
[664]4089            return GIET_FAT32_IO_ERROR;
[587]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 )
[664]4100_printf("\n[DEBUG FAT] _fat_load_no_cache(): P[%d,%d,%d] loaded <%s> at vaddr = %x"
[587]4101        " / size = %x\n", x , y , p , pathname , buffer_vbase , file_size );
4102#endif
4103
[664]4104    return GIET_FAT32_OK;
[587]4105}  // end _fat_load_no_cache()
[258]4106
4107
[587]4108
[761]4109
[773]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//////////////////////////////////////////////////////
[761]4198int _get_file_cache_buffer( fat_inode_t*        inode,
4199                            unsigned int        cluster_id,
4200                            unsigned int        writable,
[750]4201                            fat_cache_desc_t**  desc )
4202{
4203
[773]4204#if GIET_DEBUG_FAT
[750]4205if ( _get_proctime() > GIET_DEBUG_FAT )
[773]4206_printf("\n[DEBUG FAT] _get_file_cache_buffer() : enters in File-Cache <%s>"
[761]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] );
[750]4211#endif
[761]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;
[750]4218    }
[761]4219
4220    // checking arguments
4221    if ( inode == NULL )   // illegal inode argument
[750]4222    {
[761]4223        _printf("\n[FAT ERROR] in _get_file_cache_buffer() : illegal inode argument\n");
4224        return GIET_FAT32_INVALID_ARG;
4225    }
[750]4226
[761]4227    // add cache levels if needed
4228    while ( _get_levels_from_size( (cluster_id + 1) * 4096 ) > inode->levels )
4229    {
[750]4230
[773]4231#if GIET_DEBUG_FAT
[750]4232if ( _get_proctime() > GIET_DEBUG_FAT )
[761]4233_printf("\n[DEBUG FAT] _get_file_cache_buffer() : add a File-Cache level\n" );
[750]4234#endif
[761]4235
4236        inode->cache = _allocate_one_cache_node( inode->cache );
4237        inode->levels++;
[750]4238    }
4239
[773]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;
[761]4245
[750]4246    // search the 64-tree cache from top to bottom
4247    while ( level )
4248    {
4249        // compute child index at each level
[761]4250        unsigned int index = (cluster_id >> (6*(level-1))) & 0x3F;
[750]4251
[761]4252        if ( level == 1 )        // last level => children are buffer descriptors
[750]4253        {
[773]4254            fat_cache_desc_t*   pdesc   = (fat_cache_desc_t*)node->children[index];
[761]4255            unsigned int        next    = 0;
4256            unsigned int        prev    = 0;
[773]4257            unsigned int        current;
[761]4258            unsigned int        cid;
4259            unsigned int        lba;
[783]4260            unsigned int        one_cluster_allocated;
[750]4261
[773]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 )   
[750]4268            {
4269
[773]4270#if GIET_DEBUG_FAT
[750]4271if ( _get_proctime() > GIET_DEBUG_FAT )
[773]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 ,
[761]4276        (unsigned int)inode->cache , cluster_id , 
4277        (unsigned int)inode->cache->children[cluster_id] );
[750]4278#endif
[783]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 );
[773]4282
[783]4283                if ( one_cluster_allocated )  // cluster already allocated => allocate buffer
[750]4284                {
[761]4285                    // scan the FAT to find the cluster index for cluster_id
[773]4286                    current = inode->cluster;
[761]4287                    for ( cid = 0 ; cid < cluster_id ; cid++ )
4288                    {
4289                        // get next cluster index from FAT
[750]4290                        if ( _get_fat_entry( current , &next ) ) return 1;
4291                        current = next;
4292                    }
[761]4293
4294                    // compute lba
[750]4295                    lba = _cluster_to_lba( current );
4296
[761]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) );
[750]4301
[761]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,
[750]4313                                      8 ) )
[761]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                }
[773]4323                else if ( writable == 0 ) // not writable and cluster not allocated in FAT
[750]4324                {
[761]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;
[750]4330                }
[773]4331                else   // writable and cluster NOT allocated in FAT => allocate cluster & buffer
[761]4332                {
4333                    // scan the FAT to allocate all required clusters
[773]4334                    current = inode->cluster;
[761]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
[783]4340                            if ( _one_cluster_allocate( inode , &current ) )
[761]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                    }
[750]4360
[773]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
[761]4366                    _update_dir_entry( inode );
[750]4367
[761]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                }
[773]4382            }  // end File-Cache miss handling
[750]4383
4384            // return pdesc pointer
4385            *desc = pdesc;
4386
[773]4387#if GIET_DEBUG_FAT
[761]4388if ( _get_proctime() > GIET_DEBUG_FAT )
[773]4389_printf("\n[DEBUG FAT] _get_file_cache_buffer(): found buffer = %x "
[761]4390        " in file <%s> for cluster_id %d\n",
4391        (unsigned int)pdesc->buffer , inode->name , cluster_id );
4392#endif
[750]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
[761]4412    return GIET_FAT32_OK;
[750]4413
[761]4414}  // end _get_file_cache_buffer()
[750]4415
[773]4416
4417
4418
4419
4420
[258]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.