OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [fs/] [fat/] [current/] [src/] [fatfs_supp.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      fatfs_supp.c
4
//
5
//      FAT file system support functions
6
//
7
//==========================================================================
8
// ####ECOSGPLCOPYRIGHTBEGIN####                                            
9
// -------------------------------------------                              
10
// This file is part of eCos, the Embedded Configurable Operating System.   
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):           Savin Zlobec <savin@elatec.si> 
43
// Date:                2003-06-30
44
//
45
//####DESCRIPTIONEND####
46
//
47
//==========================================================================
48
 
49
#include <pkgconf/fs_fat.h>
50
#include <pkgconf/infra.h>
51
 
52
#include <cyg/infra/cyg_type.h>
53
#include <cyg/infra/cyg_ass.h>
54
#include <cyg/infra/cyg_trac.h>
55
#include <cyg/infra/diag.h>
56
#include <cyg/io/io.h>
57
#include <cyg/fs/fatfs.h>
58
#include <blib/blib.h>
59
 
60
#include <sys/types.h>
61
#include <ctype.h>
62
 
63
#include "fatfs.h"
64
 
65
//==========================================================================
66
// FAT defines & macros
67
 
68
// -------------------------------------------------------------------------
69
// FAT dir entry attributes macros
70
 
71
#define DENTRY_IS_RDONLY(_dentry_)  (S_FATFS_ISRDONLY((_dentry_)->attr))
72
#define DENTRY_IS_HIDDEN(_dentry_)  (S_FATFS_ISHIDDEN((_dentry_)->attr))
73
#define DENTRY_IS_SYSTEM(_dentry_)  (S_FATFS_ISSYSTEM((_dentry_)->attr))
74
#define DENTRY_IS_VOLUME(_dentry_)  (S_FATFS_ISVOLUME((_dentry_)->attr))
75
#define DENTRY_IS_DIR(_dentry_)     (S_FATFS_ISDIR((_dentry_)->attr))
76
#define DENTRY_IS_ARCHIVE(_dentry_) (S_FATFS_ISARCHIVE((_dentry_)->attr))
77
 
78
#define DENTRY_IS_DELETED(_dentry_) \
79
    (0xE5 == (cyg_uint8)((_dentry_)->name[0]))
80
 
81
#define DENTRY_IS_ZERO(_dentry_) \
82
    (0x00 == (cyg_uint8)((_dentry_)->name[0]))
83
 
84
// -------------------------------------------------------------------------
85
// FAT disk data access macros
86
 
87
// FIXME: support big endian machines!
88
 
89
#define GET_BYTE(_data_, _var_, _off_) \
90
    (_var_ = *( ((cyg_uint8 *)_data_) + (_off_) ) )
91
 
92
#define GET_WORD(_data_, _var_, _off_)                      \
93
    (_var_ = *( ((cyg_uint8 *)_data_) + (_off_) ) |         \
94
             *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) << 8)
95
 
96
#define GET_DWORD(_data_, _var_, _off_)                         \
97
    (_var_ = *( ((cyg_uint8 *)_data_) + (_off_))             |  \
98
             *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) << 8   |  \
99
             *( ((cyg_uint8 *)_data_) + (_off_) + 2 ) << 16  |  \
100
             *( ((cyg_uint8 *)_data_) + (_off_) + 3 ) << 24)
101
 
102
#define GET_BYTES(_data_, _var_, _size_, _off_) \
103
    memcpy((void *)(_var_), (void*)(((cyg_uint8 *)_data_)+(_off_)),_size_)
104
 
105
#define SET_BYTE(_data_, _val_, _off_) \
106
    (*( ((cyg_uint8 *)_data_) + (_off_) ) = _val_)
107
 
108
#define SET_WORD(_data_, _val_, _off_)                                   \
109
    do {                                                                 \
110
        *( ((cyg_uint8 *)_data_) + (_off_) )     = _val_         & 0xFF; \
111
        *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) = (_val_ >> 8)  & 0xFF; \
112
    } while (0)
113
 
114
#define SET_DWORD(_data_, _val_, _off_)                                  \
115
    do {                                                                 \
116
        *( ((cyg_uint8 *)_data_) + (_off_) )     = _val_         & 0xFF; \
117
        *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) = (_val_ >> 8)  & 0xFF; \
118
        *( ((cyg_uint8 *)_data_) + (_off_) + 2 ) = (_val_ >> 16) & 0xFF; \
119
        *( ((cyg_uint8 *)_data_) + (_off_) + 3 ) = (_val_ >> 24) & 0xFF; \
120
    } while (0)
121
 
122
#define SET_BYTES(_data_, _var_, _size_, _off_) \
123
    memcpy((void *)(((cyg_uint8 *)_data_)+(_off_)), (void *)(_var_), _size_)
124
 
125
// -------------------------------------------------------------------------
126
// FAT table entries types 
127
 
128
#define TENTRY_REGULAR  0 // Used when entry points to next file cluster 
129
#define TENTRY_FREE     1 // Free cluster
130
#define TENTRY_LAST     2 // Last cluster of file 
131
#define TENTRY_RESERVED 3 // Reserved cluster
132
#define TENTRY_BAD      4 // Bad cluster 
133
 
134
// -------------------------------------------------------------------------
135
// FAT table structures size 
136
 
137
#define DENTRY_SIZE 0x20 // Dir entry size
138
 
139
// -------------------------------------------------------------------------
140
// Time & date defines 
141
 
142
#define JD_1_JAN_1970 2440588 // 1 Jan 1970 in Julian day number
143
 
144
// -------------------------------------------------------------------------
145
// Code tracing defines 
146
 
147
#ifdef FATFS_TRACE_DIR_ENTRY
148
# define TDE 1
149
#else
150
# define TDE 0
151
#endif
152
 
153
#ifdef FATFS_TRACE_CLUSTER
154
# define TCL 1
155
#else
156
# define TCL 0
157
#endif
158
 
159
#ifdef FATFS_TRACE_DATA
160
# define TDO 1
161
#else
162
# define TDO 0
163
#endif
164
 
165
//==========================================================================
166
// FAT structures 
167
 
168
// -------------------------------------------------------------------------
169
// FAT table boot record structure 
170
 
171
typedef struct fat_boot_record_s
172
{
173
    cyg_uint16    jump;           // 00h : Jump code
174
//  cyg_uint8     jump0;          //                 + NOP
175
    char          oem_name[8+1];  // 03h : OEM name
176
    cyg_uint16    bytes_per_sec;  // 0Bh : cyg_bytes per sector
177
    cyg_uint8     sec_per_clu;    // 0Dh : Sectors per cluster
178
    cyg_uint16    res_sec_num;    // 0Eh : Number of reserved sectors
179
    cyg_uint8     fat_tbls_num;   // 10h : Number of copies of fat
180
    cyg_uint16    max_root_dents; // 11h : Maximum number of root dir entries
181
    cyg_uint16    sec_num_32;     // 13h : Number of sectors in partition < 32MB
182
    cyg_uint8     media_desc;     // 15h : Media descriptor
183
    cyg_uint16    sec_per_fat;    // 16h : Sectors per FAT
184
    cyg_uint16    sec_per_track;  // 18h : Sectors per track
185
    cyg_uint16    heads_num;      // 1Ah : Number of heads
186
    cyg_uint32    hsec_num;       // 1Ch : Number of hidden sectors
187
    cyg_uint32    sec_num;        // 20h : Number of sectors in partition
188
    cyg_uint8     exe_marker[2];  // 1FEh: Executable marker (55h AAh)
189
 
190
// FAT32 specific fields
191
 
192
    cyg_uint32    sec_per_fat_32; // 24h : Sectors per FAT
193
    cyg_uint16    ext_flags;      // 28h : Flags
194
    cyg_uint16    fs_ver;         // 2Ah : FS version
195
    cyg_uint32    root_cluster;   // 2Ch : Root dir cluster
196
    cyg_uint16    fs_info_sec;    // 30h : Sector number of FSINFO structure
197
    cyg_uint16    bk_boot_sec;    // 32h : Sector number of backup boot record
198
//  cyg_uint8     reserved[12];   // 34h : Reserved
199
 
200
// Fields with different locations on FAT12/16 and FAT32 
201
 
202
    cyg_uint8     drv_num;        // 24h (40h) : Drive number of partition 
203
//  cyg_uint8     reserved1;      // 25h (41h) : Reserved 1
204
    cyg_uint8     ext_sig;        // 26h (42h) : Extended signature
205
    cyg_uint32    ser_num;        // 27h (43h) : Serial number of partition
206
    char          vol_name[11+1]; // 2Bh (47h) : Volume name of partition
207
    char          fat_name[8+1];  // 36h (52h) : FAT name
208
 
209
} fat_boot_record_t;
210
 
211
// -------------------------------------------------------------------------
212
// FAT dir entry structure 
213
 
214
typedef struct fat_raw_dir_entry_s
215
{
216
    char       name[8+1];   // 00h : Name
217
    char       ext[3+1];    // 08h : Extension
218
    cyg_uint8  attr;        // 0Bh : Attribute
219
    cyg_uint8  nt_reserved; // 0Ch : Win NT Reserved field
220
    cyg_uint8  crt_sec_100; // 0Dh : Creation time ms stamp 0 - 199
221
    cyg_uint16 crt_time;    // 0Eh : Creation time
222
    cyg_uint16 crt_date;    // 10h : Creation date
223
    cyg_uint16 acc_date;    // 12h : Last access date
224
    cyg_uint16 cluster_HI;  // 14h : Starting cluster HI WORD (FAT32)
225
    cyg_uint16 wrt_time;    // 16h : Time    
226
    cyg_uint16 wrt_date;    // 18h : Date
227
    cyg_uint16 cluster;     // 1Ah : Starting cluster 
228
    cyg_uint32 size;        // 1Ch : Size of the file    
229
} fat_raw_dir_entry_t;
230
 
231
// -------------------------------------------------------------------------
232
// FAT cluster opts 
233
 
234
typedef enum cluster_opts_e
235
{
236
    CO_NONE       = 0x00, // NULL option
237
    CO_EXTEND     = 0x01, // Extend cluster chain if one cluster too short
238
    CO_ERASE_NEW  = 0x02, // Erase newly allocated cluster
239
    CO_MARK_LAST  = 0x04  // Mark  newly allocated cluster as last
240
} cluster_opts_t;
241
 
242
//==========================================================================
243
// Utility functions 
244
 
245
// -------------------------------------------------------------------------
246
// get_val_log2()
247
// Gets the log2 of given value or returns 0 if value is not a power of 2. 
248
 
249
static cyg_uint32
250
get_val_log2(cyg_uint32 val)
251
{
252
    cyg_uint32 i, log2;
253
 
254
    i    = val;
255
    log2 = 0;
256
 
257
    while (0 == (i & 1))
258
    {
259
        i >>= 1;
260
        log2++;
261
    }
262
 
263
    if (i != 1) return 0;
264
    else        return log2;
265
}
266
 
267
// -------------------------------------------------------------------------
268
// cluster_to_block_pos()
269
// Converts cluster position to blib block position.
270
 
271
static void
272
cluster_to_block_pos(fatfs_disk_t *disk,
273
                     cyg_uint32    cluster,
274
                     cyg_uint32    cluster_pos,
275
                     cyg_uint32   *block,
276
                     cyg_uint32   *block_pos)
277
{
278
    cyg_uint32 block_size      = cyg_blib_get_block_size(&disk->blib);
279
    cyg_uint32 block_size_log2 = cyg_blib_get_block_size_log2(&disk->blib);
280
 
281
    *block = (cluster - 2) << (disk->cluster_size_log2 - block_size_log2);
282
 
283
    *block_pos = disk->fat_data_pos + cluster_pos;
284
 
285
    if (*block_pos > block_size)
286
    {
287
        *block     += *block_pos >> block_size_log2;
288
        *block_pos  = *block_pos & (block_size - 1);
289
    }
290
}
291
 
292
// -------------------------------------------------------------------------
293
// disk_write()
294
// Writes data to disk.
295
 
296
static __inline__ int
297
disk_write(fatfs_disk_t *disk,
298
           void         *buf,
299
           cyg_uint32   *len,
300
           cyg_uint32    pos)
