📄 fatfs_supp.c
字号:
//==========================================================================
//
// fatfs_supp.c
//
// FAT file system support functions
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 2003 Savin Zlobec
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): savin
// Date: 2003-06-30
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/fs_fat.h>
#include <pkgconf/infra.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/cyg_trac.h>
#include <cyg/infra/diag.h>
#include <cyg/io/io.h>
#include <blib/blib.h>
#include <sys/types.h>
#include <ctype.h>
#include "fatfs.h"
//==========================================================================
// FAT defines & macros
// -------------------------------------------------------------------------
// FAT dir entry attributes
#define DENTRY_ATTR_RDONLY 0x01 // Read only
#define DENTRY_ATTR_HIDDEN 0x02 // Hidden
#define DENTRY_ATTR_SYSTEM 0x04 // System
#define DENTRY_ATTR_VOLUME 0x08 // Volume label
#define DENTRY_ATTR_DIR 0x10 // Subdirectory
#define DENTRY_ATTR_ARCHIVE 0x20 // Needs archiving
// -------------------------------------------------------------------------
// FAT dir entry attributes macros
#define DENTRY_IS_RDONLY(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_RDONLY)
#define DENTRY_IS_HIDDEN(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_HIDDEN)
#define DENTRY_IS_SYSTEM(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_SYSTEM)
#define DENTRY_IS_VOLUME(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_VOLUME)
#define DENTRY_IS_DIR(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_DIR)
#define DENTRY_IS_ARCHIVE(_dentry_) ((_dentry_)->attr & DENTRY_ATTR_ARCHIVE)
#define DENTRY_IS_DELETED(_dentry_) \ (0xE5 == (unsigned char)((_dentry_)->name[0]))
#define DENTRY_IS_ZERO(_dentry_) \ (0x00 == (unsigned char)((_dentry_)->name[0]))
// -------------------------------------------------------------------------
// FAT disk data access macros
// FIXME: support big endian machines!
#define GET_BYTE(_data_, _var_, _off_) \ (_var_ = *( ((cyg_uint8 *)_data_) + (_off_) ) )
#define GET_WORD(_data_, _var_, _off_) \ (_var_ = *( ((cyg_uint8 *)_data_) + (_off_) ) | \ *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) << 8)
#define GET_DWORD(_data_, _var_, _off_) \ (_var_ = *( ((cyg_uint8 *)_data_) + (_off_)) | \ *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) << 8 | \ *( ((cyg_uint8 *)_data_) + (_off_) + 2 ) << 16 | \ *( ((cyg_uint8 *)_data_) + (_off_) + 3 ) << 24)
#define GET_BYTES(_data_, _var_, _size_, _off_) \ memcpy((void *)(_var_), (void*)(((cyg_uint8 *)_data_)+(_off_)),_size_)
#define SET_BYTE(_data_, _val_, _off_) \ (*( ((cyg_uint8 *)_data_) + (_off_) ) = _val_)
#define SET_WORD(_data_, _val_, _off_) \ do { \ *( ((cyg_uint8 *)_data_) + (_off_) ) = _val_ & 0xFF; \ *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) = (_val_ >> 8) & 0xFF; \ } while (0)
#define SET_DWORD(_data_, _val_, _off_) \ do { \ *( ((cyg_uint8 *)_data_) + (_off_) ) = _val_ & 0xFF; \ *( ((cyg_uint8 *)_data_) + (_off_) + 1 ) = (_val_ >> 8) & 0xFF; \ *( ((cyg_uint8 *)_data_) + (_off_) + 2 ) = (_val_ >> 16) & 0xFF; \ *( ((cyg_uint8 *)_data_) + (_off_) + 3 ) = (_val_ >> 24) & 0xFF; \ } while (0)
#define SET_BYTES(_data_, _var_, _size_, _off_) \ memcpy((void *)(((cyg_uint8 *)_data_)+(_off_)), (void *)(_var_), _size_)
// -------------------------------------------------------------------------
// FAT table entries types
#define TENTRY_REGULAR 0 // Used when entry points to next file cluster
#define TENTRY_FREE 1 // Free cluster
#define TENTRY_LAST 2 // Last cluster of file
#define TENTRY_RESERVED 3 // Reserved cluster
#define TENTRY_BAD 4 // Bad cluster
// -------------------------------------------------------------------------
// FAT table structures size
#define DENTRY_SIZE 0x20 // Dir entry size
// -------------------------------------------------------------------------
// Time & date defines
#define JD_1_JAN_1970 2440588 // 1 Jan 1970 in Julian day number
// -------------------------------------------------------------------------
// Code tracing defines
#ifdef FATFS_TRACE_FAT_TABLE
# define TFT 1
#else
# define TFT 0
#endif
#ifdef FATFS_TRACE_DIR_ENTRY
# define TDE 1
#else
# define TDE 0
#endif
#ifdef FATFS_TRACE_CLUSTER
# define TCL 1
#else
# define TCL 0
#endif
#ifdef FATFS_TRACE_DATA
# define TDO 1
#else
# define TDO 0
#endif
// -------------------------------------------------------------------------
// FAT table entry type strings
#if TFT
static const char *tentry_type_name[5] = {
"REGULAR", "FREE", "LAST", "RESERVED", "BAD"
};
#endif
//==========================================================================
// FAT structures
// -------------------------------------------------------------------------
// FAT table boot record structure
typedef struct fat_boot_record_s
{
cyg_uint16 jump; // 00h : Jump code
// cyg_uint8 jump0; // + NOP
char oem_name[8+1]; // 03h : OEM name
cyg_uint16 bytes_per_sec; // 0Bh : cyg_bytes per sector
cyg_uint8 sec_per_clust; // 0Dh : Sectors per cluster
cyg_uint16 res_sec_num; // 0Eh : Number of reserved sectors
cyg_uint8 fat_tbls_num; // 10h : Number of copies of fat
cyg_uint16 max_root_dents; // 11h : Maximum number of root dir entries
cyg_uint16 sec_num_32; // 13h : Number of sectors in partition < 32MB
cyg_uint8 media_desc; // 15h : Media descriptor
cyg_uint16 sec_per_fat; // 16h : Sectors per FAT
cyg_uint16 sec_per_track; // 18h : Sectors per track
cyg_uint16 heads_num; // 1Ah : Number of heads
cyg_uint32 hsec_num; // 1Ch : Number of hidden sectors
cyg_uint32 sec_num; // 20h : Number of sectors in partition
cyg_uint16 ldrv_num; // 24h : Logical drive number of partition
cyg_uint8 ext_sig; // 26h : Extended signature
cyg_uint32 ser_num; // 27h : Serial number of partition
char vol_name[11+1]; // 2Bh : Volume name of partition
char fat_name[8+1]; // 36h : FAT name
// unsigned char exe_code[448]; // 3Eh : Executable code
unsigned char exe_marker[2]; // 1FEh: Executable marker (55h AAh)
} fat_boot_record_t;
// -------------------------------------------------------------------------
// FAT dir entry structure
typedef struct fat_dir_entry_s
{
char name[8+1]; // 00h : Name
char ext[3+1]; // 08h : Extension
cyg_uint8 attr; // 0Bh : Attribute
cyg_uint8 nt_reserved; // 0Ch : Win NT Reserved field
cyg_uint8 crt_sec_100; // 0Dh : Creation time ms stamp 0 - 199
cyg_uint16 crt_time; // 0Eh : Creation time
cyg_uint16 crt_date; // 10h : Creation date
cyg_uint16 acc_date; // 12h : Last access date
cyg_uint16 cluster_HI; // 14h : Starting cluster HI WORD (FAT32)
cyg_uint16 wrt_time; // 16h : Time
cyg_uint16 wrt_date; // 18h : Date
cyg_uint16 cluster; // 1Ah : Starting cluster
cyg_uint32 size; // 1Ch : Size of the file
fatfs_data_pos_t pos; // Positon on disk
} fat_dir_entry_t;
// -------------------------------------------------------------------------
// FAT cluster opts
typedef enum cluster_opts_e
{
CO_NONE = 0x00, // NULL option
CO_EXTEND = 0x01, // Extend cluster chain if one cluster too short
CO_ERASE_NEW = 0x02, // Erase newly allocated cluster
CO_MARK_LAST = 0x04 // Mark newly allocated cluster as last
} cluster_opts_t;
//==========================================================================
// Utility functions
// -------------------------------------------------------------------------
// get_val_log2()
// Gets the log2 of given value or returns 0 if value is
// not power of 2.
static cyg_uint32
get_val_log2(cyg_uint32 val)
{
cyg_uint32 i, log2;
i = val;
log2 = 0;
while (0 == (i & 1))
{
i >>= 1;
log2++;
}
if (i != 1)
return 0;
else
return log2;
}
// -------------------------------------------------------------------------
// get_data_disk_apos()
// Gets the absolute data position on disk from cluster number and
// position inside given cluster.
static __inline__ cyg_uint32
get_data_disk_apos(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 pos)
{
return (disk->fat_data_pos + disk->cluster_size * (cluster - 2) + pos);
}
// -------------------------------------------------------------------------
// jdays_to_gdate()
// Converts juilan days into gregorian date.
static void
jdays_to_gdate(cyg_uint32 jd, int *day, int *month, int *year)
{
cyg_uint32 l, n, i, j;
l = jd + 68569;
n = (4 * l) / 146097;
l = l - (146097 * n + 3) / 4;
i = (4000 * (l + 1)) / 1461001;
l = l - (1461 * i) / 4 + 31;
j = (80 * l) / 2447;
*day = l - (2447 * j) / 80;
l = j / 11;
*month = j + 2 - (12 * l);
*year = 100 * (n - 49) + i + l;
}
// -------------------------------------------------------------------------
// gdate_to_jdays()
// Converts gregorian date to juilan days.
static void
gdate_to_jdays(int day, int month, int year, cyg_uint32 *jd)
{
*jd = day - 32075 + 1461*(year + 4800 + (month - 14)/12)/4 +
367*(month - 2 - (month - 14)/12*12)/12 -
3*((year + 4900 + (month - 14)/12)/100)/4;
}
// -------------------------------------------------------------------------
// date_unix2dos()
// Converts unix timestamp to dos time and date.
static void
date_unix2dos(cyg_uint32 unix_timestamp,
cyg_uint16 *dos_time,
cyg_uint16 *dos_date)
{
cyg_uint32 jd;
cyg_uint16 dtime, ddate;
int hour, min, sec;
int day, month, year;
hour = (unix_timestamp / 3600) % 24;
min = (unix_timestamp / 60) % 60;
sec = unix_timestamp % 60;
jd = JD_1_JAN_1970 + unix_timestamp / (3600 * 24);
jdays_to_gdate(jd, &day, &month, &year);
CYG_TRACE7(TDE, "ts=%d date=%d:%d:%d %d-%d-%d",
unix_timestamp, hour, min, sec, year, month, day);
if (year < 1980)
year = 1980;
dtime = (hour << 11) | (min << 5) | (sec >> 1);
ddate = ((year - 1980) << 9) | (month << 5) | day;
CYG_TRACE2(TDE, "dos time=%d date=%d", dtime, ddate);
if (NULL != dos_time) *dos_time = dtime;
if (NULL != dos_date) *dos_date = ddate;
}
// -------------------------------------------------------------------------
// date_dos2unix()
// Converts dos time and date to unix timestamp.
static void
date_dos2unix(cyg_uint16 dos_time,
cyg_uint16 dos_date,
cyg_uint32 *unix_timestamp)
{
int hour, min, sec;
int day, month, year;
cyg_uint32 ts;
sec = (dos_time & ((1<<5)-1)) * 2;
dos_time >>= 5;
min = (dos_time & ((1<<6)-1));
dos_time >>= 6;
hour = dos_time;
day = (dos_date & ((1<<5)-1));
dos_date >>= 5;
month = (dos_date & ((1<<4)-1));
dos_date >>= 4;
year = dos_date + 1980;
gdate_to_jdays(day, month, year, &ts);
ts -= JD_1_JAN_1970;
ts = (ts * 24 * 3600) + (sec + min * 60 + hour * 3600);
*unix_timestamp = ts;
CYG_TRACE2(TDE, "dos time=%d date=%d", dos_time, dos_date);
CYG_TRACE7(TDE, "timestamp=%d date=%d:%d:%d %d-%d-%d",
ts, hour, min, sec, year, month, day);
}
//==========================================================================
// FAT boot record functions
// -------------------------------------------------------------------------
// print_boot_record()
// Prints FAT boot record.
#if TFT
static void
print_boot_record(fat_boot_record_t* fbr)
{
diag_printf("FAT: FBR jump code: 0x%02X\n", fbr->jump);
diag_printf("FAT: FBR oem name: '%.8s'\n", fbr->oem_name);
diag_printf("FAT: FBR bytes per sec: %u\n", fbr->bytes_per_sec);
diag_printf("FAT: FBR sec per cluster: %u\n", fbr->sec_per_clust);
diag_printf("FAT: FBR reserved sec: %u\n", fbr->res_sec_num);
diag_printf("FAT: FBR fat tbls num: %u\n", fbr->fat_tbls_num);
diag_printf("FAT: FBR max root dents: %u\n", fbr->max_root_dents);
diag_printf("FAT: FBR sec num (32): %u\n", fbr->sec_num_32);
diag_printf("FAT: FBR media desc: 0x%02X\n", fbr->media_desc);
diag_printf("FAT: FBR sec per fat: %u\n", fbr->sec_per_fat);
diag_printf("FAT: FBR sec per track: %u\n", fbr->sec_per_track);
diag_printf("FAT: FBR heads num: %u\n", fbr->heads_num);
diag_printf("FAT: FBR hidden sec num: %u\n", fbr->hsec_num);
diag_printf("FAT: FBR sec num: %u\n", fbr->sec_num);
diag_printf("FAT: FBR log drv num: %u\n", fbr->ldrv_num);
diag_printf("FAT: FBR ext sig: 0x%02X\n", fbr->ext_sig);
diag_printf("FAT: FBR ser num: 0x%08X\n", fbr->ser_num);
diag_printf("FAT: FBR vol name: '%.11s'\n", fbr->vol_name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -