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

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

fat32: disallow move into own subdirectory

"mv / home/a" would crash,
"mv home home/sub" would unfortunately succeed.

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