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

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