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

📄 fat16.c

📁 MMC/SD操作
💻 C
📖 第 1 页 / 共 4 页
字号:
}/** * \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 entries */    if(buffer[0] == FAT16_DIRENTRY_DELETED)        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 entries */    if(buffer[0] == FAT16_DIRENTRY_DELETED)        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. *  * \param[in,out] dir_entry The directory entry to fill. * \param[in] raw_entry A pointer to 32 bytes of raw data. * \returns 0 on failure, 1 on success and 2 if the *          directory entry is complete. */uint8_t fat16_interpret_dir_entry(struct fat16_dir_entry_struct* dir_entry, const uint8_t* raw_entry){    if(!dir_entry || !raw_entry || !raw_entry[0])        return 0;    char* long_name = dir_entry->long_name;    if(raw_entry[11] == 0x0f)    {        uint16_t char_offset = ((raw_entry[0] & 0x3f) - 1) * 13;        if(char_offset + 12 < sizeof(dir_entry->long_name))        {            /* Lfn supports unicode, but we do not, for now.             * So we assume pure ascii and read only every             * second byte.             */            long_name[char_offset + 0] = raw_entry[1];            long_name[char_offset + 1] = raw_entry[3];            long_name[char_offset + 2] = raw_entry[5];            long_name[char_offset + 3] = raw_entry[7];            long_name[char_offset + 4] = raw_entry[9];            long_name[char_offset + 5] = raw_entry[14];            long_name[char_offset + 6] = raw_entry[16];            long_name[char_offset + 7] = raw_entry[18];            long_name[char_offset + 8] = raw_entry[20];            long_name[char_offset + 9] = raw_entry[22];            long_name[char_offset + 10] = raw_entry[24];            long_name[char_offset + 11] = raw_entry[28];            long_name[char_offset + 12] = raw_entry[30];        }        return 1;    }    else    {        /* if we do not have a long name, take the short one */        if(long_name[0] == '\0')        {            uint8_t i;            for(i = 0; i < 8; ++i)            {                if(raw_entry[i] == ' ')                    break;                long_name[i] = raw_entry[i];            }            if(raw_entry[8] != ' ')            {                long_name[i++] = '.';                uint8_t j = 8;                for(; j < 11; ++j)                {                    if(raw_entry[j] != ' ')                    {                        long_name[i++] = raw_entry[j];                    }                    else                    {                        break;                    }                }            }             long_name[i] = '\0';        }                /* extract properties of file and store them within the structure */        dir_entry->attributes = raw_entry[11];        dir_entry->cluster = ((uint16_t) raw_entry[26]) |                             ((uint16_t) raw_entry[27] << 8);        dir_entry->file_size = ((uint32_t) raw_entry[28]) |                               ((uint32_t) raw_entry[29] << 8) |                               ((uint32_t) raw_entry[30] << 16) |                               ((uint32_t) raw_entry[31] << 24);        return 2;    }}/** * \ingroup fat16_file * Retrieves the directory entry of a path. * * The given path may both describe a file or a directory. * * \param[in] fs The FAT16 filesystem on which to search. * \param[in] path The path of which to read the directory entry. * \param[out] dir_entry The directory entry to fill. * \returns 0 on failure, 1 on success. * \see fat16_read_dir */uint8_t fat16_get_dir_entry_of_path(struct fat16_fs_struct* fs, const char* path, struct fat16_dir_entry_struct* dir_entry){    if(!fs || !path || path[0] == '\0' || !dir_entry)        return 0;    if(path[0] == '/')        ++path;    /* begin with the root directory */    memset(dir_entry, 0, sizeof(*dir_entry));    dir_entry->attributes = FAT16_ATTRIB_DIR;    if(path[0] == '\0')        return 1;    while(1)    {        struct fat16_dir_struct* dd = fat16_open_dir(fs, dir_entry);        if(!dd)            break;        /* extract the next hierarchy we will search for */        const char* sep_pos = strchr(path, '/');        if(!sep_pos)            sep_pos = path + strlen(path);        uint8_t length_to_sep = sep_pos - path;                /* read directory entries */        while(fat16_read_dir(dd, dir_entry))        {            /* check if we have found the next hierarchy */            if((strlen(dir_entry->long_name) != length_to_sep ||                strncmp(path, dir_entry->long_name, length_to_sep) != 0))                continue;            fat16_close_dir(dd);            dd = 0;            if(path[length_to_sep] == '\0')                /* we iterated through the whole path and have found the file */                return 1;            if(dir_entry->attributes & FAT16_ATTRIB_DIR)            {                /* we found a parent directory of the file we are searching for */                path = sep_pos + 1;                break;            }            /* a parent of the file exists, but not the file itself */            return 0;        }        fat16_close_dir(dd);    }        return 0;}/** * \ingroup fat16_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. */uint16_t fat16_get_next_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num){    if(!fs || cluster_num < 2)        return 0;    /* read appropriate fat entry */    uint8_t fat_entry[2];    if(!fs->partition->device_read(fs->header.fat_offset + 2 * cluster_num, fat_entry, 2))        return 0;    /* determine next cluster from fat */    cluster_num = ((uint16_t) fat_entry[0]) |                  ((uint16_t) fat_entry[1] << 8);        if(cluster_num == FAT16_CLUSTER_FREE ||       cluster_num == FAT16_CLUSTER_BAD ||       (cluster_num >= FAT16_CLUSTER_RESERVED_MIN && cluster_num <= FAT16_CLUSTER_RESERVED_MAX) ||       (cluster_num >= FAT16_CLUSTER_LAST_MIN && cluster_num <= FAT16_CLUSTER_LAST_MAX))        return 0;        return cluster_num;}/** * \ingroup fat16_fs * Appends a cluster to an existing cluster chain. * * Set cluster_num to zero to allocate the first cluster * within the chain. * * \param[in] fs The file system on which to operate. * \param[in] cluster_num The cluster to which to append a free one. * \returns 0 on failure, the number of the new cluster on success. */uint16_t fat16_append_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num){#if FAT16_WRITE_SUPPORT    if(!fs)        return 0;        uint32_t fat_offset_from = fs->header.fat_offset;    uint32_t fat_offset_to = fat_offset_from + fs->header.fat_size;    uint32_t fat_offset = fat_offset_from;    device_read_t device_read = fs->partition->device_read;    device_write_t device_write = fs->partition->device_write;    uint16_t cluster_new = 0;    uint8_t buffer[2];    while(1)    {        if(!device_read(fat_offset, buffer, sizeof(buffer)))            return 0;        /* check if this is a free cluster */        if(buffer[0] == (FAT16_CLUSTER_FREE & 0xff) &&           buffer[1] == ((FAT16_CLUSTER_FREE >> 8) & 0xff))            break;        ++cluster_new;        fat_offset += sizeof(buffer);                /* abort if we reached the end of the fat */        if(fat_offset >= fat_offset_to)            return 0;    }    buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff;    buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff;    if(!device_write(fat_offset_from + 2 * cluster_new, buffer, sizeof(buffer)))        return 0;        if(cluster_num >= 2)    {        buffer[0] = cluster_new & 0xff;        buffer[1] = (cluster_new >> 8) & 0xff;        device_write(fat_offset_from + 2 * cluster_num, buffer, sizeof(buffer));    }    return cluster_new;    #else    return 0;#endif}/** * \ingroup fat16_fs * Frees a cluster. * * Marks the specified cluster as free. It may then again be * used for future file allocations. * * \param[in] fs The filesystem on which to operate. * \param[in] cluster_num The cluster which to free. * \returns 0 on failure, 1 on success. */uint8_t fat16_free_cluster(struct fat16_fs_struct* fs, uint16_t cluster_num){#if FAT16_WRITE_SUPPORT    if(!fs || cluster_num < 2)        return 0;    uint32_t fat_offset = fs->header.fat_offset;    uint8_t buffer[2];        buffer[0] = FAT16_CLUSTER_FREE & 0xff;    buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff;    return fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2);#else    return 0;#endif}/** * \ingroup fat16_file * Opens a file on a FAT16 filesystem. * * \param[in] fs The filesystem on which the file to open lies. * \param[in] dir_entry The directory entry of the file to open. * \returns The file handle, or 0 on failure. * \see fat16_close_file */struct fat16_file_struct* fat16_open_file(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry){    if(!fs || !dir_entry || (dir_entry->attributes & FAT16_ATTRIB_DIR))        return 0;    struct fat16_file_struct* fd = malloc(sizeof(*fd));    if(!fd)        return 0;        memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry));    fd->fs = fs;    fd->pos = 0;    return fd;}/** * \ingroup fat16_file * Closes a file. * * \param[in] fd The file handle of the file to close. * \see fat16_open_file */void fat16_close_file(struct fat16_file_struct* fd){    if(fd)        free(fd);}/** * \ingroup fat16_file * Reads data from a file. *  * The data requested is read from the current file location. * * \param[in] fd The file handle of the file from which to read. * \param[out] buffer The buffer into which to write. * \param[in] buffer_len The amount of data to read. * \returns The number of bytes read, 0 on end of file, or -1 on failure. * \see fat16_write_file */

⌨️ 快捷键说明

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