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

📄 fat16.c

📁 包装了一个开源的FAT16文件系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*  * Copyright (c) 2006-2007 by Roland Riegel <feedback@roland-riegel.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include "partition.h"#include "fat16.h"#include "fat16_config.h"#include "sd-reader_config.h"#include "fat16int.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. * * \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. *//** * @} *//** * \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){    struct fat16_fs_struct* fs;
#if USE_DYNAMIC_MEMORY==0
	uint8_t i;
#endif
    if(!partition ||#if FAT16_WRITE_SUPPORT       !partition->device_write ||       !partition->device_write_interval#else       0#endif      )        return 0;#if USE_DYNAMIC_MEMORY    fs = malloc(sizeof(*fs));    if(!fs)        return 0;#else    fs = fat16_fs_handlers;    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. */uint8_t fat16_read_header(struct fat16_fs_struct* fs){    
	uint8_t buffer[25];
	uint32_t partition_offset;
	uint16_t bytes_per_sector;    uint8_t sectors_per_cluster;    uint16_t reserved_sectors;    uint8_t fat_copies;    uint16_t max_root_entries;    uint16_t sector_count_16;    uint16_t sectors_per_fat;    uint32_t sector_count;

	struct partition_struct* partition;
	struct fat16_header_struct* header;

    /* ensure we really have a FAT16 fs here */    uint32_t data_sector_count;    uint32_t data_cluster_count;

	if(!fs)        return 0;    partition = fs->partition;    if(!partition)        return 0;    /* read fat parameters */    partition_offset = partition->offset * 512;    if(!partition->device_read(partition_offset + 0x0b, buffer, sizeof(buffer)))        return 0;    bytes_per_sector = ((uint16_t) buffer[0x00]) |                                ((uint16_t) buffer[0x01] << 8);    sectors_per_cluster = buffer[0x02];    reserved_sectors = ((uint16_t) buffer[0x03]) |                                ((uint16_t) buffer[0x04] << 8);    fat_copies = buffer[0x05];    max_root_entries = ((uint16_t) buffer[0x06]) |                                ((uint16_t) buffer[0x07] << 8);    sector_count_16 = ((uint16_t) buffer[0x08]) |                               ((uint16_t) buffer[0x09] << 8);    sectors_per_fat = ((uint16_t) buffer[0x0b]) |                               ((uint16_t) buffer[0x0c] << 8);    sector_count = ((uint32_t) buffer[0x15]) |                            ((uint32_t) buffer[0x16] << 8) |                            ((uint32_t) buffer[0x17] << 16) |                            ((uint32_t) 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 */    data_sector_count = sector_count                                 - reserved_sectors                                 - (uint32_t) sectors_per_fat * fat_copies                                 - ((max_root_entries * 32 + bytes_per_sector - 1) / bytes_per_sector);    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 */    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 */                         (uint32_t) reserved_sectors * bytes_per_sector;    header->fat_size = (data_cluster_count + 2) * 2;    header->sector_size = bytes_per_sector;    header->cluster_size = (uint16_t) ( (uint32_t) bytes_per_sector * sectors_per_cluster );    header->root_dir_offset = /* jump to fats */                              header->fat_offset +                              /* jump to root directory entries */                              (uint32_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 */                                  (uint32_t) 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 */uint8_t fat16_read_root_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, struct fat16_dir_entry_struct* dir_entry){    uint8_t buffer[32];    const struct fat16_header_struct* header = &fs->header;    device_read_interval_t device_read_interval;
	struct fat16_read_callback_arg arg;

    if(!fs || !dir_entry)        return 0;    /* we read from the root directory entry */    device_read_interval = fs->partition->device_read_interval;    /* seek to the n-th entry */    memset(&arg, 0, sizeof(arg));    arg.entry_num = entry_num;    if(!device_read_interval(header->root_dir_offset,                             buffer,                             sizeof(buffer),                             (U16)(header->cluster_zero_offset - header->root_dir_offset),                             fat16_dir_entry_seek_callback,                             &arg) ||       arg.entry_offset == 0      )        return 0;    /* read entry */    memset(dir_entry, 0, sizeof(*dir_entry));    if(!device_read_interval(arg.entry_offset,                             buffer,                             sizeof(buffer),                             arg.byte_count,                             fat16_dir_entry_read_callback,                             dir_entry))        return 0;    return dir_entry->long_name[0] != '\0' ? 1 : 0;}/** * \ingroup fat16_fs * Reads a directory entry of a given parent directory. * * \param[in] fs Descriptor of file system to use. * \param[in] entry_num The index of the directory entry to read. * \param[in] parent Directory entry descriptor in which to read directory entry. * \param[out] dir_entry Directory entry descriptor which will get filled.该内存由caller负责分配 * \returns 0 on failure, 1 on success * \see fat16_read_root_dir_entry, fat16_read_dir_entry_by_path */uint8_t fat16_read_sub_dir_entry(const struct fat16_fs_struct* fs, uint16_t entry_num, const struct fat16_dir_entry_struct* parent, struct fat16_dir_entry_struct* dir_entry){

    uint8_t buffer[32];    uint32_t cluster_offset;    uint16_t cluster_size;    uint16_t cluster_num;    struct fat16_read_callback_arg arg;
    if(!fs || !parent || !dir_entry)        return 0;    /* we are in a parent directory and want to search within its directory entry table */    if(!(parent->attributes & FAT16_ATTRIB_DIR))        return 0;    /* loop through all clusters of the directory */    cluster_size = fs->header.cluster_size;    cluster_num = parent->cluster;    while(1)    {        /* calculate new cluster offset */        cluster_offset = fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * cluster_size;        /* seek to the n-th entry */        memset(&arg, 0, sizeof(arg));        arg.entry_num = entry_num;        if(!fs->partition->device_read_interval(cluster_offset,                                                buffer,                                                sizeof(buffer),                                                cluster_size,                                                fat16_dir_entry_seek_callback,                                                &arg)          )            return 0;        /* check if we found the entry */        if(arg.entry_offset)            break;        /* get number of next cluster */
		cluster_num = fat16_get_next_cluster(fs, cluster_num);        if(!cluster_num)            return 0; /* directory entry not found */    }    memset(dir_entry, 0, sizeof(*dir_entry));    /* read entry */    if(!fs->partition->device_read_interval(arg.entry_offset,                                            buffer,                                            sizeof(buffer),                                            arg.byte_count,                                            fat16_dir_entry_read_callback,                                            dir_entry))        return 0;    return dir_entry->long_name[0] != '\0' ? 1 : 0;}/** * \ingroup fat16_fs * Callback function for seeking through subdirectory entries. */uint8_t fat16_dir_entry_seek_callback(uint8_t* buffer, uint32_t offset, void* p){    struct fat16_read_callback_arg* arg = p;    /* skip deleted or empty entries */    if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0])        return 1;    if(arg->entry_cur == arg->entry_num)    {        arg->entry_offset = offset;        arg->byte_count = buffer[11] == 0x0f ?                          ((buffer[0] & FAT16_DIRENTRY_LFNSEQMASK) + 1) * 32 :                          32;        return 0;    }    /* if we read a 8.3 entry, we reached a new directory entry */    if(buffer[11] != 0x0f)        ++arg->entry_cur;    return 1;}/** * \ingroup fat16_fs * Callback function for reading a directory entry. */uint8_t fat16_dir_entry_read_callback(uint8_t* buffer, uint32_t offset, void* p){    struct fat16_dir_entry_struct* dir_entry = p;    /* there should not be any deleted or empty entries */    if(buffer[0] == FAT16_DIRENTRY_DELETED || !buffer[0])        return 0;    if(!dir_entry->entry_offset)        dir_entry->entry_offset = offset;        switch(fat16_interpret_dir_entry(dir_entry, buffer))    {        case 0: /* failure */            return 0;        case 1: /* buffer successfully parsed, continue */            return 1;        case 2: /* directory entry complete, finish */            return 0;    }    return 0;}/** * \ingroup fat16_fs * Interprets a raw directory entry and puts the contained * information into the directory entry. *  * For a single file there may exist multiple directory * entries. All except the last one are lfn entries, which * contain parts of the long filename. The last directory * entry is a traditional 8.3 style one. It contains all * other information like size, cluster, date and time. * 

⌨️ 快捷键说明

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