301
{
302
    return cyg_blib_write(&disk->blib, buf, len, 0, pos);
303
}
304
 
305
// -------------------------------------------------------------------------
306
// disk_read()
307
// Reads data from disk.
308
 
309
static __inline__ int
310
disk_read(fatfs_disk_t *disk,
311
          void         *buf,
312
          cyg_uint32   *len,
313
          cyg_uint32    pos)
314
{
315
    return cyg_blib_read(&disk->blib, buf, len, 0, pos);
316
}
317
 
318
// -------------------------------------------------------------------------
319
// disk_cluster_write()
320
// Writes data to disk at specified cluster position.
321
 
322
static __inline__ int
323
disk_cluster_write(fatfs_disk_t *disk,
324
                   void         *buf,
325
                   cyg_uint32   *len,
326
                   cyg_uint32    cluster,
327
                   cyg_uint32    cluster_pos)
328
{
329
    cyg_uint32 block, block_pos;
330
 
331
    cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
332
 
333
    return cyg_blib_write(&disk->blib, buf, len, block, block_pos);
334
}
335
 
336
// -------------------------------------------------------------------------
337
// disk_cluster_read()
338
// Reads data from disk at specified cluster position.
339
 
340
static __inline__ int
341
disk_cluster_read(fatfs_disk_t *disk,
342
                  void         *buf,
343
                  cyg_uint32   *len,
344
                  cyg_uint32    cluster,
345
                  cyg_uint32    cluster_pos)
346
{
347
    cyg_uint32 block, block_pos;
348
 
349
    cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
350
 
351
    return cyg_blib_read(&disk->blib, buf, len, block, block_pos);
352
}
353
 
354
// -------------------------------------------------------------------------
355
// jdays_to_gdate()
356
// Converts juilan days into gregorian date.
357
 
358
static void
359
jdays_to_gdate(cyg_uint32 jd, int *day, int *month, int *year)
360
{
361
    cyg_uint32 l, n, i, j;
362
 
363
    l = jd + 68569;
364
    n = (4 * l) / 146097;
365
    l = l - (146097 * n + 3) / 4;
366
    i = (4000 * (l + 1)) / 1461001;
367
    l = l - (1461 * i) / 4 + 31;
368
    j = (80 * l) / 2447;
369
    *day = l - (2447 * j) / 80;
370
 
371
    l = j / 11;
372
    *month = j + 2 - (12 * l);
373
    *year = 100 * (n - 49) + i + l;
374
}
375
 
376
// -------------------------------------------------------------------------
377
// gdate_to_jdays()
378
// Converts gregorian date to juilan days.
379
 
380
static void
381
gdate_to_jdays(int day, int month, int year, cyg_uint32 *jd)
382
{
383
    *jd = day - 32075 + 1461*(year + 4800 + (month - 14)/12)/4 +
384
          367*(month - 2 - (month - 14)/12*12)/12 -
385
          3*((year + 4900 + (month - 14)/12)/100)/4;
386
}
387
 
388
// -------------------------------------------------------------------------
389
// date_unix2dos()
390
// Converts unix timestamp to dos time and date. 
391
 
392
static void
393
date_unix2dos(time_t  unix_timestamp,
394
              cyg_uint16 *dos_time,
395
              cyg_uint16 *dos_date)
396
{
397
    cyg_uint32 jd;
398
    cyg_uint16 dtime, ddate;
399
    int        hour, min, sec;
400
    int        day, month, year;
401
 
402
    hour = (unix_timestamp / 3600) % 24;
403
    min  = (unix_timestamp / 60) % 60;
404
    sec  =  unix_timestamp % 60;
405
 
406
    jd = JD_1_JAN_1970 + unix_timestamp / (3600 * 24);
407
    jdays_to_gdate(jd, &day, &month, &year);
408
 
409
    CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
410
               unix_timestamp, hour, min, sec, year, month, day);
411
 
412
    if (year < 1980)
413
        year = 1980;
414
 
415
    dtime = (hour << 11) | (min << 5) | (sec >> 1);
416
    ddate = ((year - 1980) << 9) | (month << 5) | day;
417
 
418
    CYG_TRACE2(TDE, "dos time=%d date=%d", dtime, ddate);
419
 
420
    if (NULL != dos_time) *dos_time = dtime;
421
    if (NULL != dos_date) *dos_date = ddate;
422
}
423
 
424
// -------------------------------------------------------------------------
425
// date_dos2unix()
426
// Converts dos time and date to unix timestamp. 
427
 
428
static void
429
date_dos2unix(cyg_uint16  dos_time,
430
              cyg_uint16  dos_date,
431
              time_t *unix_timestamp)
432
{
433
    cyg_uint32 ts;
434
    int        hour, min, sec;
435
    int        day, month, year;
436
 
437
    sec        = (dos_time & ((1<<5)-1)) * 2;
438
    dos_time >>= 5;
439
    min        = (dos_time & ((1<<6)-1));
440
    dos_time >>= 6;
441
    hour       = dos_time;
442
 
443
    day        = (dos_date & ((1<<5)-1));
444
    dos_date >>= 5;
445
    month      = (dos_date & ((1<<4)-1));
446
    dos_date >>= 4;
447
    year       = dos_date + 1980;
448
 
449
    gdate_to_jdays(day, month, year, &ts);
450
 
451
    ts -= JD_1_JAN_1970;
452
    ts  = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600);
453
 
454
    *unix_timestamp = ts;
455
 
456
    CYG_TRACE2(TDE, "dos time=%d date=%d", dos_time, dos_date);
457
    CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
458
                    ts, hour, min, sec, year, month, day);
459
}
460
 
461
//==========================================================================
462
// FAT boot record functions 
463
 
464
#if TDE 
465
 
466
// -------------------------------------------------------------------------
467
// print_boot_record()
468
// Prints FAT boot record.
469
 
470
static void
471
print_boot_record(fat_boot_record_t* fbr)
472
{
473
    diag_printf("FAT: FBR jump code:       0x%02X\n", fbr->jump);
474
    diag_printf("FAT: FBR oem name:       '%.8s'\n",  fbr->oem_name);
475
    diag_printf("FAT: FBR bytes per sec:   %u\n",     fbr->bytes_per_sec);
476
    diag_printf("FAT: FBR sec per cluster: %u\n",     fbr->sec_per_clu);
477
    diag_printf("FAT: FBR reserved sec:    %u\n",     fbr->res_sec_num);
478
    diag_printf("FAT: FBR fat tbls num:    %u\n",     fbr->fat_tbls_num);
479
    diag_printf("FAT: FBR max root dents:  %u\n",     fbr->max_root_dents);
480
    diag_printf("FAT: FBR sec num (32):    %u\n",     fbr->sec_num_32);
481
    diag_printf("FAT: FBR media desc:      0x%02X\n", fbr->media_desc);
482
    diag_printf("FAT: FBR sec per fat:     %u\n",     fbr->sec_per_fat);
483
    diag_printf("FAT: FBR sec per track:   %u\n",     fbr->sec_per_track);
484
    diag_printf("FAT: FBR heads num:       %u\n",     fbr->heads_num);
485
    diag_printf("FAT: FBR hidden sec num:  %u\n",     fbr->hsec_num);
486
    diag_printf("FAT: FBR sec num:         %u\n",     fbr->sec_num);
487
 
488
    if (0 == fbr->sec_per_fat)
489
    {
490
        diag_printf("FAT: FBR sec per fat32:   %u\n",     fbr->sec_per_fat_32);
491
        diag_printf("FAT: FBR ext flags:       0x%04X\n", fbr->ext_flags);
492
        diag_printf("FAT: FBR fs ver:          %u\n",     fbr->fs_ver);
493
        diag_printf("FAT: FBR root cluster:    %u\n",     fbr->root_cluster);
494
        diag_printf("FAT: FBR fs info sec:     %u\n",     fbr->fs_info_sec);
495
    }
496
 
497
    diag_printf("FAT: FBR drv num:         %u\n",     fbr->drv_num);
498
    diag_printf("FAT: FBR ext sig:         0x%02X\n", fbr->ext_sig);
499
    diag_printf("FAT: FBR ser num:         0x%08X\n", fbr->ser_num);
500
    diag_printf("FAT: FBR vol name:       '%.11s'\n", fbr->vol_name);
501
    diag_printf("FAT: FBR fat name:       '%.8s'\n",  fbr->fat_name);
502
    diag_printf("FAT: FBR exe mark:        0x%02X 0x%02X\n",
503
                fbr->exe_marker[0], fbr->exe_marker[1]);
504
}
505
 
506
#endif // TDE
507
 
508
// -------------------------------------------------------------------------
509
// read_boot_record()
510
// Reads FAT boot record from disk.
511
 
512
static int
513
read_boot_record(fatfs_disk_t *disk, fat_boot_record_t *fbr)
514
{
515
    cyg_uint8 data[0x5A];
516
    cyg_uint32 len;
517
    int err;
518
 
519
    len = 0x5A;
520
    err = disk_read(disk, (void*)data, &len, 0);
521
    if (err != ENOERR)
522
        return err;
523
 
524
    GET_WORD(data,  fbr->jump,           0x00);
525
    GET_BYTES(data, fbr->oem_name, 8,    0x03);
526
    GET_WORD(data,  fbr->bytes_per_sec,  0x0B);
527
    GET_BYTE(data,  fbr->sec_per_clu,    0x0D);
528
    GET_WORD(data,  fbr->res_sec_num,    0x0E);
529
    GET_BYTE(data,  fbr->fat_tbls_num,   0x10);
530
    GET_WORD(data,  fbr->max_root_dents, 0x11);
531
    GET_WORD(data,  fbr->sec_num_32,     0x13);
532
    GET_BYTE(data,  fbr->media_desc,     0x15);
533
    GET_WORD(data,  fbr->sec_per_fat,    0x16);
534
    GET_WORD(data,  fbr->sec_per_track,  0x18);
535
    GET_WORD(data,  fbr->heads_num,      0x1A);
536
    GET_DWORD(data, fbr->hsec_num,       0x1C);
537
    GET_DWORD(data, fbr->sec_num,        0x20);
538
 
539
    // This is a quick check for FAT12/16 or FAT32 boot record.
540
    // The sec_per_fat field must be 0 on FAT32, since this
541
    // field plays a crucial role in detection of the FAT type 
542
    // (12,16,32) it is quite safe to make this assumption.
543
    if (0 == fbr->sec_per_fat)
544
    {
545
        GET_DWORD(data, fbr->sec_per_fat_32, 0x24);
546
        GET_WORD(data,  fbr->ext_flags,      0x28);
547
        GET_WORD(data,  fbr->fs_ver,         0x2A);
548
        GET_DWORD(data, fbr->root_cluster,   0x2C);
549
        GET_WORD(data,  fbr->fs_info_sec,    0x30);
550
        GET_WORD(data,  fbr->bk_boot_sec,    0x32);
551
        GET_BYTE(data,  fbr->drv_num,        0x40);
552
        GET_BYTE(data,  fbr->ext_sig,        0x42);
553
        GET_DWORD(data, fbr->ser_num,        0x43);
554
        GET_BYTES(data, fbr->vol_name, 11,   0x47);
555
        GET_BYTES(data, fbr->fat_name, 8,    0x52);
556
    }
557
    else
558
    {
559
        GET_BYTE(data,  fbr->drv_num,        0x24);
560
        GET_BYTE(data,  fbr->ext_sig,        0x26);
561
        GET_DWORD(data, fbr->ser_num,        0x27);
562
        GET_BYTES(data, fbr->vol_name, 11,   0x2B);
563
        GET_BYTES(data, fbr->fat_name, 8,    0x36);
564
    }
565
 
566
    // Read the end marker
567
    len = 0x02;
568
    err = disk_read(disk, (void*)data, &len, 0x1FE);
569
    if (err != ENOERR)
570
        return err;
571
 
572
    GET_BYTES(data, fbr->exe_marker, 2,  0);
573
 
574
    // Zero terminate strings
575
    fbr->oem_name[8]  = '\0';
576
    fbr->vol_name[11] = '\0';
577
    fbr->fat_name[8]  = '\0';
578
 
579
#if TDE 
580
    print_boot_record(fbr);
581
#endif
582
 
583
    return ENOERR;
584
}
585
 
