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

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

Cosmetic.

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