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

Last change on this file since 746 was 746, checked in by alain, 8 years ago

Improve the _fat_lseek() function to support
the SEEK_END value for the <whence> argument.

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