586
//==========================================================================
587
// FAT table entry functions 
588
 
589
// -------------------------------------------------------------------------
590
// read_tentry()
591
// Reads FAT table entry from disk.
592
 
593
static int
594
read_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
595
{
596
    cyg_uint8  data[4];
597
    cyg_uint32 pos, num3;
598
    cyg_uint32 e;
599
    cyg_uint32 len;
600
    int err;
601
 
602
    switch (disk->fat_type)
603
    {
604
        case FATFS_FAT12:
605
            num3 = num * 3;
606
            pos  = disk->fat_tbl_pos + (num3 >> 1);
607
            len  = 2;
608
 
609
            err = disk_read(disk, (void*)data, &len, pos);
610
            if (err != ENOERR)
611
                return err;
612
 
613
            GET_WORD(data, e, 0x00);
614
 
615
            if (0 == (num3 & 1)) *entry = e        & 0x0FFF;
616
            else                 *entry = (e >> 4) & 0x0FFF;
617
 
618
            break;
619
 
620
        case FATFS_FAT16:
621
            pos = disk->fat_tbl_pos + (num << 1);
622
            len = 2;
623
 
624
            err = disk_read(disk, (void*)data, &len, pos);
625
            if (err != ENOERR)
626
                return err;
627
 
628
            GET_WORD(data, e, 0x00);
629
            *entry = e;
630
 
631
            break;
632
 
633
        case FATFS_FAT32:
634
            pos = disk->fat_tbl_pos + (num << 2);
635
            len = 4;
636
 
637
            err = disk_read(disk, (void*)data, &len, pos);
638
            if (err != ENOERR)
639
                return err;
640
 
641
            GET_DWORD(data, e, 0x00);
642
            *entry = e & 0x0FFFFFFF;
643
 
644
            break;
645
 
646
        default:
647
            CYG_ASSERT(false, "Unknown FAT type");
648
    }
649
    return ENOERR;
650
}
651
 
652
// -------------------------------------------------------------------------
653
// write_tentry()
654
// Writes FAT table entry to disk (to all copies of FAT).
655
 
656
static int
657
write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
658
{
659
    cyg_uint8  data[4];
660
    cyg_uint32 pos=0, num3;
661
    cyg_uint32 e;
662
    cyg_uint32 len;
663
    int i;
664
    int err;
665
 
666
    switch (disk->fat_type)
667
    {
668
        case FATFS_FAT12:
669
            num3 = num * 3;
670
            pos  = disk->fat_tbl_pos + (num3 >> 1);
671
            len  = 2;
672
 
673
            err = disk_read(disk, (void*)data, &len, pos);
674
            if (err != ENOERR)
675
                return err;
676
 
677
            GET_WORD(data, e, 0x00);
678
 
679
            if (0 == (num3 & 1)) e = (e & 0xF000) | (*entry & 0x0FFF);
680
            else                 e = (e & 0x000F) | ((*entry & 0x0FFF) << 4);
681
 
682
            SET_WORD(data, e, 0x00);
683
 
684
            break;
685
 
686
        case FATFS_FAT16:
687
            pos = disk->fat_tbl_pos + (num << 1);
688
            len = 2;
689
 
690
            e = *entry;
691
            SET_WORD(data, e, 0x00);
692
 
693
            break;
694
 
695
        case FATFS_FAT32:
696
            pos = disk->fat_tbl_pos + (num << 2);
697
            len = 4;
698
 
699
            err = disk_read(disk, (void*)data, &len, pos);
700
            if (err != ENOERR)
701
                return err;
702
 
703
            GET_DWORD(data, e, 0x00);
704
 
705
            e = (e & 0xF0000000) | *entry;
706
 
707
            SET_DWORD(data, e, 0x00);
708
 
709
            break;
710
 
711
        default:
712
            CYG_ASSERT(false, "Unknown FAT type");
713
    }
714
 
715
    for (i = 0; i < disk->fat_tbls_num; i++)
716
    {
717
        err = disk_write(disk, (void*)data, &len, pos);
718
        if (err != ENOERR)
719
            return err;
720
 
721
        pos += disk->fat_tbl_size;
722
    }
723
 
724
    return ENOERR;
725
}
726
 
727
// -------------------------------------------------------------------------
728
// get_tentry_type()
729
// Gets the type of FAT table entry.
730
 
731
static int
732
get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry)
733
{
734
    int type;
735
 
736
    switch (disk->fat_type)
737
    {
738
        case FATFS_FAT12:
739
            if (entry < 0x0FF0)
740
            {
741
                if (0x0000 == entry)  type = TENTRY_FREE;
742
                else                  type = TENTRY_REGULAR;
743
            }
744
            else if (entry >= 0x0FF8) type = TENTRY_LAST;
745
            else if (0x0FF7 == entry) type = TENTRY_BAD;
746
            else                      type = TENTRY_RESERVED;
747
 
748
            break;
749
 
750
        case FATFS_FAT16:
751
            if (entry < 0xFFF0)
752
            {
753
                if (0x0000 == entry)  type = TENTRY_FREE;
754
                else                  type = TENTRY_REGULAR;
755
            }
756
            else if (entry >= 0xFFF8) type = TENTRY_LAST;
757
            else if (0xFFF7 == entry) type = TENTRY_BAD;
758
            else                      type = TENTRY_RESERVED;
759
 
760
            break;
761
 
762
        case FATFS_FAT32:
763
 
764
            if (entry < 0x0FFFFFF0)
765
            {
766
                if (0x00000000 == entry)  type = TENTRY_FREE;
767
                else                      type = TENTRY_REGULAR;
768
            }
769
            else if (entry >= 0x0FFFFFF8) type = TENTRY_LAST;
770
            else if (0x0FFFFFF7 == entry) type = TENTRY_BAD;
771
            else                          type = TENTRY_RESERVED;
772
 
773
            break;
774
 
775
        default:
776
            CYG_ASSERT(false, "Unknown FAT type");
777
            type = TENTRY_BAD; // least likely to cause damage
778
    }
779
    return type;
780
}
781
 
782
// -------------------------------------------------------------------------
783
// set_tentry_type()
784
// Sets the type of FAT table entry.
785
 
786
static void
787
set_tentry_type(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
788
{
789
    switch (disk->fat_type)
790
    {
791
        case FATFS_FAT12:
792
            switch (type)
793
            {
794
                case TENTRY_FREE:     *entry = 0x0000; return;
795
                case TENTRY_LAST:     *entry = 0x0FF8; return;
796
                case TENTRY_RESERVED: *entry = 0x0FF0; return;
797
                case TENTRY_BAD:      *entry = 0x0FF7; return;
798
                default:
799
                    CYG_ASSERT(false, "Unknown tentry type");
800
            }
801
            break;
802
 
803
        case FATFS_FAT16:
804
            switch (type)
805
            {
806
                case TENTRY_FREE:     *entry = 0x0000; return;
807
                case TENTRY_LAST:     *entry = 0xFFF8; return;
808
                case TENTRY_RESERVED: *entry = 0xFFF0; return;
809
                case TENTRY_BAD:      *entry = 0xFFF7; return;
810
                default:
811
                    CYG_ASSERT(false, "Unknown tentry type");
812
            }
813
            break;
814
 
815
        case FATFS_FAT32:
816
            switch (type)
817
            {
818
                case TENTRY_FREE:     *entry = 0x00000000; return;
819
                case TENTRY_LAST:     *entry = 0x0FFFFFF8; return;
820
                case TENTRY_RESERVED: *entry = 0x0FFFFFF0; return;
821
                case TENTRY_BAD:      *entry = 0x0FFFFFF7; return;
822
                default:
823
                    CYG_ASSERT(false, "Unknown tentry type");
824
            }
825
            break;
826
 
827
        default:
828
            CYG_ASSERT(false, "Unknown FAT type");
829
    }
830
}
831
 
832
// -------------------------------------------------------------------------
833
// get_tentry_next_cluster()
834
// Gets the the next file cluster number from FAT table entry.
835
 
836
static __inline__ cyg_uint32
837
get_tentry_next_cluster(fatfs_disk_t *disk, cyg_uint32 entry)
838
{
839
    return entry;
840
}
841
 
842
// -------------------------------------------------------------------------
843
// set_tentry_next_cluster()
844
// Sets the the next cluster number to FAT table entry.
845
 
846
static __inline__ void
847
set_tentry_next_cluster(fatfs_disk_t *disk,
848
                        cyg_uint32   *entry,
849
                        cyg_uint32    next_cluster)
850
{
851
    *entry = next_cluster;
852
}
853
 
854
//==========================================================================
855
// FAT cluster functions 
856
 
857
// -------------------------------------------------------------------------
858
// erase_cluster()
859
// Erases cluster (fills with 0x00).
860
 
861
static int
862
erase_cluster(fatfs_disk_t *disk, cyg_uint32 cluster)
863
{
864
    cyg_uint8  data[32];
865
    cyg_uint32 pos;
866
    cyg_uint32 len;
867
    int err, i;
868
 
869
    pos = 0;
870
    len = 32;
871
    memset((void*)data, 0x00, len);
872
 
873
    CYG_TRACE1(TCL, "erasing cluster=%d", cluster);
874
 
875
    for (i = 0; i < (disk->cluster_size >> 5); i++)
876
    {
877
        err = disk_cluster_write(disk, (void*)data, &len, cluster, pos);
878
        if (err != ENOERR)
879
            return err;
880
 
881
        pos += len;
882
    }
883
 
884
    return ENOERR;
885
}
886
 
887
// -------------------------------------------------------------------------
888
// mark_cluster()
889
// Marks cluster (sets the cluster's FAT table entry to given type). 
890
 
891
static int
892
mark_cluster(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 type)
893
{
894
    cyg_uint32 tentry;
895
 
896
    set_tentry_type(disk, &tentry, type);
897
    return write_tentry(disk, cluster, &tentry);
898
}
899
 
900
// -------------------------------------------------------------------------
901
// link_cluster()
902
// Links two clusters.
903
 
904
static int
905
link_cluster(fatfs_disk_t *disk, cyg_uint32 cluster1, cyg_uint32 cluster2)
906
{
907
    cyg_uint32 tentry;
908
 
909
    set_tentry_next_cluster(disk, &tentry, cluster2);
910
    return write_tentry(disk, cluster1, &tentry);
911
}
912
 
913
// -------------------------------------------------------------------------
914
// find_next_free_cluster()
915
// Finds first free cluster starting from given cluster.
916
// If none is available free_cluster is set to 0.
917
// If CO_MARK_LAST is set in opts the found cluster is marked as LAST.
918
// If CO_ERASE_NEW is set in opts the found cluster is erased.
919
 
920
static int
921
find_next_free_cluster(fatfs_disk_t   *disk,
922
                       cyg_uint32      start_cluster,
923
                       cyg_uint32     *free_cluster,
924
                       cluster_opts_t  opts)
925
{
926
    cyg_uint32 c, tentry;
927
    int        err;
928
 
929
    if (start_cluster < 2) c = 2;
930
    else                   c = start_cluster + 1;
931
 
932
    *free_cluster = 0;
933
 
934
    CYG_TRACE1(TCL, "starting at cluster=%d", c);
935
 
936
    // Search from the starting cluster to the end of FAT and
937
    // from start of FAT to the starting cluster
938
    while (c != start_cluster)
939
    {
940
        // Check for end of FAT
941
        if (c >= disk->fat_tbl_nents)
942
        {
943
            c = 2;
944
            if (c >= start_cluster)
945
                break;
946
        }
947
 
948
        err = read_tentry(disk, c, &tentry);
949
        if (err != ENOERR)
950
            return err;
951
 
952
        if (TENTRY_FREE == get_tentry_type(disk, tentry))
953
        {
954
            CYG_TRACE1(TCL, "found free cluster=%d", c);
955
 
956
            *free_cluster = c;
957
 
958
            if (opts & CO_MARK_LAST)
959
                err = mark_cluster(disk, c, TENTRY_LAST);
960
            if ((err == ENOERR) && (opts & CO_ERASE_NEW))
961
                err = erase_cluster(disk, c);
962
 
963
            return err;
964
        }
965
        c++;
966
    }
967
 
968
    // No free clusters found
969
 
970
    CYG_TRACE0(TCL, "!!! no free clusters found");
971
 
972
    return ENOSPC;
973
}
974
 
975
// -------------------------------------------------------------------------
976
// find_and_append_cluster()
977
// Finds a free cluster on disk and appends it to the given cluster. 
978
// New cluster is marked as LAST. 
979
 
980
static int
981
find_and_append_cluster(fatfs_disk_t   *disk,
982
                        cyg_uint32      cluster,
983
                        cyg_uint32     *new_cluster,
984
                        cluster_opts_t  opts)
985
{
986
    cyg_uint32 free_cluster;
987
    int        err;
988
 
989
    err = find_next_free_cluster(disk, cluster,
990
        &free_cluster, opts | CO_MARK_LAST);
991
    if (err != ENOERR)
992
        return err;
993
 
994
    err = link_cluster(disk, cluster, free_cluster);
995
    if (err != ENOERR)
996
        return err;
997
 
998
    *new_cluster = free_cluster;
999
 
1000
    CYG_TRACE2(TCL, "appending new cluster=%d to cluster=%d",
1001
                    free_cluster, cluster);
1002
 
1003
    return ENOERR;
1004
}
1005
 
1006
// -------------------------------------------------------------------------
1007
// find_nth_cluster0()
1008
// Finds nth cluster in chain (ie nth cluster of file) searching
1009
// from given position. The result is returned by the same position
1010
// variable. 
1011
 
1012
static int
1013
find_nth_cluster0(fatfs_disk_t     *disk,
1014
                  fatfs_data_pos_t *pos,
1015
                  cyg_uint32        n)
1016
{
1017
    cyg_uint32 cluster, cluster_snum;
1018
    int        err = ENOERR;
1019
 
1020
    if (pos->cluster_snum == n)
1021
        return ENOERR;
1022
 
1023
    cluster      = pos->cluster;
1024
    cluster_snum = pos->cluster_snum;
1025
 
1026
    CYG_TRACE4(TCL, "cluster=%d snum=%d n=%d n_to_search=%d",
1027
                    cluster, cluster_snum, n, n-cluster_snum);
1028
 
1029
    // Adjust the number of clusters that should be
1030
    // walked according to the given position
1031
    n -= cluster_snum;
1032
 
1033
    // Walk the cluster chain for n clusters or until last cluster
1034
    while (n > 0)
1035
    {
1036
        cyg_uint32 tentry;
1037
 
1038
        err = read_tentry(disk, cluster, &tentry);
1039
        if (err != ENOERR)
1040
            return err;
1041
 
1042
        switch (get_tentry_type(disk, tentry))
1043
        {
1044
            case TENTRY_REGULAR:
1045
                break;
1046
            case TENTRY_LAST:
1047
                CYG_TRACE1(TCL, "chain end at n=%d", n);
1048
                err = EEOF; // File has less clusters than given n
1049
                            // this err should be caught by the 
1050
                            // calling function 
1051
                goto out;
1052
            default:
1053
                // Inconsistant FAT table state !!!
1054
                CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x n=%d",
1055
                                tentry, n);
1056
                err = EIO;
1057
                goto out;
1058
        }
1059
        cluster = get_tentry_next_cluster(disk, tentry);
1060
        cluster_snum++;
1061
        n--;
1062
    }
1063
 
1064
out:
1065
    pos->cluster      = cluster;
1066
    pos->cluster_snum = cluster_snum;
1067
 
1068
    CYG_TRACE2(TCL, "nth cluster=%d snum=%d", cluster, cluster_snum);
1069
 
1070
    return err;
1071
}
1072
 
