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