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

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

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

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