1073
// -------------------------------------------------------------------------
1074
// find_nth_cluster()
1075
// Finds nth cluster in chain (ie nth cluster of file) searching 
1076
// from given position. The result is returned by the same position
1077
// variable. If the chain ends one cluster before the given nth cluster 
1078
// and the CO_EXTEND is specified, than the chain is extended by one cluster.
1079
 
1080
static int
1081
find_nth_cluster(fatfs_disk_t     *disk,
1082
                 fatfs_data_pos_t *pos,
1083
                 cyg_uint32        n,
1084
                 cluster_opts_t    opts)
1085
{
1086
    int err;
1087
 
1088
    // Find nth cluster 
1089
    err = find_nth_cluster0(disk, pos, n);
1090
 
1091
    // EEOF meens that the cluster chain ended early
1092
    if ((err != EEOF) || !(opts & CO_EXTEND))
1093
        return err;
1094
 
1095
    // Check if one cluster short
1096
    if (pos->cluster_snum == (n - 1))
1097
    {
1098
        // Extend the chain for one cluster
1099
        cyg_uint32 new_cluster;
1100
 
1101
        // Append new cluster to the end of chain
1102
        err = find_and_append_cluster(disk, pos->cluster, &new_cluster, opts);
1103
        if (err != ENOERR)
1104
            return err;
1105
 
1106
        // Update position
1107
        pos->cluster       = new_cluster;
1108
        pos->cluster_snum += 1;
1109
        pos->cluster_pos   = 0;
1110
 
1111
        CYG_TRACE1(TCL, "appended new cluster=%d", new_cluster);
1112
    }
1113
 
1114
    return err;
1115
}
1116
 
1117
// -------------------------------------------------------------------------
1118
// get_next_cluster()
1119
// Gets next cluster in chain (ie next cluster of file).
1120
// If CO_EXTEND is specified and the current cluster is last in the 
1121
// chain then the chain is extended by one cluster.
1122
 
1123
static int
1124
get_next_cluster(fatfs_disk_t     *disk,
1125
                 fatfs_data_pos_t *pos,
1126
                 cluster_opts_t    opts)
1127
{
1128
    int err;
1129
 
1130
    err = find_nth_cluster(disk, pos, pos->cluster_snum + 1, opts);
1131
    if (err != ENOERR)
1132
        return err;
1133
 
1134
    // Reset inside cluster position
1135
    pos->cluster_pos = 0;
1136
 
1137
    return ENOERR;
1138
}
1139
 
1140
// -------------------------------------------------------------------------
1141
// get_position_from_off()
1142
// Gets position from given offset. The search is started from the
1143
// given position and the result is returned by the same variable. 
1144
// If CO_EXTEND is specified the file is extended if one cluster too short.
1145
 
1146
static int
1147
get_position_from_off(fatfs_disk_t     *disk,
1148
                      cyg_uint32        first_cluster,
1149
                      cyg_uint32        offset,
1150
                      fatfs_data_pos_t *pos,
1151
                      cluster_opts_t    opts)
1152
{
1153
    fatfs_data_pos_t new_pos;
1154
    cyg_uint32       n;
1155
    int              err;
1156
 
1157
    // Position inside the cluster
1158
    new_pos.cluster_pos = offset & (disk->cluster_size - 1);
1159
 
1160
    // Cluster seq number to be searched for
1161
    n = offset >> disk->cluster_size_log2;
1162
 
1163
    if (n < pos->cluster_snum)
1164
    {
1165
        // Start searching from first cluster
1166
        new_pos.cluster      = first_cluster;
1167
        new_pos.cluster_snum = 0;
1168
    }
1169
    else
1170
    {
1171
        // Start searching from the current position
1172
        new_pos.cluster      = pos->cluster;
1173
        new_pos.cluster_snum = pos->cluster_snum;
1174
    }
1175
 
1176
    err = find_nth_cluster(disk, &new_pos, n, opts);
1177
 
1178
    // Err could be EEOF wich means that the given 
1179
    // offset if out of given file (cluster chain)
1180
 
1181
    if (EEOF == err)
1182
        new_pos.cluster_pos = disk->cluster_size;
1183
 
1184
    *pos = new_pos;
1185
 
1186
    return err;
1187
}
1188
 
1189
// -------------------------------------------------------------------------
1190
// free_cluster_chain()
1191
// Marks all clusters FREE from given cluster to the last cluster in chain.
1192
 
1193
static int
1194
free_cluster_chain(fatfs_disk_t *disk, cyg_uint32 start_cluster)
1195
{
1196
    cyg_uint32 c, next_c, tentry;
1197
    bool       last;
1198
    int        err;
1199
 
1200
    CYG_TRACE1(TCL, "start cluster=%d", start_cluster);
1201
 
1202
    c = next_c = start_cluster;
1203
    last = false;
1204
    while (!last)
1205
    {
1206
        err = read_tentry(disk, c, &tentry);
1207
        if (err != ENOERR)
1208
            return err;
1209
 
1210
        switch (get_tentry_type(disk, tentry))
1211
        {
1212
            case TENTRY_LAST:
1213
                // Last cluster in chain
1214
                last = true;
1215
                break;
1216
            case TENTRY_REGULAR:
1217
                // Get next cluster in chain
1218
                next_c = get_tentry_next_cluster(disk, tentry);
1219
                break;
1220
            default:
1221
                CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x c=%d",
1222
                                tentry, c);
1223
                return EIO;
1224
        }
1225
 
1226
        // Set the current tentry to FREE 
1227
        set_tentry_type(disk, &tentry, TENTRY_FREE);
1228
        err = write_tentry(disk, c, &tentry);
1229
        if (err != ENOERR)
1230
            return err;
1231
 
1232
        // Next cluster in chain
1233
        c = next_c;
1234
    }
1235
 
1236
    CYG_TRACE1(TCL, "last cluster=%d", c);
1237
 
1238
    return ENOERR;
1239
}
1240
 
1241
//==========================================================================
1242
// FAT dir entry functions 
1243
 
1244
// -------------------------------------------------------------------------
1245
// print_raw_dentry()
1246
// Prints FAT directory entry. 
1247
 
1248
#if TDE
1249
static void
1250
print_raw_dentry(fat_raw_dir_entry_t* dentry)
1251
{
1252
    if (DENTRY_IS_DELETED(dentry))
1253
        diag_printf("FAT: FDE name:    '?%.7s'\n", &dentry->name[1]);
1254
    else
1255
        diag_printf("FAT: FDE name:    '%.8s'\n", dentry->name);
1256
    diag_printf("FAT: FDE ext:     '%.3s'\n", dentry->ext);
1257
    diag_printf("FAT: FDE attr:     %c%c%c%c%c%c\n",
1258
                (DENTRY_IS_RDONLY(dentry)  ? 'R' : '-'),
1259
                (DENTRY_IS_HIDDEN(dentry)  ? 'H' : '-'),
1260
                (DENTRY_IS_SYSTEM(dentry)  ? 'S' : '-'),
1261
                (DENTRY_IS_VOLUME(dentry)  ? 'V' : '-'),
1262
                (DENTRY_IS_DIR(dentry)     ? 'D' : '-'),
1263
                (DENTRY_IS_ARCHIVE(dentry) ? 'A' : '-'));
1264
    diag_printf("FAT: FDE crt time: %u\n", dentry->crt_time);
1265
    diag_printf("FAT: FDE crt date: %u\n", dentry->crt_date);
1266
    diag_printf("FAT: FDE acc date: %u\n", dentry->acc_date);
1267
    diag_printf("FAT: FDE wrt time: %u\n", dentry->wrt_time);
1268
    diag_printf("FAT: FDE wrt date: %u\n", dentry->wrt_date);
1269
    diag_printf("FAT: FDE cluster:  %u\n", (dentry->cluster_HI << 16) | dentry->cluster);
1270
    diag_printf("FAT: FDE size:     %u\n", dentry->size);
1271
}
1272
#endif // TDE
1273
 
1274
// -------------------------------------------------------------------------
1275
// read_raw_dentry()
1276
// Reads dir entry from disk.
1277
 
1278
static int
1279
read_raw_dentry(fatfs_disk_t        *disk,
1280
                fatfs_data_pos_t    *pos,
1281
                fat_raw_dir_entry_t *dentry)
1282
{
1283
    cyg_uint8  data[DENTRY_SIZE];
1284
    cyg_uint32 len;
1285
    int err;
1286
 
1287
    CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
1288
               pos->cluster, pos->cluster_snum, pos->cluster_pos);
1289
 
1290
    len = DENTRY_SIZE;
1291
 
1292
    // Check if we are reading the FAT12/16 root directory
1293
    if (0 == pos->cluster)
