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

Last change on this file since 816 was 808, checked in by alain, 9 years ago

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

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