📄 fat16.c
字号:
* \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){ char* long_name;
uint16_t char_offset;
uint8_t i,j;
if(!dir_entry || !raw_entry || !raw_entry[0]) return 0;
long_name = dir_entry->long_name; if(raw_entry[11] == 0x0f) { 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') { 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++] = '.'; 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){
char* sep_pos;
struct fat16_dir_struct* dd;
uint8_t length_to_sep;
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) { dd = fat16_open_dir(fs, dir_entry); if(!dd) break; /* extract the next hierarchy we will search for */ sep_pos = strchr(path, '/'); if(!sep_pos) sep_pos = (char *)path + strlen(path); length_to_sep =(U8)( 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){ uint8_t fat_entry[2];
if(!fs || cluster_num < 2) return 0; /* read appropriate fat entry */ 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
device_read_t device_read; device_write_t device_write; uint32_t fat_offset; uint16_t cluster_max; uint16_t cluster_next; uint16_t count_left;
uint8_t buffer[2]; uint16_t cluster_new; if(!fs) return 0; device_read = fs->partition->device_read; device_write = fs->partition->device_write; fat_offset = fs->header.fat_offset; cluster_max = (U16) (fs->header.fat_size >> 1); cluster_next = 0; count_left = count; for(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 uint8_t buffer[2];
uint32_t fat_offset;
uint16_t cluster_num_next;
if(!fs || cluster_num < 2) return 0; fat_offset = fs->header.fat_offset; while(cluster_num) { if(!fs->partition->device_read(fat_offset + 2 * cluster_num, buffer, 2)) return 0; /* get next cluster of current cluster before freeing current cluster */ cluster_num_next = ((uint16_t) buffer[0]) | ((uint16_t) buffer[1] << 8); if(cluster_num_next == FAT16_CLUSTER_FREE) return 1; if(cluster_num_next == FAT16_CLUSTER_BAD || (cluster_num_next >= FAT16_CLUSTER_RESERVED_MIN && cluster_num_next <= FAT16_CLUSTER_RESERVED_MAX ) ) return 0; if(cluster_num_next >= FAT16_CLUSTER_LAST_MIN && cluster_num_next <= FAT16_CLUSTER_LAST_MAX) cluster_num_next = 0; /* free cluster */ buffer[0] = FAT16_CLUSTER_FREE & 0xff; buffer[1] = (FAT16_CLUSTER_FREE >> 8) & 0xff; fs->partition->device_write(fat_offset + 2 * cluster_num, buffer, 2); /* We continue in any case here, even if freeing the cluster failed. * The cluster is lost, but maybe we can still free up some later ones. */ cluster_num = cluster_num_next; } return 1;#else return 0;#endif}/** * \ingroup fat16_fs * Frees a part of a cluster chain and correctly terminates the rest. * * Marks the specified cluster as the new end of a cluster chain and * frees all following clusters. * * \param[in] fs The filesystem on which to operate. * \param[in] cluster_num The new end of the cluster chain. * \returns 0 on failure, 1 on success. * \see fat16_free_clusters */uint8_t fat16_terminate_clusters(const struct fat16_fs_struct* fs, uint16_t cluster_num){#if FAT16_WRITE_SUPPORT
uint16_t cluster_num_next;
uint8_t buffer[2];
if(!fs || cluster_num < 2) return 0; /* fetch next cluster before overwriting the cluster entry */ cluster_num_next = fat16_get_next_cluster(fs, cluster_num); /* mark cluster as the last one */ buffer[0] = FAT16_CLUSTER_LAST_MAX & 0xff; buffer[1] = (FAT16_CLUSTER_LAST_MAX >> 8) & 0xff; if(!fs->partition->device_write(fs->header.fat_offset + 2 * cluster_num, buffer, 2)) return 0; /* free remaining clusters */ if(cluster_num_next) return fat16_free_clusters(fs, cluster_num_next); else return 1;#else return 0;#endif}/** * \ingroup fat16_fs * Clears a single cluster. * * The complete cluster is filled with zeros. * * \param[in] fs The filesystem on which to operate. * \param[in] cluster_num The cluster to clear. * \returns 0 on failure, 1 on success. */uint8_t fat16_clear_cluster(const struct fat16_fs_struct* fs, uint16_t cluster_num){#if FAT16_WRITE_SUPPORT
uint32_t cluster_offset; uint8_t zero[64]; //old is 16
if(cluster_num < 2) return 0; cluster_offset = fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * fs->header.cluster_size; return fs->partition->device_write_interval(cluster_offset, zero, fs->header.cluster_size, fat16_clear_cluster_callback, 0 );#else return 0;#endif}/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -