📄 fat16.c
字号:
/* 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;#else return 0;#endif}/** * \ingroup fat16_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 fat16_delete_file */uint8_t fat16_create_file(struct fat16_dir_struct* parent, const char* file, struct fat16_dir_entry_struct* dir_entry){#if FAT16_WRITE_SUPPORT
struct fat16_fs_struct* fs;
if(!parent || !file || !file[0] || !dir_entry) return 0; /* check if the file already exists */ while(1) { if(!fat16_read_dir(parent, dir_entry)) break; if(strcmp(file, dir_entry->long_name) == 0) { fat16_reset_dir(parent); return 0; } } 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 */
dir_entry->entry_offset = fat16_find_offset_for_dir_entry(fs, parent, dir_entry); if(!dir_entry->entry_offset) return 0; /* write directory entry to disk */ if(!fat16_write_dir_entry(fs, dir_entry)) return 0; return 1; #else return 0;#endif}/** * \ingroup fat16_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 fat16_create_file */uint8_t fat16_delete_file(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry){#if FAT16_WRITE_SUPPORT
uint32_t dir_entry_offset;
uint8_t buffer[12];
if(!fs || !dir_entry) return 0; /* get offset of the file's directory entry */ dir_entry_offset = dir_entry->entry_offset; if(!dir_entry_offset) return 0; 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] = FAT16_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 || fat16_free_clusters(fs, dir_entry->cluster));#else return 0;#endif}/** * \ingroup fat16_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 fat16_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 fat16_delete_dir */uint8_t fat16_create_dir(struct fat16_dir_struct* parent, const char* dir, struct fat16_dir_entry_struct* dir_entry){#if FAT16_WRITE_SUPPORT
struct fat16_fs_struct* fs;
uint16_t dir_cluster;
if(!parent || !dir || !dir[0] || !dir_entry) return 0; /* check if the file or directory already exists */ while(1) { if(!fat16_read_dir(parent, dir_entry)) break; if(strcmp(dir, dir_entry->long_name) == 0) { fat16_reset_dir(parent); return 0; } } fs = parent->fs; /* allocate cluster which will hold directory entries */ dir_cluster = fat16_append_clusters(fs, 0, 1); if(!dir_cluster) return 0; /* clear cluster to prevent bogus directory entries */ fat16_clear_cluster(fs, dir_cluster); memset(dir_entry, 0, sizeof(*dir_entry)); dir_entry->attributes = FAT16_ATTRIB_DIR; /* create "." directory self reference */ dir_entry->entry_offset = fs->header.cluster_zero_offset + (uint32_t) (dir_cluster - 2) * fs->header.cluster_size; dir_entry->long_name[0] = '.'; dir_entry->cluster = dir_cluster; if(!fat16_write_dir_entry(fs, dir_entry)) { fat16_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(!fat16_write_dir_entry(fs, dir_entry)) { fat16_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 */
dir_entry->entry_offset = fat16_find_offset_for_dir_entry(fs, parent, dir_entry); if(!dir_entry->entry_offset) { fat16_free_clusters(fs, dir_cluster); return 0; } /* write directory to disk */ if(!fat16_write_dir_entry(fs, dir_entry)) { fat16_free_clusters(fs, dir_cluster); return 0; } return 1; #else return 0;#endif}/** * \ingroup fat16_dir * Deletes a directory. * * This is just a synonym for fat16_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 fat16_create_dir */#ifdef DOXYGENuint8_t fat16_delete_dir(struct fat16_fs_struct* fs, struct fat16_dir_entry_struct* dir_entry);#endif/** * \ingroup fat16_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 fat16_get_file_modification_date(const struct fat16_dir_entry_struct* dir_entry, uint16_t* year, uint8_t* month, uint8_t* day){#if FAT16_DATETIME_SUPPORT 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}/** * \ingroup fat16_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 fat16_get_file_modification_time(const struct fat16_dir_entry_struct* dir_entry, uint8_t* hour, uint8_t* min, uint8_t* sec){#if FAT16_DATETIME_SUPPORT if(!dir_entry) return; *hour = (dir_entry->modification_time >> 11) & 0x1f; *min = (dir_entry->modification_time >> 5) & 0x3f; *sec = ((dir_entry->modification_time >> 0) & 0x1f) * 2;#endif}/** * \ingroup fat16_file * Sets the modification time of a date. * * \param[in] dir_entry The directory entry for which to set the modification date. * \param[in] year The year the file was last modified. * \param[in] month The month the file was last modified. * \param[in] day The day the file was last modified. */void fat16_set_file_modification_date(struct fat16_dir_entry_struct* dir_entry, uint16_t year, uint8_t month, uint8_t day){#if FAT16_WRITE_SUPPORT#if FAT16_DATETIME_SUPPORT if(!dir_entry) return; dir_entry->modification_date = ((year - 1980) << 9) | ((uint16_t) month << 5) | ((uint16_t) day << 0);#endif#endif}/** * \ingroup fat16_file * Sets the modification time of a file. * * \param[in] dir_entry The directory entry for which to set the modification time. * \param[in] hour The year the file was last modified. * \param[in] min The month the file was last modified. * \param[in] sec The day the file was last modified. */void fat16_set_file_modification_time(struct fat16_dir_entry_struct* dir_entry, uint8_t hour, uint8_t min, uint8_t sec){#if FAT16_WRITE_SUPPORT#if FAT16_DATETIME_SUPPORT if(!dir_entry) return; dir_entry->modification_time = ((uint16_t) hour << 11) | ((uint16_t) min << 5) | ((uint16_t) sec >> 1) ;#endif#endif}/** * \ingroup fat16_fs * Returns the amount of total storage capacity of the filesystem in bytes. * * \param[in] fs The filesystem on which to operate. * \returns 0 on failure, the filesystem size in bytes otherwise. */uint32_t fat16_get_fs_size(const struct fat16_fs_struct* fs){ if(!fs) return 0; return (fs->header.fat_size / 2 - 2) * fs->header.cluster_size;}/** * \ingroup fat16_fs * Returns the amount of free storage capacity on the filesystem in bytes. * * \note As the FAT16 filesystem is cluster based, this function does not * return continuous values but multiples of the cluster size. * * \param[in] fs The filesystem on which to operate. * \returns 0 on failure, the free filesystem space in bytes otherwise. */uint32_t fat16_get_fs_free(const struct fat16_fs_struct* fs){
uint8_t fat[32]; struct fat16_usage_count_callback_arg count_arg;
uint32_t fat_offset; uint32_t fat_size;
if(!fs) return 0; count_arg.cluster_count = 0; count_arg.buffer_size = sizeof(fat); fat_offset = fs->header.fat_offset; fat_size = fs->header.fat_size;
while(fat_size > 0) { uint16_t length = UINT16_MAX - 1; if(fat_size < length) length = (U16) fat_size; if(!fs->partition->device_read_interval(fat_offset, fat, sizeof(fat), length, fat16_get_fs_free_callback, &count_arg ) ) return 0; fat_offset += length; fat_size -= length; } return (uint32_t) count_arg.cluster_count * fs->header.cluster_size;}/** * \ingroup fat16_fs * Callback function used for counting free clusters. */uint8_t fat16_get_fs_free_callback(uint8_t* buffer, uint32_t offset, void* p){ struct fat16_usage_count_callback_arg* count_arg = (struct fat16_usage_count_callback_arg*) p; uint8_t buffer_size = count_arg->buffer_size; uint8_t i; for(i = 0; i < buffer_size; i += 2) { if((((uint16_t) buffer[1] << 8) | ((uint16_t) buffer[0] << 0)) == FAT16_CLUSTER_FREE) ++(count_arg->cluster_count); buffer += 2; } return 1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -