📄 fat16.c
字号:
/****************************************Copyright (c)**************************************************
** 思 蜕 盟 豆 皮 开 发 小 组
** stmfans 论坛
**
** QQ 群: 65081316 StmFans思蜕盟 1组
** QQ 群: 68584951 StmFans思蜕盟 2组
** http://www.stmfans.com/bbs/
**
** This program was produced by the
** IAR Embedded Workbench 4.0 Kickstart 442
** Copyright 2008-2009 stmfans
** Chip type : STM32F103VB
** Program type : Application
** Clock frequency : 8.000000 MHz
** Memory model :
** External SRAM size :
** Data Stack size :
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名: fat16.c
**创 建 人: 陈海
**最后修改日期: 2008年10月23日
**描 述: 豆皮开发板教程
**
**--------------历史版本信息----------------------------------------------------------------------------
** 创建人: Roland Riegel
** 版 本: v0.01
** 日 期: 2008年06月08日
** 描 述: 原始版本
**
**--------------当前版本信息----------------------------------------------------------------------------
** 创建人: 陈海
** 版 本: v0.02
** 日 期: 2008年10月23日
** 描 述: 当前版本
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "fat16.h"
#include <string.h>
#if USE_DYNAMIC_MEMORY
#include <stdlib.h>
#endif
/**
* \addtogroup fat16 FAT16 support
*
* This module implements FAT16 read and write access.
*
* The following features are supported:
* - File names up to 31 characters long.
* - Unlimited depth of subdirectories.
* - Short 8.3 and long filenames.
* - Creating and deleting files.
* - Reading and writing from and to files.
* - File resizing.
* - File sizes of up to 4 gigabytes.
*
* @{
*/
/**
* \file
* FAT16 implementation (license: GPLv2 or LGPLv2.1)
*
* \author Roland Riegel
*/
/**
* \addtogroup fat16_config FAT16 configuration
* Preprocessor defines to configure the FAT16 implementation.
*/
/**
* \addtogroup fat16_fs FAT16 access
* Basic functions for handling a FAT16 filesystem.
*/
/**
* \addtogroup fat16_file FAT16 file functions
* Functions for managing files.
*/
/**
* \addtogroup fat16_dir FAT16 directory functions
* Functions for managing directories.
*/
/**
* @}
*/
#define FAT16_CLUSTER_FREE 0x0000
#define FAT16_CLUSTER_RESERVED_MIN 0xfff0
#define FAT16_CLUSTER_RESERVED_MAX 0xfff6
#define FAT16_CLUSTER_BAD 0xfff7
#define FAT16_CLUSTER_LAST_MIN 0xfff8
#define FAT16_CLUSTER_LAST_MAX 0xffff
#define FAT16_DIRENTRY_DELETED 0xe5
#define FAT16_DIRENTRY_LFNLAST (1 << 6)
#define FAT16_DIRENTRY_LFNSEQMASK ((1 << 6) - 1)
/* Each entry within the directory table has a size of 32 bytes
* and either contains a 8.3 DOS-style file name or a part of a
* long file name, which may consist of several directory table
* entries at once.
*
* multi-byte integer values are stored little-endian!
*
* 8.3 file name entry:
* ====================
* offset length description
* 0 8 name (space padded)
* 8 3 extension (space padded)
* 11 1 attributes (FAT16_ATTRIB_*)
*
* long file name (lfn) entry ordering for a single file name:
* ===========================================================
* LFN entry n
* ...
* LFN entry 2
* LFN entry 1
* 8.3 entry (see above)
*
* lfn entry:
* ==========
* offset length description
* 0 1 ordinal field
* 1 2 unicode character 1
* 3 3 unicode character 2
* 5 3 unicode character 3
* 7 3 unicode character 4
* 9 3 unicode character 5
* 11 1 attribute (always 0x0f)
* 12 1 type (reserved, always 0)
* 13 1 checksum
* 14 2 unicode character 6
* 16 2 unicode character 7
* 18 2 unicode character 8
* 20 2 unicode character 9
* 22 2 unicode character 10
* 24 2 unicode character 11
* 26 2 cluster (unused, always 0)
* 28 2 unicode character 12
* 30 2 unicode character 13
*
* The ordinal field contains a descending number, from n to 1.
* For the n'th lfn entry the ordinal field is or'ed with 0x40.
* For deleted lfn entries, the ordinal field is set to 0xe5.
*/
struct fat16_header_struct
{
u32 size;
u32 fat_offset;
u32 fat_size;
u16 sector_size;
u16 cluster_size;
u32 root_dir_offset;
u32 cluster_zero_offset;
};
struct fat16_fs_struct
{
struct partition_struct* partition;
struct fat16_header_struct header;
};
struct fat16_file_struct
{
struct fat16_fs_struct* fs;
struct fat16_dir_entry_struct dir_entry;
u32 pos;
u16 pos_cluster;
};
struct fat16_dir_struct
{
struct fat16_fs_struct* fs;
struct fat16_dir_entry_struct dir_entry;
u16 entry_next;
};
struct fat16_read_callback_arg
{
u16 entry_cur;
u16 entry_num;
u32 entry_offset;
u8 byte_count;
};
struct fat16_usage_count_callback_arg
{
u16 cluster_count;
u8 buffer_size;
};
#if !USE_DYNAMIC_MEMORY
static struct fat16_fs_struct fat16_fs_handlers[FAT16_FS_COUNT];
static struct fat16_file_struct fat16_file_handlers[FAT16_FILE_COUNT];
static struct fat16_dir_struct fat16_dir_handlers[FAT16_DIR_COUNT];
#endif
static u8 fat16_read_header(struct fat16_fs_struct* fs);
static u8 fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, u16 entry_num, struct fat16_dir_entry_struct* dir_entry);
static u8 fat16_read_sub_dir_entry(const struct fat16_fs_struct* fs, u16 entry_num, const struct fat16_dir_entry_struct* parent, struct fat16_dir_entry_struct* dir_entry);
static u8 fat16_dir_entry_seek_callback(u8* buffer, u32 offset, void* p);
static u8 fat16_dir_entry_read_callback(u8* buffer, u32 offset, void* p);
static u8 fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const u8* raw_entry);
static u16 fat16_get_next_cluster(const struct fat16_fs_struct* fs, u16 cluster_num);
static u16 fat16_append_clusters(const struct fat16_fs_struct* fs, u16 cluster_num, u16 count);
static u8 fat16_free_clusters(const struct fat16_fs_struct* fs, u16 cluster_num);
static u8 fat16_terminate_clusters(const struct fat16_fs_struct* fs, u16 cluster_num);
static u8 fat16_clear_cluster(const struct fat16_fs_struct* fs, u16 cluster_num);
static u16 fat16_clear_cluster_callback(u8* buffer, u32 offset, void* p);
static u32 fat16_find_offset_for_dir_entry(const struct fat16_fs_struct* fs, const struct fat16_dir_struct* parent, const struct fat16_dir_entry_struct* dir_entry);
static u8 fat16_write_dir_entry(const struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry);
static u8 fat16_get_fs_free_callback(u8* buffer, u32 offset, void* p);
//static void fat16_set_file_modification_date(struct fat16_dir_entry_struct* dir_entry, u16 year, u8 month, u8 day);
//static void fat16_set_file_modification_time(struct fat16_dir_entry_struct* dir_entry, u8 hour, u8 min, u8 sec);
/**
* \ingroup fat16_fs
* Opens a FAT16 filesystem.
*
* \param[in] partition Discriptor of partition on which the filesystem resides.
* \returns 0 on error, a FAT16 filesystem descriptor on success.
* \see fat16_open
*/
struct fat16_fs_struct* fat16_open(struct partition_struct* partition)
{
if(!partition ||
#if FAT16_WRITE_SUPPORT
!partition->device_write ||
!partition->device_write_interval
#else
0
#endif
)
return 0;
#if USE_DYNAMIC_MEMORY
struct fat16_fs_struct* fs = malloc(sizeof(*fs));
if(!fs)
return 0;
#else
struct fat16_fs_struct* fs = fat16_fs_handlers;
u8 i;
for(i = 0; i < FAT16_FS_COUNT; ++i)
{
if(!fs->partition)
break;
++fs;
}
if(i >= FAT16_FS_COUNT)
return 0;
#endif
memset(fs, 0, sizeof(*fs));
fs->partition = partition;
if(!fat16_read_header(fs))
{
#if USE_DYNAMIC_MEMORY
free(fs);
#else
fs->partition = 0;
#endif
return 0;
}
return fs;
}
/**
* \ingroup fat16_fs
* Closes a FAT16 filesystem.
*
* When this function returns, the given filesystem descriptor
* will be invalid.
*
* \param[in] fs The filesystem to close.
* \see fat16_open
*/
void fat16_close(struct fat16_fs_struct* fs)
{
if(!fs)
return;
#if USE_DYNAMIC_MEMORY
free(fs);
#else
fs->partition = 0;
#endif
}
/**
* \ingroup fat16_fs
* Reads and parses the header of a FAT16 filesystem.
*
* \param[inout] fs The filesystem for which to parse the header.
* \returns 0 on failure, 1 on success.
*/
u8 fat16_read_header(struct fat16_fs_struct* fs)
{
if(!fs)
return 0;
struct partition_struct* partition = fs->partition;
if(!partition)
return 0;
/* read fat parameters */
u8 buffer[25];
u32 partition_offset = partition->offset * 512;
if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))
return 0;
u16 bytes_per_sector = ((u16) buffer[0x00]) |
((u16) buffer[0x01] << 8);
u8 sectors_per_cluster = buffer[0x02];
u16 reserved_sectors = ((u16) buffer[0x03]) |
((u16) buffer[0x04] << 8);
u8 fat_copies = buffer[0x05];
u16 max_root_entries = ((u16) buffer[0x06]) |
((u16) buffer[0x07] << 8);
u16 sector_count_16 = ((u16) buffer[0x08]) |
((u16) buffer[0x09] << 8);
u16 sectors_per_fat = ((u16) buffer[0x0b]) |
((u16) buffer[0x0c] << 8);
u32 sector_count = ((u32) buffer[0x15]) |
((u32) buffer[0x16] << 8) |
((u32) buffer[0x17] << 16) |
((u32) buffer[0x18] << 24);
if(sectors_per_fat == 0)
/* this is not a FAT16 */
return 0;
if(sector_count == 0)
{
if(sector_count_16 == 0)
/* illegal volume size */
return 0;
else
sector_count = sector_count_16;
}
/* ensure we really have a FAT16 fs here */
u32 data_sector_count = sector_count
- reserved_sectors
- (u32) sectors_per_fat * fat_copies
- ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector);
u32 data_cluster_count = data_sector_count / sectors_per_cluster;
if(data_cluster_count < 4085 || data_cluster_count >= 65525)
/* this is not a FAT16 */
return 0;
partition->type = PARTITION_TYPE_FAT16;
/* fill header information */
struct fat16_header_struct* header = &fs->header;
memset(header, 0, sizeof(*header));
header->size = sector_count * bytes_per_sector;
header->fat_offset = /* jump to partition */
partition_offset +
/* jump to fat */
(u32) reserved_sectors * bytes_per_sector;
header->fat_size = (data_cluster_count + 2) * 2;
header->sector_size = bytes_per_sector;
header->cluster_size = (u32) bytes_per_sector * sectors_per_cluster;
header->root_dir_offset = /* jump to fats */
header->fat_offset +
/* jump to root directory entries */
(u32) fat_copies * sectors_per_fat * bytes_per_sector;
header->cluster_zero_offset = /* jump to root directory entries */
header->root_dir_offset +
/* skip root directory entries */
(u32) max_root_entries * 32;
return 1;
}
/**
* \ingroup fat16_fs
* Reads a directory entry of the root directory.
*
* \param[in] fs Descriptor of file system to use.
* \param[in] entry_num The index of the directory entry to read.
* \param[out] dir_entry Directory entry descriptor which will get filled.
* \returns 0 on failure, 1 on success
* \see fat16_read_sub_dir_entry, fat16_read_dir_entry_by_path
*/
u8 fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, u16 entry_num, struct fat16_dir_entry_struct* dir_entry)
{
if(!fs || !dir_entry)
return 0;
/* we read from the root directory entry */
const struct fat16_header_struct* header = &fs->header;
device_read_interval_t device_read_interval = fs->partition->device_read_interval;
u8 buffer[32];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -