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

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

Introducing fixed format (X_WIDTH / Y_WIDTH / P_WIDTH) for processor index.

  • 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>
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();
[429]195unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
196unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
197unsigned int p       = procid & ((1<<P_WIDTH)-1);
198
[417]199_printf("\n[FAT DEBUG] _get_next_cluster() : P[%d,%d,%d] enters for cluster %x\n",
[429]200        x, y, p, cluster );
[417]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",
[429]233        x, y, p, next );
[417]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();
[429]822unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
823unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
824unsigned int p       = procid & ((1<<P_WIDTH)-1);
825
[417]826_printf("\n[FAT DEBUG] _scan_directory() : P[%d,%d,%d] enters for %s / is_sfn = %d\n", 
[429]827        x, y, p, 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", 
[429]975        x, y, p, file_name, searched_cluster );
[417]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();
[429]1012unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1013unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1014unsigned int p       = procid & ((1<<P_WIDTH)-1);
[295]1015
[429]1016_printf("\n[FAT DEBUG] _fat_init() : P[%d,%d,%d] enters", x, y, p );
[417]1017if ( mode == IOC_BOOT_MODE   ) _printf(" / IOC_BOOT_MODE\n");
1018if ( mode == IOC_KERNEL_MODE ) _printf(" / IOC_KERNEL_MODE\n");
1019if ( mode == IOC_USER_MODE   ) _printf(" / IOC_USER_MODE\n");
[258]1020#endif
1021   
[300]1022    // load Boot Record (VBR) into fat cache
[295]1023    if ( _ioc_read( 0,                   // channel
1024                    mode,                // mode for IOC driver
[300]1025                    0,                   // sector index
[258]1026                    fat.fat_cache,       // buffer address
[291]1027                    1 ) )                // one sector
[258]1028    {
[300]1029        _printf("\n[FAT ERROR] in _fat_init() cannot load VBR\n");
[258]1030        return -1;
1031    }
[300]1032    fat.cache_lba = 0;
[258]1033
1034#if GIET_DEBUG_FAT
[417]1035_printf("\n[FAT DEBUG] _fat_init() : Boot Sector Loaded\n");
[258]1036#endif
1037
1038    // checking various FAT32 assuptions from boot sector
[417]1039    if( _read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 ) != 512 )
[258]1040    {
[295]1041        _printf("\n[FAT ERROR] The sector size must be 512 bytes\n");
[258]1042        return -1; 
1043    }
[417]1044    if( _read_entry( BPB_NUMFATS, fat.fat_cache, 1 ) != 1 )
[258]1045    {
[295]1046        _printf("\n[FAT ERROR] The number of FAT copies in FAT region must be 1\n");
[258]1047        return -1; 
1048    }
[417]1049    if( (_read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 ) & 0xF) != 0 )
[258]1050    {
[295]1051        _printf("\n[FAT ERROR] The FAT region in FAT32 must be multiple of 32 sectors\n");
[258]1052        return -1; 
1053    }
[417]1054    if( _read_entry( BPB_FAT32_ROOTCLUS, fat.fat_cache, 1 ) != 2 )
[258]1055    {
[295]1056        _printf("\n[FAT ERROR] The first cluster index must be 2\n");
[258]1057        return -1; 
1058    }
[300]1059    // FS Info always in sector 1
[417]1060    fat.fs_info_lba         = _read_entry( BPB_FAT32_FSINFO, fat.fat_cache, 1 );
[258]1061
[300]1062    // initialise fat descriptor from VBR
[417]1063    fat.sectors_per_cluster = _read_entry( BPB_SECPERCLUS, fat.fat_cache, 1 );
1064    fat.sector_size         = _read_entry( BPB_BYTSPERSEC, fat.fat_cache, 1 );
[258]1065    fat.cluster_size        = fat.sectors_per_cluster * 512;
[417]1066    fat.fat_sectors         = _read_entry( BPB_FAT32_FATSZ32, fat.fat_cache, 1 );
1067    fat.fat_lba             = _read_entry( BPB_RSVDSECCNT, fat.fat_cache, 1 );
[300]1068    fat.data_lba            = fat.fat_lba + fat.fat_sectors;
[354]1069    fat.fat_lock.value      = 0;
[258]1070    fat.initialised         = FAT_INITIALISED;
1071
1072    // initialise file descriptor array
1073    for( n = 0 ; n < GIET_OPEN_FILES_MAX ; n++ ) fat.fd[n].used = 0;
1074
[291]1075#if GIET_DEBUG_FAT
[417]1076_printf("\n[FAT DEBUG] _fat_init() : FS_INFO Sector = %x\n", fat.fs_info_lba );
[291]1077#endif
1078
1079    // load FS_INFO into fat cache
[295]1080    if ( _ioc_read( 0,                  // channel
1081                    mode,               // mode for IOC driver
[291]1082                    fat.fs_info_lba,    // sector index
1083                    fat.fat_cache,      // buffer address
1084                    1 ) )               // one sector
1085    { 
[295]1086        _printf("\n[FAT ERROR] in _fat_init() cannot load FS_INFO Sector\n"); 
[291]1087        return -1;
1088    }
1089    fat.cache_lba = fat.fs_info_lba;
1090
[417]1091    fat.number_free_cluster    = _read_entry( FS_FREE_CLUSTER     , fat.fat_cache, 1);
1092    fat.last_cluster_allocated = _read_entry( FS_FREE_CLUSTER_HINT, fat.fat_cache, 1);
[291]1093
[358]1094
[291]1095#if GIET_DEBUG_FAT
[429]1096_printf("\n[FAT DEBUG] _fat_init() : P[%d,%d,%d] initialises FAT descriptor\n", x, y, p );
[358]1097_fat_print();
[429]1098_printf("\n[FAT DEBUG] _fat_init() : P[%d,%d,%d] exit\n", x, y, p );
[291]1099#endif
1100
[258]1101    return 0;
1102}  // end _fat_init()
1103
1104/////////////////
1105void _fat_print()
1106{
[358]1107    _printf("\n########################## FAT32 ################################"); 
1108    _printf("\nFAT initialised                  %x", fat.initialised );
1109    _printf("\nSector Size  (bytes)             %x", fat.sector_size );
1110    _printf("\nSectors per cluster              %x", fat.sectors_per_cluster );
1111    _printf("\nFAT region first lba             %x", fat.fat_lba );
1112    _printf("\nData region first lba            %x", fat.data_lba );
1113    _printf("\nNumber of sectors for one FAT    %x", fat.fat_sectors );
1114    _printf("\nNumber of free clusters          %x", fat.number_free_cluster );
[360]1115    _printf("\nLast allocated cluster           %x", fat.last_cluster_allocated );
[358]1116    _printf("\n#################################################################\n");
[258]1117}
1118
1119///////////////////////////////////////////////////////////////////////////////
[354]1120// This function checks that the kernel FAT structure has been initialised.
1121// It makes the FAT initialisation if it is the first open request.
[258]1122// This function searches a file identified by the "pathname" argument.
1123// It starts from root (cluster 2) to scan successively each subdirectory.
1124// When the file is not found, but the path is found, and "creat" is set,
1125// a new file is created and introduced in the directory.
1126// Finally, it sets a new open file in the file descriptors array.
[354]1127// The same file can be open several times by differents tasks.
[258]1128///////////////////////////////////////////////////////////////////////////////
1129// Returns file descriptor index if success, returns -1 if error.
1130///////////////////////////////////////////////////////////////////////////////
1131int _fat_open( unsigned     mode,
1132               char*        pathname,
1133               unsigned int creat )
1134{
[354]1135    char                 name[256];        // buffer for one name in pathname
1136    unsigned int         nb_read;              // number of characters written in name[]
1137    unsigned int         cluster;          // current cluster index when scanning FAT
1138    unsigned int         dir_cluster;      // previous cluster index when scanning FAT
1139    unsigned int         fd_id;            // index when scanning file descriptors array
1140    unsigned int         file_size = 0;    // number of bytes
1141    unsigned int         last_name = 0;    // directory containing file name is reached
1142    unsigned int         lba       = 0;    // lba of dir_entry for this file
[258]1143   
1144#if GIET_DEBUG_FAT
[295]1145unsigned int procid  = _get_procid();
[429]1146unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1147unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1148unsigned int p       = procid & ((1<<P_WIDTH)-1);
1149
[417]1150_printf("\n[FAT DEBUG] _fat_open() : P[%d,%d,%d] enters for path %s\n",
[429]1151        x, y, p, pathname );
[258]1152#endif
1153
[295]1154    // checking arguments
1155    if ( creat )
1156    {
1157        _printf("[FAT ERROR] in _fat_open() : create not supported yet\n");
1158        return -1;
1159    }
1160
1161    // takes the FAT lock for exclusive access
[354]1162    _get_lock( &fat.fat_lock );
[295]1163
1164#if GIET_DEBUG_FAT
[417]1165_printf("\n[FAT DEBUG] _fat_open() : P[%d,%d,%d] takes the FAT lock\n",
[429]1166        x, y, p );
[295]1167#endif
1168
1169    // FAT initialisation if required
[258]1170    if( fat.initialised != FAT_INITIALISED )
1171    {
[289]1172        if ( _fat_init( mode ) )
1173        {
[295]1174            _printf("[FAT ERROR] in _fat_open() : Cannot initialize FAT descriptor\n");
[354]1175            _release_lock( &fat.fat_lock );
[295]1176            return -1;
[289]1177        }
[258]1178    }
1179 
[263]1180    // Scan the directories, starting from the root directory (cluster 2)
[258]1181    // - The get_name_from_path() function extracts (successively)
1182    //   each directory name from the pathname, and store it in name[] buffer
[417]1183    // - The _scan_directory() function scan one (or several) cluster(s) containing
[258]1184    //   a directory looking for name[], and return the cluster index
1185    //   corresponding to the directory/file found.
1186    nb_read     = 0;
1187    cluster     = 2;
1188    last_name   = 0;
1189    while ( get_name_from_path( pathname, name, &nb_read) )
1190    {
1191
1192#if GIET_DEBUG_FAT
[417]1193_printf("\n[FAT DEBUG] _fat_open() : P[%d,%d,%d] search dir/file : %s\n",
[429]1194        x, y, p, name );
[258]1195#endif
[291]1196
[258]1197        // test if we reach the last name (file name)
1198        if( pathname[nb_read] == 0 ) 
1199        {
1200            last_name   = 1;
1201            dir_cluster = cluster;
1202        }
1203
1204        // scan current directory
[417]1205        cluster  = _scan_directory( mode, cluster, name, &file_size, &lba );
[258]1206
1207        if( cluster == END_OF_CHAIN_CLUSTER && last_name && creat )
1208        {
[417]1209            cluster = _fat_create( name, 1, dir_cluster );
[258]1210        }
1211        else if ( cluster == END_OF_CHAIN_CLUSTER )
1212        {
[295]1213            _printf("\n[FAT ERROR] in _fat_open() cannot found %s\n", name );
1214
1215            // release FAT lock
[354]1216            _release_lock( &fat.fat_lock );
[295]1217
[258]1218            return -1;
1219        }
1220    }
1221
[417]1222#if GIET_DEBUG_FAT
1223_printf("\n[FAT DEBUG] _fat_open() : P[%d,%d,%d] found cluster index for file %s : %x\n",
[429]1224        x, y, p, pathname, cluster );
[417]1225#endif
1226
[258]1227    // check the next value for cluster index found
[417]1228    unsigned next = _get_next_cluster( mode, cluster );
[258]1229
1230    if ( (next != BAD_CLUSTER) && (next != FREE_CLUSTER) )
1231    {
1232        // Search an empty slot scanning open file descriptors array
1233        fd_id = 0;
1234        while ( fat.fd[fd_id].used != 0 && fd_id < GIET_OPEN_FILES_MAX )
1235        {
1236            fd_id++;
1237        }
1238
1239        // set file descriptor if found empty slot
1240        if ( fd_id < GIET_OPEN_FILES_MAX )
1241        {
1242            fat.fd[fd_id].used          = 1;
1243            fat.fd[fd_id].first_cluster = cluster;
1244            fat.fd[fd_id].file_size     = file_size;
[291]1245            fat.fd[fd_id].lba_dir_entry = lba;
[258]1246            _strcpy( fat.fd[fd_id].name, pathname );
1247
1248#if GIET_DEBUG_FAT
[417]1249_printf("\n[FAT DEBUG] _fat_open() : P[%d,%d,%d] exit : fd = %d for file %s\n",
[429]1250        x, y, p, fd_id, pathname );
[258]1251#endif
1252
[295]1253            // release FAT lock
[354]1254            _release_lock( &fat.fat_lock );
[295]1255
[258]1256            return fd_id;
1257        }
1258        else
1259        {
[295]1260            _printf("\n[FAT ERROR] in _fat_open() for file %s : fd array full\n",
1261                    pathname );
1262
1263            // release FAT lock
[354]1264            _release_lock( &fat.fat_lock );
[295]1265
[258]1266            return -1;
1267        }
1268    }
1269    else
1270    {
[295]1271        _printf("\n[FAT ERROR] in _fat_open() for file %s : bad cluster\n",
1272                pathname );
1273
1274        // release FAT lock
[354]1275        _release_lock( &fat.fat_lock );
[295]1276
[258]1277        return -1;
1278    }
1279} // end _fat_open()
1280
1281///////////////////////////////////////////////////////////////////////////////
1282// For an open file, identified by the file descriptor index, transfer
1283// an integer number of sectors from block device to a memory buffer.
1284// If the number of requested sectors exceeds the file size, it is reduced.
1285///////////////////////////////////////////////////////////////////////////////
1286// Returns number of sectors transfered if success, < 0 if error.
1287///////////////////////////////////////////////////////////////////////////////
1288int _fat_read( unsigned int mode,       // mode for IOC driver
1289               unsigned int fd_id,      // file descriptor
1290               void*        buffer,     // target buffer base address
1291               unsigned int count,      // number of sector to read
1292               unsigned int offset )    // nuber of sectors to skip in file
1293{
1294    unsigned int spc = fat.sectors_per_cluster;
1295
1296    unsigned int file_size;         // number of bytes in file
1297    unsigned int file_sectors;      // number of sectors in file
1298    unsigned int total_sectors;     // actual number of sectors to be transfered
1299    unsigned int cluster;           // cluster index
1300    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1301    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1302
1303    // arguments checking
1304    if ( fd_id >= GIET_OPEN_FILES_MAX )
1305    { 
[295]1306        _printf("\n[FAT ERROR] in _fat_read() : illegal file descriptor index\n");
[258]1307        return -1;
1308    }
1309    if ( fat.fd[fd_id].used != 1 )
1310    {
[295]1311        _printf("\n[FAT ERROR] in _fat_read() : file not open\n");
[258]1312        return -1;
1313    }
1314    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1315    {
[295]1316        _printf("\n[FAT ERROR] in _fat_read() : memory buffer not sector aligned\n");
[258]1317        return -1;
1318    }
[358]1319
1320    // compute file size as a number of sectors
1321    file_size    = fat.fd[fd_id].file_size;
1322    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1323    else                     file_sectors = (file_size >> 9); 
1324
[258]1325    if ( offset >= file_sectors )
1326    {
[295]1327        _printf("\n[FAT ERROR] offset larger than number of sectors\n");
[258]1328        return -1;
1329    }
1330
1331    // compute total number of sectors to read
1332    if ( file_sectors < (offset + count) ) total_sectors = file_sectors - offset;
1333    else                                   total_sectors = count;
1334
1335    // compute clusters and sectors to be skipped
1336    clusters_to_skip = offset / spc;
1337    sectors_to_skip  = offset % spc;
1338   
1339    // get first cluster index
1340    cluster = fat.fd[fd_id].first_cluster;
1341
1342#if GIET_DEBUG_FAT
[354]1343unsigned int procid  = _get_procid();
[429]1344unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1345unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1346unsigned int p       = procid & ((1<<P_WIDTH)-1);
[417]1347_printf("\n[FAT DEBUG] _fat_read() : P[%d,%d,%d] enters for file %s\n"
[354]1348        " - buffer vbase    = %x\n"
1349        " - skipped sectors = %x\n"
1350        " - read sectors    = %x\n"
1351        " - first cluster   = %x\n"
[295]1352        " - skiped clusters = %x\n",
[429]1353        x, y, p, fat.fd[fd_id].name, 
[354]1354        (unsigned int)buffer, offset, count, cluster, clusters_to_skip );   
[258]1355#endif
1356
1357    // compute index of first cluster to be loaded
1358    // as we may need to scan the FAT, we use the kernel mode
1359    while ( clusters_to_skip )
1360    {
[417]1361        cluster = _get_next_cluster( IOC_KERNEL_MODE, cluster );
[258]1362        clusters_to_skip--;
1363    }
1364
1365    // variables used in the loop on clusters
1366    int             todo_sectors;   // number of sectors still to be loaded
1367    unsigned int    lba;            // first sector index on device
1368    unsigned int    iter_sectors;   // number of sectors to load in iteration
1369    char*           dst;            // pointer on target buffer
1370
1371    // initialize these variables for the first iteration
1372    todo_sectors  = total_sectors;
1373    dst           = (char*)buffer;
1374    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1375    if( total_sectors < (spc - sectors_to_skip) ) iter_sectors = total_sectors;
1376    else                                          iter_sectors = spc - sectors_to_skip; 
1377
[358]1378    // loop on the clusters: one IOC access per cluster
[258]1379    while ( todo_sectors > 0 )
1380    {
1381
1382#if GIET_DEBUG_FAT
[417]1383_printf("\n[FAT DEBUG] _fat_read() : P[%d,%d,%d] makes an IOC read\n"
1384        " - cluster = %x\n"
1385        " - buf     = %x\n"
1386        " - lba     = %x\n"
1387        " - sectors = %d\n",
[429]1388        x, y, p, cluster, (unsigned int)dst, lba, iter_sectors );
[258]1389#endif
1390
[295]1391        if( _ioc_read( 0,                 // channel
1392                       mode,              // mode for IOC driver
[258]1393                       lba,               // first sector index
1394                       dst,               // buffer address
1395                       iter_sectors ) )   // number of sectors
1396        {
[295]1397            _printf("\n[FAT ERROR] in _fat_read() cannot load block %x\n", lba );
[258]1398            return -1;
1399        }
1400         
1401        // update variables for next iteration
[417]1402        cluster      = _get_next_cluster( mode, cluster );
[258]1403        todo_sectors = todo_sectors - iter_sectors;
1404        dst          = dst + (iter_sectors << 9);
1405        lba          = cluster_to_lba(cluster);
1406        if ( todo_sectors > spc ) iter_sectors = spc;
1407        else                      iter_sectors = todo_sectors;
1408    }
1409         
1410    // returns number of sectors actually transfered
1411    return total_sectors;
1412
1413}  // end _fat_read()
1414
1415///////////////////////////////////////////////////////////////////////////////
1416// For an open file, identified by the file descriptor index, transfer
1417// an integer number of sectors from a memory buffer to block device.
1418// Allocate new clusters if the offset+count larger than current file size,
1419// but the offset should be smaller than the current file size...
1420// - fat    : pointer on FAT
1421// - mode   : mode for the IOC driver
1422// - fd_id  : open file descriptor index 
1423// - buffer : base address of the memory buffer (must be sector aligned)
1424// - offset : number of sectors to skip in file
1425// - count  : number of sectors to be written.
1426///////////////////////////////////////////////////////////////////////////////
1427// Returns number of sectors written if success, < 0 if error.
1428///////////////////////////////////////////////////////////////////////////////
1429int _fat_write( unsigned int mode,       // mode for IOC driver
1430                unsigned int fd_id,      // file descriptor
1431                void*        buffer,     // target buffer base address
1432                unsigned int count,      // number of sector to write
1433                unsigned int offset )    // nuber of sectors to skip in file
1434{
[259]1435
1436    unsigned int spc = fat.sectors_per_cluster;
1437
1438    unsigned int file_size;         // number of bytes in file
1439    unsigned int file_sectors;      // number of sectors in file
1440    unsigned int cluster;           // cluster index
1441    unsigned int clusters_to_skip;  // number of clusters to skip because offset
1442    unsigned int sectors_to_skip;   // number of sectors to skip in first iteration
1443    unsigned int allocate;          // need allocate or not
[291]1444    unsigned int current_cluster;   // number of cluster allocated to the file
1445    unsigned int required_cluster;  // number of cluster needed for the write
[259]1446
1447    // compute file size as a number of sectors
1448    file_size    = fat.fd[fd_id].file_size;
1449    if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1450    else                     file_sectors = (file_size >> 9); 
1451
[291]1452    // Compute the number of clusters occupied by the file
1453    current_cluster = file_sectors / spc;
1454
1455    // Compute the number of clusters that will occupy the file (after fat_write)
1456    required_cluster = (count + offset) / spc;
1457
1458    // Check if we need to allocate new cluster(s) for the file 
1459    allocate = ( required_cluster > current_cluster );
1460
[259]1461#if GIET_DEBUG_FAT
[295]1462unsigned int procid  = _get_procid();
[429]1463unsigned int x       = procid >> (Y_WIDTH + P_WIDTH);
1464unsigned int y       = (procid >> P_WIDTH) & ((1<<Y_WIDTH)-1);
1465unsigned int p       = procid & ((1<<P_WIDTH)-1);
1466
[417]1467_printf("\n[FAT DEBUG] _fat_write() : P[%d,%d,%d] enters for file %s\n",
[295]1468        " - buffer vbase    = %x\n"
1469        " - skipped sectors = %x\n"
1470        " - write sectors   = %x\n" 
1471        " - file sectors    = %x\n" 
1472        " - need allocate   = %d\n", 
[429]1473        x, y, p, fat.fd[fd_id].name, (unsigned int)buffer, 
[295]1474        offset, count, file_sectors, allocate );
[259]1475#endif
1476
1477    // arguments checking
1478    if ( fd_id >= GIET_OPEN_FILES_MAX )
1479    { 
[295]1480        _printf("\n[FAT ERROR] in _fat_write() : illegal file descriptor index\n");
[259]1481        return -1;
1482    }
1483    if ( fat.fd[fd_id].used != 1 )
1484    {
[295]1485        _printf("\n[FAT ERROR] in _fat_write() : file not open\n");
[259]1486        return -1;
1487    }
1488    if ( ((unsigned int)buffer & 0x1FF) != 0 )
1489    {
[295]1490        _printf("\n[FAT ERROR] in _fat_write() : memory buffer not sector aligned\n");
[259]1491        return -1;
1492    }
1493
[291]1494    if ( allocate  )
1495    {
1496        if ( _fat_allocate( fd_id, (required_cluster - current_cluster) ) < 0 )
1497        {
[295]1498            _printf("\n[FAT ERROR] in _fat_write() : fat_allocate failed\n");
[291]1499            return -1;
1500        }
1501    }
1502
[259]1503    // compute clusters and sectors to be skipped
1504    clusters_to_skip = offset / spc;
1505    sectors_to_skip  = offset % spc;
1506   
1507    // get first cluster index
1508    cluster = fat.fd[fd_id].first_cluster;
1509
1510#if GIET_DEBUG_FAT
[295]1511_printf(" - first cluster   = %x\n"
1512        " - skiped clusters = %x\n",
1513        cluster, clusters_to_skip );   
[259]1514#endif
1515
1516    // compute index of first cluster to be loaded
1517    // as we may need to scan the FAT, we use the kernel mode
1518    while ( clusters_to_skip )
1519    {
[417]1520        cluster = _get_next_cluster( IOC_KERNEL_MODE, cluster );
[259]1521        clusters_to_skip--;
1522    }
1523
1524    // variables used in the loop on clusters
1525    int             todo_sectors;   // number of sectors still to be loaded
1526    unsigned int    lba;            // first sector index on device
1527    unsigned int    iter_sectors;   // number of sectors to load in iteration
1528    char*           src;            // pointer on target buffer
1529
1530    // initialize these variables for the first iteration
1531    todo_sectors  = count;
1532    src           = (char*)buffer;
1533    lba           = cluster_to_lba(cluster) + sectors_to_skip;
1534    if( count < (spc - sectors_to_skip) ) iter_sectors = count;
1535    else                                  iter_sectors = spc - sectors_to_skip; 
1536
1537    // loop on the clusters
1538    while ( todo_sectors > 0 )
1539    {
1540
1541#if GIET_DEBUG_FAT
[417]1542_printf("\n[FAT DEBUG] _fat_write() : P[%d,%d,%d] makes an IOC write : "
[295]1543        "buf = %x / lba = %x / sectors = %x\n",
[429]1544        x, y, p, (unsigned int)src, lba, iter_sectors );
[259]1545#endif
1546
[295]1547        if( _ioc_write( 0,                 // channel
1548                        mode,              // mode for IOC driver
[259]1549                        lba,               // first sector index
[295]1550                        src,               // source buffer address
[259]1551                        iter_sectors ) )   // number of sectors
1552        {
[295]1553            _printf("\n[FAT ERROR] in _fat_write() cannot write block %x\n", lba );
[259]1554            return -1;
1555        }
1556         
1557        // update variables for next iteration
[417]1558        cluster      = _get_next_cluster( mode, cluster );
[259]1559        todo_sectors = todo_sectors - iter_sectors;
1560        src          = src + (iter_sectors << 9);
1561        lba          = cluster_to_lba(cluster);
1562        if ( todo_sectors > spc ) iter_sectors = spc;
1563        else                      iter_sectors = todo_sectors;
1564    }
[291]1565
1566    // Update structure file descriptor, field file_size with
1567    // the new file size if the file is bigger than the previous file
1568    if ( ( offset + count ) > file_sectors )
1569    {
1570        fat.fd[fd_id].file_size = (count + offset) << 9;
1571    }
1572
1573    // Update entry of directory with the new value
1574    // of file size (Field : DIR_FILE_SIZE)
1575    if ( update_entry(fd_id, DIR_FILE_SIZE, fat.fd[fd_id].file_size) )
1576    {
[295]1577            _printf("\n[FAT ERROR] in _fat_write() update entry failed\n");
[291]1578            return -1;
1579    }
[259]1580         
1581    // returns number of sectors actually transfered
1582    return count;
[417]1583}  // end _fat_write()
[258]1584
1585/////////////////////////////////////////////////////////////////////////////////
[260]1586// Return stats of a file identified by "fd".
1587// (Only the file_size in sectors for this moment)
1588/////////////////////////////////////////////////////////////////////////////////
1589// Returns file size (on sectors) on success, -1 on failure.
1590/////////////////////////////////////////////////////////////////////////////////
1591int _fat_fstat( unsigned int fd_id )
1592{
1593    unsigned int file_size    = 0;
1594    unsigned int file_sectors = 0;
1595
1596    if( (fd_id < GIET_OPEN_FILES_MAX) )
1597    {
1598        file_size = fat.fd[fd_id].file_size;
1599
1600        if ( file_size & 0x1FF ) file_sectors = (file_size >> 9) + 1;
1601        else                     file_sectors = (file_size >> 9); 
1602
1603        return file_sectors;
1604    }
1605    else
1606    {
[295]1607        _printf("\n[FAT ERROR] in _fat_fstat() : illegal file descriptor index\n");
[260]1608        return -1;
1609    } 
1610} // end _fat_fstat()
1611
1612/////////////////////////////////////////////////////////////////////////////////
[258]1613// Close the file identified by the file_descriptor index.
1614/////////////////////////////////////////////////////////////////////////////////
1615// Returns 0 on success, -1 on failure.
1616/////////////////////////////////////////////////////////////////////////////////
1617int _fat_close( unsigned int fd_id )
1618{
1619    if( (fd_id < GIET_OPEN_FILES_MAX) )
1620    {
1621        fat.fd[fd_id].used = 0;
1622        return 0;
1623    }
1624    else
1625    {
[295]1626        _printf("\n[FAT ERROR] in _fat_close() : illegal file descriptor index\n");
[258]1627        return -1;
1628    } 
1629} // end fat_close()
1630
1631/////////////////////////////////////////////////////////////////////////////////////
1632// The following function implement the user_level system call.
[417]1633// The flags argument is not used, as file access modes are not implemented yet.
[258]1634/////////////////////////////////////////////////////////////////////////////////////
1635// Return the file descriptor index if success / return -1 if failure
1636/////////////////////////////////////////////////////////////////////////////////////
1637int _fat_user_open( char*  pathname,         // absolute pathname from root
1638                    unsigned int flags )     // unused: TODO
1639{
[295]1640    return _fat_open( IOC_KERNEL_MODE,       // we use KERNEL_MODE, because
[258]1641                      pathname,              // we need to write into FAT cache
[295]1642                      0 );                   // no creation if not found
[258]1643}
1644
1645/////////////////////////////////////////////////////////////////////////////////////
1646// The following function implement the user_level system call.
1647// This function should be modified to respect the UNIX specification
1648/////////////////////////////////////////////////////////////////////////////////////
1649// Return number of sectors actually transfered if success / return -1 if failure
1650/////////////////////////////////////////////////////////////////////////////////////
1651int _fat_user_read( unsigned int fd,        // file descriptor index
1652                    void*        buffer,    // destination buffer
1653                    unsigned int count,     // number of sectors to read
1654                    unsigned int offset )   // number of sectors to skip
1655{
1656    return _fat_read( IOC_USER_MODE,
1657                      fd,
1658                      buffer, 
1659                      count, 
1660                      offset );
1661}
1662
1663/////////////////////////////////////////////////////////////////////////////////////
1664// The following function implement the user_level system call.
1665// This function should be modified to respect the UNIX specification.
1666/////////////////////////////////////////////////////////////////////////////////////
1667// Return number of sectors actually transfered if success / return -1 if failure
1668/////////////////////////////////////////////////////////////////////////////////////
1669int _fat_user_write( unsigned int fd,       // file descriptor
1670                     void*        buffer,   // source buffer
1671                     unsigned int count,    // number of sectors to write
1672                     unsigned int offset )  // number of sectors to skip on file
1673{
1674    return _fat_write( IOC_USER_MODE,
1675                       fd,
1676                       buffer, 
1677                       count, 
1678                       offset );
1679}
1680
1681/////////////////////////////////////////////////////////////////////////////////////
1682int _fat_user_lseek( unsigned int fd_id,
1683                     unsigned int offset,
1684                     unsigned int whence )
1685{
[295]1686    _printf("[GIET ERROR] _fat_user_lseek() not implemented\n");
[258]1687    _exit();
1688    return 0;
1689}
1690
1691
1692// Local Variables:
1693// tab-width: 4
1694// c-basic-offset: 4
1695// c-file-offsets:((innamespace . 0)(inline-open . 0))
1696// indent-tabs-mode: nil
1697// End:
1698// vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4
1699
Note: See TracBrowser for help on using the repository browser.