1294
        err = disk_read(disk, (void*)data, &len,
1295
                        disk->fat_root_dir_pos + pos->cluster_pos);
1296
    else
1297
        err = disk_cluster_read(disk, (void*)data, &len,
1298
                                pos->cluster, pos->cluster_pos);
1299
    if (err != ENOERR)
1300
        return err;
1301
 
1302
    GET_BYTES(data, dentry->name,     8, 0x00);
1303
    GET_BYTES(data, dentry->ext,      3, 0x08);
1304
    GET_BYTE(data,  dentry->attr,        0x0B);
1305
    GET_BYTE(data,  dentry->nt_reserved, 0x0C);
1306
    GET_BYTE(data,  dentry->crt_sec_100, 0x0D);
1307
    GET_WORD(data,  dentry->crt_time,    0x0E);
1308
    GET_WORD(data,  dentry->crt_date,    0x10);
1309
    GET_WORD(data,  dentry->acc_date,    0x12);
1310
    GET_WORD(data,  dentry->cluster_HI,  0x14);
1311
    GET_WORD(data,  dentry->wrt_time,    0x16);
1312
    GET_WORD(data,  dentry->wrt_date,    0x18);
1313
    GET_WORD(data,  dentry->cluster,     0x1A);
1314
    GET_DWORD(data, dentry->size,        0x1C);
1315
 
1316
     // Zero terminate strings
1317
    dentry->name[8] = '\0';
1318
    dentry->ext[3]  = '\0';
1319
 
1320
#if TDE    
1321
    print_raw_dentry(dentry);
1322
#endif
1323
 
1324
    return ENOERR;
1325
}
1326
 
1327
// -------------------------------------------------------------------------
1328
// write_raw_dentry()
1329
// Writes raw dir entry to disk. 
1330
 
1331
static int
1332
write_raw_dentry(fatfs_disk_t        *disk,
1333
                 fatfs_data_pos_t    *pos,
1334
                 fat_raw_dir_entry_t *dentry)
1335
{
1336
    cyg_uint8  data[DENTRY_SIZE];
1337
    cyg_uint32 len;
1338
    int err;
1339
 
1340
    CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
1341
               pos->cluster, pos->cluster_snum, pos->cluster_pos);
1342
 
1343
    SET_BYTES(data, dentry->name,     8, 0x00);
1344
    SET_BYTES(data, dentry->ext,      3, 0x08);
1345
    SET_BYTE(data,  dentry->attr,        0x0B);
1346
    SET_BYTE(data,  dentry->nt_reserved, 0x0C);
1347
    SET_BYTE(data,  dentry->crt_sec_100, 0x0D);
1348
    SET_WORD(data,  dentry->crt_time,    0x0E);
1349
    SET_WORD(data,  dentry->crt_date,    0x10);
1350
    SET_WORD(data,  dentry->acc_date,    0x12);
1351
    SET_WORD(data,  dentry->cluster_HI,  0x14);
1352
    SET_WORD(data,  dentry->wrt_time,    0x16);
1353
    SET_WORD(data,  dentry->wrt_date,    0x18);
1354
    SET_WORD(data,  dentry->cluster,     0x1A);
1355
    SET_DWORD(data, dentry->size,        0x1C);
1356
 
1357
    len = DENTRY_SIZE;
1358
 
1359
    // Check if we are writting to the FAT12/16 root directory
1360
    if (0 == pos->cluster)
1361
        err = disk_write(disk, (void*)data, &len,
1362
                         disk->fat_root_dir_pos + pos->cluster_pos);
1363
    else
1364
        err = disk_cluster_write(disk, (void*)data, &len,
1365
                                 pos->cluster, pos->cluster_pos);
1366
    if (err != ENOERR)
1367
        return err;
1368
 
1369
#if TDE    
1370
    print_raw_dentry(dentry);
1371
#endif
1372
 
1373
    return ENOERR;
1374
}
1375
 
1376
// -------------------------------------------------------------------------
1377
// raw_dentry_set_deleted()
1378
// Sets the dentry filename first char to 0xE5 (ie deleted). 
1379
 
1380
static __inline__ void
1381
raw_dentry_set_deleted(fatfs_disk_t *disk, fat_raw_dir_entry_t *dentry)
1382
{
1383
    dentry->name[0] = 0xE5;
1384
}
1385
 
1386
// -------------------------------------------------------------------------
1387
// get_raw_dentry_filename()
1388
// Gets the filename from given dir entry. 
1389
 
1390
static void
1391
get_raw_dentry_filename(fat_raw_dir_entry_t *dentry, char *name)
1392
{
1393
    int   i     = 0;
1394
    char *cptr  = dentry->name;
1395
    char *cname = name;
1396
 
1397
    while (*cptr != ' ' && i < 8)
1398
    {
1399
        *cname++ = *cptr++; i++;
1400
    }
1401
    cptr = dentry->ext;
1402
 
1403
    if (*cptr != ' ')
1404
    {
1405
        *cname++ = '.'; i = 0;
1406
        while (*cptr != ' ' && i < 3)
1407
        {
1408
            *cname++ = *cptr++; i++;
1409
        }
1410
    }
1411
    *cname = '\0';
1412
 
1413
    CYG_TRACE3(TDE, "dos name='%s' dos ext='%s' filename='%s'",
1414
                    dentry->name, dentry->ext, name);
1415
}
1416
 
1417
// -------------------------------------------------------------------------
1418
// set_raw_dentry_filename()
1419
// Sets the filename of given dir entry. 
1420
 
1421
static void
1422
set_raw_dentry_filename(fat_raw_dir_entry_t *dentry,
1423
                        const char          *name,
1424
                        int                  namelen)
1425
{
1426
    int         i, nidx;
1427
    const char *cname;
1428
    char       *cptr;
1429
 
1430
    // Special case check
1431
    if ('.' == name[0])
1432
    {
1433
        if ('\0' == name[1])
1434
        {
1435
            strcpy(dentry->name, ".       ");
1436
            strcpy(dentry->ext,  "   ");
1437
            return;
1438
        }
1439
        else if ('.' == name[1] && '\0' == name[2])
1440
        {
1441
            strcpy(dentry->name, "..      ");
1442
            strcpy(dentry->ext,  "   ");
1443
            return;
1444
        }
1445
    }
1446
 
1447
    if (0 == namelen)
1448
        namelen = 9999;
1449
 
1450
    nidx  = 0;
1451
    cname = name;
1452
    cptr  = dentry->name;
1453
    for (i = 0; i < 8; i++)
1454
    {
1455
        if (*cname != '.' && *cname != '\0' && nidx++ < namelen)
1456
            *cptr++ = toupper(*cname++);
1457
        else
1458
            *cptr++ = ' ';
1459
    }
1460
    *cptr = '\0';
1461
 
1462
    while (*cname != '.' && *cname != '\0' && nidx++ < namelen)
1463
        cname++;
1464
 
1465
    if ('.' == *cname && nidx++ < namelen)
1466
        cname++;
1467
 
1468
    cptr = dentry->ext;
1469
    for (i = 0; i < 3; i++)
1470
    {
1471
        if (*cname != '.' && *cname != '\0' && nidx++ < namelen)
1472
            *cptr++ = toupper(*cname++);
1473
        else
1474
            *cptr++ = ' ';
1475
    }
1476
    *cptr = '\0';
1477
 
1478
    CYG_TRACE4(TDE, "filename='%s' namelen=%d dos name='%s' dos ext='%s'",
1479
                    name, namelen, dentry->name, dentry->ext);
1480
}
1481
 
1482
// -------------------------------------------------------------------------
1483
// read_next_raw_dentry()
1484
// Gets next dir entry searching from given position to the end.
1485
// If EEOF is returned there are no more entries in given dir.
1486
 
1487
static int
1488
read_next_raw_dentry(fatfs_disk_t        *disk,
1489
                     fatfs_data_pos_t    *pos,
1490
                     fat_raw_dir_entry_t *dentry)
1491
{
1492
    int err = ENOERR;
1493
 
1494
    // If we are reading the root dir on FAT32 we have
1495
    // to correct the position to the root dir cluster
1496
    if (FATFS_FAT32 == disk->fat_type && 0 == pos->cluster)
1497
        pos->cluster = disk->fat_root_dir_cluster;
1498
 
1499
    while (true)
1500
    {
1501
        // FAT12/16 root dir check
1502
        if (0 == pos->cluster)
1503
        {
1504
            if (pos->cluster_pos >= disk->fat_root_dir_size)
1505
                err = EEOF;
1506
        }
1507
        else
1508
        {
1509
            // Change cluster if needed
1510
            if (pos->cluster_pos >= disk->cluster_size)
1511
                err = get_next_cluster(disk, pos, CO_NONE);
1512
        }
1513
 
1514
        if (err != ENOERR)
1515
            break;
1516
 
1517
        err = read_raw_dentry(disk, pos, dentry);
1518
        if (err != ENOERR)
1519
            return err;
1520
 
1521
        if (DENTRY_IS_ZERO(dentry))
1522
        {
1523
            // If we get a ZERO dir entry, we assume that
1524
            // there are no more entries in current dir
1525
            CYG_TRACE0(TDE, "end of dir");
1526
            err = EEOF;
1527
            break;
1528
        }
1529
        else if (!DENTRY_IS_DELETED(dentry))
1530
        {
1531
            // Dir entry found
1532
            CYG_TRACE3(TDE, "found new dentry at cluster=%d snum=%d pos=%d",
1533
                            pos->cluster, pos->cluster_snum, pos->cluster_pos);
1534
            break;
1535
        }
1536
 
1537
        pos->cluster_pos += DENTRY_SIZE;
1538
    }
1539
 
1540
    // EEOF could be returned if there are no more entries in this
1541
    // dir - this should be cought by the calling function 
1542
 
1543
    return err;
1544
}
1545
 
1546
// -------------------------------------------------------------------------
1547
// get_free_raw_dentry()
1548
// Gets free dir entry slot searching from given position extending the
1549
// directory if needed. If an deleated entry is found it is reused.
1550
 
1551
static int
1552
get_free_raw_dentry(fatfs_disk_t     *disk,
1553
                    fatfs_data_pos_t *pos)
1554
{
1555
    fat_raw_dir_entry_t raw_dentry;
1556
    fatfs_data_pos_t    cpos;
1557
    int                 err = ENOERR;
1558
 
1559
    cpos = *pos;
1560
 
1561
    // If we are reading the root dir on FAT32 we have
1562
    // to correct the position to the root dir cluster
1563
    if (FATFS_FAT32 == disk->fat_type && 0 == cpos.cluster)
1564
        cpos.cluster = disk->fat_root_dir_cluster;
1565
 
1566
    CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
1567
                    pos->cluster, pos->cluster_snum, pos->cluster_pos);
1568
 
1569
    while (true)
1570
    {
1571
        // FAT12/16 root dir check
1572
        if (0 == cpos.cluster)
1573
        {
1574
            if (cpos.cluster_pos >= disk->fat_root_dir_size)
1575
                err = ENOSPC;
1576
        }
1577
        else
1578
        {
1579
            // Change cluster if needed
1580
            if (cpos.cluster_pos >= disk->cluster_size)
1581
                err = get_next_cluster(disk, &cpos, CO_EXTEND | CO_ERASE_NEW);
1582
        }
1583
 
1584
        if (err != ENOERR)
1585
            return err;
1586
 
1587
        err = read_raw_dentry(disk, &cpos, &raw_dentry);
1588
        if (err != ENOERR)
1589
            return err;
1590
 
1591
        if (DENTRY_IS_DELETED(&raw_dentry))
1592
        {
1593
            CYG_TRACE3(TDE, "deleted dentry at cluster=%d snum=%d pos=%d",
1594
                            cpos.cluster, cpos.cluster_snum, cpos.cluster_pos);
1595
 
1596
            *pos = cpos;
1597
            return ENOERR;
1598
        }
1599
        else if (DENTRY_IS_ZERO(&raw_dentry))
1600
        {
1601
            CYG_TRACE3(TDE, "zero dentry at cluster=%d snum=%d pos=%d",
1602
                            cpos.cluster, cpos.cluster_snum, cpos.cluster_pos);
1603
 
1604
            *pos = cpos;
1605
            return ENOERR;
1606
        }
1607
 
1608
        cpos.cluster_pos += DENTRY_SIZE;
1609
    }
