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

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

fat32: generic error codes

Instead of having unique error codes per function, define an error
code map. Return more meaningful codes to the user.

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