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

Last change on this file since 447 was 443, checked in by alain, 10 years ago

euh...

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