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

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

Update the fat32.c file to use a queueing spin-lock.

  • Property svn:executable set to *
File size: 64.9 KB
RevLine 
[258]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
[300]8// to a FAT32 disk on a block device. It is intended to be used
[258]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)
[417]19// 3. This FAT32 library can be used in 3 modes: BOOT/BOOT/KERNEL/USER
[295]20//    defining different behaviours for the IOC driver.
[258]21//////////////////////////////////////////////////////////////////////////////////
22
23#include <giet_config.h>
24#include <fat32.h>
[458]25#include <tty0.h>
[258]26#include <ioc_driver.h>
27#include <utils.h>
28
29//////////////////////////////////////////////////////////////////////////////////
[417]30//      Global variable : internal FAT representation
[258]31//////////////////////////////////////////////////////////////////////////////////
32
[417]33extern fat32_fs_t fat __attribute__((aligned(512)));
[258]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
[417]46    _puts("\n*********************** fat_cache_lba = ");
47    _putx( fat.cache_lba );
48    _puts(" *****************************\n");
49
50    for ( line = 0 ; line < 16 ; line++ )
[258]51    {
[417]52        // display line index
53        _putx( line );
54        _puts(" : ");
[258]55
[417]56        // display 8*4 bytes hexa
[258]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]);
[417]64            _putx( hexa );
65            _puts(" | ");
[258]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
[417]75        _puts( (char*)temp );
76        _puts("\n");
[258]77    }
[417]78    _puts("***************************************************************************\n");
79
[258]80} // end display_fat_cache() 
[291]81
[258]82//////////////////////////////////////////////////////////////////////////////////
83// This function returns the length of a FAT field. This field is identified
[417]84// by an (offset,length) mnemonic defined in fat32.h file.
[258]85//////////////////////////////////////////////////////////////////////////////////
86static inline int get_length( int offset, 
[417]87                              int length )
[258]88{
89    return length;
90}
91
92//////////////////////////////////////////////////////////////////////////////
[291]93// Write one 32 bits word "value" in a char[] buffer.
[417]94// The modified field in buffer is defined by the offset and size arguments.
[291]95//////////////////////////////////////////////////////////////////////////////
[417]96static void _write_entry( unsigned int   offset,
[291]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//////////////////////////////////////////////////////////////////////////////
[258]115// Read one 32 bits word in a char[] buffer, taking endianness into account.
[417]116// The analysed field in buffer is defined by the offset and size arguments.
[258]117//////////////////////////////////////////////////////////////////////////////
[417]118static unsigned int _read_entry( unsigned int   offset,
119                                 unsigned int   size,
120                                 char*          buffer,
121                                 unsigned int   little_indian )
[258]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
[300]178// the next cluster index from the current cluster index in the FAT.
[258]179// remark: a sector of FAT contains 128 cluster indexes.
180/////////////////////////////////////////////////////////////////////////////////
[417]181static unsigned int _get_next_cluster( unsigned int mode,
182                                       unsigned int cluster )
[258]183{
184    // compute lba of the sector containing the cluster index
[300]185    unsigned int lba = fat.fat_lba + (cluster / 128);
[258]186
[417]187#if GIET_DEBUG_FAT
188unsigned int procid  = _get_procid();
[429]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
[443]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");
[417]202#endif
203
204    if ( lba != fat.cache_lba )      // miss in fat_cache
[258]205    {
206        // we cannot access fat in user mode
207        if( mode == IOC_USER_MODE ) mode = IOC_KERNEL_MODE;
208       
209        // access fat
[295]210        if( _ioc_read( 0,                 // channel
211                       mode,              // mode for IOC driver
[258]212                       lba,               // sector index
213                       fat.fat_cache,     // fat cache
214                       1 ) )              // one sector
215        {
[443]216            _puts("[FAT_ERROR] in get_next cluster_id() : cannot read block ");
217            _putx( lba );
218            _puts("\n");
[258]219            return 1;
220        }
221        fat.cache_lba = lba;
[417]222   
223#if (GIET_DEBUG_FAT > 1)
224display_fat_cache();
225#endif
[258]226
227    }
[417]228    unsigned int next = _read_entry( ((cluster % 128) * 4), 
229                                     4, 
230                                     fat.fat_cache,
231                                     1 );
232
233#if GIET_DEBUG_FAT
[443]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");
[417]243#endif
244
245    return next;
[258]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] = '.';
[354]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;
[258]350}
351
[291]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
[258]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}
[291]398
[258]399///////////////////////////////////////////////////////////////////////////////
[291]400static int get_name_from_long( char *dir_entry,     // input : LFN dir_entry
401                               char *entry_name )   // output : name
[258]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
[291]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
[417]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
[291]489    unsigned int is_sfn;         
[417]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;
[291]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
[417]505    // Format file_name to SFN format
506    is_sfn = is_short( file_name, sfn_string );
[291]507
[295]508    if ( _ioc_read( 0,               // channel
509                    IOC_KERNEL_MODE, // mode for IOC driver
[291]510                    lba,             // sector index
511                    fat.fat_cache,   // buffer address
512                    1 ) )            // one sector
513    {
[443]514        _puts("[FAT ERROR] in update_entry() cannot read sector ");
515        _putx( lba );
516        _puts("\n");
[291]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    {
[417]525        attr = _read_entry( DIR_ATTR, fat.fat_cache + offset, 0 );
526        ord  = _read_entry( LDIR_ORD, fat.fat_cache + offset, 0 );
[291]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            {
[345]541                memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
[291]542            }
543            else if (ord == NO_MORE_ENTRY )            // end of directory : return
544            {
[443]545                _puts("[FAT ERROR] in update_entry() : reaches end of directory\n");
[291]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            {
[345]560                memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );   
[291]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            {
[443]571                _puts("[FAT ERROR] in update_entry() reaches end of directory\n");
[291]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
[417]587            if ( _strncmp( (char*)sfn_string, (char*)name_entry, 13 ) == 0 )
[291]588            {
[417]589                _write_entry(offset + field, size, fat.fat_cache, value);
[291]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;
[417]607                    _write_entry(offset + field, size, fat.fat_cache, value);
[291]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
[295]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
[291]625}
626//////////////////////////////////////////////////////////////////////////////////
[295]627// This function update FS_INFO:
628// last cluster allocated and number of free cluster.
[291]629// Return 0 in case of success, > 0 if failure.
630//////////////////////////////////////////////////////////////////////////////////
[417]631static inline unsigned int _update_fs_info( )
[291]632{
633    unsigned int lba = fat.fs_info_lba;
634
635#if GIET_DEBUG_FAT
[443]636_puts("\n[FAT DEBUG] _update_fs_info() : enters\n");
[291]637#endif
638
639    if ( lba == fat.cache_lba )            // hit cache
640    {
[417]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 );
[291]643    }
644    else                                   // miss cache
645    {
[295]646        if ( _ioc_read( 0,                 // channel
647                        IOC_KERNEL_MODE,   // mode for IOC driver
[291]648                        lba,               // sector index
[295]649                        fat.fat_cache,     // source buffer
[291]650                        1 ) )              // one sector
651        {
[443]652            _puts("[FAT_ERROR] in _update_fat() cannot read block ");
653            _putx( lba );
654            _puts("\n");
[291]655            return 1;
656        }
657        fat.cache_lba = lba;
[417]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 );
[291]660    }
[295]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
[291]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//////////////////////////////////////////////////////////////////////////////////
[417]673static inline unsigned int _update_fat( unsigned int cluster, 
674                                        unsigned int value  )
[291]675{
[300]676    unsigned int lba = fat.fat_lba + (cluster / 128);
[291]677
678#if GIET_DEBUG_FAT
[443]679_puts("\n[FAT DEBUG] _update_fat() : cluster = ");
680_putx( cluster );
681_puts(" / value = ");
682_putx( value );
683_puts("\n");
[291]684#endif
685
686    if ( lba == fat.cache_lba )            // hit cache
687    {
[417]688        _write_entry( ((cluster % 128) << 2), 4, fat.fat_cache, value );
[291]689    }
690    else                                   // miss cache
691    {
[295]692        if ( _ioc_read( 0,                 // channel
693                        IOC_KERNEL_MODE,   // mode for IOC driver
[291]694                        lba,               // sector index
[295]695                        fat.fat_cache,     // source buffer
[291]696                        1 ) )              // one sector
697        {
[443]698            _puts("[FAT_ERROR] in _update_fat() cannot read block %x\n");
[291]699            return 1;
700        }
701        fat.cache_lba = lba;
[417]702        _write_entry( ((cluster % 128) << 2), 4, fat.fat_cache, value );
[291]703    }
[295]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
[417]709} // end update_fat()
[291]710
711//////////////////////////////////////////////////////////////////////////////////
[443]712// This function allocate count clusters to a file by calling the
[417]713// _update_fat function that takes care to update the chaining of clusters.
[291]714// return 0 if success, -1 if failure
715//////////////////////////////////////////////////////////////////////////////////
716static inline int _fat_allocate( unsigned int fd_id, 
717                                 unsigned int count )
718{
[417]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
[291]723
724    // Check if free_cluster is really free (must be true)
[417]725    if ( _get_next_cluster( IOC_KERNEL_MODE, free_cluster ) != FREE_CLUSTER)
[291]726    {
[458]727        _puts("\n[FAT ERROR] in _fat_allocate() : first free cluster not free\n");
[291]728        return -1;
729    }
730    // Check if FAT contains enough cluster free for this allocation
731    if ( count > fat.number_free_cluster )
732    {
[443]733        _puts("\n[FAT ERROR] in _fat_allocate() : Not enough free cluster(s)\n");
[291]734        return -1;
735    }
736
737#if GIET_DEBUG_FAT
[443]738_puts("\n[FAT DEBUG] _fat_allocate() for fd = ");
739_putd( fd_id );
740_puts("\n");
[291]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;
[417]746        next_cluster      = _get_next_cluster( IOC_KERNEL_MODE, next_cluster );
[291]747    }while ( next_cluster < END_OF_CHAIN_CLUSTER );
748
[443]749    // Loop on the number of clusters to be allocated
[291]750    while ( cluster_to_allocate > 0 )
751    {
752
753#if GIET_DEBUG_FAT
[443]754_puts("\n[FAT DEBUG] cluster to update = ");
755_putx( last_cluster_file );
756_puts(" / free cluster = ");
[458]757_putx( free_cluster );
[443]758_puts(" / clusters required = ");
[458]759_putx( cluster_to_allocate );
[443]760_puts("\n");
[291]761#endif
762
763        // update, in the FAT, the value of last cluster allocated by the index
764        // of free cluster.
[417]765        if ( _update_fat( last_cluster_file, free_cluster ) )
[291]766        {
[443]767            _puts("\n[FAT ERROR] in _fat_allocate() : update fat failed\n");
[291]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
[417]780            if ( _update_fat( last_cluster_file, END_OF_CHAIN_CLUSTER ) )
[291]781            {
[443]782                _puts("\n[FAT ERROR] in _fat_allocate() : update fat failed\n");
[291]783                return -1;
784            }
785        }
786
787        free_cluster = free_cluster + 1;
788
789        // Check if free_cluster is really free (must be true)
[417]790        if ( _get_next_cluster( IOC_KERNEL_MODE, free_cluster ) != FREE_CLUSTER)
[291]791        {
[443]792            _puts("\n[FAT ERROR] in _fat_allocate() : free_cluster not free\n");
[291]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
[417]802    if ( _update_fs_info() )
[291]803    {
[443]804        _puts("\n[FAT ERROR] in _fat_allocate() : update fs_info failed\n");
[291]805        return -1;
806    }
807
808    return 0;
[417]809}  // end _fat_allocate()
[291]810
[258]811////////////////////////////////////////////////////////////////////////////////////////
812// This function read the blocks defined by the cluster index argument, in a data
[417]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.
[258]822////////////////////////////////////////////////////////////////////////////////////////
[417]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
[258]828{
[417]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
[258]831
[417]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
[258]843#if GIET_DEBUG_FAT
[417]844unsigned int procid  = _get_procid();
[429]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
[443]849_puts("\n[FAT DEBUG] _scan_directory() : P[");
850_putd( x );
851_puts(",");
852_putd( y );
853_puts(",");
854_putd( p );
[458]855_puts("] enters for ");
[443]856_puts( file_name );
857_puts(" / is_sfn = ");
858_putd( is_sfn );
859_puts("\n"); 
[258]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
[417]866    // load first sector from DATA region into FAT cache
[258]867    // other sectors will be loaded inside loop as required
[295]868    if( _ioc_read( 0,               // channel
869                   mode,            // mode for IOC driver
[258]870                   lba,             // sector index
871                   fat.fat_cache,   // buffer address
872                   1 ) )            // one sector
873    {
[443]874        _puts("[FAT ERROR] in _scan_directory() : cannot read sector ");
875        _putx( lba );
876        _puts("\n");
[258]877        return -1;
878    }
879
880    fat.cache_lba = lba;
881
[358]882#if ( GIET_DEBUG_FAT > 1 )
883display_fat_cache();
884#endif
885
[417]886    // in this loop we scan all names in the directory identified by cluster index
[258]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)
[417]889    while( found == 0 )
[258]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            {
[417]901                cluster = _get_next_cluster( mode, cluster );
[258]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            }
[295]908            if( _ioc_read( 0,               // channel
909                           mode,            // mode for IOC driver
[291]910                           lba,             // sector index
[258]911                           fat.fat_cache,   // buffer address
[291]912                           1 ) )            // one sector
[258]913            {
[443]914                _puts("[FAT ERROR] in _scan_directory() : cannot read sector ");
915                _putx( lba );
916                _puts("\n");
[258]917                return -1;
918            }
919            fat.cache_lba = lba;
920            block_id--;
921            offset = offset % 512;
922        }
923
[417]924        // store the directory entry pointed by offset in dir_entry buffer,
925        // if it a possible candidate for the searched name
[258]926
[417]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
[258]935            {
[417]936                offset     = offset + ((ord & 0xF) * DIR_ENTRY_SIZE);
[258]937            }
[417]938            else if ( (attr != ATTR_LONG_NAME_MASK) && 
939                      (ord  != FREE_ENTRY) && 
940                      (ord  != NO_MORE_ENTRY ) )         // SFN entry : to be checked
[258]941            {
[417]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
[258]948                {
[417]949                    found = 1;
[258]950                }
[417]951                else
[258]952                {
953                    offset = offset + DIR_ENTRY_SIZE;
954                }
955            }
[417]956            else if (ord == NO_MORE_ENTRY )              // end of directory : return
[258]957            {
[417]958                return END_OF_CHAIN_CLUSTER;
[258]959            }
[417]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
[258]966            {
[417]967                memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );
968
[258]969                get_name_from_long( dir_entry, name_entry );
970
971                unsigned shift = ((ord & 0xf) - 1) * 13;
[417]972                if ( _strncmp( (char*)(file_name + shift), 
973                               (char*)name_entry, 13 ) == 0 )  // matching EXT
[258]974                {
[417]975                    if( (ord & 0xf) == 1 )                    // long name found
976                    {
977                        long_name_found = 1;
978                    }
[258]979                }
[417]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
[258]987                {
[417]988                    memcpy( dir_entry, fat.fat_cache + offset, DIR_ENTRY_SIZE );
989                    found = 1;
[258]990                }
[417]991                else                                     // SFN entry: must be skipped
992                {
993                    offset = offset + DIR_ENTRY_SIZE;
994                }
[258]995            }
[417]996            else if (ord == NO_MORE_ENTRY )                              // end of directory : return
997            {
998                return END_OF_CHAIN_CLUSTER;
999            }
[258]1000        }
[417]1001    }  // end while
[258]1002
[417]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 )      ) ;
[258]1008
[417]1009#if GIET_DEBUG_FAT
[443]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 );
[458]1020_puts("\n"); 
[417]1021#endif
1022
1023    return searched_cluster;
1024} // end _scan_directory()
1025
1026
[258]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//////////////////////////////////////////////////////////////////////
[417]1033static int _fat_create( char*           name,
1034                        unsigned int    is_file,
1035                        unsigned int    dir_cluster )
[258]1036{
[443]1037    _puts("\n[FAT ERROR] _fat_create() not implemented\n");
[258]1038    return 0;
1039}  //end _fat_create()
1040
1041
1042
1043////////////// Extern functions //////////////////////////////////////////
1044
1045//////////////////////////////////////////////////////////////////////////
[458]1046// This function initializes the FAT structure, including the open
1047// files descriptors array and the lock protecting the FAT,
1048// from informations found in the boot record.
1049// This should be done only once.
[258]1050//////////////////////////////////////////////////////////////////////////
1051// Return 0 if success, Return -1 if failure
1052//////////////////////////////////////////////////////////////////////////
1053int _fat_init( unsigned int mode )   // mode for IOC driver
1054{
1055    unsigned int   n;
1056
1057#if GIET_DEBUG_FAT
[295]1058unsigned int procid  = _get_procid();
[429]1059unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1060unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1061unsigned int p       = procid & ((1<<P_WIDTH)-1);
[295]1062
[443]1063_puts("\n[FAT DEBUG] _fat_init() : P[");
1064_putd( x );
1065_puts(",");
1066_putd( y );
1067_puts(",");
1068_putd( p );
[458]1069_puts("] enters _fat_init()");
1070if ( mode == IOC_BOOT_MODE   ) _puts(" in BOOT_MODE\n");
1071if ( mode == IOC_KERNEL_MODE ) _puts(" in KERNEL_MODE\n");
1072if ( mode == IOC_USER_MODE   ) _puts(" in USER_MODE\n");
[258]1073#endif
[458]1074
1075    // FAT initialisation should be done only once
1076    if ( fat.initialised == FAT_INITIALISED )
1077    {
1078        _puts("\n[FAT WARNING] Strange initialisation  of a FAT already initialised...\n");
1079        return 0;
1080    }
1081
[300]1082    // load Boot Record (VBR) into fat cache
[295]1083    if ( _ioc_read( 0,                   // channel
1084                    mode,                // mode for IOC driver
[300]1085                    0,                   // sector index
[258]1086                    fat.fat_cache,       // buffer address
[291]1087                    1 ) )                // one sector
[258]1088    {
[443]1089        _puts("\n[FAT ERROR] in _fat_init() cannot load VBR\n");
[258]1090        return -1;
1091    }
[300]1092    fat.cache_lba = 0;
[258]1093
1094#if GIET_DEBUG_FAT
[443]1095_puts("\n[FAT DEBUG] _fat_init() : Boot Sector Loaded\n");
[258]1096#endif
1097
1098    // checking various FAT32 assuptions from boot sector
[417]1099    if( _read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 ) != 512 )
[258]1100    {
[443]1101        _puts("\n[FAT ERROR] The sector size must be 512 bytes\n");
[258]1102        return -1; 
1103    }
[417]1104    if( _read_entry( BPB_NUMFATS, fat.fat_cache, 1 ) != 1 )
[258]1105    {
[443]1106        _puts("\n[FAT ERROR] The number of FAT copies in FAT region must be 1\n");
[258]1107        return -1; 
1108    }
[417]1109    if( (_read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 ) & 0xF) != 0 )
[258]1110    {
[443]1111        _puts("\n[FAT ERROR] The FAT region in FAT32 must be multiple of 32 sectors\n");
[258]1112        return -1; 
1113    }
[417]1114    if( _read_entry( BPB_FAT32_ROOTCLUS, fat.fat_cache, 1 ) != 2 )
[258]1115    {
[443]1116        _puts("\n[FAT ERROR] The first cluster index must be 2\n");
[258]1117        return -1; 
1118    }
[300]1119    // FS Info always in sector 1
[417]1120    fat.fs_info_lba         = _read_entry( BPB_FAT32_FSINFO, fat.fat_cache, 1 );
[258]1121
[300]1122    // initialise fat descriptor from VBR
[417]1123    fat.sectors_per_cluster = _read_entry( BPB_SECPERCLUS, fat.fat_cache, 1 );
1124    fat.sector_size         = _read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 );
[258]1125    fat.cluster_size        = fat.sectors_per_cluster * 512;
[417]1126    fat.fat_sectors         = _read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 );
1127    fat.fat_lba             = _read_entry( BPB_RSVDSECCNT, fat.fat_cache, 1 );
[300]1128    fat.data_lba            = fat.fat_lba + fat.fat_sectors;
[258]1129    fat.initialised         = FAT_INITIALISED;
1130
[458]1131    // initalise the lock protecting the FAT
[474]1132    _spin_lock_init( &fat.fat_lock );
[458]1133
[258]1134    // initialise file descriptor array
1135    for( n = 0 ; n < GIET_OPEN_FILES_MAX ; n++ ) fat.fd[n].used = 0;
1136
[291]1137#if GIET_DEBUG_FAT
[443]1138_puts("\n[FAT DEBUG] _fat_init() : FS_INFO Sector = ");
1139_putx( fat.fs_info_lba );
1140_puts("\n");
[291]1141#endif
1142
1143    // load FS_INFO into fat cache
[295]1144    if ( _ioc_read( 0,                  // channel
1145                    mode,               // mode for IOC driver
[291]1146                    fat.fs_info_lba,    // sector index
1147                    fat.fat_cache,      // buffer address
1148                    1 ) )               // one sector
1149    { 
[443]1150        _puts("\n[FAT ERROR] in _fat_init() cannot load FS_INFO Sector\n"); 
[291]1151        return -1;
1152    }
1153    fat.cache_lba = fat.fs_info_lba;
1154
[417]1155    fat.number_free_cluster    = _read_entry( FS_FREE_CLUSTER     , fat.fat_cache, 1);
1156    fat.last_cluster_allocated = _read_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, 1);
[291]1157
[358]1158
[291]1159#if GIET_DEBUG_FAT
[358]1160_fat_print();
[458]1161_puts("\n[FAT DEBUG] P[");
[443]1162_putd( x );
1163_puts(",");
1164_putd( y );
1165_puts(",");
1166_putd( p );
[458]1167_puts("] exit _fat_init()\n");
[291]1168#endif
1169
[258]1170    return 0;
1171}  // end _fat_init()
1172
1173/////////////////
1174void _fat_print()
1175{
[443]1176    _puts("\n########################## FAT32 ################################"); 
1177    _puts("\nFAT initialised                  "); _putx( fat.initialised );
1178    _puts("\nSector Size  (bytes)             "); _putx( fat.sector_size );
1179    _puts("\nSectors per cluster              "); _putx( fat.sectors_per_cluster );
1180    _puts("\nFAT region first lba             "); _putx( fat.fat_lba );
1181    _puts("\nData region first lba            "); _putx( fat.data_lba );
1182    _puts("\nNumber of sectors for one FAT    "); _putx( fat.fat_sectors );
1183    _puts("\nNumber of free clusters          "); _putx( fat.number_free_cluster );
1184    _puts("\nLast allocated cluster           "); _putx( fat.last_cluster_allocated );
1185    _puts("\n#################################################################\n");
[258]1186}
1187
1188///////////////////////////////////////////////////////////////////////////////
[354]1189// This function checks that the kernel FAT structure has been initialised.
[458]1190// It searches a file identified by the "pathname" argument.
[258]1191// It starts from root (cluster 2) to scan successively each subdirectory.
1192// When the file is not found, but the path is found, and "creat" is set,
1193// a new file is created and introduced in the directory.
1194// Finally, it sets a new open file in the file descriptors array.
[354]1195// The same file can be open several times by differents tasks.
[258]1196///////////////////////////////////////////////////////////////////////////////
1197// Returns file descriptor index if success, returns -1 if error.
1198///////////////////////////////////////////////////////////////////////////////
1199int _fat_open( unsigned     mode,
1200               char*        pathname,
1201               unsigned int creat )
1202{
[354]1203    char                 name[256];        // buffer for one name in pathname
1204    unsigned int         nb_read;              // number of characters written in name[]
1205    unsigned int         cluster;          // current cluster index when scanning FAT
1206    unsigned int         dir_cluster;      // previous cluster index when scanning FAT
1207    unsigned int         fd_id;            // index when scanning file descriptors array
1208    unsigned int         file_size = 0;    // number of bytes
1209    unsigned int         last_name = 0;    // directory containing file name is reached
1210    unsigned int         lba       = 0;    // lba of dir_entry for this file
[258]1211   
1212#if GIET_DEBUG_FAT
[295]1213unsigned int procid  = _get_procid();
[429]1214unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1215unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1216unsigned int p       = procid & ((1<<P_WIDTH)-1);
1217
[458]1218_puts("\n[FAT DEBUG] P[");
[443]1219_putd( x );
1220_puts(",");
1221_putd( y );
1222_puts(",");
1223_putd( p );
[458]1224_puts("] enters _fat_open() for path ");
[443]1225_puts( pathname );
1226_puts("\n");
[258]1227#endif
1228
[458]1229    // checking creat argument
[295]1230    if ( creat )
1231    {
[443]1232        _puts("[FAT ERROR] in _fat_open() : create not supported yet\n");
[295]1233        return -1;
1234    }
1235
[458]1236    // checking FAT initialised
1237    if( fat.initialised != FAT_INITIALISED )
1238    {
1239        _puts("[FAT ERROR] in _fat_open() : FAT not initialised\n");
1240        return -1;
1241    }
[295]1242    // takes the FAT lock for exclusive access
[474]1243    _spin_lock_acquire( &fat.fat_lock );
[295]1244
1245#if GIET_DEBUG_FAT
[443]1246_puts("\n[FAT DEBUG] _fat_open() : P[");
1247_putd( x );
1248_puts(",");
1249_putd( y );
1250_puts(",");
1251_putd( p );
1252_puts("] takes the FAT lock\n");
[295]1253#endif
[258]1254 
[263]1255    // Scan the directories, starting from the root directory (cluster 2)
[258]1256    // - The get_name_from_path() function extracts (successively)
1257    //   each directory name from the pathname, and store it in name[] buffer
[417]1258    // - The _scan_directory() function scan one (or several) cluster(s) containing
[258]1259    //   a directory looking for name[], and return the cluster index
1260    //   corresponding to the directory/file found.
1261    nb_read     = 0;
1262    cluster     = 2;
1263    last_name   = 0;
1264    while ( get_name_from_path( pathname, name, &nb_read) )
1265    {
1266
1267#if GIET_DEBUG_FAT
[443]1268_puts("\n[FAT DEBUG] _fat_open() : P[");
1269_putd( x );
1270_puts(",");
1271_putd( y );
1272_puts(",");
1273_putd( p );
1274_puts("] search dir/file ");
1275_puts( name );
1276_puts("\n");
[258]1277#endif
[291]1278
[258]1279        // test if we reach the last name (file name)
1280        if( pathname[nb_read] == 0 ) 
1281        {
1282            last_name   = 1;
1283            dir_cluster = cluster;
1284        }
1285
1286        // scan current directory
[417]1287        cluster  = _scan_directory( mode, cluster, name, &file_size, &lba );
[258]1288
1289        if( cluster == END_OF_CHAIN_CLUSTER && last_name && creat )
1290        {
[417]1291            cluster = _fat_create( name, 1, dir_cluster );
[258]1292        }
1293        else if ( cluster == END_OF_CHAIN_CLUSTER )
1294        {
[443]1295            _puts("\n[FAT ERROR] in _fat_open() cannot found ");
1296            _puts( name );
1297            _puts("\n");
[474]1298            _spin_lock_release( &fat.fat_lock );
[258]1299            return -1;
1300        }
1301    }
1302
[417]1303#if GIET_DEBUG_FAT
[443]1304_puts("\n[FAT DEBUG] _fat_open() : P[");
1305_putd( x );
1306_puts(",");
1307_putd( y );
1308_puts(",");
1309_putd( p );
1310_puts("] cluster index for file ");
1311_puts( pathname );
1312_puts(" = ");
1313_putx( cluster );
1314_puts("\n");
[417]1315#endif
1316
[258]1317    // check the next value for cluster index found
[417]1318    unsigned next = _get_next_cluster( mode, cluster );
[258]1319
1320    if ( (next != BAD_CLUSTER) && (next != FREE_CLUSTER) )
1321    {
1322        // Search an empty slot scanning open file descriptors array
1323        fd_id = 0;
1324        while ( fat.fd[fd_id].used != 0 && fd_id < GIET_OPEN_FILES_MAX )
1325        {
1326            fd_id++;
1327        }
1328
1329        // set file descriptor if found empty slot
1330        if ( fd_id < GIET_OPEN_FILES_MAX )
1331        {
1332            fat.fd[fd_id].used          = 1;
1333            fat.fd[fd_id].first_cluster = cluster;
1334            fat.fd[fd_id].file_size     = file_size;
[291]1335            fat.fd[fd_id].lba_dir_entry = lba;
[258]1336            _strcpy( fat.fd[fd_id].name, pathname );
1337
1338#if GIET_DEBUG_FAT
[443]1339_puts("\n[FAT DEBUG] _fat_open() : P[");
1340_putd( x );
1341_puts(",");
1342_putd( y );
1343_puts(",");
1344_putd( p );
1345_puts("] exit : fd = ");
1346_putd( fd_id );
1347_puts(" for file ");
1348_puts( pathname );
1349_puts("\n");
[258]1350#endif
1351
[295]1352            // release FAT lock
[474]1353            _spin_lock_release( &fat.fat_lock );
[295]1354
[258]1355            return fd_id;
1356        }
1357        else
1358        {
[443]1359            _puts("\n[FAT ERROR] in _fat_open() for file ");
1360            _puts( pathname );
1361            _puts(" : fd array full\n");
[474]1362            _spin_lock_release( &fat.fat_lock );
[258]1363            return -1;
1364        }
1365    }
1366    else
1367    {
[443]1368        _puts("\n[FAT ERROR] in _fat_open() for file ");
1369        _puts( pathname );
1370        _puts(" : bad cluster\n");
[474]1371        _spin_lock_release( &fat.fat_lock );
[258]1372        return -1;
1373    }
1374} // end _fat_open()
1375
1376///////////////////////////////////////////////////////////////////////////////
1377// For an open file, identified by the file descriptor index, transfer
1378// an integer number of sectors from block device to a memory buffer.
1379// If the number of requested sectors exceeds the file size, it is reduced.
1380///////////////////////////////////////////////////////////////////////////////
1381// Returns number of sectors transfered if success, < 0 if error.
1382///////////////////////////////////////////////////////////////////////////////
1383int _fat_read( unsigned int mode,       // mode for IOC driver
1384               unsigned int fd_id,      // file descriptor
1385               void*        buffer,     // target buffer base address
1386               unsigned int count,      // number of sector to read
1387               unsigned int offset )    // nuber of sectors to skip in file
1388{
1389    unsigned int spc = fat.sectors_per_cluster;
1390
1391    unsigned int file_size;         // number of bytes in file
1392    unsigned int file_sectors;      // number of sectors in file
1393    unsigned int total_sectors;     // actual number of sectors to be transfered
1394    unsigned int cluster;           // cluster index
1395    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1396    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1397
1398    // arguments checking
1399    if ( fd_id >= GIET_OPEN_FILES_MAX )
1400    { 
[443]1401        _puts("\n[FAT ERROR] in _fat_read() : illegal file descriptor index\n");
[258]1402        return -1;
1403    }
1404    if ( fat.fd[fd_id].used != 1 )
1405    {
[443]1406        _puts("\n[FAT ERROR] in _fat_read() : file not open\n");
[258]1407        return -1;
1408    }
1409    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1410    {
[443]1411        _puts("\n[FAT ERROR] in _fat_read() : memory buffer not sector aligned\n");
[258]1412        return -1;
1413    }
[358]1414
1415    // compute file size as a number of sectors
1416    file_size    = fat.fd[fd_id].file_size;
1417    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1418    else                     file_sectors = (file_size >> 9); 
1419
[258]1420    if ( offset >= file_sectors )
1421    {
[443]1422        _puts("\n[FAT ERROR] offset larger than number of sectors\n");
[258]1423        return -1;
1424    }
1425
1426    // compute total number of sectors to read
1427    if ( file_sectors < (offset + count) ) total_sectors = file_sectors - offset;
1428    else                                   total_sectors = count;
1429
1430    // compute clusters and sectors to be skipped
1431    clusters_to_skip = offset / spc;
1432    sectors_to_skip  = offset % spc;
1433   
1434    // get first cluster index
1435    cluster = fat.fd[fd_id].first_cluster;
1436
1437#if GIET_DEBUG_FAT
[354]1438unsigned int procid  = _get_procid();
[429]1439unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1440unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1441unsigned int p       = procid & ((1<<P_WIDTH)-1);
[443]1442_puts("\n[FAT DEBUG] _fat_read() : P[");
1443_putd( x );
1444_puts(",");
1445_putd( y );
1446_puts(",");
1447_putd( p );
1448_puts("] enters for file ");
1449_puts( fat.fd[fd_id].name ); 
1450_puts("\n - buffer vbase    = ");
1451_putx( (unsigned int)buffer );
1452_puts("\n - skipped sectors = ");
1453_putx( offset );
1454_puts("\n - read sectors    = ");
1455_putx( count );
1456_puts("\n - first cluster   = ");
1457_putx( cluster );
1458_puts("\n - skiped clusters = ");
1459_putx( clusters_to_skip );   
1460_puts("\n");
[258]1461#endif
1462
1463    // compute index of first cluster to be loaded
1464    // as we may need to scan the FAT, we use the kernel mode
1465    while ( clusters_to_skip )
1466    {
[417]1467        cluster = _get_next_cluster( IOC_KERNEL_MODE, cluster );
[258]1468        clusters_to_skip--;
1469    }
1470
1471    // variables used in the loop on clusters
1472    int             todo_sectors;   // number of sectors still to be loaded
1473    unsigned int    lba;            // first sector index on device
1474    unsigned int    iter_sectors;   // number of sectors to load in iteration
1475    char*           dst;            // pointer on target buffer
1476
1477    // initialize these variables for the first iteration
1478    todo_sectors  = total_sectors;
1479    dst           = (char*)buffer;
1480    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1481    if( total_sectors < (spc - sectors_to_skip) ) iter_sectors = total_sectors;
1482    else                                          iter_sectors = spc - sectors_to_skip; 
1483
[358]1484    // loop on the clusters: one IOC access per cluster
[258]1485    while ( todo_sectors > 0 )
1486    {
1487
1488#if GIET_DEBUG_FAT
[443]1489_puts("\n[FAT DEBUG] _fat_read() : P[");
1490_putd( x );
1491_puts(",");
1492_putd( y );
1493_puts(",");
1494_putd( p );
1495_puts("] makes an IOC read");
1496_puts("\n - cluster = ");
1497_putx( cluster );
1498_puts("\n - buf     = ");
1499_putx( (unsigned int)dst );
1500_puts("\n - lba     = ");
1501_putx( lba );
1502_puts("\n - sectors = ");
1503_putd( iter_sectors );
1504_puts("\n");
[258]1505#endif
1506
[295]1507        if( _ioc_read( 0,                 // channel
1508                       mode,              // mode for IOC driver
[258]1509                       lba,               // first sector index
1510                       dst,               // buffer address
1511                       iter_sectors ) )   // number of sectors
1512        {
[443]1513            _puts("\n[FAT ERROR] in _fat_read() cannot load block ");
1514            _putx( lba );
1515            _puts("\n");
[258]1516            return -1;
1517        }
1518         
1519        // update variables for next iteration
[417]1520        cluster      = _get_next_cluster( mode, cluster );
[258]1521        todo_sectors = todo_sectors - iter_sectors;
1522        dst          = dst + (iter_sectors << 9);
1523        lba          = cluster_to_lba(cluster);
1524        if ( todo_sectors > spc ) iter_sectors = spc;
1525        else                      iter_sectors = todo_sectors;
1526    }
1527         
1528    // returns number of sectors actually transfered
1529    return total_sectors;
1530
1531}  // end _fat_read()
1532
1533///////////////////////////////////////////////////////////////////////////////
1534// For an open file, identified by the file descriptor index, transfer
1535// an integer number of sectors from a memory buffer to block device.
1536// Allocate new clusters if the offset+count larger than current file size,
1537// but the offset should be smaller than the current file size...
1538// - fat    : pointer on FAT
1539// - mode   : mode for the IOC driver
1540// - fd_id  : open file descriptor index 
1541// - buffer : base address of the memory buffer (must be sector aligned)
1542// - offset : number of sectors to skip in file
1543// - count  : number of sectors to be written.
1544///////////////////////////////////////////////////////////////////////////////
1545// Returns number of sectors written if success, < 0 if error.
1546///////////////////////////////////////////////////////////////////////////////
1547int _fat_write( unsigned int mode,       // mode for IOC driver
1548                unsigned int fd_id,      // file descriptor
1549                void*        buffer,     // target buffer base address
1550                unsigned int count,      // number of sector to write
1551                unsigned int offset )    // nuber of sectors to skip in file
1552{
[259]1553
1554    unsigned int spc = fat.sectors_per_cluster;
1555
1556    unsigned int file_size;         // number of bytes in file
1557    unsigned int file_sectors;      // number of sectors in file
1558    unsigned int cluster;           // cluster index
1559    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1560    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1561    unsigned int allocate;          // need allocate or not
[291]1562    unsigned int current_cluster;   // number of cluster allocated to the file
1563    unsigned int required_cluster;  // number of cluster needed for the write
[259]1564
1565    // compute file size as a number of sectors
1566    file_size    = fat.fd[fd_id].file_size;
1567    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1568    else                     file_sectors = (file_size >> 9); 
1569
[291]1570    // Compute the number of clusters occupied by the file
1571    current_cluster = file_sectors / spc;
1572
1573    // Compute the number of clusters that will occupy the file (after fat_write)
1574    required_cluster = (count + offset) / spc;
1575
1576    // Check if we need to allocate new cluster(s) for the file 
1577    allocate = ( required_cluster > current_cluster );
1578
[259]1579#if GIET_DEBUG_FAT
[295]1580unsigned int procid  = _get_procid();
[429]1581unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1582unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1583unsigned int p       = procid & ((1<<P_WIDTH)-1);
[443]1584_puts("\n[FAT DEBUG] _fat_write() : P[");
1585_putd( x );
1586_puts(",");
1587_putd( y );
1588_puts(",");
1589_putd( p );
1590_puts("] enters for file ");
1591_puts( fat.fd[fd_id].name ); 
1592_puts("\n - buffer vbase    = ");
1593_putx( (unsigned int)buffer );
1594_puts("\n - skipped sectors = ");
1595_putx( offset );
1596_puts("\n - write sectors   = ");
1597_putx( count );
1598_puts("\n - file sectors    = ");
1599_putx( file_sectors );
1600_puts("\n - need_allocate   = ");
1601_putd( allocate );   
[259]1602#endif
1603
1604    // arguments checking
1605    if ( fd_id >= GIET_OPEN_FILES_MAX )
1606    { 
[443]1607        _puts("\n[FAT ERROR] in _fat_write() : illegal file descriptor index\n");
[259]1608        return -1;
1609    }
1610    if ( fat.fd[fd_id].used != 1 )
1611    {
[443]1612        _puts("\n[FAT ERROR] in _fat_write() : file not open\n");
[259]1613        return -1;
1614    }
1615    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1616    {
[443]1617        _puts("\n[FAT ERROR] in _fat_write() : memory buffer not sector aligned\n");
[259]1618        return -1;
1619    }
1620
[291]1621    if ( allocate  )
1622    {
1623        if ( _fat_allocate( fd_id, (required_cluster - current_cluster) ) < 0 )
1624        {
[443]1625            _puts("\n[FAT ERROR] in _fat_write() : fat_allocate failed\n");
[291]1626            return -1;
1627        }
1628    }
1629
[259]1630    // compute clusters and sectors to be skipped
1631    clusters_to_skip = offset / spc;
1632    sectors_to_skip  = offset % spc;
1633   
1634    // get first cluster index
1635    cluster = fat.fd[fd_id].first_cluster;
1636
1637#if GIET_DEBUG_FAT
[443]1638_puts("\n - first cluster   = ");
1639_putx( cluster );
1640_puts("\n - skiped clusters = ");
1641_putx( clusters_to_skip );   
1642_puts("\n");
[259]1643#endif
1644
1645    // compute index of first cluster to be loaded
1646    // as we may need to scan the FAT, we use the kernel mode
1647    while ( clusters_to_skip )
1648    {
[417]1649        cluster = _get_next_cluster( IOC_KERNEL_MODE, cluster );
[259]1650        clusters_to_skip--;
1651    }
1652
1653    // variables used in the loop on clusters
1654    int             todo_sectors;   // number of sectors still to be loaded
1655    unsigned int    lba;            // first sector index on device
1656    unsigned int    iter_sectors;   // number of sectors to load in iteration
1657    char*           src;            // pointer on target buffer
1658
1659    // initialize these variables for the first iteration
1660    todo_sectors  = count;
1661    src           = (char*)buffer;
1662    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1663    if( count < (spc - sectors_to_skip) ) iter_sectors = count;
1664    else                                  iter_sectors = spc - sectors_to_skip; 
1665
1666    // loop on the clusters
1667    while ( todo_sectors > 0 )
1668    {
1669
1670#if GIET_DEBUG_FAT
[443]1671_puts("\n[FAT DEBUG] _fat_write() : P[");
1672_putd( x );
1673_puts(",");
1674_putd( y );
1675_puts(",");
1676_putd( p );
1677_puts("] makes an IOC write");
1678_puts("\n - cluster = ");
1679_putx( cluster );
1680_puts("\n - buf     = ");
1681_putx( (unsigned int)src );
1682_puts("\n - lba     = ");
1683_putx( lba );
1684_puts("\n - sectors = ");
1685_putd( iter_sectors );
1686_puts("\n");
[259]1687#endif
1688
[295]1689        if( _ioc_write( 0,                 // channel
1690                        mode,              // mode for IOC driver
[259]1691                        lba,               // first sector index
[295]1692                        src,               // source buffer address
[259]1693                        iter_sectors ) )   // number of sectors
1694        {
[443]1695            _puts("\n[FAT ERROR] in _fat_write() cannot write block ");
1696            _putx( lba );
1697            _puts("\n");
[259]1698            return -1;
1699        }
1700         
1701        // update variables for next iteration
[417]1702        cluster      = _get_next_cluster( mode, cluster );
[259]1703        todo_sectors = todo_sectors - iter_sectors;
1704        src          = src + (iter_sectors << 9);
1705        lba          = cluster_to_lba(cluster);
1706        if ( todo_sectors > spc ) iter_sectors = spc;
1707        else                      iter_sectors = todo_sectors;
1708    }
[291]1709
1710    // Update structure file descriptor, field file_size with
1711    // the new file size if the file is bigger than the previous file
1712    if ( ( offset + count ) > file_sectors )
1713    {
1714        fat.fd[fd_id].file_size = (count + offset) << 9;
1715    }
1716
1717    // Update entry of directory with the new value
1718    // of file size (Field : DIR_FILE_SIZE)
1719    if ( update_entry(fd_id, DIR_FILE_SIZE, fat.fd[fd_id].file_size) )
1720    {
[443]1721            _puts("\n[FAT ERROR] in _fat_write() update entry failed\n");
[291]1722            return -1;
1723    }
[259]1724         
1725    // returns number of sectors actually transfered
1726    return count;
[417]1727}  // end _fat_write()
[258]1728
1729/////////////////////////////////////////////////////////////////////////////////
[260]1730// Return stats of a file identified by "fd".
1731// (Only the file_size in sectors for this moment)
1732/////////////////////////////////////////////////////////////////////////////////
1733// Returns file size (on sectors) on success, -1 on failure.
1734/////////////////////////////////////////////////////////////////////////////////
1735int _fat_fstat( unsigned int fd_id )
1736{
1737    unsigned int file_size    = 0;
1738    unsigned int file_sectors = 0;
1739
1740    if( (fd_id < GIET_OPEN_FILES_MAX) )
1741    {
1742        file_size = fat.fd[fd_id].file_size;
1743
1744        if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1745        else                     file_sectors = (file_size >> 9); 
1746
1747        return file_sectors;
1748    }
1749    else
1750    {
[443]1751        _puts("\n[FAT ERROR] in _fat_fstat() : illegal file descriptor index\n");
[260]1752        return -1;
1753    } 
1754} // end _fat_fstat()
1755
1756/////////////////////////////////////////////////////////////////////////////////
[258]1757// Close the file identified by the file_descriptor index.
1758/////////////////////////////////////////////////////////////////////////////////
1759// Returns 0 on success, -1 on failure.
1760/////////////////////////////////////////////////////////////////////////////////
1761int _fat_close( unsigned int fd_id )
1762{
1763    if( (fd_id < GIET_OPEN_FILES_MAX) )
1764    {
1765        fat.fd[fd_id].used = 0;
1766        return 0;
1767    }
1768    else
1769    {
[443]1770        _puts("\n[FAT ERROR] in _fat_close() : illegal file descriptor index\n");
[258]1771        return -1;
1772    } 
1773} // end fat_close()
1774
1775/////////////////////////////////////////////////////////////////////////////////////
1776// The following function implement the user_level system call.
[417]1777// The flags argument is not used, as file access modes are not implemented yet.
[258]1778/////////////////////////////////////////////////////////////////////////////////////
1779// Return the file descriptor index if success / return -1 if failure
1780/////////////////////////////////////////////////////////////////////////////////////
1781int _fat_user_open( char*  pathname,         // absolute pathname from root
1782                    unsigned int flags )     // unused: TODO
1783{
[295]1784    return _fat_open( IOC_KERNEL_MODE,       // we use KERNEL_MODE, because
[258]1785                      pathname,              // we need to write into FAT cache
[295]1786                      0 );                   // no creation if not found
[258]1787}
1788
1789/////////////////////////////////////////////////////////////////////////////////////
1790// The following function implement the user_level system call.
1791// This function should be modified to respect the UNIX specification
1792/////////////////////////////////////////////////////////////////////////////////////
1793// Return number of sectors actually transfered if success / return -1 if failure
1794/////////////////////////////////////////////////////////////////////////////////////
1795int _fat_user_read( unsigned int fd,        // file descriptor index
1796                    void*        buffer,    // destination buffer
1797                    unsigned int count,     // number of sectors to read
1798                    unsigned int offset )   // number of sectors to skip
1799{
1800    return _fat_read( IOC_USER_MODE,
1801                      fd,
1802                      buffer, 
1803                      count, 
1804                      offset );
1805}
1806
1807/////////////////////////////////////////////////////////////////////////////////////
1808// The following function implement the user_level system call.
1809// This function should be modified to respect the UNIX specification.
1810/////////////////////////////////////////////////////////////////////////////////////
1811// Return number of sectors actually transfered if success / return -1 if failure
1812/////////////////////////////////////////////////////////////////////////////////////
1813int _fat_user_write( unsigned int fd,       // file descriptor
1814                     void*        buffer,   // source buffer
1815                     unsigned int count,    // number of sectors to write
1816                     unsigned int offset )  // number of sectors to skip on file
1817{
1818    return _fat_write( IOC_USER_MODE,
1819                       fd,
1820                       buffer, 
1821                       count, 
1822                       offset );
1823}
1824
1825/////////////////////////////////////////////////////////////////////////////////////
1826int _fat_user_lseek( unsigned int fd_id,
1827                     unsigned int offset,
1828                     unsigned int whence )
1829{
[443]1830    _puts("[GIET ERROR] _fat_user_lseek() not implemented\n");
[258]1831    _exit();
1832    return 0;
1833}
1834
1835
1836// Local Variables:
1837// tab-width: 4
1838// c-basic-offset: 4
1839// c-file-offsets:((innamespace . 0)(inline-open . 0))
1840// indent-tabs-mode: nil
1841// End:
1842// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1843
Note: See TracBrowser for help on using the repository browser.