1610
}
1611
 
1612
// -------------------------------------------------------------------------
1613
// raw_to_dentry()
1614
// Converts raw FAT dir entry to dir entry. 
1615
 
1616
static void
1617
raw_to_dentry(fat_raw_dir_entry_t *raw_dentry,
1618
              fatfs_data_pos_t    *raw_dentry_pos,
1619
              fatfs_dir_entry_t   *dentry)
1620
{
1621
    get_raw_dentry_filename(raw_dentry, dentry->filename);
1622
 
1623
    if (DENTRY_IS_DIR(raw_dentry))
1624
        dentry->mode = __stat_mode_DIR;
1625
    else
1626
        dentry->mode = __stat_mode_REG;
1627
 
1628
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1629
    dentry->attrib = raw_dentry->attr;
1630
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1631
 
1632
    date_dos2unix(raw_dentry->crt_time, raw_dentry->crt_date, &dentry->ctime);
1633
    date_dos2unix(0,                    raw_dentry->acc_date, &dentry->atime);
1634
    date_dos2unix(raw_dentry->wrt_time, raw_dentry->wrt_date, &dentry->mtime);
1635
 
1636
    dentry->size       = raw_dentry->size;
1637
    dentry->priv_data  = raw_dentry->nt_reserved;
1638
    dentry->cluster    = raw_dentry->cluster | (raw_dentry->cluster_HI << 16);
1639
    dentry->disk_pos   = *raw_dentry_pos;
1640
}
1641
 
1642
// -------------------------------------------------------------------------
1643
// dentry_to_raw()
1644
// Converts dir entry to raw FAT dir entry. 
1645
 
1646
static void
1647
dentry_to_raw(fatfs_dir_entry_t *dentry, fat_raw_dir_entry_t *raw_dentry)
1648
{
1649
    set_raw_dentry_filename(raw_dentry, dentry->filename, 0);
1650
 
1651
    if (__stat_mode_DIR == dentry->mode)
1652
        raw_dentry->attr = S_FATFS_DIR;
1653
    else
1654
        raw_dentry->attr = S_FATFS_ARCHIVE;
1655
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1656
    raw_dentry->attr = dentry->attrib;
1657
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1658
 
1659
 
1660
    date_unix2dos(dentry->ctime, &raw_dentry->crt_time, &raw_dentry->crt_date);
1661
    date_unix2dos(dentry->atime, NULL,                  &raw_dentry->acc_date);
1662
    date_unix2dos(dentry->mtime, &raw_dentry->wrt_time, &raw_dentry->wrt_date);
1663
 
1664
    raw_dentry->crt_sec_100 = 0; //FIXME
1665
    raw_dentry->size        = dentry->size;
1666
    raw_dentry->nt_reserved = dentry->priv_data;
1667
    raw_dentry->cluster     = dentry->cluster & 0xFFFF;
1668
    raw_dentry->cluster_HI  = dentry->cluster >> 16;
1669
}
1670
 
1671
//==========================================================================
1672
// FAT data functions 
1673
 
1674
// -------------------------------------------------------------------------
1675
// read_data()
1676
// Reads data from given position. 
1677
 
1678
static int
1679
read_data(fatfs_disk_t     *disk,
1680
          void             *data,
1681
          cyg_uint32       *len,
1682
          fatfs_data_pos_t *pos)
1683
{
1684
    cyg_uint8   *buf   = (cyg_uint8 *) data;
1685
    cyg_uint32   size  = *len;
1686
    int          err   = ENOERR;
1687
 
1688
    CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d",
1689
                    *len, pos->cluster, pos->cluster_snum,
1690
                    pos->cluster_pos);
1691
 
1692
    while (size > 0)
1693
    {
1694
        cyg_uint32 csize;
1695
 
1696
        // Check if we are still inside current cluster
1697
        if (pos->cluster_pos >= disk->cluster_size)
1698
        {
1699
            // Get next cluster of file 
1700
            err = get_next_cluster(disk, pos, CO_NONE);
1701
            if (err != ENOERR)
1702
                goto out;
1703
        }
1704
 
1705
        // Adjust the data chunk size to be read to the cluster boundary
1706
        if (size > (disk->cluster_size - pos->cluster_pos))
1707
            csize = disk->cluster_size - pos->cluster_pos;
1708
        else
1709
            csize = size;
1710
 
1711
        CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d",
1712
                        csize, pos->cluster, pos->cluster_snum,
1713
                        pos->cluster_pos);
1714
 
1715
        err = disk_cluster_read(disk, (void*)buf, &csize,
1716
                                pos->cluster, pos->cluster_pos);
1717
        if (err != ENOERR)
1718
            goto out;
1719
 
1720
        // Adjust running variables
1721
 
1722
        buf              += csize;
1723
        pos->cluster_pos += csize;
1724
        size             -= csize;
1725
    }
1726
 
1727
out:
1728
    *len -= size;
1729
 
1730
    CYG_TRACE1(TDO, "total len=%d", *len);
1731
 
1732
    return err;
1733
}
1734
 
1735
// -------------------------------------------------------------------------
1736
// write_data()
1737
// Writes data to given position. 
1738
 
1739
static int
1740
write_data(fatfs_disk_t     *disk,
1741
           void             *data,
1742
           cyg_uint32       *len,
1743
           fatfs_data_pos_t *pos)
1744
{
1745
    cyg_uint8   *buf   = (cyg_uint8 *) data;
1746
    cyg_uint32   size  = *len;
1747
    int          err   = ENOERR;
1748
 
1749
    CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d",
1750
                    *len, pos->cluster, pos->cluster_snum,
1751
                    pos->cluster_pos);
1752
 
1753
    while (size > 0)
1754
    {
1755
        cyg_uint32 csize;
1756
 
1757
        // Check if we are still inside current cluster
1758
        if (pos->cluster_pos >= disk->cluster_size)
1759
        {
1760
            // Get next cluster of file, if at the last 
1761
            // cluster try to extend the cluster chain 
1762
            err = get_next_cluster(disk, pos, CO_EXTEND);
1763
            if (err != ENOERR)
1764
                goto out;
1765
        }
1766
 
1767
        // Adjust the data chunk size to be read to the cluster boundary
1768
        if (size > (disk->cluster_size - pos->cluster_pos))
1769
            csize = disk->cluster_size - pos->cluster_pos;
1770
        else
1771
            csize = size;
1772
 
1773
        CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d",
1774
                        csize, pos->cluster, pos->cluster_snum,
1775
                        pos->cluster_pos);
1776
 
1777
        err = disk_cluster_write(disk, (void*)buf, &csize,
1778
                                 pos->cluster, pos->cluster_pos);
1779
        if (err != ENOERR)
1780
            goto out;
1781
 
1782
        // Adjust running variables
1783
 
1784
        buf              += csize;
1785
        pos->cluster_pos += csize;
1786
        size             -= csize;
1787
    }
1788
 
1789
out:
1790
    *len -= size;
1791
 
1792
    CYG_TRACE1(TDO, "total len=%d", *len);
1793
 
1794
    return err;
1795
}
1796
 
1797
//==========================================================================
1798
// Misc functions 
1799
 
1800
// -------------------------------------------------------------------------
1801
// init_dir_entry()
1802
// Initializes attributes of a new dir entry. 
1803
 
1804
static void
1805
init_dir_entry(fatfs_dir_entry_t *dentry,
1806
               const char        *name,
1807
               int                namelen,
1808
               mode_t             mode,
1809
               cyg_uint32         parent_cluster,
1810
               cyg_uint32         first_cluster,
1811
               fatfs_data_pos_t  *pos)
1812
{
1813
    if (0 == namelen)
1814
        namelen = 12;
1815
 
1816
    strncpy(dentry->filename, name, namelen);
1817
    dentry->filename[namelen] = '\0';
1818
 
1819
    dentry->mode  = mode;
1820
 
1821
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1822
    if (S_ISDIR(dentry->mode))
1823
        dentry->attrib = S_FATFS_DIR;
1824
    else
1825
        dentry->attrib = S_FATFS_ARCHIVE;
1826
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1827
 
1828
    dentry->ctime =
1829
    dentry->atime =
1830
    dentry->mtime = cyg_timestamp();
1831
 
1832
    dentry->priv_data      = 0;
1833
    dentry->size           = 0;
1834
    dentry->cluster        = first_cluster;
1835
    dentry->parent_cluster = parent_cluster;
1836
    dentry->disk_pos       = *pos;
1837
}
1838
 
1839
// -------------------------------------------------------------------------
1840
// is_root_dir_entry()
1841
// Check if the given dir entry is the root dir entry. 
1842
 
1843
static __inline__ bool
1844
is_root_dir_entry(fatfs_dir_entry_t *dentry)
1845
{
1846
    return ('\0' == dentry->filename[0] && 0 == dentry->cluster);
1847
}
1848
 
1849
//==========================================================================
1850
//==========================================================================
1851
// Exported functions 
1852
 
1853
// -------------------------------------------------------------------------
1854
// fatfs_init()
1855
// Gets disk info. 
1856
 
1857
int
1858
fatfs_init(fatfs_disk_t *disk)
1859
{
1860
    cyg_uint32        sec_num, sec_per_fat, root_dir_sec_num;
1861
    cyg_uint32        data_sec_num, data_clu_num;
1862
    fat_boot_record_t boot_rec;
1863
    int               err;
1864
 
1865
    CYG_CHECK_DATA_PTRC(disk);
1866
 
1867
    err = read_boot_record(disk, &boot_rec);
1868
    if (err != ENOERR)
1869
        return err;
1870
 
1871
    // Check some known boot record values
1872
    if (!(0x29 == boot_rec.ext_sig ||
1873
          0x28 == boot_rec.ext_sig)    ||
1874
        0x55 != boot_rec.exe_marker[0] ||
1875
        0xAA != boot_rec.exe_marker[1])
1876
        return EINVAL;
1877
 
1878
    // Sector and cluster sizes 
1879
    disk->sector_size       = boot_rec.bytes_per_sec;
1880
    disk->sector_size_log2  = get_val_log2(disk->sector_size);
1881
    disk->cluster_size      = boot_rec.bytes_per_sec * boot_rec.sec_per_clu;
1882
    disk->cluster_size_log2 = get_val_log2(disk->cluster_size);
1883
 
1884
    // Sector and cluster size should always be a power of 2
1885
    if (0 == disk->sector_size_log2 || 0 == disk->cluster_size_log2)
1886
        return EINVAL;
1887
 
1888
    // Determine number of sectors
1889
    if (boot_rec.sec_num_32 != 0)
1890
        sec_num = boot_rec.sec_num_32;
1891
    else
1892
        sec_num = boot_rec.sec_num;
1893
 
1894
    // Determine number of sectors per fat
1895
    if (boot_rec.sec_per_fat != 0)
1896
        sec_per_fat = boot_rec.sec_per_fat;
1897
    else
1898
        sec_per_fat = boot_rec.sec_per_fat_32;
1899
 
1900
    // Number of sectors used by root directory 
1901
    root_dir_sec_num = ((boot_rec.max_root_dents * DENTRY_SIZE) +
1902
                        (boot_rec.bytes_per_sec - 1)) / boot_rec.bytes_per_sec;
1903
 
1904
    // Number of data sectors
1905
    data_sec_num = sec_num - (boot_rec.res_sec_num +
1906
        (boot_rec.fat_tbls_num * sec_per_fat) + root_dir_sec_num);
1907
 
1908
    // Number of data clusters
1909
    data_clu_num = data_sec_num / boot_rec.sec_per_clu;
1910
 
1911
    // FAT table size and position
1912
    disk->fat_tbl_pos   = boot_rec.bytes_per_sec * boot_rec.res_sec_num;
1913
    disk->fat_tbl_size  = boot_rec.bytes_per_sec * sec_per_fat;
1914
    disk->fat_tbl_nents = data_clu_num + 2;
1915
    disk->fat_tbls_num  = boot_rec.fat_tbls_num;
1916
 
1917
    // Determine the type of FAT based on number of data clusters
1918
    if (data_clu_num < 4085)
1919
        disk->fat_type  = FATFS_FAT12;
1920
    else if (data_clu_num < 65525)
1921
        disk->fat_type  = FATFS_FAT16;
1922
    else
1923
        disk->fat_type  = FATFS_FAT32;
1924
 
1925
    // Determine root dir and data positions
1926
    if (FATFS_FAT32 != disk->fat_type)
1927
    {
1928
        disk->fat_root_dir_pos     = disk->fat_tbl_pos +
1929
                                     disk->fat_tbls_num * disk->fat_tbl_size;
1930
        disk->fat_root_dir_size    = boot_rec.max_root_dents * DENTRY_SIZE;
1931
        disk->fat_root_dir_nents   = boot_rec.max_root_dents;
1932
        disk->fat_root_dir_cluster = 0;
1933
        disk->fat_data_pos         = disk->fat_root_dir_pos +
1934
                                     disk->fat_root_dir_size;
1935
    }
1936
    else
1937
    {
1938
        disk->fat_root_dir_pos     = 0;
1939
        disk->fat_root_dir_size    = 0;
1940
        disk->fat_root_dir_nents   = 0;
1941
        disk->fat_root_dir_cluster = boot_rec.root_cluster;
1942
        disk->fat_data_pos         = disk->fat_tbl_pos +
1943
                                     disk->fat_tbls_num * disk->fat_tbl_size;
1944
    }
1945
 
1946
    return ENOERR;
1947
}
1948
 
