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

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

Fix several bugs related to new files or directories creation:

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