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

Last change on this file since 293 was 291, checked in by devigne, 11 years ago
  • Added fat_allocate function to enlarge the size of a file.
  • Recovery of FS_INFO in fat_init function, FS_INFO contains important information for the allocation of new clusters such as the last cluster allocated and the number of still free cluster.
  • Added update functions :
    • For FAT : update the chaining of clusters after allocation.
    • For DIR_ENTRY : update a field into a DIR_ENTRY, eg FILE_SIZE field after a write.
    • For FS_INFO : after allocation we must update the last cluster allocated and number of free cluster fields.
  • Property svn:executable set to *
File size: 67.1 KB
Line 
1//////////////////////////////////////////////////////////////////////////////////
2// File     : fat32.c
3// Date     : 01/09/2013
4// Authors  : Marco Jankovic, Cesar Fuguet & Alain Greiner
5// Copyright (c) UPMC-LIP6
6//////////////////////////////////////////////////////////////////////////////////
7// The fat32.h and fat32.c files define a library of access functions
8// to a FAT32 partition on a block device. It is intended to be used
9// by the GIET_VM nano-kernel for both the boot code and the kernel code.
10// This code uses functions defined in the utils.c and drivers.c files.
11//////////////////////////////////////////////////////////////////////////////////
12// Implementation notes:
13// 1. the "lba" (Logical Block Address) is the physical sector index on
14//    the block device. The physical sector size is supposed to be 512 bytes.
15// 2. the "cluster" variable is actually a cluster index. A cluster contains
16//    typically 8 sectors (4K bytes) and the cluster index is a 32 bits word.
17// 2. This FAT32 library uses a FAT cache whose storage capacity is one
18//    sector (512 bytes, or 128 cluster indexes in FAT)
19// 3. This FAT32 library can be used in three modes: BOOT/KERNEL/USER
20//    defining three different behaviours for the IOC driver.
21//////////////////////////////////////////////////////////////////////////////////
22
23#include <giet_config.h>
24#include <fat32.h>
25#include <tty_driver.h>
26#include <ioc_driver.h>
27#include <utils.h>
28
29//////////////////////////////////////////////////////////////////////////////////
30//      Global variable used by all FAT access functions
31//////////////////////////////////////////////////////////////////////////////////
32
33__attribute__((section (".kdata"))) 
34fat32_fs_t fat __attribute__((aligned(64)));
35
36//////////////////////////////////////////////////////////////////////////////////
37// This function displays the content of the FAT cache
38//////////////////////////////////////////////////////////////////////////////////
39#if GIET_DEBUG_FAT
40void display_fat_cache()
41{
42    unsigned int line;
43    unsigned int word;
44    unsigned int temp[9];
45
46    temp[8] = 0;
47
48    _tty_get_lock( 0 );
49    _puts("\n*********************** fat_cache_lba = ");
50    _putx( fat.cache_lba );
51    _puts(" **************************\n");
52
53    for ( line=0 ; line<16 ; line++ )
54    {
55        // display address
56        _putx( (fat.cache_lba<<9) + (line<<5) );
57        _puts(" : ");
58
59        // display data hexa
60        for ( word=0 ; word<8 ; word++ )
61        {
62            unsigned int byte  = (line<<5) + (word<<2);
63            unsigned int hexa  = (fat.fat_cache[byte  ]<<24) |
64                                 (fat.fat_cache[byte+1]<<16) |
65                                 (fat.fat_cache[byte+2]<< 8) |
66                                 (fat.fat_cache[byte+3]);
67            _putx( hexa );
68            _puts(" | ");
69
70            // prepare display ascii
71            temp[word] = fat.fat_cache[byte]         |
72                         (fat.fat_cache[byte+1]<<8)  |
73                         (fat.fat_cache[byte+2]<<16) |
74                         (fat.fat_cache[byte+3]<<24) ;
75        }
76       
77        // display data ascii
78        _puts( (char*)temp );
79        _puts("\n");
80    }
81    _puts("***************************************************************************\n");
82    _tty_release_lock( 0 );
83} // end display_fat_cache() 
84#endif
85
86//////////////////////////////////////////////////////////////////////////////////
87// This function returns the length of a FAT field. This field is identified
88// man by an (offset,length) mnemonic defined in fat32.h file.
89//////////////////////////////////////////////////////////////////////////////////
90static inline int get_length( int offset, 
91                              int length)
92{
93    return length;
94}
95
96//////////////////////////////////////////////////////////////////////////////
97// Write one 32 bits word "value" in a char[] buffer.
98// This field is defined by the offset and size arguments.
99//////////////////////////////////////////////////////////////////////////////
100static void write_entry( unsigned int   offset,
101                         unsigned int   size,
102                         char*          buffer,
103                         unsigned int   value )
104{
105    unsigned int turn = 0;
106    unsigned int res  = value;
107    unsigned int mask = 0x000000ff;
108
109    while( turn != size - 1 )
110    {
111        buffer[ offset + turn ] = res & mask;
112        res = res >> 8;
113        turn++;
114    }
115    buffer[offset + turn] = res & mask;
116}
117
118//////////////////////////////////////////////////////////////////////////////
119// Read one 32 bits word in a char[] buffer, taking endianness into account.
120// This field is defined by the offset and size arguments.
121//////////////////////////////////////////////////////////////////////////////
122static unsigned int read_entry( unsigned int   offset,
123                                unsigned int   size,
124                                char*          buffer,
125                                unsigned int   little_indian )
126{
127    unsigned int turn;
128    unsigned int res  = 0;
129    unsigned int mask = 0x000000ff;
130
131    if( little_indian )
132    {
133        turn = size;
134        while( turn != 1 )
135        {
136            res = res | (buffer[offset + (turn-1)] & mask);
137            res = res << 8;
138            turn--;
139        }
140        res = (buffer[offset + (turn-1)] & mask) | res;
141    }
142    else
143    {
144        turn = 0;
145        while( turn != size - 1 )
146        {
147
148            res = res  | (buffer[ offset + turn ] & mask );
149            res = res << 8;
150            turn++;
151        }
152        res = res | (buffer[offset + turn] & mask);
153    }
154    return res;
155}
156
157//////////////////////////////////////////////////////////////////////////////////
158// This function retuns the cluster index from the lba of a DATA sector.
159// The lba must be larger than the lba of the first DATA sector.
160// The DATA region indexing starts a cluster 2.
161//////////////////////////////////////////////////////////////////////////////////
162static inline unsigned int lba_to_cluster( unsigned int lba )                   
163{
164   if (lba < fat.data_lba ) return 0;
165
166   return ( (lba - fat.data_lba) / fat.sectors_per_cluster) + 2; 
167}
168
169//////////////////////////////////////////////////////////////////////////////////
170// This function retuns the lba of first sector in DATA region
171// from the cluster index. The cluster index must be larger than 2.
172//////////////////////////////////////////////////////////////////////////////////
173static inline unsigned int cluster_to_lba( unsigned int cluster )       
174{
175   if ( cluster < 2 ) return 0; 
176
177   return  (fat.sectors_per_cluster * (cluster - 2)) + fat.data_lba;
178}
179
180/////////////////////////////////////////////////////////////////////////////////
181// This function search the FAT (using the FAT cache), and returns
182// the next cluster index from the curent cluster index in the FAT.
183// remark: a sector of FAT contains 128 cluster indexes.
184/////////////////////////////////////////////////////////////////////////////////
185static unsigned int get_next_cluster_id( unsigned int mode,
186                                         unsigned int cluster )
187{
188    // compute lba of the sector containing the cluster index
189    unsigned int lba = fat.partition_lba + 32 + (cluster / 128);
190
191    if ( lba == fat.cache_lba )      // hit in cache
192    {
193        return read_entry( ((cluster % 128) * 4), 
194                           4, 
195                           fat.fat_cache,
196                           1 );
197    }
198    else                                  // miss in cache
199    {
200        // we cannot access fat in user mode
201        if( mode == IOC_USER_MODE ) mode = IOC_KERNEL_MODE;
202       
203        // access fat
204        if( _ioc_read( mode,              // mode for IOC driver
205                       lba,               // sector index
206                       fat.fat_cache,     // fat cache
207                       1 ) )              // one sector
208        {
209            _tty_get_lock( 0 );
210            _puts("[FAT_ERROR] in get_next cluster_id() cannot read block ");
211            _putd( lba );
212            _puts("\n");
213            _tty_release_lock( 0 );
214            return 1;
215        }
216        fat.cache_lba = lba;
217
218        return read_entry( ((cluster % 128) * 4), 
219                           4, 
220                           fat.fat_cache,
221                           1 );
222    }
223}
224
225//////////////////////////////////////////////////////
226static inline unsigned char to_upper(unsigned char c)
227{
228   if (c >= 'a' && c <= 'z') return (c & ~(0x20));
229   else                      return c;
230}
231
232////////////////////////////////////////////////////////////////
233// This function is a filter:
234// Return the c character if c is a legal short name character
235// Return the '_' character if c is illegal
236////////////////////////////////////////////////////////////////
237static unsigned char illegal_short(unsigned char c)
238{
239   const unsigned char illegal_char [] =";+=[]’,\"*\\<>/?:|\0";
240   short i = 0;
241   while (illegal_char[i]!='\0')
242   {
243      if (c == illegal_char[i])
244         return '_';
245      i++;
246   }
247   return c;
248}
249
250/////////////////////////////////////////////////////////////////////////////////
251// This function test if the string argument is a legal SFN (Short File Name)
252// and copies this name (removing the .) in the sfn_string argument.
253// Criteria for a Short File Name are:
254// - separator is '.' (extension is not mandatory)
255// - 1 <= name length <= 8
256// - 0 <= extension length <= 3
257// - no illegal character (see illega_short() function)
258// Return 1 if it string is a legal SFN
259// Return 0 if not legal SFN
260/////////////////////////////////////////////////////////////////////////////////
261static int is_short( char* string, 
262                     char* sfn_string)
263{
264    int s_size   = 0;
265    int dot_ext  = 0;       // dot offset in the filename
266    int name_len = 0;       // length of file name
267    int ext_len  = 0;       // length of extension
268    int i        = 0;
269    int sc_i     = 0;
270    char ch;
271
272#if GIET_DEBUG_FAT
273_tty_get_lock( 0 );
274_puts("\n[FAT DEBUG] filename ");
275_puts( string );
276_tty_release_lock( 0 );
277#endif
278
279    if(string[0] == '.' && string[1] == '\0')
280    {
281        sfn_string[0] = '.';
282
283#if GIET_DEBUG_FAT
284_tty_get_lock( 0 );
285_puts(" converted to 8.3 SFN format : ");
286_puts( sfn_string );
287_puts("\n");
288_tty_release_lock( 0 );
289#endif
290
291      return 1;
292   }
293
294   if(string[0] == '.' && string[1] == '.' && string[2] == '\0')
295   {
296      sfn_string[0] = '.';
297      sfn_string[1] = '.';
298
299#if GIET_DEBUG_FAT
300_tty_get_lock( 0 );
301_puts(" converted to 8.3 SFN format : ");
302_puts( string );
303_puts("\n");
304_tty_release_lock( 0 );
305#endif
306
307      return 1;
308   }
309
310   sfn_string[11] = '\0';
311
312   while (string[s_size] != '\0')
313   {
314      if (string[s_size] == '.')
315      {
316         dot_ext = s_size;
317         ext_len = -1;
318      }
319      ext_len++;
320      s_size++;
321   }
322
323   if (dot_ext != 0)
324   {
325      name_len = s_size - ext_len - 1;
326   }
327   else
328   {
329      name_len = s_size;
330      ext_len = 0;
331   }
332
333   if ( ext_len > 3 || ( name_len > 8))
334   {
335      return 0;
336   }
337
338   if (dot_ext != 0)
339   {
340      while (i != ext_len)
341      {
342         ch = to_upper(string[dot_ext + 1 + i]);
343         ch = illegal_short(ch);
344         sfn_string[8+i] = ch;
345         i++;
346      } 
347   }
348   i = 0;
349   sc_i = 0;
350   while (i!= name_len)
351   {
352      ch = to_upper(string[i]);
353      ch = illegal_short(ch);
354      if (ch != '.')
355         sfn_string[sc_i++] = ch;
356      i++;
357   }
358
359#if GIET_DEBUG_FAT
360_tty_get_lock( 0 );
361_puts(" converted to 8.3 SFN format : ");
362_puts( sfn_string );
363_puts("\n");
364_tty_release_lock( 0 );
365#endif
366
367   return 1;
368}
369
370///////////////////////////////////////////////////////////////////////
371// This function analyses the pathname argument, from the character
372// defined by the *nb_read argument.
373// It copies the found name (between '/') in the name[] buffer,
374// and updates the nb_read argument.
375// Return 1 if name found, Return 0 if NUL character found,
376///////////////////////////////////////////////////////////////////////
377static int get_name_from_path( char*          pathname,
378                               char*          name,
379                               unsigned int*  nb_read ) 
380{
381    if ( pathname[*nb_read] == 0 ) return 0;
382
383    int i = (pathname[*nb_read] == '/')? (*nb_read) + 1 : *nb_read;
384    int j = 0;
385   
386    while(pathname[i] != '/' && pathname[i] != '\0')
387    {
388        name[j] = pathname[i];   
389        j++;
390        i++;
391    }
392    name[j] = 0;
393
394    if ( pathname[i] == '/' ) *nb_read += j+1;
395    else                      *nb_read += j;
396
397    return 1;
398}
399
400////////////////////////////////////////////////////////////////////////////////
401static int get_name_from_short( char* dir_entry,     // input:  SFN dir_entry
402                                char* entry_name )   // output: name
403{
404    unsigned int i   = 0;
405    unsigned int length = get_length(DIR_NAME);
406
407    while ( i < length )
408    {
409        entry_name[i] = dir_entry[i];
410        i++;
411    }
412    entry_name[i] = '\0';
413
414    return i;
415}
416
417///////////////////////////////////////////////////////////////////////////////
418static int get_name_from_long( char *dir_entry,     // input : LFN dir_entry
419                               char *entry_name )   // output : name
420{
421    unsigned int   entry_name_offset   = 0;
422    unsigned int   dir_entry_offset    = get_length(LDIR_ORD);
423    unsigned int   l_name_1            = get_length(LDIR_NAME_1);
424    unsigned int   l_name_2            = get_length(LDIR_NAME_2);
425    unsigned int   l_name_3            = get_length(LDIR_NAME_3);
426    unsigned int   l_attr              = get_length(LDIR_ATTR);
427    unsigned int   l_type              = get_length(LDIR_TYPE);
428    unsigned int   l_chksum            = get_length(LDIR_CHKSUM);
429    unsigned int   l_rsvd              = get_length(LDIR_RSVD);
430
431    unsigned int j            = 0;
432    unsigned int eof          = 0;
433
434    while ( (dir_entry_offset != DIR_ENTRY_SIZE)  && (!eof) )
435    {
436        while (j != l_name_1 && !eof )
437        {
438            if ( (dir_entry[dir_entry_offset] == 0x00) || 
439                 (dir_entry[dir_entry_offset] == 0xFF) )
440            {
441                eof = 1;
442                continue;
443            }
444            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
445            dir_entry_offset += 2;
446            j += 2;
447            entry_name_offset++;
448        }
449
450        dir_entry_offset += (l_attr + l_type + l_chksum);
451        j = 0;
452
453        while (j != l_name_2 && !eof )
454        {
455            if ( (dir_entry[dir_entry_offset] == 0x00) || 
456                 (dir_entry[dir_entry_offset] == 0xFF) )
457            {
458                eof = 1;
459                continue;
460            }
461            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
462            dir_entry_offset += 2;
463            j += 2;
464            entry_name_offset++;
465        }
466
467        dir_entry_offset += l_rsvd;
468        j = 0;
469
470        while (j != l_name_3 && !eof )
471        {
472            if ( (dir_entry[dir_entry_offset] == 0x00) || 
473                 (dir_entry[dir_entry_offset] == 0xFF) )
474            {
475                eof = 1;
476                continue;
477            }
478            entry_name[entry_name_offset] = dir_entry[dir_entry_offset];
479            dir_entry_offset += 2;
480            j += 2;
481            entry_name_offset++;
482        }
483    }
484    entry_name[entry_name_offset] = '\0';
485
486    return entry_name_offset;
487} // end get_name_from_long()
488
489//////////////////////////////////////////////////////////////////////////////////////
490// This function update a DIR_ENTRY, write a new value into a specific field
491// (ex : DIR_FILE_SIZE, when we want update the file size after a fat_write)
492// Return 0 in case of success, > 0 if failure.
493//////////////////////////////////////////////////////////////////////////////////////
494// TODO : make this function less complex
495//////////////////////////////////////////////////////////////////////////////////////
496static inline unsigned int update_entry( unsigned int fd_id, 
497                                         unsigned int field,
498                                         unsigned int size,
499                                         unsigned int value )
500{
501    char dir_entry[32];   // buffer to store a full directory_entry
502    char name_entry[14];  // buffer to store a 13 characters (partial) name
503    char file_name[256];  // buffer to store the name (not pathname) of the file
504    char sfn[12]            = {[0 ... 10] = ' ', '\0'};      // buffer for a Short File Name
505
506    unsigned int lba       = fat.fd[fd_id].lba_dir_entry;    // Lba of file dir_entry
507    unsigned int is_sfn;         
508    unsigned int attr      = 0;                              // directory entry attribute
509    unsigned int ord       = 0;                              // directory entry sequence
510    unsigned int found     = 0;                              // name found
511    unsigned int offset    = 0;
512    unsigned int i         = 0;
513    unsigned int nb_read   = 0;
514
515    for ( i = 0 ; i < 32 ; i++ ) dir_entry[i]  = 0;
516    for ( i = 0 ; i < 14 ; i++ ) name_entry[i] = 0;
517   
518    // Get the name of the file.
519    while ( get_name_from_path( fat.fd[fd_id].name, file_name, &nb_read ) )
520    {
521    }
522
523    // Check if file_name is short
524    is_sfn = is_short( file_name, sfn );
525
526    if ( _ioc_read( IOC_KERNEL_MODE, // mode for IOC driver
527                    lba,             // sector index
528                    fat.fat_cache,   // buffer address
529                    1 ) )            // one sector
530    {
531        _tty_get_lock( 0 );
532        _puts("[FAT ERROR] in update_entry() cannot read sector ");
533        _putd( lba );
534        _puts("\n");
535        _tty_release_lock( 0 );
536        return 1;
537    }
538    fat.cache_lba = lba;
539
540    // - the offset increment is an integer number of directory entry (32 bytes)
541    // - the exit condition is success (name found) or failure (end of directory)
542    while ( !found )
543    {
544        attr = read_entry( DIR_ATTR, fat.fat_cache + offset, 0 );
545        ord  = read_entry( LDIR_ORD, fat.fat_cache + offset, 0 );
546
547        if ( is_sfn == 1 )                                     // searched name is short
548        {
549            if      ( (ord != FREE_ENTRY ) &&
550                    (ord != NO_MORE_ENTRY) &&
551                    (attr == ATTR_LONG_NAME_MASK) )    // LFN entry : skipped
552            {
553                offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
554                continue;
555            }
556            else if ( (attr != ATTR_LONG_NAME_MASK) && 
557                    (ord  != FREE_ENTRY) && 
558                    (ord  != NO_MORE_ENTRY ) )         // SFN entry : checked
559            {
560                _memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
561            }
562            else if (ord == NO_MORE_ENTRY )            // end of directory : return
563            {
564                _tty_get_lock( 0 );
565                _puts("[FAT ERROR] in update_entry() end of directory reaches ");
566                _puts("\n");
567                _tty_release_lock( 0 );
568                return 1;
569            }
570            else                                                                           // free entry : skipped
571            {
572                offset = offset + DIR_ENTRY_SIZE;
573                continue;
574            }
575        }
576        else                                           // searched name is long
577        {
578            if      ( (attr == ATTR_LONG_NAME_MASK) && 
579                    (ord != FREE_ENTRY) &&
580                    (ord != NO_MORE_ENTRY) )           // LFN entry : checked
581            {
582                _memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
583            }
584            else if ( (attr != ATTR_LONG_NAME_MASK) && 
585                    (ord  != FREE_ENTRY) && 
586                    (ord  != NO_MORE_ENTRY))               // SFN entry : skipped
587            {
588                offset = offset + DIR_ENTRY_SIZE;
589                continue;
590            }
591            else if (ord == NO_MORE_ENTRY )                        // end of directory : return
592            {
593                _tty_get_lock( 0 );
594                _puts("[FAT ERROR] in update_entry() end of directory reaches ");
595                _puts("\n");
596                _tty_release_lock( 0 );
597                return 1;
598            }
599            else                                       // free entry : skipped
600            {
601                offset = offset + DIR_ENTRY_SIZE;
602                continue;
603            }
604        }
605
606        // testing the name extracted from dir entry
607
608        if ( is_sfn == 1 )                             // searched name is short
609        {
610            get_name_from_short( dir_entry, name_entry );
611
612            if ( _strncmp( (char*)sfn, (char*)name_entry, 13 ) == 0 )
613            {
614                write_entry(offset + field, size, fat.fat_cache, value);
615                found = 1;
616            }
617            else                                                                       // no matching : skip
618            {
619                offset = offset + DIR_ENTRY_SIZE;
620            }
621        }
622        else                                           // searched name is long
623        {
624            get_name_from_long( dir_entry, name_entry );
625
626            unsigned shift = ((ord & 0xf) - 1) * 13;
627            if ( _strncmp( (char*)(file_name + shift), (char*)name_entry, 13 ) == 0 )
628            {
629                if ( (ord & 0xf) == 1 )
630                {
631                    offset = offset + DIR_ENTRY_SIZE;
632                    write_entry(offset + field, size, fat.fat_cache, value);
633                    found = 1;
634                }
635                offset = offset + DIR_ENTRY_SIZE;
636                continue;
637            }
638            else                                                                       // no matching : skip
639            {
640                offset = offset + ((ord & 0xf) * DIR_ENTRY_SIZE) + DIR_ENTRY_SIZE;
641            }
642        }
643    }
644
645    return _ioc_write( IOC_KERNEL_MODE,
646                       lba, 
647                       fat.fat_cache,
648                       1     );
649}
650//////////////////////////////////////////////////////////////////////////////////
651// This function update FS_INFO, for new last cluster allocated and number of free
652// cluster.
653// Return 0 in case of success, > 0 if failure.
654//////////////////////////////////////////////////////////////////////////////////
655static inline unsigned int update_fs_info( )
656{
657    unsigned int lba = fat.fs_info_lba;
658
659#if GIET_DEBUG_FAT
660_tty_get_lock( 0 );
661_puts("\n[FAT DEBUG] Enter in update_fs_info()\n");
662_tty_release_lock( 0 );
663#endif
664
665    if ( lba == fat.cache_lba )            // hit cache
666    {
667        write_entry( FS_FREE_CLUSTER     , fat.fat_cache, fat.number_free_cluster );
668        write_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, fat.last_cluster_allocated );
669    }
670    else                                   // miss cache
671    {
672        if ( _ioc_read( IOC_KERNEL_MODE,   // mode for IOC driver
673                        lba,               // sector index
674                        fat.fat_cache,     // fat cache
675                        1 ) )              // one sector
676        {
677            _tty_get_lock( 0 );
678            _puts("[FAT_ERROR] in update_fat() cannot read block ");
679            _putd( lba );
680            _puts("\n");
681            _tty_release_lock( 0 );
682            return 1;
683        }
684        fat.cache_lba = lba;
685        write_entry( FS_FREE_CLUSTER     , fat.fat_cache, fat.number_free_cluster );
686        write_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, fat.last_cluster_allocated );
687    }
688    return _ioc_write( IOC_KERNEL_MODE,       
689                       lba,           
690                       fat.fat_cache,           
691                       1 ); 
692}
693
694//////////////////////////////////////////////////////////////////////////////////
695// This function update FAT, write a new value into cluster index.
696// Used by the function _fat_allocate to update the chaining of clusters.
697// Return 0 in case of success, > 0 if failure.
698//////////////////////////////////////////////////////////////////////////////////
699static inline unsigned int update_fat( unsigned int cluster, 
700                                       unsigned int value  )
701{
702    unsigned int lba = fat.partition_lba + 32 + (cluster / 128);
703
704#if GIET_DEBUG_FAT
705_tty_get_lock( 0 );
706_puts("\n[FAT DEBUG] Enter in update_fat() :\n");
707_puts("    - Cluster to update = ");
708_putd( cluster );
709_puts("\n");
710_puts("    - Value to write = ");
711_putd( value );
712_puts("\n");
713_tty_release_lock( 0 );
714#endif
715
716    if ( lba == fat.cache_lba )            // hit cache
717    {
718        write_entry( ((cluster % 128) << 2), 4, fat.fat_cache, value );
719    }
720    else                                   // miss cache
721    {
722        if ( _ioc_read( IOC_KERNEL_MODE,   // mode for IOC driver
723                        lba,               // sector index
724                        fat.fat_cache,     // fat cache
725                        1 ) )              // one sector
726        {
727            _tty_get_lock( 0 );
728            _puts("[FAT_ERROR] in update_fat() cannot read block ");
729            _putd( lba );
730            _puts("\n");
731            _tty_release_lock( 0 );
732            return 1;
733        }
734        fat.cache_lba = lba;
735        write_entry( ((cluster % 128) << 2), 4, fat.fat_cache, value );
736    }
737    return _ioc_write( IOC_KERNEL_MODE,       
738                       lba,           
739                       fat.fat_cache,           
740                       1 ); 
741}
742
743//////////////////////////////////////////////////////////////////////////////////
744// This function allocate a count number of cluster to a file by calling the
745// update_fat function that takes care to update the chaining of clusters.
746// return 0 if success, -1 if failure
747//////////////////////////////////////////////////////////////////////////////////
748static inline int _fat_allocate( unsigned int fd_id, 
749                                 unsigned int count )
750{
751    unsigned int next_cluster        = fat.fd[fd_id].first_cluster;   // Get the first cluster of file
752    unsigned int cluster_to_allocate = count;                         // Number of cluster to allocate
753
754    unsigned int last_cluster_file;                                   // Last cluster of the file (EOC)
755
756    unsigned int free_cluster = fat.last_cluster_allocated + 1;       // First free cluster
757
758    // Check if free_cluster is really free (must be true)
759    if ( get_next_cluster_id( IOC_KERNEL_MODE, free_cluster ) != FREE_CLUSTER)
760    {
761        _tty_get_lock( 0 );
762        _puts("\n[FAT ERROR] in _fat_allocate() : first free_cluster isnt free\n");
763        _tty_release_lock( 0 );
764        return -1;
765    }
766    // Check if FAT contains enough cluster free for this allocation
767    if ( count > fat.number_free_cluster )
768    {
769        _tty_get_lock( 0 );
770        _puts("\n[FAT ERROR] in _fat_allocate() : Not enough free cluster(s) for this allocation\n");
771        _tty_release_lock( 0 );
772        return -1;
773    }
774
775#if GIET_DEBUG_FAT
776_tty_get_lock( 0 );
777_puts("\n[FAT DEBUG] Enter in _fat_allocate() :\n");
778_puts("    - Need to allocate ");
779_putd( count );
780_puts(" cluster(s) for file ");
781_putd( fd_id );
782_puts("\n");
783_tty_release_lock( 0 );
784#endif
785
786    // Get the last cluster allocated for the file (seek END_OF_CHAIN_CLUSTER).
787    do{
788        last_cluster_file = next_cluster;
789        next_cluster      = get_next_cluster_id( IOC_KERNEL_MODE, next_cluster );
790    }while ( next_cluster < END_OF_CHAIN_CLUSTER );
791
792    // Loop on the number of cluster needed to be allocated
793    while ( cluster_to_allocate > 0 )
794    {
795
796#if GIET_DEBUG_FAT
797_tty_get_lock( 0 );
798_puts("\n[FAT DEBUG] Cluster to update is : ");
799_putd( last_cluster_file );
800_puts("\n");
801_puts("[FAT DEBUG] Free cluster is : ");
802_putd( free_cluster );
803_puts("\n");
804_puts("[FAT DEBUG] Number of cluster need to be allocated : ");
805_putd( cluster_to_allocate );
806_puts("\n");
807_tty_release_lock( 0 );
808#endif
809
810        // update, in the FAT, the value of last cluster allocated by the index
811        // of free cluster.
812        if ( update_fat( last_cluster_file, free_cluster ) )
813        {
814            _tty_get_lock( 0 );
815            _puts("\n[FAT ERROR] in _fat_allocate() : update fat for file ");
816            _putd( fd_id );
817            _puts(" failed\n");
818            _tty_release_lock( 0 );
819            return -1;
820        }
821
822        cluster_to_allocate = cluster_to_allocate - 1;
823        // Last cluster allocated is then free_cluster
824        last_cluster_file = free_cluster;
825
826        // Last cluster to allocate done, then we must close the chain of clusters
827        if ( cluster_to_allocate == 0 )
828        {
829            // update, in the FAT, the value of the last cluster allocated by
830            // END_OF_CHAIN_CLUSTER
831            if ( update_fat( last_cluster_file, END_OF_CHAIN_CLUSTER ) )
832            {
833                _tty_get_lock( 0 );
834                _puts("\n[FAT ERROR] in _fat_allocate() : update fat for file ");
835                _putd( fd_id );
836                _puts(" failed\n");
837                _tty_release_lock( 0 );
838                return -1;
839            }
840        }
841
842        free_cluster = free_cluster + 1;
843
844        // Check if free_cluster is really free (must be true)
845        if ( get_next_cluster_id( IOC_KERNEL_MODE, free_cluster ) != FREE_CLUSTER)
846        {
847            _tty_get_lock( 0 );
848            _puts("\n[FAT ERROR] in _fat_allocate() : free_cluster isnt free\n");
849            _tty_release_lock( 0 );
850            return -1;
851        }
852    }
853
854    // Update field number_free_cluster and last_cluster_allocated
855    // of structure fat for next fat_allocate
856    fat.last_cluster_allocated = last_cluster_file;
857    fat.number_free_cluster    = fat.number_free_cluster - count;
858
859    if ( update_fs_info() )
860    {
861        _tty_get_lock( 0 );
862        _puts("\n[FAT ERROR] in _fat_allocate() : update fs_info for file ");
863        _putd( fd_id );
864        _puts(" failed\n");
865        _tty_release_lock( 0 );
866        return -1;
867    }
868
869    return 0;
870}
871
872///////////////////////////////////////////////////////////////////////////////
873// This function returns the cluster index from a (32 bytes) directory entry
874///////////////////////////////////////////////////////////////////////////////
875static inline unsigned int read_cluster( char* buf )                 
876{
877   unsigned int cluster = read_entry( DIR_FST_CLUS_HI, buf, 1 ) << 16;
878   cluster = cluster | read_entry( DIR_FST_CLUS_LO, buf, 1 );
879   return cluster;
880} 
881
882
883////////////////////////////////////////////////////////////////////////////////////////
884// This function read the blocks defined by the cluster index argument, in a data
885// region containing a directory to search the name of a file/firectory,
886// and returns the cluster index of the file/directory when the name has been found.
887// Return cluster index if name found / Return -1 if not found,
888////////////////////////////////////////////////////////////////////////////////////////
889static int scan_directory( unsigned int   mode,            // mode for IOC driver
890                           unsigned int   cluster,         // cluster containing dir_entry
891                           char*          file_name,       // searched file/directory name
892                           unsigned int*  file_size,       // file size
893                           unsigned int*  lba_dir_entry )  // lba of dir_entry
894{
895
896#if GIET_DEBUG_FAT
897_tty_get_lock( 0 );
898_puts("\n[FAT DEBUG] enter _scan_directory() searching dir/file : ");
899_puts( file_name );
900_puts("\n");
901_tty_release_lock( 0 );
902#endif
903
904    char dir_entry[32];   // buffer to store a full directory_entry
905    char name_entry[14];  // buffer to store a 13 characters (partial) name
906
907    char sfn[12]            = {[0 ... 10] = ' ', '\0'};   // buffer for a Short File Name
908    unsigned int  is_sfn    = is_short(file_name, sfn);   // if file_name is short, sfn = 1     
909    unsigned int  offset    = 0;                          // byte offset in block
910    unsigned int  block_id  = fat.sectors_per_cluster;   // sector index initialisation       
911    unsigned int  lba       = cluster_to_lba(cluster);   
912    unsigned int  attr      = 0;                          // directory entry attribute
913    unsigned int  ord       = 0;                          // directory entry sequence
914    unsigned int  found     = 0;                          // name found
915    unsigned int  i;
916
917    for( i = 0 ; i < 32 ; i++ ) dir_entry[i]  = 0;
918    for( i = 0 ; i < 14 ; i++ ) name_entry[i] = 0;
919
920    // load first cluster sector from DATA region into FAT cache
921    // other sectors will be loaded inside loop as required
922    if( _ioc_read( mode,            // mode for IOC driver
923                   lba,             // sector index
924                   fat.fat_cache,   // buffer address
925                   1 ) )            // one sector
926    {
927        _tty_get_lock( 0 );
928        _puts("[FAT ERROR] in scan directory() cannot read sector ");
929        _putd( lba );
930        _puts("\n");
931        _tty_release_lock( 0 );
932        return -1;
933    }
934
935    fat.cache_lba = lba;
936
937    #if GIET_DEBUG_FAT
938    display_fat_cache();
939    #endif
940
941    // in this loop we scan all names in directory identified by cluster:
942    // - the offset increment is an integer number of directory entry (32 bytes)
943    // - the exit condition is success (name found) or failure (end of directory)
944    while( 1 )
945    {
946        // load a new sector if required
947        if (offset >= 512)             
948        {
949            if ( block_id )           // not a new cluster
950            {
951                lba += 1;
952                block_id --;
953            }
954            else                                          // get next cluster
955            {
956                cluster = get_next_cluster_id( mode, cluster );
957
958                if ( cluster >= END_OF_CHAIN_CLUSTER  ) return END_OF_CHAIN_CLUSTER;
959
960                lba      = cluster_to_lba(cluster);
961                block_id = fat.sectors_per_cluster;
962            }
963            if( _ioc_read( mode,            // mode for IOC driver
964                           lba,             // sector index
965                           fat.fat_cache,   // buffer address
966                           1 ) )            // one sector
967            {
968                _tty_get_lock( 0 );
969                _puts("[FAT ERROR] in scan directory() cannot read sector ");
970                _putd( lba );
971                _puts("\n");
972                _tty_release_lock( 0 );
973                return -1;
974            }
975            fat.cache_lba = lba;
976            block_id--;
977            offset = offset % 512;
978        }
979
980        // analyse a directory entry (pointed by fat.fat_cache + offset)
981        if ( !found )
982        { 
983            attr = read_entry( DIR_ATTR, fat.fat_cache + offset, 0);   
984            ord  = read_entry( LDIR_ORD, fat.fat_cache + offset, 0);
985
986            if ( is_sfn == 1 )                            // searched name is short
987            {
988                if      ( (ord != FREE_ENTRY ) &&
989                          (ord != NO_MORE_ENTRY) &&
990                          (attr == ATTR_LONG_NAME_MASK) )    // LFN entry : skipped
991                {
992                                        offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
993                    continue;
994                }
995                else if ( (attr != ATTR_LONG_NAME_MASK) && 
996                          (ord  != FREE_ENTRY) && 
997                          (ord  != NO_MORE_ENTRY ) )         // SFN entry : checked
998                {
999                    _memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
1000                    offset = offset + DIR_ENTRY_SIZE;
1001                }
1002                else if (ord == NO_MORE_ENTRY )              // end of directory : return
1003                {
1004                    return END_OF_CHAIN_CLUSTER;
1005                }
1006                else                                                                         // free entry : skipped
1007                {
1008                    offset = offset + DIR_ENTRY_SIZE;
1009                    continue;
1010                }
1011            }
1012            else                                      // searched name is long
1013            {
1014                if( (attr == ATTR_LONG_NAME_MASK) && 
1015                    (ord != FREE_ENTRY) &&
1016                    (ord != NO_MORE_ENTRY) )                 // LFN entry : checked
1017                {
1018                    _memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
1019                    offset = offset + DIR_ENTRY_SIZE;
1020                }
1021                else if( (attr != ATTR_LONG_NAME_MASK) && 
1022                         (ord  != FREE_ENTRY) && 
1023                         (ord  != NO_MORE_ENTRY))                        // SFN entry : skipped
1024                {
1025                    offset = offset + DIR_ENTRY_SIZE;
1026                    continue;
1027                }
1028                else if (ord == NO_MORE_ENTRY )                          // end of director : return
1029                {
1030                    return END_OF_CHAIN_CLUSTER;
1031                }
1032                else                                           // free entry : skipped
1033                {
1034                    offset = offset + DIR_ENTRY_SIZE;
1035                    continue;
1036                }
1037            }
1038
1039            // testing the name extracted from dir entry
1040            if ( is_sfn == 1 )                            // searched name is short
1041            {
1042                get_name_from_short( dir_entry, name_entry );
1043
1044                if ( _strncmp( (char*)sfn, (char*)name_entry, 13 ) == 0 )
1045                {
1046                    *file_size = read_entry( DIR_FILE_SIZE , dir_entry, 1 );
1047                    *lba_dir_entry = lba;
1048                    return read_cluster( dir_entry );
1049                }
1050            }
1051            else                                         // searched name is long
1052            {
1053                get_name_from_long( dir_entry, name_entry );
1054
1055                unsigned shift = ((ord & 0xf) - 1) * 13;
1056                if ( _strncmp( (char*)(file_name + shift), (char*)name_entry, 13 ) == 0 )
1057                {
1058                    if( (ord & 0xf) == 1 )  found = 1;
1059                    continue;
1060                }
1061                else                                                                 // no matching : skip
1062                {
1063                    offset = offset + ((ord & 0xf) * DIR_ENTRY_SIZE);
1064                }
1065            }
1066        } 
1067        else    // file found
1068        {
1069            _memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
1070            offset     = offset + DIR_ENTRY_SIZE;
1071            *file_size = read_entry( DIR_FILE_SIZE, dir_entry, 1 );
1072            *lba_dir_entry = lba;
1073
1074#if GIET_DEBUG_FAT
1075_tty_get_lock( 0 );
1076_puts("\n[FAT DEBUG] FILE FOUND\n");
1077_tty_release_lock( 0 );
1078#endif
1079            return read_cluster( dir_entry );
1080        }
1081    }
1082    return -1;
1083} // end scan_directory()
1084
1085
1086//////////////////////////////////////////////////////////////////////
1087// This function create a new entry in a directory identified
1088// by "dir_cluster". The name is defined by "name".
1089// The type (dir/file) is defined by "is_file".
1090// Returns cluster index if success, Returns -1 if error.
1091//////////////////////////////////////////////////////////////////////
1092static int fat_create( char*           name,
1093                       unsigned int    is_file,
1094                       unsigned int    dir_cluster )
1095{
1096    _tty_get_lock( 0 );
1097    _puts("\n[FAT ERROR] _fat_create() not implemented\n");
1098    _tty_release_lock( 0 );
1099    return 0;
1100}  //end _fat_create()
1101
1102
1103
1104////////////// Extern functions //////////////////////////////////////////
1105
1106//////////////////////////////////////////////////////////////////////////
1107// This function initializes the FAT structure, including the
1108// files descriptors array, from informations found in the boot record.
1109//////////////////////////////////////////////////////////////////////////
1110// Return 0 if success, Return -1 if failure
1111//////////////////////////////////////////////////////////////////////////
1112int _fat_init( unsigned int mode )   // mode for IOC driver
1113{
1114    unsigned int   n;
1115
1116#if GIET_DEBUG_FAT
1117_tty_get_lock( 0 );
1118_puts("\n[FAT DEBUG] Enter _fat_init() / fat_cache_base = ");
1119_putx( (unsigned int)fat.fat_cache );
1120_puts("\n");
1121_tty_release_lock( 0 );
1122#endif
1123
1124    // load Master Boot Record (sector 0) into fat cache
1125    if ( _ioc_read( mode,             // mode for IOC driver
1126                    0,                // sector index
1127                    fat.fat_cache,    // buffer address
1128                    1 ) )             // one sector
1129    { 
1130        _tty_get_lock( 0 );
1131        _puts("\n[FAT ERROR] in _fat_init() cannot load Boot Sector\n"); 
1132        _tty_release_lock( 0 );
1133        return -1;
1134    }
1135    fat.cache_lba = 0;
1136   
1137    // checking Boot sector integrity
1138    if( MBR_SIGNATURE_VALUE != read_entry( MBR_SIGNATURE_POSITION, fat.fat_cache, 1))
1139    {
1140        _tty_get_lock( 0 );
1141        _puts("\n[FAT ERROR] Boot sector not recognized or corrupt \n"); 
1142        _tty_release_lock( 0 );
1143        return -1; 
1144    }
1145
1146#if GIET_DEBUG_FAT
1147_tty_get_lock( 0 );
1148_puts("\n[FAT DEBUG] Boot Sector Loaded\n");
1149_tty_release_lock( 0 );
1150#endif
1151
1152    // initialise fat descriptor from Boot sector
1153    fat.partition_lba     = read_entry( FIRST_PARTITION_BEGIN_LBA, fat.fat_cache, 1 );
1154    fat.partition_sectors = read_entry( FIRST_PARTITION_SIZE,      fat.fat_cache, 1 );
1155
1156    // load Partition Boot Record (first partition sector) into fat cache
1157    if ( _ioc_read( mode,                // mode for IOC driver
1158                    fat.partition_lba,   // sector index
1159                    fat.fat_cache,       // buffer address
1160                    1 ) )                // one sector
1161    {
1162        _tty_get_lock( 0 );
1163        _puts("\n[FAT ERROR] in _fat_init() cannot load block ");
1164        _putd( fat.partition_lba );
1165        _puts("\n"); 
1166        _tty_release_lock( 0 );
1167        return -1;
1168    }
1169    fat.cache_lba = fat.partition_lba;
1170
1171#if GIET_DEBUG_FAT
1172_tty_get_lock( 0 );
1173_puts("\n[FAT DEBUG] Partition First Sector Loaded\n");
1174_tty_release_lock( 0 );
1175#endif
1176
1177
1178    // checking various FAT32 assuptions from boot sector
1179    if( read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 ) != 512 )
1180    {
1181        _tty_get_lock( 0 );
1182        _puts("\n[FAT ERROR] The sector size must be 512 bytes\n");
1183        _tty_release_lock( 0 );
1184        return -1; 
1185    }
1186    if( read_entry( BPB_RSVDSECCNT, fat.fat_cache, 1 ) != 32 ) 
1187    {
1188        _tty_get_lock( 0 );
1189        _puts("\n[FAT ERROR] The RSVD region in FAT32 must be 32 sectors\n");
1190        _tty_release_lock( 0 );
1191        return -1; 
1192    }
1193    if( read_entry( BPB_NUMFATS, fat.fat_cache, 1 ) != 1 )
1194    {
1195        _tty_get_lock( 0 );
1196        _puts("\n[FAT ERROR] The number of FAT copies in FAT region must be 1\n");
1197        _tty_release_lock( 0 );
1198        return -1; 
1199    }
1200    if( (read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 ) & 0xF) != 0 )
1201    {
1202        _tty_get_lock( 0 );
1203        _puts("\n[FAT ERROR] The FAT region in FAT32 must be multiple of 32 sectors\n");
1204        _tty_release_lock( 0 );
1205        return -1; 
1206    }
1207
1208    if( read_entry( BPB_FAT32_ROOTCLUS, fat.fat_cache, 1 ) != 2 )
1209    {
1210        _tty_get_lock( 0 );
1211        _puts("\n[FAT ERROR] The first cluster index must be 2\n");
1212        _tty_release_lock( 0 );
1213        return -1; 
1214    }
1215    fat.fs_info_lba         = read_entry( BPB_FAT32_FSINFO, fat.fat_cache, 1 ) + fat.partition_lba;
1216
1217    // initialise fat descriptor from partition first sector
1218    fat.sectors_per_cluster = read_entry( BPB_SECPERCLUS, fat.fat_cache, 1 );
1219    fat.sector_size         = read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 );
1220    fat.cluster_size        = fat.sectors_per_cluster * 512;
1221    fat.fat_sectors         = read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 );
1222    fat.data_lba            = 32 + fat.fat_sectors + fat.partition_lba;
1223    fat.initialised         = FAT_INITIALISED;
1224
1225    // initialise file descriptor array
1226    for( n = 0 ; n < GIET_OPEN_FILES_MAX ; n++ ) fat.fd[n].used = 0;
1227
1228#if GIET_DEBUG_FAT
1229_tty_get_lock( 0 );
1230_puts("\n[FAT DEBUG] FS_INFO Sector = ");
1231_putd(fat.fs_info_lba);
1232_puts("\n");
1233_tty_release_lock( 0 );
1234#endif
1235
1236    // load FS_INFO into fat cache
1237    if ( _ioc_read( mode,               // mode for IOC driver
1238                    fat.fs_info_lba,    // sector index
1239                    fat.fat_cache,      // buffer address
1240                    1 ) )               // one sector
1241    { 
1242        _tty_get_lock( 0 );
1243        _puts("\n[FAT ERROR] in _fat_init() cannot load FS_INFO Sector\n"); 
1244        _tty_release_lock( 0 );
1245        return -1;
1246    }
1247    fat.cache_lba = fat.fs_info_lba;
1248
1249    fat.number_free_cluster    = read_entry( FS_FREE_CLUSTER     , fat.fat_cache, 1);
1250    fat.last_cluster_allocated = read_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, 1);
1251
1252#if GIET_DEBUG_FAT
1253_tty_get_lock( 0 );
1254_puts("\n[FAT DEBUG] Number of Free Clusters = ");
1255_putd(fat.number_free_cluster);
1256_puts("\n");
1257_puts("\n[FAT DEBUG] Last known cluster allocated = ");
1258_putd(fat.last_cluster_allocated);
1259_puts("\n");
1260_puts("\n[FAT DEBUG] FS_INFO Sector Loaded\n");
1261_tty_release_lock( 0 );
1262#endif
1263
1264
1265#if GIET_DEBUG_FAT
1266_tty_get_lock( 0 );
1267_puts("\n[FAT DEBUG] Exit _fat_init()\n");
1268_tty_release_lock( 0 );
1269#endif
1270
1271    return 0;
1272}  // end _fat_init()
1273
1274/////////////////
1275void _fat_print()
1276{
1277    _puts("\n################################ FAT32 ###############################"); 
1278    _puts("\nFAT initialised                "); _putx( fat.initialised );
1279    _puts("\nSector Size  (bytes)           "); _putx( fat.sector_size );
1280    _puts("\nSectors per cluster            "); _putx( fat.sectors_per_cluster );
1281    _puts("\nPartition size (sectors)       "); _putx( fat.partition_sectors );
1282    _puts("\nPartition first lba            "); _putx( fat.partition_lba ); 
1283    _puts("\nData region first lba          "); _putx( fat.data_lba );
1284    _puts("\nNumber of sectors for one FAT  "); _putx( fat.fat_sectors );
1285    _puts("\n######################################################################\n");
1286}
1287
1288///////////////////////////////////////////////////////////////////////////////
1289// This function checks that the kernel FAT structure has been initialised,
1290// and makes the FAT initialisation if it is the first user open request.
1291// This function searches a file identified by the "pathname" argument.
1292// It starts from root (cluster 2) to scan successively each subdirectory.
1293// When the file is not found, but the path is found, and "creat" is set,
1294// a new file is created and introduced in the directory.
1295// Finally, it sets a new open file in the file descriptors array.
1296///////////////////////////////////////////////////////////////////////////////
1297// Returns file descriptor index if success, returns -1 if error.
1298///////////////////////////////////////////////////////////////////////////////
1299int _fat_open( unsigned     mode,
1300               char*        pathname,
1301               unsigned int creat )
1302{
1303    char                 name[256];    // buffer for one name in pathname
1304    unsigned int         nb_read;          // number of characters written in name[]
1305    unsigned int         cluster;      // current cluster index when scanning FAT
1306    unsigned int         dir_cluster;  // previous cluster index when scanning FAT
1307    unsigned int         fd_id;        // index when scanning file descriptors array
1308    unsigned int         file_size;    // number of bytes
1309    unsigned int         last_name;    // directory containing file name is reached
1310    unsigned int         lba;          // lba of dir_entry for this file
1311   
1312#if GIET_DEBUG_FAT
1313_tty_get_lock( 0 );
1314_puts("\n[FAT DEBUG] enter _fat_open() for file ");
1315_puts( pathname );
1316_puts("\n");
1317_tty_release_lock( 0 );
1318#endif
1319
1320    // check FAT initialised
1321    if( fat.initialised != FAT_INITIALISED )
1322    {
1323        if ( _fat_init( mode ) )
1324        {
1325            _puts("[FAT ERROR] Cannot initialize FAT descriptor from Boot Sector\n");
1326            _exit();
1327        }
1328
1329#if GIET_DEBUG_FAT
1330_tty_get_lock( 0 );
1331_puts("\n[FAT DEBUG] FAT initialisation completed at cycle ");
1332_putd(_get_proctime());
1333_puts("\n");
1334_fat_print();
1335_tty_release_lock( 0 );
1336#endif
1337    }
1338 
1339    // Scan the directories, starting from the root directory (cluster 2)
1340    // - The get_name_from_path() function extracts (successively)
1341    //   each directory name from the pathname, and store it in name[] buffer
1342    // - The scan_directory() function scan one (or several) cluster(s) containing
1343    //   a directory looking for name[], and return the cluster index
1344    //   corresponding to the directory/file found.
1345    nb_read     = 0;
1346    cluster     = 2;
1347    last_name   = 0;
1348    while ( get_name_from_path( pathname, name, &nb_read) )
1349    {
1350
1351#if GIET_DEBUG_FAT
1352_tty_get_lock( 0 );
1353_puts("\n[FAT DEBUG] _fat_open : search dir/file : ");
1354_puts( name );
1355_puts("\n");
1356_tty_release_lock( 0 );
1357#endif
1358
1359        // test if we reach the last name (file name)
1360        if( pathname[nb_read] == 0 ) 
1361        {
1362            last_name   = 1;
1363            dir_cluster = cluster;
1364        }
1365
1366        // scan current directory
1367        cluster  = scan_directory( mode, cluster, name, &file_size, &lba );
1368
1369        if( cluster == END_OF_CHAIN_CLUSTER && last_name && creat )
1370        {
1371            cluster = fat_create( name, 1, dir_cluster );
1372        }
1373        else if ( cluster == END_OF_CHAIN_CLUSTER )
1374        {
1375            _tty_get_lock( 0 );
1376            _puts("\n[FAT ERROR] in _fat_open() for file ");
1377            _puts( pathname );
1378            _puts(" : cannot found name ");
1379            _puts( name );
1380            _puts("\n");
1381            _tty_release_lock( 0 );
1382            return -1;
1383        }
1384    }
1385
1386#if GIET_DEBUG_FAT
1387_tty_get_lock( 0 );
1388_puts("\n[FAT DEBUG] File ");
1389_puts( pathname );
1390_puts(" found\n");
1391_tty_release_lock( 0 );
1392#endif
1393
1394    // check the next value for cluster index found
1395    unsigned next = get_next_cluster_id( mode, cluster );
1396
1397    if ( (next != BAD_CLUSTER) && (next != FREE_CLUSTER) )
1398    {
1399        // Search an empty slot scanning open file descriptors array
1400        fd_id = 0;
1401        while ( fat.fd[fd_id].used != 0 && fd_id < GIET_OPEN_FILES_MAX )
1402        {
1403            fd_id++;
1404        }
1405
1406        // set file descriptor if found empty slot
1407        if ( fd_id < GIET_OPEN_FILES_MAX )
1408        {
1409            fat.fd[fd_id].used          = 1;
1410            fat.fd[fd_id].first_cluster = cluster;
1411            fat.fd[fd_id].file_size     = file_size;
1412            fat.fd[fd_id].lba_dir_entry = lba;
1413            _strcpy( fat.fd[fd_id].name, pathname );
1414
1415#if GIET_DEBUG_FAT
1416_tty_get_lock( 0 );
1417_puts("\n[FAT DEBUG] file  ");
1418_puts( pathname );
1419_puts(" open with fd_id = ");
1420_putd( fd_id );
1421_puts("\n");
1422_tty_release_lock( 0 );
1423#endif
1424
1425            return fd_id;
1426        }
1427        else
1428        {
1429            _tty_get_lock( 0 );
1430            _puts("\n[FAT ERROR] in _fat_open() for file ");
1431            _puts( pathname );
1432            _puts(" : file descriptor array full\n ");
1433            _tty_release_lock( 0 );
1434            return -1;
1435        }
1436    }
1437    else
1438    {
1439        _tty_get_lock( 0 );
1440        _puts("\n[FAT ERROR] in _fat_open() for file ");
1441        _puts( pathname );
1442        _puts(" : file found, but bad cluster\n");
1443        _tty_release_lock( 0 );
1444        return -1;
1445    }
1446} // end _fat_open()
1447
1448///////////////////////////////////////////////////////////////////////////////
1449// For an open file, identified by the file descriptor index, transfer
1450// an integer number of sectors from block device to a memory buffer.
1451// If the number of requested sectors exceeds the file size, it is reduced.
1452///////////////////////////////////////////////////////////////////////////////
1453// Returns number of sectors transfered if success, < 0 if error.
1454///////////////////////////////////////////////////////////////////////////////
1455int _fat_read( unsigned int mode,       // mode for IOC driver
1456               unsigned int fd_id,      // file descriptor
1457               void*        buffer,     // target buffer base address
1458               unsigned int count,      // number of sector to read
1459               unsigned int offset )    // nuber of sectors to skip in file
1460{
1461
1462#if GIET_DEBUG_FAT
1463_tty_get_lock( 0 );
1464_puts("\n[FAT DEBUG] Enter _fat_read() for file ");
1465_puts( fat.fd[fd_id].name );
1466_puts("\n - buffer base     = ");
1467_putx( (unsigned int)buffer );
1468_puts("\n - skipped sectors = ");
1469_putd( offset );
1470_puts("\n - read sectors    = "); 
1471_putd( count );
1472_tty_release_lock( 0 );
1473#endif
1474
1475    unsigned int spc = fat.sectors_per_cluster;
1476
1477    unsigned int file_size;         // number of bytes in file
1478    unsigned int file_sectors;      // number of sectors in file
1479    unsigned int total_sectors;     // actual number of sectors to be transfered
1480    unsigned int cluster;           // cluster index
1481    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1482    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1483
1484    // compute file size as a number of sectors
1485    file_size    = fat.fd[fd_id].file_size;
1486    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1487    else                     file_sectors = (file_size >> 9); 
1488
1489    // arguments checking
1490    if ( fd_id >= GIET_OPEN_FILES_MAX )
1491    { 
1492        _tty_get_lock( 0 );
1493        _puts("\n[FAT ERROR] in _fat_read() : illegal file descriptor index\n");
1494        _tty_release_lock( 0 );
1495        return -1;
1496    }
1497    if ( fat.fd[fd_id].used != 1 )
1498    {
1499        _tty_get_lock( 0 );
1500        _puts("\n[FAT ERROR] in _fat_read() : file not open\n");
1501        _tty_release_lock( 0 );
1502        return -1;
1503    }
1504    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1505    {
1506        _tty_get_lock( 0 );
1507        _puts("\n[FAT ERROR] in _fat_read() : memory buffer not sector aligned\n");
1508        _tty_release_lock( 0 );
1509        return -1;
1510    }
1511    if ( offset >= file_sectors )
1512    {
1513        _tty_get_lock( 0 );
1514        _puts("\n[FAT ERROR] offset larger than number of sectors in file\n");
1515        _puts(" - offset       = ");
1516        _putd( offset );
1517        _puts(" - file_sectors = ");
1518        _putd( file_sectors );
1519        _tty_release_lock( 0 );
1520        return -1;
1521    }
1522
1523    // compute total number of sectors to read
1524    if ( file_sectors < (offset + count) ) total_sectors = file_sectors - offset;
1525    else                                   total_sectors = count;
1526
1527    // compute clusters and sectors to be skipped
1528    clusters_to_skip = offset / spc;
1529    sectors_to_skip  = offset % spc;
1530   
1531    // get first cluster index
1532    cluster = fat.fd[fd_id].first_cluster;
1533
1534#if GIET_DEBUG_FAT
1535_tty_get_lock( 0 );
1536_puts("\n - first cluster   = ");
1537_putd( cluster );   
1538_puts("\n - skiped clusters = ");
1539_putd( clusters_to_skip );   
1540_puts("\n");
1541_tty_release_lock( 0 );
1542#endif
1543
1544    // compute index of first cluster to be loaded
1545    // as we may need to scan the FAT, we use the kernel mode
1546    while ( clusters_to_skip )
1547    {
1548        cluster = get_next_cluster_id( IOC_KERNEL_MODE, cluster );
1549        clusters_to_skip--;
1550    }
1551
1552    // variables used in the loop on clusters
1553    int             todo_sectors;   // number of sectors still to be loaded
1554    unsigned int    lba;            // first sector index on device
1555    unsigned int    iter_sectors;   // number of sectors to load in iteration
1556    char*           dst;            // pointer on target buffer
1557
1558    // initialize these variables for the first iteration
1559    todo_sectors  = total_sectors;
1560    dst           = (char*)buffer;
1561    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1562    if( total_sectors < (spc - sectors_to_skip) ) iter_sectors = total_sectors;
1563    else                                          iter_sectors = spc - sectors_to_skip; 
1564
1565    // loop on the clusters
1566    while ( todo_sectors > 0 )
1567    {
1568
1569#if GIET_DEBUG_FAT
1570_tty_get_lock( 0 );
1571_puts("\n[FAT DEBUG] _fat_read() IOC request : buf = ");
1572_putx( (unsigned int)dst );
1573_puts(" / lba = ");
1574_putd( lba );
1575_puts(" / sectors = "); 
1576_putd( iter_sectors );
1577_puts("\n"); 
1578_tty_release_lock( 0 );
1579#endif
1580
1581        if( _ioc_read( mode,              // mode for IOC driver
1582                       lba,               // first sector index
1583                       dst,               // buffer address
1584                       iter_sectors ) )   // number of sectors
1585        {
1586            _tty_get_lock( 0 );
1587            _puts("\n[FAT ERROR] in _fat_read() cannot load block ");
1588            _putd( lba );
1589            _puts("\n"); 
1590            _tty_release_lock( 0 );
1591            return -1;
1592        }
1593         
1594        // update variables for next iteration
1595        cluster      = get_next_cluster_id( mode, cluster );
1596        todo_sectors = todo_sectors - iter_sectors;
1597        dst          = dst + (iter_sectors << 9);
1598        lba          = cluster_to_lba(cluster);
1599        if ( todo_sectors > spc ) iter_sectors = spc;
1600        else                      iter_sectors = todo_sectors;
1601    }
1602         
1603    // returns number of sectors actually transfered
1604    return total_sectors;
1605
1606}  // end _fat_read()
1607
1608///////////////////////////////////////////////////////////////////////////////
1609// For an open file, identified by the file descriptor index, transfer
1610// an integer number of sectors from a memory buffer to block device.
1611// Allocate new clusters if the offset+count larger than current file size,
1612// but the offset should be smaller than the current file size...
1613// - fat    : pointer on FAT
1614// - mode   : mode for the IOC driver
1615// - fd_id  : open file descriptor index 
1616// - buffer : base address of the memory buffer (must be sector aligned)
1617// - offset : number of sectors to skip in file
1618// - count  : number of sectors to be written.
1619///////////////////////////////////////////////////////////////////////////////
1620// Returns number of sectors written if success, < 0 if error.
1621///////////////////////////////////////////////////////////////////////////////
1622int _fat_write( unsigned int mode,       // mode for IOC driver
1623                unsigned int fd_id,      // file descriptor
1624                void*        buffer,     // target buffer base address
1625                unsigned int count,      // number of sector to write
1626                unsigned int offset )    // nuber of sectors to skip in file
1627{
1628
1629    unsigned int spc = fat.sectors_per_cluster;
1630
1631    unsigned int file_size;         // number of bytes in file
1632    unsigned int file_sectors;      // number of sectors in file
1633    unsigned int cluster;           // cluster index
1634    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1635    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1636    unsigned int allocate;          // need allocate or not
1637    unsigned int current_cluster;   // number of cluster allocated to the file
1638    unsigned int required_cluster;  // number of cluster needed for the write
1639
1640    // compute file size as a number of sectors
1641    file_size    = fat.fd[fd_id].file_size;
1642    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1643    else                     file_sectors = (file_size >> 9); 
1644
1645    // Compute the number of clusters occupied by the file
1646    current_cluster = file_sectors / spc;
1647
1648    // Compute the number of clusters that will occupy the file (after fat_write)
1649    required_cluster = (count + offset) / spc;
1650
1651    // Check if we need to allocate new cluster(s) for the file 
1652    allocate = ( required_cluster > current_cluster );
1653
1654#if GIET_DEBUG_FAT
1655_tty_get_lock( 0 );
1656_puts("\n[FAT DEBUG] Enter _fat_write() for file ");
1657_puts( fat.fd[fd_id].name );
1658_puts("\n - buffer base     = ");
1659_putx( (unsigned int)buffer );
1660_puts("\n - skipped sectors = ");
1661_putd( offset );
1662_puts("\n - write sectors    = "); 
1663_putd( count );
1664_puts("\n - file size (sectors)  = "); 
1665_putd( file_sectors );
1666_puts("\n - need allocate = "); 
1667 allocate ? _puts( "True" ) : _puts( "False");
1668_tty_release_lock( 0 );
1669#endif
1670
1671    // arguments checking
1672    if ( fd_id >= GIET_OPEN_FILES_MAX )
1673    { 
1674        _tty_get_lock( 0 );
1675        _puts("\n[FAT ERROR] in _fat_write() : illegal file descriptor index\n");
1676        _tty_release_lock( 0 );
1677        return -1;
1678    }
1679    if ( fat.fd[fd_id].used != 1 )
1680    {
1681        _tty_get_lock( 0 );
1682        _puts("\n[FAT ERROR] in _fat_write() : file not open\n");
1683        _tty_release_lock( 0 );
1684        return -1;
1685    }
1686    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1687    {
1688        _tty_get_lock( 0 );
1689        _puts("\n[FAT ERROR] in _fat_write() : memory buffer not sector aligned\n");
1690        _tty_release_lock( 0 );
1691        return -1;
1692    }
1693
1694    if ( allocate  )
1695    {
1696        if ( _fat_allocate( fd_id, (required_cluster - current_cluster) ) < 0 )
1697        {
1698            _tty_get_lock( 0 );
1699            _puts("\n[FAT ERROR] in _fat_write() : fat_allocate for file ");
1700            _putd( fd_id );
1701            _puts(" failed\n");
1702            _tty_release_lock( 0 );
1703            return -1;
1704        }
1705    }
1706
1707    // compute clusters and sectors to be skipped
1708    clusters_to_skip = offset / spc;
1709    sectors_to_skip  = offset % spc;
1710   
1711    // get first cluster index
1712    cluster = fat.fd[fd_id].first_cluster;
1713
1714#if GIET_DEBUG_FAT
1715_tty_get_lock( 0 );
1716_puts("\n - first cluster   = ");
1717_putd( cluster );   
1718_puts("\n - skiped clusters = ");
1719_putd( clusters_to_skip );   
1720_puts("\n");
1721_tty_release_lock( 0 );
1722#endif
1723
1724    // compute index of first cluster to be loaded
1725    // as we may need to scan the FAT, we use the kernel mode
1726    while ( clusters_to_skip )
1727    {
1728        cluster = get_next_cluster_id( IOC_KERNEL_MODE, cluster );
1729        clusters_to_skip--;
1730    }
1731
1732    // variables used in the loop on clusters
1733    int             todo_sectors;   // number of sectors still to be loaded
1734    unsigned int    lba;            // first sector index on device
1735    unsigned int    iter_sectors;   // number of sectors to load in iteration
1736    char*           src;            // pointer on target buffer
1737
1738    // initialize these variables for the first iteration
1739    todo_sectors  = count;
1740    src           = (char*)buffer;
1741    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1742    if( count < (spc - sectors_to_skip) ) iter_sectors = count;
1743    else                                  iter_sectors = spc - sectors_to_skip; 
1744
1745    // loop on the clusters
1746    while ( todo_sectors > 0 )
1747    {
1748
1749#if GIET_DEBUG_FAT
1750_tty_get_lock( 0 );
1751_puts("\n[FAT DEBUG] _fat_write() IOC request : buf = ");
1752_putx( (unsigned int)src );
1753_puts(" / lba = ");
1754_putd( lba );
1755_puts(" / sectors = "); 
1756_putd( iter_sectors );
1757_puts("\n"); 
1758_tty_release_lock( 0 );
1759#endif
1760
1761        if( _ioc_write( mode,              // mode for IOC driver
1762                        lba,               // first sector index
1763                        src,               // buffer address
1764                        iter_sectors ) )   // number of sectors
1765        {
1766            _tty_get_lock( 0 );
1767            _puts("\n[FAT ERROR] in _fat_write() cannot write block ");
1768            _putd( lba );
1769            _puts("\n"); 
1770            _tty_release_lock( 0 );
1771            return -1;
1772        }
1773         
1774        // update variables for next iteration
1775        cluster      = get_next_cluster_id( mode, cluster );
1776        todo_sectors = todo_sectors - iter_sectors;
1777        src          = src + (iter_sectors << 9);
1778        lba          = cluster_to_lba(cluster);
1779        if ( todo_sectors > spc ) iter_sectors = spc;
1780        else                      iter_sectors = todo_sectors;
1781    }
1782
1783    // Update structure file descriptor, field file_size with
1784    // the new file size if the file is bigger than the previous file
1785    if ( ( offset + count ) > file_sectors )
1786    {
1787        fat.fd[fd_id].file_size = (count + offset) << 9;
1788    }
1789
1790    // Update entry of directory with the new value
1791    // of file size (Field : DIR_FILE_SIZE)
1792    if ( update_entry(fd_id, DIR_FILE_SIZE, fat.fd[fd_id].file_size) )
1793    {
1794            _tty_get_lock( 0 );
1795            _puts("\n[FAT ERROR] in _fat_write() update entry for file ");
1796            _putd( fd_id );
1797            _puts(" failed\n"); 
1798            _tty_release_lock( 0 );
1799            return -1;
1800    }
1801         
1802    // returns number of sectors actually transfered
1803    return count;
1804}
1805
1806/////////////////////////////////////////////////////////////////////////////////
1807// Return stats of a file identified by "fd".
1808// (Only the file_size in sectors for this moment)
1809/////////////////////////////////////////////////////////////////////////////////
1810// Returns file size (on sectors) on success, -1 on failure.
1811/////////////////////////////////////////////////////////////////////////////////
1812int _fat_fstat( unsigned int fd_id )
1813{
1814    unsigned int file_size    = 0;
1815    unsigned int file_sectors = 0;
1816
1817    if( (fd_id < GIET_OPEN_FILES_MAX) )
1818    {
1819        file_size = fat.fd[fd_id].file_size;
1820
1821        if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1822        else                     file_sectors = (file_size >> 9); 
1823
1824        return file_sectors;
1825    }
1826    else
1827    {
1828        _tty_get_lock( 0 );
1829        _puts("\n[FAT ERROR] in _fat_fstat() : illegal file descriptor index\n");
1830        _tty_release_lock( 0 );
1831        return -1;
1832    } 
1833} // end _fat_fstat()
1834
1835/////////////////////////////////////////////////////////////////////////////////
1836// Close the file identified by the file_descriptor index.
1837/////////////////////////////////////////////////////////////////////////////////
1838// Returns 0 on success, -1 on failure.
1839/////////////////////////////////////////////////////////////////////////////////
1840int _fat_close( unsigned int fd_id )
1841{
1842    if( (fd_id < GIET_OPEN_FILES_MAX) )
1843    {
1844        fat.fd[fd_id].used = 0;
1845        return 0;
1846    }
1847    else
1848    {
1849        _tty_get_lock( 0 );
1850        _puts("\n[FAT ERROR] in _fat_close() : illegal file descriptor index\n");
1851        _tty_release_lock( 0 );
1852        return -1;
1853    } 
1854} // end fat_close()
1855
1856/////////////////////////////////////////////////////////////////////////////////////
1857// The following function implement the user_level system call.
1858// The flags argument is nor used, as file access modes are not implemented yet.
1859/////////////////////////////////////////////////////////////////////////////////////
1860// Return the file descriptor index if success / return -1 if failure
1861/////////////////////////////////////////////////////////////////////////////////////
1862int _fat_user_open( char*  pathname,         // absolute pathname from root
1863                    unsigned int flags )     // unused: TODO
1864{
1865    return _fat_open( IOC_KERNEL_MODE,       // we KERNEL_MODE, because
1866                      pathname,              // we need to write into FAT cache
1867                      0 );       
1868}
1869
1870/////////////////////////////////////////////////////////////////////////////////////
1871// The following function implement the user_level system call.
1872// This function should be modified to respect the UNIX specification
1873/////////////////////////////////////////////////////////////////////////////////////
1874// Return number of sectors actually transfered if success / return -1 if failure
1875/////////////////////////////////////////////////////////////////////////////////////
1876int _fat_user_read( unsigned int fd,        // file descriptor index
1877                    void*        buffer,    // destination buffer
1878                    unsigned int count,     // number of sectors to read
1879                    unsigned int offset )   // number of sectors to skip
1880{
1881    return _fat_read( IOC_USER_MODE,
1882                      fd,
1883                      buffer, 
1884                      count, 
1885                      offset );
1886}
1887
1888/////////////////////////////////////////////////////////////////////////////////////
1889// The following function implement the user_level system call.
1890// This function should be modified to respect the UNIX specification.
1891/////////////////////////////////////////////////////////////////////////////////////
1892// Return number of sectors actually transfered if success / return -1 if failure
1893/////////////////////////////////////////////////////////////////////////////////////
1894int _fat_user_write( unsigned int fd,       // file descriptor
1895                     void*        buffer,   // source buffer
1896                     unsigned int count,    // number of sectors to write
1897                     unsigned int offset )  // number of sectors to skip on file
1898{
1899    return _fat_write( IOC_USER_MODE,
1900                       fd,
1901                       buffer, 
1902                       count, 
1903                       offset );
1904}
1905
1906/////////////////////////////////////////////////////////////////////////////////////
1907int _fat_user_lseek( unsigned int fd_id,
1908                     unsigned int offset,
1909                     unsigned int whence )
1910{
1911    _tty_get_lock( 0 );
1912    _puts("[GIET ERROR] _fat_user_lseek function not implemented\n");
1913    _tty_release_lock( 0 );
1914    _exit();
1915    return 0;
1916}
1917
1918
1919// Local Variables:
1920// tab-width: 4
1921// c-basic-offset: 4
1922// c-file-offsets:((innamespace . 0)(inline-open . 0))
1923// indent-tabs-mode: nil
1924// End:
1925// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1926
Note: See TracBrowser for help on using the repository browser.