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

Last change on this file since 636 was 636, checked in by guerin, 9 years ago

fat32: don't try to load cluster -1 in _get_buffer_from_cache()

This was causing a hardlock when trying to remove /bin.

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