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

📄 fat16.c

📁 AVR读取SD卡里FAT格式内容的源程序
💻 C
📖 第 1 页 / 共 5 页
字号:
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){    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 */    uint8_t buffer[32];    uint32_t cluster_offset;    uint16_t cluster_size = fs->header.cluster_size;    uint16_t cluster_num = parent->cluster;    struct fat16_read_callback_arg arg;    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 */        if(!(cluster_num = fat16_get_next_cluster(fs, 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. *  * \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(long_name[0] == 0x05)                long_name[0] = (char) FAT16_DIRENTRY_DELETED;            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);#if FAT16_DATETIME_SUPPORT        dir_entry->modification_time = ((uint16_t) raw_entry[22]) |                                       ((uint16_t) raw_entry[23] << 8);        dir_entry->modification_date = ((uint16_t) raw_entry[24]) |                                       ((uint16_t) raw_entry[25] << 8);#endif        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 new cluster chain to an existing one. * * Set cluster_num to zero to create a completely new one. * * \param[in] fs The file system on which to operate. * \param[in] cluster_num The cluster to which to append the new chain. * \param[in] count The number of clusters to allocate. * \returns 0 on failure, the number of the first new cluster on success. */uint16_t fat16_append_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num, uint16_t count){#if FAT16_WRITE_SUPPORT    if(!fs)        return 0;    device_read_t device_read = fs->partition->device_read;    device_write_t device_write = fs->partition->device_write;    uint32_t fat_offset = fs->header.fat_offset;    uint16_t cluster_max = fs->header.fat_size / 2;    uint16_t cluster_next = 0;    uint16_t count_left = count;    uint8_t buffer[2];    for(uint16_t cluster_new = 0; cluster_new < cluster_max; ++cluster_new)    {        if(!device_read(fat_offset + 2 * cluster_new, 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))        {            /* allocate cluster */            if(count_left == count)            {                buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff;                buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff;            }            else            {                buffer[0] = cluster_next & 0xff;                buffer[1] = (cluster_next >> 8) & 0xff;            }            if(!device_write(fat_offset + 2 * cluster_new, buffer, sizeof(buffer)))                break;            cluster_next = cluster_new;            if(--count_left == 0)                break;        }    }    do    {        if(count_left > 0)            break;        /* We allocated a new cluster chain. Now join         * it with the existing one.         */        if(cluster_num >= 2)        {            buffer[0] = cluster_next & 0xff;            buffer[1] = (cluster_next >> 8) & 0xff;            if(!device_write(fat_offset + 2 * cluster_num, buffer, sizeof(buffer)))                break;        }        return cluster_next;    } while(0);    /* No space left on device or writing error.     * Free up all clusters already allocated.     */    fat16_free_clusters(fs, cluster_next);    return 0;#else    return 0;#endif}/** * \ingroup fat16_fs * Frees a cluster chain, or a part thereof. * * Marks the specified cluster and all clusters which are sequentially * referenced by it as free. They may then be used again for future * file allocations. * * \note If this function is used for freeing just a part of a cluster *       chain, the new end of the chain is not correctly terminated *       within the FAT. Use fat16_terminate_clusters() instead. * * \param[in] fs The filesystem on which to operate. * \param[in] cluster_num The starting cluster of the chain which to free. * \returns 0 on failure, 1 on success. * \see fat16_terminate_clusters */uint8_t fat16_free_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num){#if FAT16_WRITE_SUPPORT    if(!fs || cluster_num < 2)

⌨️ 快捷键说明

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