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

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

fat32: spelling fixes

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