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

Last change on this file since 757 was 750, checked in by alain, 9 years ago

Makes _fat_buffer_from_cache() an external function, to implement the giet_fat_mmap system call.

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