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

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

fat32: don't keep tree structure when releasing cache

This fixes a bunch of memleaks.

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