⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat16.c

📁 基于STM32的 模拟时序
💻 C
📖 第 1 页 / 共 5 页
字号:
/****************************************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 + -