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

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

Cosmetic

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