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

📄 fat.c

📁 This project provides a general purpose library which implements read and write support for MMC, SD
💻 C
📖 第 1 页 / 共 5 页
字号:
#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_fs * Writes a directory entry to disk. * * \note The file name is not checked for invalid characters. * * \note The generation of the short 8.3 file name is quite * simple. The first eight characters are used for the filename. * The extension, if any, is made up of the first three characters * following the last dot within the long filename. If the * filename (without the extension) is longer than eight characters, * the lower byte of the cluster number replaces the last two * characters to avoid name clashes. In any other case, it is your * responsibility to avoid name clashes. * * \param[in] fs The filesystem on which to operate. * \param[in] dir_entry The directory entry to write. * \returns 0 on failure, 1 on success. */uint8_t fat_write_dir_entry(const struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry){    if(!fs || !dir_entry)        return 0;    #if FAT_DATETIME_SUPPORT    {        uint16_t year;        uint8_t month;        uint8_t day;        uint8_t hour;        uint8_t min;        uint8_t sec;        fat_get_datetime(&year, &month, &day, &hour, &min, &sec);        fat_set_file_modification_date(dir_entry, year, month, day);        fat_set_file_modification_time(dir_entry, hour, min, sec);    }#endif    device_write_t device_write = fs->partition->device_write;    offset_t offset = dir_entry->entry_offset;    const char* name = dir_entry->long_name;    uint8_t name_len = strlen(name);    uint8_t lfn_entry_count = (name_len + 12) / 13;    uint8_t buffer[32];    /* write 8.3 entry */    /* generate 8.3 file name */    memset(&buffer[0], ' ', 11);    char* name_ext = strrchr(name, '.');    if(name_ext && *++name_ext)    {        uint8_t name_ext_len = strlen(name_ext);        name_len -= name_ext_len + 1;        if(name_ext_len > 3)            name_ext_len = 3;                memcpy(&buffer[8], name_ext, name_ext_len);    }        if(name_len <= 8)    {        memcpy(buffer, name, name_len);        /* For now, we create lfn entries for all files,         * except the "." and ".." directory references.         * This is to avoid difficulties with capitalization,         * as 8.3 filenames allow uppercase letters only.         *         * Theoretically it would be possible to leave         * the 8.3 entry alone if the basename and the         * extension have no mixed capitalization.         */        if(name[0] == '.' &&           ((name[1] == '.' && name[2] == '\0') ||            name[1] == '\0')          )            lfn_entry_count = 0;    }    else    {        memcpy(buffer, name, 8);        /* Minimize 8.3 name clashes by appending         * the lower byte of the cluster number.         */        uint8_t num = dir_entry->cluster & 0xff;        buffer[6] = (num < 0xa0) ? ('0' + (num >> 4)) : ('a' + (num >> 4));        num &= 0x0f;        buffer[7] = (num < 0x0a) ? ('0' + num) : ('a' + num);    }    if(buffer[0] == FAT_DIRENTRY_DELETED)        buffer[0] = 0x05;    /* fill directory entry buffer */    memset(&buffer[11], 0, sizeof(buffer) - 11);    buffer[0x0b] = dir_entry->attributes;#if FAT_DATETIME_SUPPORT    *((uint16_t*) &buffer[0x16]) = htol16(dir_entry->modification_time);    *((uint16_t*) &buffer[0x18]) = htol16(dir_entry->modification_date);#endif#if FAT_FAT32_SUPPORT    *((uint16_t*) &buffer[0x14]) = htol16((uint16_t) (dir_entry->cluster >> 16));#endif    *((uint16_t*) &buffer[0x1a]) = htol16(dir_entry->cluster);    *((uint32_t*) &buffer[0x1c]) = htol32(dir_entry->file_size);    /* write to disk */    if(!device_write(offset + (uint16_t) lfn_entry_count * 32, buffer, sizeof(buffer)))        return 0;        /* calculate checksum of 8.3 name */    uint8_t checksum = buffer[0];    for(uint8_t i = 1; i < 11; ++i)        checksum = ((checksum >> 1) | (checksum << 7)) + buffer[i];        /* write lfn entries */    for(uint8_t lfn_entry = lfn_entry_count; lfn_entry > 0; --lfn_entry)    {        memset(buffer, 0xff, sizeof(buffer));                /* set file name */        const char* long_name_curr = name + (lfn_entry - 1) * 13;        uint8_t i = 1;        while(i < 0x1f)        {            buffer[i++] = *long_name_curr;            buffer[i++] = 0;            switch(i)            {                case 0x0b:                    i = 0x0e;                    break;                case 0x1a:                    i = 0x1c;                    break;            }            if(!*long_name_curr++)                break;        }                /* set index of lfn entry */        buffer[0x00] = lfn_entry;        if(lfn_entry == lfn_entry_count)            buffer[0x00] |= FAT_DIRENTRY_LFNLAST;        /* mark as lfn entry */        buffer[0x0b] = 0x0f;        /* set 8.3 checksum */        buffer[0x0d] = checksum;        /* clear reserved bytes */        buffer[0x0c] = 0;        buffer[0x1a] = 0;        buffer[0x1b] = 0;        /* write entry */        device_write(offset, buffer, sizeof(buffer));            offset += sizeof(buffer);    }        return 1;}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_file * Creates a file. * * Creates a file and obtains the directory entry of the * new file. If the file to create already exists, the * directory entry of the existing file will be returned * within the dir_entry parameter. * * \note The file name is not checked for invalid characters. * * \note The generation of the short 8.3 file name is quite * simple. The first eight characters are used for the filename. * The extension, if any, is made up of the first three characters * following the last dot within the long filename. If the * filename (without the extension) is longer than eight characters, * the lower byte of the cluster number replaces the last two * characters to avoid name clashes. In any other case, it is your * responsibility to avoid name clashes. * * \param[in] parent The handle of the directory in which to create the file. * \param[in] file The name of the file to create. * \param[out] dir_entry The directory entry to fill for the new file. * \returns 0 on failure, 1 on success. * \see fat_delete_file */uint8_t fat_create_file(struct fat_dir_struct* parent, const char* file, struct fat_dir_entry_struct* dir_entry){    if(!parent || !file || !file[0] || !dir_entry)        return 0;    /* check if the file already exists */    while(1)    {        if(!fat_read_dir(parent, dir_entry))            break;        if(strcmp(file, dir_entry->long_name) == 0)        {            fat_reset_dir(parent);            return 0;        }    }    struct fat_fs_struct* fs = parent->fs;    /* prepare directory entry with values already known */    memset(dir_entry, 0, sizeof(*dir_entry));    strncpy(dir_entry->long_name, file, sizeof(dir_entry->long_name) - 1);    /* find place where to store directory entry */    if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))        return 0;        /* write directory entry to disk */    if(!fat_write_dir_entry(fs, dir_entry))        return 0;        return 1;}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_file * Deletes a file or directory. * * If a directory is deleted without first deleting its * subdirectories and files, disk space occupied by these * files will get wasted as there is no chance to release * it and mark it as free. *  * \param[in] fs The filesystem on which to operate. * \param[in] dir_entry The directory entry of the file to delete. * \returns 0 on failure, 1 on success. * \see fat_create_file */uint8_t fat_delete_file(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry){    if(!fs || !dir_entry)        return 0;    /* get offset of the file's directory entry */    offset_t dir_entry_offset = dir_entry->entry_offset;    if(!dir_entry_offset)        return 0;    uint8_t buffer[12];    while(1)    {        /* read directory entry */        if(!fs->partition->device_read(dir_entry_offset, buffer, sizeof(buffer)))            return 0;                /* mark the directory entry as deleted */        buffer[0] = FAT_DIRENTRY_DELETED;                /* write back entry */        if(!fs->partition->device_write(dir_entry_offset, buffer, sizeof(buffer)))            return 0;        /* check if we deleted the whole entry */        if(buffer[11] != 0x0f)            break;        dir_entry_offset += 32;    }    /* We deleted the directory entry. The next thing to do is     * marking all occupied clusters as free.     */    return (dir_entry->cluster == 0 || fat_free_clusters(fs, dir_entry->cluster));}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_dir * Creates a directory. * * Creates a directory and obtains its directory entry. * If the directory to create already exists, its * directory entry will be returned within the dir_entry * parameter. * * \note The notes which apply to fat_create_file also * apply to this function. * * \param[in] parent The handle of the parent directory of the new directory. * \param[in] dir The name of the directory to create. * \param[out] dir_entry The directory entry to fill for the new directory. * \returns 0 on failure, 1 on success. * \see fat_delete_dir */uint8_t fat_create_dir(struct fat_dir_struct* parent, const char* dir, struct fat_dir_entry_struct* dir_entry){    if(!parent || !dir || !dir[0] || !dir_entry)        return 0;    /* check if the file or directory already exists */    while(fat_read_dir(parent, dir_entry))    {        if(strcmp(dir, dir_entry->long_name) == 0)        {            fat_reset_dir(parent);            return 0;        }    }    struct fat_fs_struct* fs = parent->fs;    /* allocate cluster which will hold directory entries */    cluster_t dir_cluster = fat_append_clusters(fs, 0, 1);    if(!dir_cluster)        return 0;    /* clear cluster to prevent bogus directory entries */    fat_clear_cluster(fs, dir_cluster);        memset(dir_entry, 0, sizeof(*dir_entry));    dir_entry->attributes = FAT_ATTRIB_DIR;    /* create "." directory self reference */    dir_entry->entry_offset = fs->header.cluster_zero_offset +                              (offset_t) (dir_cluster - 2) * fs->header.cluster_size;    dir_entry->long_name[0] = '.';    dir_entry->cluster = dir_cluster;    if(!fat_write_dir_entry(fs, dir_entry))    {        fat_free_clusters(fs, dir_cluster);        return 0;    }    /* create ".." parent directory reference */    dir_entry->entry_offset += 32;    dir_entry->long_name[1] = '.';    dir_entry->cluster = parent->dir_entry.cluster;    if(!fat_write_dir_entry(fs, dir_entry))    {        fat_free_clusters(fs, dir_cluster);        return 0;    }    /* fill directory entry */    strncpy(dir_entry->long_name, dir, sizeof(dir_entry->long_name) - 1);    dir_entry->cluster = dir_cluster;    /* find place where to store directory entry */    if(!(dir_entry->entry_offset = fat_find_offset_for_dir_entry(fs, parent, dir_entry)))    {        fat_free_clusters(fs, dir_cluster);        return 0;    }    /* write directory to disk */    if(!fat_write_dir_entry(fs, dir_entry))    {        fat_free_clusters(fs, dir_cluster);        return 0;    }    return 1;}#endif/** * \ingroup fat_dir * Deletes a directory. * * This is just a synonym for fat_delete_file(). * If a directory is deleted without first deleting its * subdirectories and files, disk space occupied by these * files will get wasted as there is no chance to release * it and mark it as free. *  * \param[in] fs The filesystem on which to operate. * \param[in] dir_entry The directory entry of the directory to delete. * \returns 0 on failure, 1 on success. * \see fat_create_dir */#ifdef DOXYGENuint8_t fat_delete_dir(struct fat_fs_struct* fs, struct fat_dir_entry_struct* dir_entry);#endif#if DOXYGEN || FAT_DATETIME_SUPPORT/** * \ingroup fat_file * Returns the modification date of a file. * * \param[in] dir_entry The directory entry of which to return the modification date. * \param[out] year The year the file was last modified. * \param[out] month The month the file was last modified. * \param[out] day The day the file was last modified. */void fat_get_file_modification_date(const struct fat_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day){    if(!dir_entry)        return;    *year = 1980 + ((dir_entry->modification_date >> 9) & 0x7f);    *month = (dir_entry->modification_date >> 5) & 0x0f;    *day = (dir_entry->modification_date >> 0) & 0x1f;}#endif#if DOXYGEN || FAT_DATETIME_SUPPORT/** * \ingroup fat_file * Returns the modification time of a file. * * \param[in] dir_entry The directory entry of which to return the modification time. * \param[out] hour The hour the file was last modified. * \param[out] min The min the file was last modified. * \param[out] sec The sec the file was last modified. */void fat_get_file_modification_time(const struct fat_dir_entry_struct* dir_e

⌨️ 快捷键说明

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