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

📄 fat.c

📁 This project provides a general purpose library which implements read and write support for MMC, SD
💻 C
📖 第 1 页 / 共 5 页
字号:
        {            /* free all clusters no longer needed */            fat_terminate_clusters(fd->fs, cluster_num);        }    } while(0);    /* correct file position */    if(size < fd->pos)    {        fd->pos = size;        fd->pos_cluster = 0;    }    return 1;}#endif/** * \ingroup fat_dir * Opens a directory. * * \param[in] fs The filesystem on which the directory to open resides. * \param[in] dir_entry The directory entry which stands for the directory to open. * \returns An opaque directory descriptor on success, 0 on failure. * \see fat_close_dir */struct fat_dir_struct* fat_open_dir(struct fat_fs_struct* fs, const struct fat_dir_entry_struct* dir_entry){    if(!fs || !dir_entry || !(dir_entry->attributes & FAT_ATTRIB_DIR))        return 0;#if USE_DYNAMIC_MEMORY    struct fat_dir_struct* dd = malloc(sizeof(*dd));    if(!dd)        return 0;#else    struct fat_dir_struct* dd = fat_dir_handles;    uint8_t i;    for(i = 0; i < FAT_DIR_COUNT; ++i)    {        if(!dd->fs)            break;        ++dd;    }    if(i >= FAT_DIR_COUNT)        return 0;#endif        memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry));    dd->fs = fs;    dd->entry_cluster = dir_entry->cluster;    dd->entry_offset = 0;    return dd;}/** * \ingroup fat_dir * Closes a directory descriptor. * * This function destroys a directory descriptor which was * previously obtained by calling fat_open_dir(). When this * function returns, the given descriptor will be invalid. * * \param[in] dd The directory descriptor to close. * \see fat_open_dir */void fat_close_dir(struct fat_dir_struct* dd){    if(dd)#if USE_DYNAMIC_MEMORY        free(dd);#else        dd->fs = 0;#endif}/** * \ingroup fat_dir * Reads the next directory entry contained within a parent directory. * * \param[in] dd The descriptor of the parent directory from which to read the entry. * \param[out] dir_entry Pointer to a buffer into which to write the directory entry information. * \returns 0 on failure, 1 on success. * \see fat_reset_dir */uint8_t fat_read_dir(struct fat_dir_struct* dd, struct fat_dir_entry_struct* dir_entry){    if(!dd || !dir_entry)        return 0;    /* get current position of directory handle */    struct fat_fs_struct* fs = dd->fs;    const struct fat_header_struct* header = &fs->header;    uint16_t cluster_size = header->cluster_size;    cluster_t cluster_num = dd->entry_cluster;    uint16_t cluster_offset = dd->entry_offset;    struct fat_read_dir_callback_arg arg;    /* reset directory entry */    memset(dir_entry, 0, sizeof(*dir_entry));    /* reset callback arguments */    memset(&arg, 0, sizeof(arg));    arg.dir_entry = dir_entry;    /* check if we read from the root directory */    if(cluster_num == 0)    {#if FAT_FAT32_SUPPORT        if(fs->partition->type == PARTITION_TYPE_FAT32)            cluster_num = header->root_dir_cluster;        else#endif            cluster_size = header->cluster_zero_offset - header->root_dir_offset;    }    /* read entries */    uint8_t buffer[32];    while(!arg.finished)    {        /* read directory entries up to the cluster border */        uint16_t cluster_left = cluster_size - cluster_offset;        uint32_t pos = cluster_offset;        if(cluster_num == 0)            pos += header->root_dir_offset;        else            pos += fat_cluster_offset(fs, cluster_num);        arg.bytes_read = 0;        if(!fs->partition->device_read_interval(pos,                                                buffer,                                                sizeof(buffer),                                                cluster_left,                                                fat_dir_entry_read_callback,                                                &arg)          )            return 0;        cluster_offset += arg.bytes_read;        if(cluster_offset >= cluster_size)        {            /* we reached the cluster border and switch to the next cluster */            cluster_offset = 0;            /* get number of next cluster */            if(!(cluster_num = fat_get_next_cluster(fs, cluster_num)))            {                /* directory entry not found, reset directory handle */                cluster_num = dd->dir_entry.cluster;                break;            }        }    }    dd->entry_cluster = cluster_num;    dd->entry_offset = cluster_offset;    return dir_entry->long_name[0] != '\0' ? 1 : 0;}/** * \ingroup fat_dir * Resets a directory handle. * * Resets the directory handle such that reading restarts * with the first directory entry. * * \param[in] dd The directory handle to reset. * \returns 0 on failure, 1 on success. * \see fat_read_dir */uint8_t fat_reset_dir(struct fat_dir_struct* dd){    if(!dd)        return 0;    dd->entry_cluster = dd->dir_entry.cluster;    dd->entry_offset = 0;    return 1;}/** * \ingroup fat_fs * Callback function for reading a directory entry. */uint8_t fat_dir_entry_read_callback(uint8_t* buffer, offset_t offset, void* p){    struct fat_read_dir_callback_arg* arg = p;    struct fat_dir_entry_struct* dir_entry = arg->dir_entry;    arg->bytes_read += 32;    /* skip deleted or empty entries */    if(buffer[0] == FAT_DIRENTRY_DELETED || !buffer[0])        return 1;    if(!dir_entry->entry_offset)        dir_entry->entry_offset = offset;        switch(fat_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 */        {            arg->finished = 1;            return 0;        }    }    return 0;}/** * \ingroup fat_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 fat_interpret_dir_entry(struct fat_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)    {        /* Lfn supports unicode, but we do not, for now.         * So we assume pure ascii and read only every         * second byte.         */        uint16_t char_offset = ((raw_entry[0] & 0x3f) - 1) * 13;        const uint8_t char_mapping[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };        for(uint8_t i = 0; i <= 12 && char_offset + i < sizeof(dir_entry->long_name) - 1; ++i)            long_name[char_offset + i] = raw_entry[char_mapping[i]];        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];                /* Windows NT and later versions do not store LFN entries                 * for 8.3 names which have a lowercase basename, extension                 * or both when everything else is uppercase. They use two                 * extra bits to signal a lowercase basename or extension.                 */                if((raw_entry[12] & 0x08) && raw_entry[i] >= 'A' && raw_entry[i] <= 'Z')                    long_name[i] += 'a' - 'A';            }            if(long_name[0] == 0x05)                long_name[0] = (char) FAT_DIRENTRY_DELETED;            if(raw_entry[8] != ' ')            {                long_name[i++] = '.';                uint8_t j = 8;                for(; j < 11; ++j)                {                    if(raw_entry[j] == ' ')                        break;                    long_name[i] = raw_entry[j];                    /* See above for the lowercase 8.3 name handling of                     * Windows NT and later.                     */                    if((raw_entry[12] & 0x10) && raw_entry[j] >= 'A' && raw_entry[j] <= 'Z')                        long_name[i] += 'a' - 'A';                    ++i;                }            }             long_name[i] = '\0';        }                /* extract properties of file and store them within the structure */        dir_entry->attributes = raw_entry[11];        dir_entry->cluster = ltoh16(*((uint16_t*) &raw_entry[26]));#if FAT_FAT32_SUPPORT        dir_entry->cluster |= ((cluster_t) ltoh16(*((uint16_t*) &raw_entry[20]))) << 16;#endif        dir_entry->file_size = ltoh32(*((uint32_t*) &raw_entry[28]));#if FAT_DATETIME_SUPPORT        dir_entry->modification_time = ltoh16(*((uint16_t*) &raw_entry[22]));        dir_entry->modification_date = ltoh16(*((uint16_t*) &raw_entry[24]));#endif        return 2;    }}#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_fs * Searches for space where to store a directory entry. * * \param[in] fs The filesystem on which to operate. * \param[in] parent The directory in which to search. * \param[in] dir_entry The directory entry for which to search space. * \returns 0 on failure, a device offset on success. */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){    if(!fs || !dir_entry)        return 0;    /* search for a place where to write the directory entry to disk */    uint8_t free_dir_entries_needed = (strlen(dir_entry->long_name) + 12) / 13 + 1;    uint8_t free_dir_entries_found = 0;    cluster_t cluster_num = parent->dir_entry.cluster;    offset_t dir_entry_offset = 0;    offset_t offset = 0;    offset_t offset_to = 0;#if FAT_FAT32_SUPPORT    uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32);#endif    if(cluster_num == 0)    {#if FAT_FAT32_SUPPORT        if(is_fat32)        {            cluster_num = fs->header.root_dir_cluster;        }        else#endif        {            /* we read/write from the root directory entry */            offset = fs->header.root_dir_offset;            offset_to = fs->header.cluster_zero_offset;            dir_entry_offset = offset;        }    }        while(1)    {        if(offset == offset_to)        {            if(cluster_num == 0)                /* We iterated through the whole root directory and                 * could not find enough space for the directory entry.                 */                return 0;            if(offset)            {                /* We reached a cluster boundary and have to                 * switch to the next cluster.                 */                cluster_t cluster_next = fat_get_next_cluster(fs, cluster_num);                if(!cluster_next)                {                    cluster_next = fat_append_clusters(fs, cluster_num, 1);                    if(!cluster_next)                        return 0;                    /* we appended a new cluster and know it is free */                    dir_entry_offset = fs->header.cluster_zero_offset +                                       (offset_t) (cluster_next - 2) * fs->header.cluster_size;                    /* clear cluster to avoid garbage directory entries */                    fat_clear_cluster(fs, cluster_next);                    break;                }                cluster_num = cluster_next;            }            offset = fat_cluster_offset(fs, cluster_num);            offset_to = offset + fs->header.cluster_size;            dir_entry_offset = offset;            free_dir_entries_found = 0;        }                /* read next lfn or 8.3 entry */        uint8_t first_char;        if(!fs->partition->device_read(offset, &first_char, sizeof(first_char)))            return 0;        /* check if we found a free directory entry */        if(first_char == FAT_DIRENTRY_DELETED || !first_char)        {            /* check if we have the needed number of available entries */            ++free_dir_entries_found;            if(free_dir_entries_found >= free_dir_entries_needed)                break;            offset += 32;        }        else        {            offset += 32;            dir_entry_offset = offset;            free_dir_entries_found = 0;        }    }    return dir_entry_offset;}#endif

⌨️ 快捷键说明

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