1949
// -------------------------------------------------------------------------
1950
// fatfs_get_root_dir_entry()
1951
// Gets root dir entry. 
1952
 
1953
void
1954
fatfs_get_root_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
1955
{
1956
    CYG_CHECK_DATA_PTRC(disk);
1957
    CYG_CHECK_DATA_PTRC(dentry);
1958
 
1959
    dentry->mode           = __stat_mode_DIR;
1960
#ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1961
    dentry->attrib         = S_FATFS_DIR;
1962
#endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1963
    dentry->size           = disk->fat_root_dir_size;
1964
    dentry->ctime          = 0;
1965
    dentry->atime          = 0;
1966
    dentry->mtime          = 0;
1967
    dentry->filename[0]    = '\0';
1968
    dentry->cluster        = 0;
1969
    dentry->parent_cluster = 0;
1970
 
1971
    dentry->disk_pos.cluster      = 0;
1972
    dentry->disk_pos.cluster_snum = 0;
1973
    dentry->disk_pos.cluster_pos  = 0;
1974
}
1975
 
1976
// -------------------------------------------------------------------------
1977
// fatfs_get_disk_usage()
1978
// Gets disk space.
1979
 
1980
int
1981
fatfs_get_disk_usage(fatfs_disk_t *disk,
1982
                     cyg_uint32   *total_clusters,
1983
                     cyg_uint32   *free_clusters)
1984
{
1985
    cyg_uint32 c, nfree, tentry;
1986
    int        err;
1987
 
1988
    nfree = 0;
1989
    for (c = 2; c < disk->fat_tbl_nents; c++)
1990
    {
1991
        err = read_tentry(disk, c, &tentry);
1992
        if (err != ENOERR)
1993
            return err;
1994
 
1995
        if (TENTRY_FREE == get_tentry_type(disk, tentry))
1996
            nfree++;
1997
    }
1998
 
1999
    *total_clusters = disk->fat_tbl_nents - 2;
2000
    *free_clusters  = nfree;
2001
 
2002
    return ENOERR;
2003
}
2004
 
2005
 
2006
// -------------------------------------------------------------------------
2007
// fatfs_read_dir_entry()
2008
// Reads dir entry at given position.
2009
// If there is no dir entry at given position the next closest is returned 
2010
// and the position is updated. If EEOF error is returned, then there are 
2011
// no more dir entries in given dir. 
2012
 
2013
int
2014
fatfs_read_dir_entry(fatfs_disk_t      *disk,
2015
                     fatfs_dir_entry_t *dir,
2016
                     fatfs_data_pos_t  *pos,
2017
                     fatfs_dir_entry_t *dentry)
2018
{
2019
    fat_raw_dir_entry_t raw_dentry;
2020
    int                 err;
2021
 
2022
    CYG_CHECK_DATA_PTRC(disk);
2023
    CYG_CHECK_DATA_PTRC(dir);
2024
    CYG_CHECK_DATA_PTRC(pos);
2025
    CYG_CHECK_DATA_PTRC(dentry);
2026
 
2027
    err = read_next_raw_dentry(disk, pos, &raw_dentry);
2028
    if (err != ENOERR)
2029
       return err;
2030
 
2031
    raw_to_dentry(&raw_dentry, pos, dentry);
2032
    dentry->parent_cluster = dir->cluster;
2033
 
2034
    // Increment position for next call
2035
    pos->cluster_pos += DENTRY_SIZE;
2036
 
2037
    return ENOERR;
2038
}
2039
 
2040
// -------------------------------------------------------------------------
2041
// fatfs_initpos()
2042
// Initializes position to the start of the given file.
2043
 
2044
int
2045
fatfs_initpos(fatfs_disk_t      *disk,
2046
              fatfs_dir_entry_t *file,
2047
              fatfs_data_pos_t  *pos)
2048
{
2049
    CYG_CHECK_DATA_PTRC(disk);
2050
    CYG_CHECK_DATA_PTRC(file);
2051
    CYG_CHECK_DATA_PTRC(pos);
2052
 
2053
    pos->cluster      = file->cluster;
2054
    pos->cluster_snum = 0;
2055
    pos->cluster_pos  = 0;
2056
 
2057
    return ENOERR;
2058
}
2059
 
2060
// -------------------------------------------------------------------------
2061
// fatfs_setpos()
2062
// Sets the file position from offset.
2063
 
2064
int
2065
fatfs_setpos(fatfs_disk_t      *disk,
2066
             fatfs_dir_entry_t *file,
2067
             fatfs_data_pos_t  *pos,
2068
             cyg_uint32         offset)
2069
{
2070
    int err;
2071
 
2072
    CYG_CHECK_DATA_PTRC(disk);
2073
    CYG_CHECK_DATA_PTRC(file);
2074
    CYG_CHECK_DATA_PTRC(pos);
2075
 
2076
    err = get_position_from_off(disk, file->cluster, offset, pos, CO_NONE);
2077
 
2078
    if (EEOF == err && offset == file->size)
2079
        return ENOERR;
2080
    else
2081
        return err;
2082
}
2083
 
2084
// -------------------------------------------------------------------------
2085
// fatfs_getpos()
2086
// Gets the file offset from position.
2087
 
2088
cyg_uint32
2089
fatfs_getpos(fatfs_disk_t      *disk,
2090
             fatfs_dir_entry_t *file,
2091
             fatfs_data_pos_t  *pos)
2092
{
2093
    CYG_CHECK_DATA_PTRC(disk);
2094
    CYG_CHECK_DATA_PTRC(file);
2095
    CYG_CHECK_DATA_PTRC(pos);
2096
 
2097
    return (pos->cluster_snum << disk->cluster_size_log2) + pos->cluster_pos;
2098
}
2099
 
2100
// -------------------------------------------------------------------------
2101
// fatfs_write_dir_entry()
2102
// Writes dir entry to disk.
2103
 
2104
int
2105
fatfs_write_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
2106
{
2107
    fat_raw_dir_entry_t raw_dentry;
2108
    int                 err;
2109
 
2110
    CYG_CHECK_DATA_PTRC(disk);
2111
    CYG_CHECK_DATA_PTRC(dentry);
2112
 
2113
    dentry_to_raw(dentry, &raw_dentry);
2114
    err = write_raw_dentry(disk, &dentry->disk_pos, &raw_dentry);
2115
    return err;
2116
}
2117
 
2118
// -------------------------------------------------------------------------
2119
// fatfs_delete_file()
2120
// Marks dir entry as deleted and frees its cluster chain.
2121
 
2122
int
2123
fatfs_delete_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file)
2124
{
2125
    fat_raw_dir_entry_t raw_dentry;
2126
    int                 err;
2127
 
2128
    CYG_CHECK_DATA_PTRC(disk);
2129
    CYG_CHECK_DATA_PTRC(file);
2130
 
2131
    if (is_root_dir_entry(file))
2132
        return EINVAL;
2133
 
2134
    CYG_TRACE1(TDE, "filename='%s'", file->filename);
2135
 
2136
    dentry_to_raw(file, &raw_dentry);
2137
 
2138
    // Check if we are about to delete a directory
2139
    if (DENTRY_IS_DIR(&raw_dentry))
2140
    {
2141
        fat_raw_dir_entry_t raw_cdentry;
2142
        fatfs_data_pos_t    pos;
2143
        int                 i = 0;
2144
 
2145
        fatfs_initpos(disk, file, &pos);
2146
 
2147
        CYG_TRACE0(TDE, "got directory");
2148
 
2149
        // Count number of entries in this dir    
2150
 
2151
        while (true)
2152
        {
2153
            err = read_next_raw_dentry(disk, &pos, &raw_cdentry);
2154
 
2155
            if (EEOF == err)
2156
                break;
2157
            else if (err != ENOERR)
2158
                return err;
2159
 
2160
            pos.cluster_pos += DENTRY_SIZE;
2161
            i++;
2162
        }
2163
        CYG_TRACE1(TDE, "child count=%d", i);
2164
 
2165
        // Check if the dir is empty (except '.' and '..')
2166
        if (i > 2)
2167
            return EPERM;
2168
    }
2169
 
2170
    // Free file clusters
2171
    free_cluster_chain(disk, raw_dentry.cluster | (raw_dentry.cluster_HI << 16));
2172
    raw_dentry_set_deleted(disk, &raw_dentry);
2173
    err = write_raw_dentry(disk, &file->disk_pos, &raw_dentry);
2174
    return err;
2175
}
2176
 
2177
// -------------------------------------------------------------------------
2178
// fatfs_create_file()
2179
// Creates a new file.
2180
 
2181
int
2182
fatfs_create_file(fatfs_disk_t      *disk,
2183
                  fatfs_dir_entry_t *dir,
2184
                  const char        *name,
2185
                  int                namelen,
2186
                  fatfs_dir_entry_t *dentry)
2187
{
2188
    fatfs_data_pos_t pos;
2189
    int              err;
2190
 
2191
    CYG_CHECK_DATA_PTRC(disk);
2192
    CYG_CHECK_DATA_PTRC(dir);
2193
    CYG_CHECK_DATA_PTRC(name);
2194
    CYG_CHECK_DATA_PTRC(dentry);
2195
 
2196
    CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename);
2197
 
2198
    fatfs_initpos(disk, dir, &pos);
2199
 
2200
    // Get free dir entry in parent dir
2201
    err = get_free_raw_dentry(disk, &pos);
2202
    if (err != ENOERR)
2203
        return err;
2204
 
2205
    // Create new file dir entry
2206
 
2207
    init_dir_entry(dentry,
2208
                   name,
2209
                   namelen,
2210
                   __stat_mode_REG,
2211
                   dir->cluster,
2212
                   0,
2213
                   &pos);
2214
 
2215
    err = fatfs_write_dir_entry(disk, dentry);
2216
    if (err != ENOERR)
2217
       return err;
2218
 
2219
    return ENOERR;
2220
}
2221
 
2222
// -------------------------------------------------------------------------
2223
// fatfs_create_dir()
2224
// Creates a new directory.
2225
 
2226
int
2227
fatfs_create_dir(fatfs_disk_t      *disk,
2228
                 fatfs_dir_entry_t *dir,
2229
                 const char        *name,
2230
                 int                namelen,
2231
                 fatfs_dir_entry_t *dentry)
2232
{
2233
    fatfs_dir_entry_t cdentry;
2234
    fatfs_data_pos_t  pos;
2235
    cyg_uint32        free_cluster;
2236
    int               err;
2237
 
2238
    CYG_CHECK_DATA_PTRC(disk);
2239
    CYG_CHECK_DATA_PTRC(dir);
2240
    CYG_CHECK_DATA_PTRC(name);
2241
    CYG_CHECK_DATA_PTRC(dentry);
2242
 
2243
    CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename);
2244
 
2245
    // Get free cluster
