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

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

Major evolution of the FAT32 library: i
Introduce a distributed File-Caches architecture,
a distributed FAT-Cache, and a distributed Inodes-Tree structure.
Provide Posix-like system calls.

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