1 //==========================================================================
5 // FAT file system support functions
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.
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.
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
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.
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.
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.
36 // -------------------------------------------
37 //####ECOSGPLCOPYRIGHTEND####
38 //==========================================================================
39 //#####DESCRIPTIONBEGIN####
41 // Author(s): Savin Zlobec <savin@elatec.si>
44 //####DESCRIPTIONEND####
46 //==========================================================================
48 #include <pkgconf/fs_fat.h>
49 #include <pkgconf/infra.h>
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>
59 #include <sys/types.h>
64 //==========================================================================
65 // FAT defines & macros
67 // -------------------------------------------------------------------------
68 // FAT dir entry attributes macros
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))
77 #define DENTRY_IS_DELETED(_dentry_) \
78 (0xE5 == (cyg_uint8)((_dentry_)->name[0]))
80 #define DENTRY_IS_ZERO(_dentry_) \
81 (0x00 == (cyg_uint8)((_dentry_)->name[0]))
83 // -------------------------------------------------------------------------
84 // FAT disk data access macros
86 // FIXME: support big endian machines!
88 #define GET_BYTE(_data_, _var_, _off_) \
89 (_var_ = *( ((cyg_uint8 *)_data_) + (_off_) ) )
91 #define GET_WORD(_data_, _var_, _off_) \
92 (_var_ = *( ((cyg_uint8 *)_data_) + (_off_) ) | \
93 *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) << 8)
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)
101 #define GET_BYTES(_data_, _var_, _size_, _off_) \
102 memcpy((void *)(_var_), (void*)(((cyg_uint8 *)_data_)+(_off_)),_size_)
104 #define SET_BYTE(_data_, _val_, _off_) \
105 (*( ((cyg_uint8 *)_data_) + (_off_) ) = _val_)
107 #define SET_WORD(_data_, _val_, _off_) \
109 *( ((cyg_uint8 *)_data_) + (_off_) ) = _val_ & 0xFF; \
110 *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) = (_val_ >> 8) & 0xFF; \
113 #define SET_DWORD(_data_, _val_, _off_) \
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; \
121 #define SET_BYTES(_data_, _var_, _size_, _off_) \
122 memcpy((void *)(((cyg_uint8 *)_data_)+(_off_)), (void *)(_var_), _size_)
124 // -------------------------------------------------------------------------
125 // FAT table entries types
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
133 // -------------------------------------------------------------------------
134 // FAT table structures size
136 #define DENTRY_SIZE 0x20 // Dir entry size
138 // -------------------------------------------------------------------------
139 // Time & date defines
141 #define JD_1_JAN_1970 2440588 // 1 Jan 1970 in Julian day number
143 // -------------------------------------------------------------------------
144 // Code tracing defines
146 #ifdef FATFS_TRACE_DIR_ENTRY
152 #ifdef FATFS_TRACE_CLUSTER
158 #ifdef FATFS_TRACE_DATA
164 //==========================================================================
167 // -------------------------------------------------------------------------
168 // FAT table boot record structure
170 typedef struct fat_boot_record_s
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)
189 // FAT32 specific fields
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
199 // Fields with different locations on FAT12/16 and FAT32
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
210 // -------------------------------------------------------------------------
211 // FAT dir entry structure
213 typedef struct fat_raw_dir_entry_s
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;
230 // -------------------------------------------------------------------------
233 typedef enum cluster_opts_e
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
241 //==========================================================================
244 // -------------------------------------------------------------------------
246 // Gets the log2 of given value or returns 0 if value is not a power of 2.
249 get_val_log2(cyg_uint32 val)
262 if (i != 1) return 0;
266 // -------------------------------------------------------------------------
267 // cluster_to_block_pos()
268 // Converts cluster position to blib block position.
271 cluster_to_block_pos(fatfs_disk_t *disk,
273 cyg_uint32 cluster_pos,
275 cyg_uint32 *block_pos)
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);
280 *block = (cluster - 2) << (disk->cluster_size_log2 - block_size_log2);
282 *block_pos = disk->fat_data_pos + cluster_pos;
284 if (*block_pos > block_size)
286 *block += *block_pos >> block_size_log2;
287 *block_pos = *block_pos & (block_size - 1);
291 // -------------------------------------------------------------------------
293 // Writes data to disk.
295 static __inline__ int
296 disk_write(fatfs_disk_t *disk,
301 return cyg_blib_write(&disk->blib, buf, len, 0, pos);
304 // -------------------------------------------------------------------------
306 // Reads data from disk.
308 static __inline__ int
309 disk_read(fatfs_disk_t *disk,
314 return cyg_blib_read(&disk->blib, buf, len, 0, pos);
317 // -------------------------------------------------------------------------
318 // disk_cluster_write()
319 // Writes data to disk at specified cluster position.
321 static __inline__ int
322 disk_cluster_write(fatfs_disk_t *disk,
326 cyg_uint32 cluster_pos)
328 cyg_uint32 block, block_pos;
330 cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
332 return cyg_blib_write(&disk->blib, buf, len, block, block_pos);
335 // -------------------------------------------------------------------------
336 // disk_cluster_read()
337 // Reads data from disk at specified cluster position.
339 static __inline__ int
340 disk_cluster_read(fatfs_disk_t *disk,
344 cyg_uint32 cluster_pos)
346 cyg_uint32 block, block_pos;
348 cluster_to_block_pos(disk, cluster, cluster_pos, &block, &block_pos);
350 return cyg_blib_read(&disk->blib, buf, len, block, block_pos);
353 // -------------------------------------------------------------------------
355 // Converts juilan days into gregorian date.
358 jdays_to_gdate(cyg_uint32 jd, int *day, int *month, int *year)
360 cyg_uint32 l, n, i, j;
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;
368 *day = l - (2447 * j) / 80;
371 *month = j + 2 - (12 * l);
372 *year = 100 * (n - 49) + i + l;
375 // -------------------------------------------------------------------------
377 // Converts gregorian date to juilan days.
380 gdate_to_jdays(int day, int month, int year, cyg_uint32 *jd)
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;
387 // -------------------------------------------------------------------------
389 // Converts unix timestamp to dos time and date.
392 date_unix2dos(time_t unix_timestamp,
393 cyg_uint16 *dos_time,
394 cyg_uint16 *dos_date)
397 cyg_uint16 dtime, ddate;
399 int day, month, year;
401 hour = (unix_timestamp / 3600) % 24;
402 min = (unix_timestamp / 60) % 60;
403 sec = unix_timestamp % 60;
405 jd = JD_1_JAN_1970 + unix_timestamp / (3600 * 24);
406 jdays_to_gdate(jd, &day, &month, &year);
408 CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
409 unix_timestamp, hour, min, sec, year, month, day);
414 dtime = (hour << 11) | (min << 5) | (sec >> 1);
415 ddate = ((year - 1980) << 9) | (month << 5) | day;
417 CYG_TRACE2(TDE, "dos time=%d date=%d", dtime, ddate);
419 if (NULL != dos_time) *dos_time = dtime;
420 if (NULL != dos_date) *dos_date = ddate;
423 // -------------------------------------------------------------------------
425 // Converts dos time and date to unix timestamp.
428 date_dos2unix(cyg_uint16 dos_time,
430 time_t *unix_timestamp)
434 int day, month, year;
436 sec = (dos_time & ((1<<5)-1)) * 2;
438 min = (dos_time & ((1<<6)-1));
442 day = (dos_date & ((1<<5)-1));
444 month = (dos_date & ((1<<4)-1));
446 year = dos_date + 1980;
448 gdate_to_jdays(day, month, year, &ts);
451 ts = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600);
453 *unix_timestamp = ts;
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);
460 //==========================================================================
461 // FAT boot record functions
465 // -------------------------------------------------------------------------
466 // print_boot_record()
467 // Prints FAT boot record.
470 print_boot_record(fat_boot_record_t* fbr)
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);
487 if (0 == fbr->sec_per_fat)
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);
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]);
507 // -------------------------------------------------------------------------
508 // read_boot_record()
509 // Reads FAT boot record from disk.
512 read_boot_record(fatfs_disk_t *disk, fat_boot_record_t *fbr)
514 cyg_uint8 data[0x5A];
519 err = disk_read(disk, (void*)data, &len, 0);
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);
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)
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);
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);
565 // Read the end marker
567 err = disk_read(disk, (void*)data, &len, 0x1FE);
571 GET_BYTES(data, fbr->exe_marker, 2, 0);
573 // Zero terminate strings
574 fbr->oem_name[8] = '\0';
575 fbr->vol_name[11] = '\0';
576 fbr->fat_name[8] = '\0';
579 print_boot_record(fbr);
585 //==========================================================================
586 // FAT table entry functions
588 // -------------------------------------------------------------------------
590 // Reads FAT table entry from disk.
593 read_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
596 cyg_uint32 pos, num3;
601 switch (disk->fat_type)
605 pos = disk->fat_tbl_pos + (num3 >> 1);
608 err = disk_read(disk, (void*)data, &len, pos);
612 GET_WORD(data, e, 0x00);
614 if (0 == (num3 & 1)) *entry = e & 0x0FFF;
615 else *entry = (e >> 4) & 0x0FFF;
620 pos = disk->fat_tbl_pos + (num << 1);
623 err = disk_read(disk, (void*)data, &len, pos);
627 GET_WORD(data, e, 0x00);
633 pos = disk->fat_tbl_pos + (num << 2);
636 err = disk_read(disk, (void*)data, &len, pos);
640 GET_DWORD(data, e, 0x00);
641 *entry = e & 0x0FFFFFFF;
646 CYG_ASSERT(false, "Unknown FAT type");
651 // -------------------------------------------------------------------------
653 // Writes FAT table entry to disk (to all copies of FAT).
656 write_tentry(fatfs_disk_t *disk, cyg_uint32 num, cyg_uint32 *entry)
659 cyg_uint32 pos=0, num3;
665 switch (disk->fat_type)
669 pos = disk->fat_tbl_pos + (num3 >> 1);
672 err = disk_read(disk, (void*)data, &len, pos);
676 GET_WORD(data, e, 0x00);
678 if (0 == (num3 & 1)) e = (e & 0xF000) | (*entry & 0x0FFF);
679 else e = (e & 0x000F) | ((*entry & 0x0FFF) << 4);
681 SET_WORD(data, e, 0x00);
686 pos = disk->fat_tbl_pos + (num << 1);
690 SET_WORD(data, e, 0x00);
695 pos = disk->fat_tbl_pos + (num << 2);
698 err = disk_read(disk, (void*)data, &len, pos);
702 GET_DWORD(data, e, 0x00);
704 e = (e & 0xF0000000) | *entry;
706 SET_DWORD(data, e, 0x00);
711 CYG_ASSERT(false, "Unknown FAT type");
714 for (i = 0; i < disk->fat_tbls_num; i++)
716 err = disk_write(disk, (void*)data, &len, pos);
720 pos += disk->fat_tbl_size;
726 // -------------------------------------------------------------------------
728 // Gets the type of FAT table entry.
731 get_tentry_type(fatfs_disk_t *disk, cyg_uint32 entry)
735 switch (disk->fat_type)
740 if (0x0000 == entry) type = TENTRY_FREE;
741 else type = TENTRY_REGULAR;
743 else if (entry >= 0x0FF8) type = TENTRY_LAST;
744 else if (0x0FF7 == entry) type = TENTRY_BAD;
745 else type = TENTRY_RESERVED;
752 if (0x0000 == entry) type = TENTRY_FREE;
753 else type = TENTRY_REGULAR;
755 else if (entry >= 0xFFF8) type = TENTRY_LAST;
756 else if (0xFFF7 == entry) type = TENTRY_BAD;
757 else type = TENTRY_RESERVED;
763 if (entry < 0x0FFFFFF0)
765 if (0x00000000 == entry) type = TENTRY_FREE;
766 else type = TENTRY_REGULAR;
768 else if (entry >= 0x0FFFFFF8) type = TENTRY_LAST;
769 else if (0x0FFFFFF7 == entry) type = TENTRY_BAD;
770 else type = TENTRY_RESERVED;
775 CYG_ASSERT(false, "Unknown FAT type");
776 type = TENTRY_BAD; // least likely to cause damage
781 // -------------------------------------------------------------------------
783 // Sets the type of FAT table entry.
786 set_tentry_type(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
788 switch (disk->fat_type)
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;
798 CYG_ASSERT(false, "Unknown tentry type");
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;
810 CYG_ASSERT(false, "Unknown tentry type");
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;
822 CYG_ASSERT(false, "Unknown tentry type");
827 CYG_ASSERT(false, "Unknown FAT type");
831 // -------------------------------------------------------------------------
832 // get_tentry_next_cluster()
833 // Gets the the next file cluster number from FAT table entry.
835 static __inline__ cyg_uint32
836 get_tentry_next_cluster(fatfs_disk_t *disk, cyg_uint32 entry)
841 // -------------------------------------------------------------------------
842 // set_tentry_next_cluster()
843 // Sets the the next cluster number to FAT table entry.
845 static __inline__ void
846 set_tentry_next_cluster(fatfs_disk_t *disk,
848 cyg_uint32 next_cluster)
850 *entry = next_cluster;
853 //==========================================================================
854 // FAT cluster functions
856 // -------------------------------------------------------------------------
858 // Erases cluster (fills with 0x00).
861 erase_cluster(fatfs_disk_t *disk, cyg_uint32 cluster)
870 memset((void*)data, 0x00, len);
872 CYG_TRACE1(TCL, "erasing cluster=%d", cluster);
874 for (i = 0; i < (disk->cluster_size >> 5); i++)
876 err = disk_cluster_write(disk, (void*)data, &len, cluster, pos);
886 // -------------------------------------------------------------------------
888 // Marks cluster (sets the cluster's FAT table entry to given type).
891 mark_cluster(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 type)
895 set_tentry_type(disk, &tentry, type);
896 return write_tentry(disk, cluster, &tentry);
899 // -------------------------------------------------------------------------
901 // Links two clusters.
904 link_cluster(fatfs_disk_t *disk, cyg_uint32 cluster1, cyg_uint32 cluster2)
908 set_tentry_next_cluster(disk, &tentry, cluster2);
909 return write_tentry(disk, cluster1, &tentry);
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.
920 find_next_free_cluster(fatfs_disk_t *disk,
921 cyg_uint32 start_cluster,
922 cyg_uint32 *free_cluster,
925 cyg_uint32 c, tentry;
928 if (start_cluster < 2) c = 2;
929 else c = start_cluster + 1;
933 CYG_TRACE1(TCL, "starting at cluster=%d", c);
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)
939 // Check for end of FAT
940 if (c >= disk->fat_tbl_nents)
943 if (c >= start_cluster)
947 err = read_tentry(disk, c, &tentry);
951 if (TENTRY_FREE == get_tentry_type(disk, tentry))
953 CYG_TRACE1(TCL, "found free cluster=%d", c);
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);
967 // No free clusters found
969 CYG_TRACE0(TCL, "!!! no free clusters found");
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.
980 find_and_append_cluster(fatfs_disk_t *disk,
982 cyg_uint32 *new_cluster,
985 cyg_uint32 free_cluster;
988 err = find_next_free_cluster(disk, cluster,
989 &free_cluster, opts | CO_MARK_LAST);
993 err = link_cluster(disk, cluster, free_cluster);
997 *new_cluster = free_cluster;
999 CYG_TRACE2(TCL, "appending new cluster=%d to cluster=%d",
1000 free_cluster, cluster);
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
1012 find_nth_cluster0(fatfs_disk_t *disk,
1013 fatfs_data_pos_t *pos,
1016 cyg_uint32 cluster, cluster_snum;
1019 if (pos->cluster_snum == n)
1022 cluster = pos->cluster;
1023 cluster_snum = pos->cluster_snum;
1025 CYG_TRACE4(TCL, "cluster=%d snum=%d n=%d n_to_search=%d",
1026 cluster, cluster_snum, n, n-cluster_snum);
1028 // Adjust the number of clusters that should be
1029 // walked according to the given position
1032 // Walk the cluster chain for n clusters or until last cluster
1037 err = read_tentry(disk, cluster, &tentry);
1041 switch (get_tentry_type(disk, tentry))
1043 case TENTRY_REGULAR:
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
1052 // Inconsistant FAT table state !!!
1053 CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x n=%d",
1058 cluster = get_tentry_next_cluster(disk, tentry);
1064 pos->cluster = cluster;
1065 pos->cluster_snum = cluster_snum;
1067 CYG_TRACE2(TCL, "nth cluster=%d snum=%d", cluster, cluster_snum);
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.
1080 find_nth_cluster(fatfs_disk_t *disk,
1081 fatfs_data_pos_t *pos,
1083 cluster_opts_t opts)
1088 err = find_nth_cluster0(disk, pos, n);
1090 // EEOF meens that the cluster chain ended early
1091 if ((err != EEOF) || !(opts & CO_EXTEND))
1094 // Check if one cluster short
1095 if (pos->cluster_snum == (n - 1))
1097 // Extend the chain for one cluster
1098 cyg_uint32 new_cluster;
1100 // Append new cluster to the end of chain
1101 err = find_and_append_cluster(disk, pos->cluster, &new_cluster, opts);
1106 pos->cluster = new_cluster;
1107 pos->cluster_snum += 1;
1108 pos->cluster_pos = 0;
1110 CYG_TRACE1(TCL, "appended new cluster=%d", new_cluster);
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.
1123 get_next_cluster(fatfs_disk_t *disk,
1124 fatfs_data_pos_t *pos,
1125 cluster_opts_t opts)
1129 err = find_nth_cluster(disk, pos, pos->cluster_snum + 1, opts);
1133 // Reset inside cluster position
1134 pos->cluster_pos = 0;
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.
1146 get_position_from_off(fatfs_disk_t *disk,
1147 cyg_uint32 first_cluster,
1149 fatfs_data_pos_t *pos,
1150 cluster_opts_t opts)
1152 fatfs_data_pos_t new_pos;
1156 // Position inside the cluster
1157 new_pos.cluster_pos = offset & (disk->cluster_size - 1);
1159 // Cluster seq number to be searched for
1160 n = offset >> disk->cluster_size_log2;
1162 if (n < pos->cluster_snum)
1164 // Start searching from first cluster
1165 new_pos.cluster = first_cluster;
1166 new_pos.cluster_snum = 0;
1170 // Start searching from the current position
1171 new_pos.cluster = pos->cluster;
1172 new_pos.cluster_snum = pos->cluster_snum;
1175 err = find_nth_cluster(disk, &new_pos, n, opts);
1177 // Err could be EEOF wich means that the given
1178 // offset if out of given file (cluster chain)
1181 new_pos.cluster_pos = disk->cluster_size;
1188 // -------------------------------------------------------------------------
1189 // free_cluster_chain()
1190 // Marks all clusters FREE from given cluster to the last cluster in chain.
1193 free_cluster_chain(fatfs_disk_t *disk, cyg_uint32 start_cluster)
1195 cyg_uint32 c, next_c, tentry;
1199 CYG_TRACE1(TCL, "start cluster=%d", start_cluster);
1201 c = next_c = start_cluster;
1205 err = read_tentry(disk, c, &tentry);
1209 switch (get_tentry_type(disk, tentry))
1212 // Last cluster in chain
1215 case TENTRY_REGULAR:
1216 // Get next cluster in chain
1217 next_c = get_tentry_next_cluster(disk, tentry);
1220 CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x c=%d",
1225 // Set the current tentry to FREE
1226 set_tentry_type(disk, &tentry, TENTRY_FREE);
1227 err = write_tentry(disk, c, &tentry);
1231 // Next cluster in chain
1235 CYG_TRACE1(TCL, "last cluster=%d", c);
1240 //==========================================================================
1241 // FAT dir entry functions
1243 // -------------------------------------------------------------------------
1244 // print_raw_dentry()
1245 // Prints FAT directory entry.
1249 print_raw_dentry(fat_raw_dir_entry_t* dentry)
1251 if (DENTRY_IS_DELETED(dentry))
1252 diag_printf("FAT: FDE name: '?%.7s'\n", &dentry->name[1]);
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);
1273 // -------------------------------------------------------------------------
1274 // read_raw_dentry()
1275 // Reads dir entry from disk.
1278 read_raw_dentry(fatfs_disk_t *disk,
1279 fatfs_data_pos_t *pos,
1280 fat_raw_dir_entry_t *dentry)
1282 cyg_uint8 data[DENTRY_SIZE];
1286 CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
1287 pos->cluster, pos->cluster_snum, pos->cluster_pos);
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);
1296 err = disk_cluster_read(disk, (void*)data, &len,
1297 pos->cluster, pos->cluster_pos);
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);
1315 // Zero terminate strings
1316 dentry->name[8] = '\0';
1317 dentry->ext[3] = '\0';
1320 print_raw_dentry(dentry);
1326 // -------------------------------------------------------------------------
1327 // write_raw_dentry()
1328 // Writes raw dir entry to disk.
1331 write_raw_dentry(fatfs_disk_t *disk,
1332 fatfs_data_pos_t *pos,
1333 fat_raw_dir_entry_t *dentry)
1335 cyg_uint8 data[DENTRY_SIZE];
1339 CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
1340 pos->cluster, pos->cluster_snum, pos->cluster_pos);
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);
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);
1363 err = disk_cluster_write(disk, (void*)data, &len,
1364 pos->cluster, pos->cluster_pos);
1369 print_raw_dentry(dentry);
1375 // -------------------------------------------------------------------------
1376 // raw_dentry_set_deleted()
1377 // Sets the dentry filename first char to 0xE5 (ie deleted).
1379 static __inline__ void
1380 raw_dentry_set_deleted(fatfs_disk_t *disk, fat_raw_dir_entry_t *dentry)
1382 dentry->name[0] = 0xE5;
1385 // -------------------------------------------------------------------------
1386 // get_raw_dentry_filename()
1387 // Gets the filename from given dir entry.
1390 get_raw_dentry_filename(fat_raw_dir_entry_t *dentry, char *name)
1393 char *cptr = dentry->name;
1396 while (*cptr != ' ' && i < 8)
1398 *cname++ = *cptr++; i++;
1404 *cname++ = '.'; i = 0;
1405 while (*cptr != ' ' && i < 3)
1407 *cname++ = *cptr++; i++;
1412 CYG_TRACE3(TDE, "dos name='%s' dos ext='%s' filename='%s'",
1413 dentry->name, dentry->ext, name);
1416 // -------------------------------------------------------------------------
1417 // set_raw_dentry_filename()
1418 // Sets the filename of given dir entry.
1421 set_raw_dentry_filename(fat_raw_dir_entry_t *dentry,
1429 // Special case check
1432 if ('\0' == name[1])
1434 strcpy(dentry->name, ". ");
1435 strcpy(dentry->ext, " ");
1438 else if ('.' == name[1] && '\0' == name[2])
1440 strcpy(dentry->name, ".. ");
1441 strcpy(dentry->ext, " ");
1451 cptr = dentry->name;
1452 for (i = 0; i < 8; i++)
1454 if (*cname != '.' && *cname != '\0' && nidx++ < namelen)
1455 *cptr++ = toupper(*cname++);
1461 while (*cname != '.' && *cname != '\0' && nidx++ < namelen)
1464 if ('.' == *cname && nidx++ < namelen)
1468 for (i = 0; i < 3; i++)
1470 if (*cname != '.' && *cname != '\0' && nidx++ < namelen)
1471 *cptr++ = toupper(*cname++);
1477 CYG_TRACE4(TDE, "filename='%s' namelen=%d dos name='%s' dos ext='%s'",
1478 name, namelen, dentry->name, dentry->ext);
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.
1487 read_next_raw_dentry(fatfs_disk_t *disk,
1488 fatfs_data_pos_t *pos,
1489 fat_raw_dir_entry_t *dentry)
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;
1500 // FAT12/16 root dir check
1501 if (0 == pos->cluster)
1503 if (pos->cluster_pos >= disk->fat_root_dir_size)
1508 // Change cluster if needed
1509 if (pos->cluster_pos >= disk->cluster_size)
1510 err = get_next_cluster(disk, pos, CO_NONE);
1516 err = read_raw_dentry(disk, pos, dentry);
1520 if (DENTRY_IS_ZERO(dentry))
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");
1528 else if (!DENTRY_IS_DELETED(dentry))
1531 CYG_TRACE3(TDE, "found new dentry at cluster=%d snum=%d pos=%d",
1532 pos->cluster, pos->cluster_snum, pos->cluster_pos);
1536 pos->cluster_pos += DENTRY_SIZE;
1539 // EEOF could be returned if there are no more entries in this
1540 // dir - this should be cought by the calling function
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.
1551 get_free_raw_dentry(fatfs_disk_t *disk,
1552 fatfs_data_pos_t *pos)
1554 fat_raw_dir_entry_t raw_dentry;
1555 fatfs_data_pos_t cpos;
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;
1565 CYG_TRACE3(TDE, "cluster=%d snum=%d pos=%d",
1566 pos->cluster, pos->cluster_snum, pos->cluster_pos);
1570 // FAT12/16 root dir check
1571 if (0 == cpos.cluster)
1573 if (cpos.cluster_pos >= disk->fat_root_dir_size)
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);
1586 err = read_raw_dentry(disk, &cpos, &raw_dentry);
1590 if (DENTRY_IS_DELETED(&raw_dentry))
1592 CYG_TRACE3(TDE, "deleted dentry at cluster=%d snum=%d pos=%d",
1593 cpos.cluster, cpos.cluster_snum, cpos.cluster_pos);
1598 else if (DENTRY_IS_ZERO(&raw_dentry))
1600 CYG_TRACE3(TDE, "zero dentry at cluster=%d snum=%d pos=%d",
1601 cpos.cluster, cpos.cluster_snum, cpos.cluster_pos);
1607 cpos.cluster_pos += DENTRY_SIZE;
1611 // -------------------------------------------------------------------------
1613 // Converts raw FAT dir entry to dir entry.
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)
1620 get_raw_dentry_filename(raw_dentry, dentry->filename);
1622 if (DENTRY_IS_DIR(raw_dentry))
1623 dentry->mode = __stat_mode_DIR;
1625 dentry->mode = __stat_mode_REG;
1627 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1628 dentry->attrib = raw_dentry->attr;
1629 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
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);
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;
1641 // -------------------------------------------------------------------------
1643 // Converts dir entry to raw FAT dir entry.
1646 dentry_to_raw(fatfs_dir_entry_t *dentry, fat_raw_dir_entry_t *raw_dentry)
1648 set_raw_dentry_filename(raw_dentry, dentry->filename, 0);
1650 if (__stat_mode_DIR == dentry->mode)
1651 raw_dentry->attr = S_FATFS_DIR;
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
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);
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;
1670 //==========================================================================
1671 // FAT data functions
1673 // -------------------------------------------------------------------------
1675 // Reads data from given position.
1678 read_data(fatfs_disk_t *disk,
1681 fatfs_data_pos_t *pos)
1683 cyg_uint8 *buf = (cyg_uint8 *) data;
1684 cyg_uint32 size = *len;
1687 CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d",
1688 *len, pos->cluster, pos->cluster_snum,
1695 // Check if we are still inside current cluster
1696 if (pos->cluster_pos >= disk->cluster_size)
1698 // Get next cluster of file
1699 err = get_next_cluster(disk, pos, CO_NONE);
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;
1710 CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d",
1711 csize, pos->cluster, pos->cluster_snum,
1714 err = disk_cluster_read(disk, (void*)buf, &csize,
1715 pos->cluster, pos->cluster_pos);
1719 // Adjust running variables
1722 pos->cluster_pos += csize;
1729 CYG_TRACE1(TDO, "total len=%d", *len);
1734 // -------------------------------------------------------------------------
1736 // Writes data to given position.
1739 write_data(fatfs_disk_t *disk,
1742 fatfs_data_pos_t *pos)
1744 cyg_uint8 *buf = (cyg_uint8 *) data;
1745 cyg_uint32 size = *len;
1748 CYG_TRACE4(TDO, "len=%d cluster=%d snum=%d pos=%d",
1749 *len, pos->cluster, pos->cluster_snum,
1756 // Check if we are still inside current cluster
1757 if (pos->cluster_pos >= disk->cluster_size)
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);
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;
1772 CYG_TRACE4(TDO, "-- len=%d cluster=%d snum=%d pos=%d",
1773 csize, pos->cluster, pos->cluster_snum,
1776 err = disk_cluster_write(disk, (void*)buf, &csize,
1777 pos->cluster, pos->cluster_pos);
1781 // Adjust running variables
1784 pos->cluster_pos += csize;
1791 CYG_TRACE1(TDO, "total len=%d", *len);
1796 //==========================================================================
1799 // -------------------------------------------------------------------------
1801 // Initializes attributes of a new dir entry.
1804 init_dir_entry(fatfs_dir_entry_t *dentry,
1808 cyg_uint32 parent_cluster,
1809 cyg_uint32 first_cluster,
1810 fatfs_data_pos_t *pos)
1815 strncpy(dentry->filename, name, namelen);
1816 dentry->filename[namelen] = '\0';
1818 dentry->mode = mode;
1820 #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES
1821 if (S_ISDIR(dentry->mode))
1822 dentry->attrib = S_FATFS_DIR;
1824 dentry->attrib = S_FATFS_ARCHIVE;
1825 #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES
1829 dentry->mtime = cyg_timestamp();
1831 dentry->priv_data = 0;
1833 dentry->cluster = first_cluster;
1834 dentry->parent_cluster = parent_cluster;
1835 dentry->disk_pos = *pos;
1838 // -------------------------------------------------------------------------
1839 // is_root_dir_entry()
1840 // Check if the given dir entry is the root dir entry.
1842 static __inline__ bool
1843 is_root_dir_entry(fatfs_dir_entry_t *dentry)
1845 return ('\0' == dentry->filename[0] && 0 == dentry->cluster);
1848 //==========================================================================
1849 //==========================================================================
1850 // Exported functions
1852 // -------------------------------------------------------------------------
1857 fatfs_init(fatfs_disk_t *disk)
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;
1864 CYG_CHECK_DATA_PTRC(disk);
1866 err = read_boot_record(disk, &boot_rec);
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])
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);
1882 // Sector and cluster size should always be a power of 2
1883 if (0 == disk->sector_size_log2 || 0 == disk->cluster_size_log2)
1886 // Determine number of sectors
1887 if (boot_rec.sec_num_32 != 0)
1888 sec_num = boot_rec.sec_num_32;
1890 sec_num = boot_rec.sec_num;
1892 // Determine number of sectors per fat
1893 if (boot_rec.sec_per_fat != 0)
1894 sec_per_fat = boot_rec.sec_per_fat;
1896 sec_per_fat = boot_rec.sec_per_fat_32;
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;
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);
1906 // Number of data clusters
1907 data_clu_num = data_sec_num / boot_rec.sec_per_clu;
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;
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;
1921 disk->fat_type = FATFS_FAT32;
1923 // Determine root dir and data positions
1924 if (FATFS_FAT32 != disk->fat_type)
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;
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;
1947 // -------------------------------------------------------------------------
1948 // fatfs_get_root_dir_entry()
1949 // Gets root dir entry.
1952 fatfs_get_root_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
1954 CYG_CHECK_DATA_PTRC(disk);
1955 CYG_CHECK_DATA_PTRC(dentry);
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;
1965 dentry->filename[0] = '\0';
1966 dentry->cluster = 0;
1967 dentry->parent_cluster = 0;
1969 dentry->disk_pos.cluster = 0;
1970 dentry->disk_pos.cluster_snum = 0;
1971 dentry->disk_pos.cluster_pos = 0;
1974 // -------------------------------------------------------------------------
1975 // fatfs_get_disk_usage()
1979 fatfs_get_disk_usage(fatfs_disk_t *disk,
1980 cyg_uint32 *total_clusters,
1981 cyg_uint32 *free_clusters)
1983 cyg_uint32 c, nfree, tentry;
1987 for (c = 2; c < disk->fat_tbl_nents; c++)
1989 err = read_tentry(disk, c, &tentry);
1993 if (TENTRY_FREE == get_tentry_type(disk, tentry))
1997 *total_clusters = disk->fat_tbl_nents - 2;
1998 *free_clusters = nfree;
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.
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)
2017 fat_raw_dir_entry_t raw_dentry;
2020 CYG_CHECK_DATA_PTRC(disk);
2021 CYG_CHECK_DATA_PTRC(dir);
2022 CYG_CHECK_DATA_PTRC(pos);
2023 CYG_CHECK_DATA_PTRC(dentry);
2025 err = read_next_raw_dentry(disk, pos, &raw_dentry);
2029 raw_to_dentry(&raw_dentry, pos, dentry);
2030 dentry->parent_cluster = dir->cluster;
2032 // Increment position for next call
2033 pos->cluster_pos += DENTRY_SIZE;
2038 // -------------------------------------------------------------------------
2040 // Initializes position to the start of the given file.
2043 fatfs_initpos(fatfs_disk_t *disk,
2044 fatfs_dir_entry_t *file,
2045 fatfs_data_pos_t *pos)
2047 CYG_CHECK_DATA_PTRC(disk);
2048 CYG_CHECK_DATA_PTRC(file);
2049 CYG_CHECK_DATA_PTRC(pos);
2051 pos->cluster = file->cluster;
2052 pos->cluster_snum = 0;
2053 pos->cluster_pos = 0;
2058 // -------------------------------------------------------------------------
2060 // Sets the file position from offset.
2063 fatfs_setpos(fatfs_disk_t *disk,
2064 fatfs_dir_entry_t *file,
2065 fatfs_data_pos_t *pos,
2070 CYG_CHECK_DATA_PTRC(disk);
2071 CYG_CHECK_DATA_PTRC(file);
2072 CYG_CHECK_DATA_PTRC(pos);
2074 err = get_position_from_off(disk, file->cluster, offset, pos, CO_NONE);
2076 if (EEOF == err && offset == file->size)
2082 // -------------------------------------------------------------------------
2084 // Gets the file offset from position.
2087 fatfs_getpos(fatfs_disk_t *disk,
2088 fatfs_dir_entry_t *file,
2089 fatfs_data_pos_t *pos)
2091 CYG_CHECK_DATA_PTRC(disk);
2092 CYG_CHECK_DATA_PTRC(file);
2093 CYG_CHECK_DATA_PTRC(pos);
2095 return (pos->cluster_snum << disk->cluster_size_log2) + pos->cluster_pos;
2098 // -------------------------------------------------------------------------
2099 // fatfs_write_dir_entry()
2100 // Writes dir entry to disk.
2103 fatfs_write_dir_entry(fatfs_disk_t *disk, fatfs_dir_entry_t *dentry)
2105 fat_raw_dir_entry_t raw_dentry;
2108 CYG_CHECK_DATA_PTRC(disk);
2109 CYG_CHECK_DATA_PTRC(dentry);
2111 dentry_to_raw(dentry, &raw_dentry);
2112 err = write_raw_dentry(disk, &dentry->disk_pos, &raw_dentry);
2116 // -------------------------------------------------------------------------
2117 // fatfs_delete_file()
2118 // Marks dir entry as deleted and frees its cluster chain.
2121 fatfs_delete_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file)
2123 fat_raw_dir_entry_t raw_dentry;
2126 CYG_CHECK_DATA_PTRC(disk);
2127 CYG_CHECK_DATA_PTRC(file);
2129 if (is_root_dir_entry(file))
2132 CYG_TRACE1(TDE, "filename='%s'", file->filename);
2134 dentry_to_raw(file, &raw_dentry);
2136 // Check if we are about to delete a directory
2137 if (DENTRY_IS_DIR(&raw_dentry))
2139 fat_raw_dir_entry_t raw_cdentry;
2140 fatfs_data_pos_t pos;
2143 fatfs_initpos(disk, file, &pos);
2145 CYG_TRACE0(TDE, "got directory");
2147 // Count number of entries in this dir
2151 err = read_next_raw_dentry(disk, &pos, &raw_cdentry);
2155 else if (err != ENOERR)
2158 pos.cluster_pos += DENTRY_SIZE;
2161 CYG_TRACE1(TDE, "child count=%d", i);
2163 // Check if the dir is empty (except '.' and '..')
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);
2175 // -------------------------------------------------------------------------
2176 // fatfs_create_file()
2177 // Creates a new file.
2180 fatfs_create_file(fatfs_disk_t *disk,
2181 fatfs_dir_entry_t *dir,
2184 fatfs_dir_entry_t *dentry)
2186 fatfs_data_pos_t pos;
2189 CYG_CHECK_DATA_PTRC(disk);
2190 CYG_CHECK_DATA_PTRC(dir);
2191 CYG_CHECK_DATA_PTRC(name);
2192 CYG_CHECK_DATA_PTRC(dentry);
2194 CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename);
2196 fatfs_initpos(disk, dir, &pos);
2198 // Get free dir entry in parent dir
2199 err = get_free_raw_dentry(disk, &pos);
2203 // Create new file dir entry
2205 init_dir_entry(dentry,
2213 err = fatfs_write_dir_entry(disk, dentry);
2220 // -------------------------------------------------------------------------
2221 // fatfs_create_dir()
2222 // Creates a new directory.
2225 fatfs_create_dir(fatfs_disk_t *disk,
2226 fatfs_dir_entry_t *dir,
2229 fatfs_dir_entry_t *dentry)
2231 fatfs_dir_entry_t cdentry;
2232 fatfs_data_pos_t pos;
2233 cyg_uint32 free_cluster;
2236 CYG_CHECK_DATA_PTRC(disk);
2237 CYG_CHECK_DATA_PTRC(dir);
2238 CYG_CHECK_DATA_PTRC(name);
2239 CYG_CHECK_DATA_PTRC(dentry);
2241 CYG_TRACE2(TDE, "filename='%s' parent='%s'", name, dir->filename);
2244 err = find_next_free_cluster(disk,
2247 CO_MARK_LAST | CO_ERASE_NEW);
2251 fatfs_initpos(disk, dir, &pos);
2253 // Get free dir entry in parent dir
2254 err = get_free_raw_dentry(disk, &pos);
2258 // Create new dir entry
2260 init_dir_entry(dentry,
2268 err = fatfs_write_dir_entry(disk, dentry);
2272 // Create '.' and '..' dir entries
2274 fatfs_initpos(disk, dentry, &pos);
2276 CYG_TRACE0(TDE, "Creating '.' entry");
2278 init_dir_entry(&cdentry,
2286 err = fatfs_write_dir_entry(disk, &cdentry);
2290 pos.cluster_pos += DENTRY_SIZE;
2292 CYG_TRACE0(TDE, "Creating '..' entry");
2294 init_dir_entry(&cdentry,
2302 err = fatfs_write_dir_entry(disk, &cdentry);
2309 // -------------------------------------------------------------------------
2310 // fatfs_trunc_file()
2311 // Truncates a file to zero length.
2314 fatfs_trunc_file(fatfs_disk_t *disk, fatfs_dir_entry_t *file)
2318 CYG_CHECK_DATA_PTRC(disk);
2319 CYG_CHECK_DATA_PTRC(file);
2321 CYG_TRACE1(TDE, "file='%s'", file->filename);
2323 if (S_ISDIR(file->mode))
2326 if (0 == file->size)
2329 err = free_cluster_chain(disk, file->cluster);
2333 // Update file attributes
2338 file->atime = cyg_timestamp();
2340 return fatfs_write_dir_entry(disk, file);
2343 // -------------------------------------------------------------------------
2344 // fatfs_rename_file()
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,
2355 fat_raw_dir_entry_t raw_dentry;
2356 fatfs_data_pos_t new_pos;
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);
2365 if (is_root_dir_entry(target))
2368 strncpy(target->filename, name, namelen);
2369 target->filename[namelen] = '\0';
2371 // Moving around in same dir
2375 CYG_TRACE0(TDE, "same dir");
2376 return fatfs_write_dir_entry(disk, target);
2379 CYG_TRACE0(TDE, "different dirs");
2381 // Moving around in different dirs
2383 fatfs_initpos(disk, dir2, &new_pos);
2385 CYG_TRACE0(TDE, "writing to new dir");
2387 // Get free dir entry in target dir
2389 err = get_free_raw_dentry(disk, &new_pos);
2393 // Write file dentry to new location
2395 dentry_to_raw(target, &raw_dentry);
2396 err = write_raw_dentry(disk, &new_pos, &raw_dentry);
2400 CYG_TRACE0(TDE, "deleting from old dir");
2402 // Delete dentry at old location
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);
2412 // Set file new position and parent cluster
2414 target->disk_pos = new_pos;
2415 target->parent_cluster = dir2->cluster;
2417 // If we moved a directory, we also have to correct the '..' entry
2419 if ( S_ISDIR(target->mode) )
2421 fat_raw_dir_entry_t raw_cdentry;
2422 fatfs_data_pos_t pos;
2424 fatfs_initpos(disk, target, &pos);
2426 CYG_TRACE0(TDE, "moving directory - correcting '..' entry");
2430 err = read_next_raw_dentry(disk, &pos, &raw_cdentry);
2433 return EINVAL; // This dir doesn't have the '..' entry,
2434 // that means something is very wrong
2435 else if (err != ENOERR)
2438 if (0 == strncmp("..", raw_cdentry.name, 2))
2440 raw_cdentry.cluster = dir2->cluster & 0xFFFF;
2441 raw_cdentry.cluster_HI = dir2->cluster >> 16;
2442 err = write_raw_dentry(disk, &pos, &raw_cdentry);
2448 pos.cluster_pos += DENTRY_SIZE;
2455 // -------------------------------------------------------------------------
2456 // fatfs_read_data()
2457 // Reads data from disk.
2460 fatfs_read_data(fatfs_disk_t *disk,
2461 fatfs_dir_entry_t *file,
2462 fatfs_data_pos_t *pos,
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);
2472 return read_data(disk, data, len, pos);
2475 // -------------------------------------------------------------------------
2476 // fatfs_write_data()
2477 // Writes data to disk.
2480 fatfs_write_data(fatfs_disk_t *disk,
2481 fatfs_dir_entry_t *file,
2482 fatfs_data_pos_t *pos,
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);
2494 // Check if this file has a zero size and no first cluster
2496 if (0 == file->size && 0 == file->cluster)
2498 cyg_uint32 free_cluster;
2500 CYG_TRACE0(TDO, "new cluster for zero file");
2502 err = find_next_free_cluster(disk, 0, &free_cluster, CO_MARK_LAST);
2510 file->cluster = free_cluster;
2511 fatfs_initpos(disk, file, pos);
2514 return write_data(disk, data, len, pos);
2517 // -------------------------------------------------------------------------
2519 // These enable the definition of local versions of certain routines
2520 // if the given packages are not present.
2522 #ifndef CYGPKG_LIBC_I18N
2527 return (('a' <= c) && (c <= 'z')) ? c - 'a' + 'A' : c ;
2532 #ifndef CYGFUN_LIBC_STRING_BSD_FUNCS
2535 strcasecmp( const char *s1, const char *s2 )
2538 CYG_REPORT_FUNCNAMETYPE( "strcasecmp", "returning %d" );
2539 CYG_REPORT_FUNCARG2( "s1=%08x, s2=%08x", s1, s2 );
2541 CYG_CHECK_DATA_PTR( s1, "s1 is not a valid pointer!" );
2542 CYG_CHECK_DATA_PTR( s2, "s2 is not a valid pointer!" );
2544 while (*s1 != '\0' && toupper(*s1) == toupper(*s2))
2550 ret = toupper(*(unsigned char *) s1) - toupper(*(unsigned char *) s2);
2551 CYG_REPORT_RETVAL( ret );
2556 strncasecmp( const char *s1, const char *s2, size_t n )
2559 CYG_REPORT_FUNCNAMETYPE( "strncasecmp", "returning %d" );
2560 CYG_REPORT_FUNCARG3( "s1=%08x, s2=%08x, n=%d", s1, s2, n );
2564 CYG_REPORT_RETVAL(0);
2568 CYG_CHECK_DATA_PTR( s1, "s1 is not a valid pointer!" );
2569 CYG_CHECK_DATA_PTR( s2, "s2 is not a valid pointer!" );
2571 while (n-- != 0 && toupper(*s1) == toupper(*s2))
2573 if (n == 0 || *s1 == '\0' || *s2 == '\0')
2579 ret = toupper(*(unsigned char *) s1) - toupper(*(unsigned char *) s2);
2580 CYG_REPORT_RETVAL( ret );
2586 // -------------------------------------------------------------------------