2246
    err = find_next_free_cluster(disk,
2247
                                 0,
2248
                                 &free_cluster,
2249
                                 CO_MARK_LAST | CO_ERASE_NEW);
2250
    if (err != ENOERR)
2251
        return err;
2252
 
2253
    fatfs_initpos(disk, dir, &pos);
2254
 
2255
    // Get free dir entry in parent dir
2256
    err = get_free_raw_dentry(disk, &pos);
2257
    if (err != ENOERR)
2258
        return err;
2259
 
2260
    // Create new dir entry
2261
 
2262
    init_dir_entry(dentry,
2263
                   name,
2264
                   namelen,
2265
                   __stat_mode_DIR,
2266
                   dir->cluster,
2267
                   free_cluster,
2268
                   &pos);
2269
 
2270
    err = fatfs_write_dir_entry(disk, dentry);
2271
    if (err != ENOERR)
2272
       return err;
2273
 
2274
    // Create '.' and '..' dir entries
2275
 
2276
    fatfs_initpos(disk, dentry, &pos);
2277
 
2278
    CYG_TRACE0(TDE, "Creating '.' entry");
2279
 
2280
    init_dir_entry(&cdentry,
2281
                   ".",
2282
                   0,
2283
                   __stat_mode_DIR,
2284
                   dentry->cluster,
2285
                   dentry->cluster,
2286
                   &pos);
2287
 
2288
    err = fatfs_write_dir_entry(disk, &cdentry);
2289
    if (err != ENOERR)
2290
        return err;
2291
 
2292
    pos.cluster_pos += DENTRY_SIZE;
2293
 
2294
    CYG_TRACE0(TDE, "Creating '..' entry");
2295
 
2296
    init_dir_entry(&cdentry,
2297
                   "..",
2298
                   0,
2299
                   __stat_mode_DIR,
2300
                   dentry->cluster,
2301
                   dir->cluster,
2302
                   &pos);
2303
 
2304
    err = fatfs_write_dir_entry(disk, &cdentry);
2305
    if (err != ENOERR)
2306
        return err;
2307
 
2308
    return ENOERR;
2309
}
2310
 
2311
// -------------------------------------------------------------------------
2312
// fatfs_trunc_file()
2313
// Truncates a file to zero length.
2314
 
2315
int
2316
fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file)
2317
{
2318
    int err;
2319
 
2320
    CYG_CHECK_DATA_PTRC(disk);
2321
    CYG_CHECK_DATA_PTRC(file);
2322
 
2323
    CYG_TRACE1(TDE, "file='%s'", file->filename);
2324
 
2325
    if (S_ISDIR(file->mode))
2326
        return EINVAL;
2327
 
2328
    if (0 == file->size)
2329
        return ENOERR;
2330
 
2331
    err = free_cluster_chain(disk, file->cluster);
2332
    if (err != ENOERR)
2333
        return err;
2334
 
2335
    // Update file attributes
2336
 
2337
    file->cluster = 0;
2338
    file->size    = 0;
2339
    file->mtime   =
2340
    file->atime   = cyg_timestamp();
2341
 
2342
    return fatfs_write_dir_entry(disk, file);
2343
}
2344
 
2345
// -------------------------------------------------------------------------
2346
// fatfs_rename_file()
2347
// Renames a file.
2348
 
2349
int
2350
fatfs_rename_file(fatfs_disk_t      *disk,
2351
                  fatfs_dir_entry_t *dir1,
2352
                  fatfs_dir_entry_t *target,
2353
                  fatfs_dir_entry_t *dir2,
2354
                  const char        *name,
2355
                  int                namelen)
2356
{
2357
    fat_raw_dir_entry_t raw_dentry;
2358
    fatfs_data_pos_t    new_pos;
2359
    int                 err;
2360
 
2361
    CYG_CHECK_DATA_PTRC(disk);
2362
    CYG_CHECK_DATA_PTRC(dir1);
2363
    CYG_CHECK_DATA_PTRC(target);
2364
    CYG_CHECK_DATA_PTRC(dir2);
2365
    CYG_CHECK_DATA_PTRC(name);
2366
 
2367
    if (is_root_dir_entry(target))
2368
        return EINVAL;
2369
 
2370
    strncpy(target->filename, name, namelen);
2371
    target->filename[namelen] = '\0';
2372
 
2373
    // Moving around in same dir
2374
 
2375
    if (dir1 == dir2)
2376
    {
2377
        CYG_TRACE0(TDE, "same dir");
2378
        return fatfs_write_dir_entry(disk, target);
2379
    }
2380
 
2381
    CYG_TRACE0(TDE, "different dirs");
2382
 
2383
    // Moving around in different dirs
2384
 
2385
    fatfs_initpos(disk, dir2, &new_pos);
2386
 
2387
    CYG_TRACE0(TDE, "writing to new dir");
2388
 
2389
    // Get free dir entry in target dir
2390
 
2391
    err = get_free_raw_dentry(disk, &new_pos);
2392
    if (err != ENOERR)
2393
        return err;
2394
 
2395
    // Write file dentry to new location
2396
 
2397
    dentry_to_raw(target, &raw_dentry);
2398
    err = write_raw_dentry(disk, &new_pos, &raw_dentry);
2399
    if (err != ENOERR)
2400
        return err;
2401
 
2402
    CYG_TRACE0(TDE, "deleting from old dir");
2403
 
2404
    // Delete dentry at old location
2405
 
2406
    raw_dentry_set_deleted(disk, &raw_dentry);
2407
    raw_dentry.size    = 0;
2408
    raw_dentry.cluster = 0;
2409
    raw_dentry.cluster_HI = 0;
2410
    err = write_raw_dentry(disk, &target->disk_pos, &raw_dentry);
2411
    if (err != ENOERR)
2412
        return err;
2413
 
2414
    // Set file new position and parent cluster
2415
 
2416
    target->disk_pos       = new_pos;
2417
    target->parent_cluster = dir2->cluster;
2418
 
2419
    // If we moved a directory, we also have to correct the '..' entry  
2420
 
2421
    if ( S_ISDIR(target->mode) )
2422
    {
2423
        fat_raw_dir_entry_t raw_cdentry;
2424
        fatfs_data_pos_t    pos;
2425
 
2426
        fatfs_initpos(disk, target, &pos);
2427
 
2428
        CYG_TRACE0(TDE, "moving directory - correcting '..' entry");
2429
 
2430
        while (true)
2431
        {
2432
            err = read_next_raw_dentry(disk, &pos, &raw_cdentry);
2433
 
2434
            if (EEOF == err)
2435
                return EINVAL; // This dir doesn't have the '..' entry,
2436
                               // that means something is very wrong
2437
            else if (err != ENOERR)
2438
                return err;
2439
 
2440
            if (0 == strncmp("..", raw_cdentry.name, 2))
2441
            {
2442
                raw_cdentry.cluster = dir2->cluster & 0xFFFF;
2443
                raw_cdentry.cluster_HI = dir2->cluster >> 16;
2444
                err = write_raw_dentry(disk, &pos, &raw_cdentry);
2445
                if (err != ENOERR)
2446
                    return err;
2447
                break;
2448
            }
2449
 
2450
            pos.cluster_pos += DENTRY_SIZE;
2451
        }
2452
    }
2453
 
2454
    return ENOERR;
2455
}
2456
 
2457
// -------------------------------------------------------------------------
2458
// fatfs_read_data()
2459
// Reads data from disk. 
2460
 
2461
int
2462
fatfs_read_data(fatfs_disk_t      *disk,
2463
                fatfs_dir_entry_t *file,
2464
                fatfs_data_pos_t  *pos,
2465
                void              *data,
2466
                cyg_uint32        *len)
2467
{
2468
    CYG_CHECK_DATA_PTRC(disk);
2469
    CYG_CHECK_DATA_PTRC(file);
2470
    CYG_CHECK_DATA_PTRC(data);
2471
    CYG_CHECK_DATA_PTRC(len);
2472
    CYG_CHECK_DATA_PTRC(pos);
2473
 
2474
    return read_data(disk, data, len, pos);
2475
}
2476
 
2477
// -------------------------------------------------------------------------
2478
// fatfs_write_data()
2479
// Writes data to disk. 
2480
 
2481
int
2482
fatfs_write_data(fatfs_disk_t      *disk,
2483
                 fatfs_dir_entry_t *file,
2484
                 fatfs_data_pos_t  *pos,
2485
                 void              *data,
2486
                 cyg_uint32        *len)
2487
{
2488
    int err;
2489
 
2490
    CYG_CHECK_DATA_PTRC(disk);
2491
    CYG_CHECK_DATA_PTRC(file);
2492
    CYG_CHECK_DATA_PTRC(data);
2493
    CYG_CHECK_DATA_PTRC(len);
2494
    CYG_CHECK_DATA_PTRC(pos);
2495
 
2496
    // Check if this file has a zero size and no first cluster
2497
 
2498
    if (0 == file->size && 0 == file->cluster)
2499
    {
2500
        cyg_uint32 free_cluster;
2501
 
2502
        CYG_TRACE0(TDO, "new cluster for zero file");
2503
 
2504
        err = find_next_free_cluster(disk, 0, &free_cluster, CO_MARK_LAST);
2505
 
2506
        if (err != ENOERR)
2507
        {
2508
            *len = 0;
2509
            return err;
2510
        }
2511
 
2512
        file->cluster = free_cluster;
2513
        fatfs_initpos(disk, file, pos);
2514
    }
2515
 
2516
    return write_data(disk, data, len, pos);
2517
}
2518
 
2519
// -------------------------------------------------------------------------
2520
// Support routines
2521
// These enable the definition of local versions of certain routines
2522
// if the given packages are not present.
2523
 
2524
#ifndef CYGPKG_LIBC_I18N
2525
 
2526
__externC int
2527
toupper( int c )
2528
{
2529
    return (('a' <= c) && (c <= 'z')) ? c - 'a' + 'A' : c ;
2530
}
2531
 
2532
#endif
2533
 
2534
#ifndef CYGFUN_LIBC_STRING_BSD_FUNCS
2535
 
2536
__externC int
2537
strcasecmp( const char *s1, const char *s2 )
2538
{
2539
    int ret;
2540
    CYG_REPORT_FUNCNAMETYPE( "strcasecmp", "returning %d" );
2541
    CYG_REPORT_FUNCARG2( "s1=%08x, s2=%08x", s1, s2 );
2542
 
2543
    CYG_CHECK_DATA_PTR( s1, "s1 is not a valid pointer!" );
2544
    CYG_CHECK_DATA_PTR( s2, "s2 is not a valid pointer!" );
2545
 
2546
    while (*s1 != '\0' && toupper(*s1) == toupper(*s2))
2547
    {
2548
        s1++;
2549
        s2++;
2550
    }
2551
 
2552
    ret = toupper(*(unsigned char *) s1) - toupper(*(unsigned char *) s2);
2553
    CYG_REPORT_RETVAL( ret );
2554
    return ret;
2555
}
2556
 
2557
__externC int
2558
strncasecmp( const char *s1, const char *s2, size_t n )
2559
{
2560
    int ret;
2561
    CYG_REPORT_FUNCNAMETYPE( "strncasecmp", "returning %d" );
2562
    CYG_REPORT_FUNCARG3( "s1=%08x, s2=%08x, n=%d", s1, s2, n );
2563
 
2564
    if (n == 0)
2565
    {
2566
        CYG_REPORT_RETVAL(0);
2567
        return 0;
2568
    }
2569
 
2570
    CYG_CHECK_DATA_PTR( s1, "s1 is not a valid pointer!" );
2571
    CYG_CHECK_DATA_PTR( s2, "s2 is not a valid pointer!" );
2572
 
2573
    while (n-- != 0 && toupper(*s1) == toupper(*s2))
2574
    {
2575
        if (n == 0 || *s1 == '\0' || *s2 == '\0')
2576
            break;
2577
        s1++;
2578
        s2++;
2579
    }
2580
 
2581
    ret = toupper(*(unsigned char *) s1) - toupper(*(unsigned char *) s2);
2582
    CYG_REPORT_RETVAL( ret );
2583
    return ret;
2584
}
2585
 
2586
#endif
2587
 
2588
// -------------------------------------------------------------------------
2589
// EOF fatfs_supp.c

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.