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

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

Cosmetic.

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