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

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

fat32: use _allocate_one_cache_node() where possible

This could fix non-NULL'd children pointers.

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