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

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

Align the fat structure (including the fat cache) on 512 bytes.

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