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

Last change on this file since 766 was 761, checked in by alain, 9 years ago

Replace the _get_buffer_from_cache() function by

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