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

📄 fat.c

📁 AVR 单片机上实现SD卡的读写
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  * Copyright (c) 2006-2008 by Roland Riegel <feedback@roland-riegel.de> * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as * published by the Free Software Foundation. */#include "byteordering.h"#include "partition.h"#include "fat.h"#include "fat_config.h"#include "sd-reader_config.h"#include <string.h>#if USE_DYNAMIC_MEMORY    #include <stdlib.h>#endif/** * \addtogroup fat FAT support * * This module implements FAT16/FAT32 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 * FAT implementation (license: GPLv2 or LGPLv2.1) * * \author Roland Riegel *//** * \addtogroup fat_config FAT configuration * Preprocessor defines to configure the FAT implementation. *//** * \addtogroup fat_fs FAT access * Basic functions for handling a FAT filesystem. *//** * \addtogroup fat_file FAT file functions * Functions for managing files. *//** * \addtogroup fat_dir FAT 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 FAT32_CLUSTER_FREE 0x00000000#define FAT32_CLUSTER_RESERVED_MIN 0x0ffffff0#define FAT32_CLUSTER_RESERVED_MAX 0x0ffffff6#define FAT32_CLUSTER_BAD 0x0ffffff7#define FAT32_CLUSTER_LAST_MIN 0x0ffffff8#define FAT32_CLUSTER_LAST_MAX 0x0fffffff#define FAT_DIRENTRY_DELETED 0xe5#define FAT_DIRENTRY_LFNLAST (1 << 6)#define FAT_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 (FAT_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 fat_header_struct{    offset_t size;    offset_t fat_offset;    uint32_t fat_size;    uint16_t sector_size;    uint16_t cluster_size;    offset_t cluster_zero_offset;    offset_t root_dir_offset;#if FAT_FAT32_SUPPORT    cluster_t root_dir_cluster;#endif};struct fat_fs_struct{    struct partition_struct* partition;    struct fat_header_struct header;};struct fat_file_struct{    struct fat_fs_struct* fs;    struct fat_dir_entry_struct dir_entry;    offset_t pos;    cluster_t pos_cluster;};struct fat_dir_struct{    struct fat_fs_struct* fs;    struct fat_dir_entry_struct dir_entry;    cluster_t entry_cluster;    uint16_t entry_offset;};struct fat_read_dir_callback_arg{    struct fat_dir_entry_struct* dir_entry;    uintptr_t bytes_read;    uint8_t finished;};struct fat_usage_count_callback_arg{    cluster_t cluster_count;    uintptr_t buffer_size;};#if !USE_DYNAMIC_MEMORYstatic struct fat_fs_struct fat_fs_handles[FAT_FS_COUNT];static struct fat_file_struct fat_file_handles[FAT_FILE_COUNT];static struct fat_dir_struct fat_dir_handles[FAT_DIR_COUNT];#endifstatic uint8_t fat_read_header(struct fat_fs_struct* fs);static cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num);static offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num);static uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p);static uint8_t fat_interpret_dir_entry(struct fat_dir_entry_struct* dir_entry, const uint8_t* raw_entry);static uint8_t fat_get_fs_free_16_callback(uint8_t* buffer, offset_t offset, void* p);#if FAT_FAT32_SUPPORTstatic uint8_t fat_get_fs_free_32_callback(uint8_t* buffer, offset_t offset, void* p);#endif#if FAT_WRITE_SUPPORTstatic cluster_t fat_append_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count);static uint8_t fat_free_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num);static uint8_t fat_terminate_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num);static uint8_t fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num);static uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p);static offset_t fat_find_offset_for_dir_entry(const struct fat_fs_struct* fs, const struct fat_dir_struct* parent, const struct fat_dir_entry_struct* dir_entry);static uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);#if FAT_DATETIME_SUPPORTstatic void fat_set_file_modification_date(struct fat_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day);static void fat_set_file_modification_time(struct fat_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec);#endif#endif/** * \ingroup fat_fs * Opens a FAT filesystem. * * \param[in] partition Discriptor of partition on which the filesystem resides. * \returns 0 on error, a FAT filesystem descriptor on success. * \see fat_close */struct fat_fs_struct* fat_open(struct partition_struct* partition){    if(!partition ||#if FAT_WRITE_SUPPORT       !partition->device_write ||       !partition->device_write_interval#else       0#endif      )        return 0;#if USE_DYNAMIC_MEMORY    struct fat_fs_struct* fs = malloc(sizeof(*fs));    if(!fs)        return 0;#else    struct fat_fs_struct* fs = fat_fs_handles;    uint8_t i;    for(i = 0; i < FAT_FS_COUNT; ++i)    {        if(!fs->partition)            break;        ++fs;    }    if(i >= FAT_FS_COUNT)        return 0;#endif    memset(fs, 0, sizeof(*fs));    fs->partition = partition;    if(!fat_read_header(fs))    {#if USE_DYNAMIC_MEMORY        free(fs);#else        fs->partition = 0;#endif        return 0;    }        return fs;}/** * \ingroup fat_fs * Closes a FAT filesystem. * * When this function returns, the given filesystem descriptor * will be invalid. * * \param[in] fs The filesystem to close. * \see fat_open */void fat_close(struct fat_fs_struct* fs){    if(!fs)        return;#if USE_DYNAMIC_MEMORY    free(fs);#else    fs->partition = 0;#endif}/** * \ingroup fat_fs * Reads and parses the header of a FAT filesystem. * * \param[inout] fs The filesystem for which to parse the header. * \returns 0 on failure, 1 on success. */uint8_t fat_read_header(struct fat_fs_struct* fs){    if(!fs)        return 0;    struct partition_struct* partition = fs->partition;    if(!partition)        return 0;    /* read fat parameters */#if FAT_FAT32_SUPPORT    uint8_t buffer[37];#else    uint8_t buffer[25];#endif    offset_t partition_offset = (offset_t) partition->offset * 512;    if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))        return 0;    uint16_t bytes_per_sector = ltoh16(*((uint16_t*) &buffer[0x00]));    uint16_t reserved_sectors = ltoh16(*((uint16_t*) &buffer[0x03]));    uint8_t sectors_per_cluster = buffer[0x02];    uint8_t fat_copies = buffer[0x05];    uint16_t max_root_entries = ltoh16(*((uint16_t*) &buffer[0x06]));    uint16_t sector_count_16 = ltoh16(*((uint16_t*) &buffer[0x08]));    uint16_t sectors_per_fat = ltoh16(*((uint16_t*) &buffer[0x0b]));    uint32_t sector_count = ltoh32(*((uint32_t*) &buffer[0x15]));#if FAT_FAT32_SUPPORT    uint32_t sectors_per_fat32 = ltoh32(*((uint32_t*) &buffer[0x19]));    uint32_t cluster_root_dir = ltoh32(*((uint32_t*) &buffer[0x21]));#endif    if(sector_count == 0)    {        if(sector_count_16 == 0)            /* illegal volume size */            return 0;        else            sector_count = sector_count_16;    }#if FAT_FAT32_SUPPORT    if(sectors_per_fat != 0)        sectors_per_fat32 = sectors_per_fat;    else if(sectors_per_fat32 == 0)        /* this is neither FAT16 nor FAT32 */        return 0;#else    if(sectors_per_fat == 0)        /* this is not a FAT16 */        return 0;#endif    /* determine the type of FAT we have here */    uint32_t data_sector_count = sector_count                                 - reserved_sectors#if FAT_FAT32_SUPPORT                                 - sectors_per_fat32 * fat_copies#else                                 - (uint32_t) sectors_per_fat * fat_copies#endif                                 - ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector);    uint32_t data_cluster_count = data_sector_count / sectors_per_cluster;    if(data_cluster_count < 4085)        /* this is a FAT12, not supported */        return 0;    else if(data_cluster_count < 65525)        /* this is a FAT16 */        partition->type = PARTITION_TYPE_FAT16;    else        /* this is a FAT32 */        partition->type = PARTITION_TYPE_FAT32;    /* fill header information */    struct fat_header_struct* header = &fs->header;    memset(header, 0, sizeof(*header));        header->size = (offset_t) sector_count * bytes_per_sector;    header->fat_offset = /* jump to partition */                         partition_offset +                         /* jump to fat */                         (offset_t) reserved_sectors * bytes_per_sector;    header->fat_size = (data_cluster_count + 2) * sizeof(cluster_t);    header->sector_size = bytes_per_sector;    header->cluster_size = (uint16_t) bytes_per_sector * sectors_per_cluster;#if FAT_FAT32_SUPPORT    if(partition->type == PARTITION_TYPE_FAT16)#endif    {        header->root_dir_offset = /* jump to fats */                                  header->fat_offset +                                  /* jump to root directory entries */                                  (offset_t) 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 */                                      (offset_t) max_root_entries * 32;    }#if FAT_FAT32_SUPPORT    else    {        header->cluster_zero_offset = /* jump to fats */                                      header->fat_offset +                                      /* skip fats */                                      (offset_t) fat_copies * sectors_per_fat32 * bytes_per_sector;        header->root_dir_cluster = cluster_root_dir;    }#endif    return 1;}/** * \ingroup fat_fs * Retrieves the next following cluster of a given cluster. * * Using the filesystem file allocation table, this function returns * the number of the cluster containing the data directly following * the data within the cluster with the given number. * * \param[in] fs The filesystem for which to determine the next cluster. * \param[in] cluster_num The number of the cluster for which to determine its successor. * \returns The wanted cluster number, or 0 on error. */cluster_t fat_get_next_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num){    if(!fs || cluster_num < 2)        return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -