📄 fat.c
字号:
#if FAT_FAT32_SUPPORT if(fs->partition->type == PARTITION_TYPE_FAT32) { /* read appropriate fat entry */ uint32_t fat_entry; if(!fs->partition->device_read(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) return 0; /* determine next cluster from fat */ cluster_num = ltoh32(fat_entry); if(cluster_num == FAT32_CLUSTER_FREE || cluster_num == FAT32_CLUSTER_BAD || (cluster_num >= FAT32_CLUSTER_RESERVED_MIN && cluster_num <= FAT32_CLUSTER_RESERVED_MAX) || (cluster_num >= FAT32_CLUSTER_LAST_MIN && cluster_num <= FAT32_CLUSTER_LAST_MAX)) return 0; } else#endif { /* read appropriate fat entry */ uint16_t fat_entry; if(!fs->partition->device_read(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) return 0; /* determine next cluster from fat */ cluster_num = ltoh16(fat_entry); 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;}#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_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. */cluster_t fat_append_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num, cluster_t count){ if(!fs) return 0; device_read_t device_read = fs->partition->device_read; device_write_t device_write = fs->partition->device_write; offset_t fat_offset = fs->header.fat_offset; cluster_t count_left = count; cluster_t cluster_next = 0; cluster_t cluster_max; uint16_t fat_entry16;#if FAT_FAT32_SUPPORT uint32_t fat_entry32; uint8_t is_fat32 = (fs->partition->type == PARTITION_TYPE_FAT32); if(is_fat32) cluster_max = fs->header.fat_size / sizeof(fat_entry32); else#endif cluster_max = fs->header.fat_size / sizeof(fat_entry16); for(cluster_t cluster_new = 2; cluster_new < cluster_max; ++cluster_new) {#if FAT_FAT32_SUPPORT if(is_fat32) { if(!device_read(fat_offset + cluster_new * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32))) return 0; } else#endif { if(!device_read(fat_offset + cluster_new * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16))) return 0; }#if FAT_FAT32_SUPPORT if(is_fat32) { /* check if this is a free cluster */ if(fat_entry32 != HTOL32(FAT32_CLUSTER_FREE)) continue; /* allocate cluster */ if(cluster_next == 0) fat_entry32 = HTOL32(FAT32_CLUSTER_LAST_MAX); else fat_entry32 = htol32(cluster_next); if(!device_write(fat_offset + cluster_new * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32))) break; } else#endif { /* check if this is a free cluster */ if(fat_entry16 != HTOL16(FAT16_CLUSTER_FREE)) continue; /* allocate cluster */ if(cluster_next == 0) fat_entry16 = HTOL16(FAT16_CLUSTER_LAST_MAX); else fat_entry16 = htol16((uint16_t) cluster_next); if(!device_write(fat_offset + cluster_new * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16))) 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 any). */ if(cluster_num >= 2) {#if FAT_FAT32_SUPPORT if(is_fat32) { fat_entry32 = htol32(cluster_next); if(!device_write(fat_offset + cluster_num * sizeof(fat_entry32), (uint8_t*) &fat_entry32, sizeof(fat_entry32))) break; } else#endif { fat_entry16 = htol16((uint16_t) cluster_next); if(!device_write(fat_offset + cluster_num * sizeof(fat_entry16), (uint8_t*) &fat_entry16, sizeof(fat_entry16))) break; } } return cluster_next; } while(0); /* No space left on device or writing error. * Free up all clusters already allocated. */ fat_free_clusters(fs, cluster_next); return 0;}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_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 fat_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 fat_terminate_clusters */uint8_t fat_free_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num){ if(!fs || cluster_num < 2) return 0; offset_t fat_offset = fs->header.fat_offset;#if FAT_FAT32_SUPPORT if(fs->partition->type == PARTITION_TYPE_FAT32) { uint32_t fat_entry; while(cluster_num) { if(!fs->partition->device_read(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) return 0; /* get next cluster of current cluster before freeing current cluster */ uint32_t cluster_num_next = ltoh32(fat_entry); if(cluster_num_next == FAT32_CLUSTER_FREE) return 1; if(cluster_num_next == FAT32_CLUSTER_BAD || (cluster_num_next >= FAT32_CLUSTER_RESERVED_MIN && cluster_num_next <= FAT32_CLUSTER_RESERVED_MAX ) ) return 0; if(cluster_num_next >= FAT32_CLUSTER_LAST_MIN && cluster_num_next <= FAT32_CLUSTER_LAST_MAX) cluster_num_next = 0; /* free cluster */ fat_entry = HTOL32(FAT32_CLUSTER_FREE); fs->partition->device_write(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)); /* 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; } } else#endif { uint16_t fat_entry; while(cluster_num) { if(!fs->partition->device_read(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) return 0; /* get next cluster of current cluster before freeing current cluster */ uint16_t cluster_num_next = ltoh16(fat_entry); 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 */ fat_entry = HTOL16(FAT16_CLUSTER_FREE); fs->partition->device_write(fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry)); /* 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;}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_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 fat_free_clusters */uint8_t fat_terminate_clusters(const struct fat_fs_struct* fs, cluster_t cluster_num){ if(!fs || cluster_num < 2) return 0; /* fetch next cluster before overwriting the cluster entry */ cluster_t cluster_num_next = fat_get_next_cluster(fs, cluster_num); /* mark cluster as the last one */#if FAT_FAT32_SUPPORT if(fs->partition->type == PARTITION_TYPE_FAT32) { uint32_t fat_entry = HTOL32(FAT32_CLUSTER_LAST_MAX); if(!fs->partition->device_write(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) return 0; } else#endif { uint16_t fat_entry = HTOL16(FAT16_CLUSTER_LAST_MAX); if(!fs->partition->device_write(fs->header.fat_offset + cluster_num * sizeof(fat_entry), (uint8_t*) &fat_entry, sizeof(fat_entry))) return 0; } /* free remaining clusters */ if(cluster_num_next) return fat_free_clusters(fs, cluster_num_next); else return 1;}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_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 fat_clear_cluster(const struct fat_fs_struct* fs, cluster_t cluster_num){ if(cluster_num < 2) return 0; offset_t cluster_offset = fat_cluster_offset(fs, cluster_num); uint8_t zero[16]; memset(zero, 0, sizeof(zero)); return fs->partition->device_write_interval(cluster_offset, zero, fs->header.cluster_size, fat_clear_cluster_callback, 0 );}#endif#if DOXYGEN || FAT_WRITE_SUPPORT/** * \ingroup fat_fs * Callback function for clearing a cluster. */uintptr_t fat_clear_cluster_callback(uint8_t* buffer, offset_t offset, void* p){ return 16;}#endif/** * \ingroup fat_fs * Calculates the offset of the specified cluster. * * \param[in] fs The filesystem on which to operate. * \param[in] cluster_num The cluster whose offset to calculate. * \returns The cluster offset. */offset_t fat_cluster_offset(const struct fat_fs_struct* fs, cluster_t cluster_num){ if(!fs || cluster_num < 2) return 0; return fs->header.cluster_zero_offset + (offset_t) (cluster_num - 2) * fs->header.cluster_size;}/** * \ingroup fat_file * Retrieves the directory entry of a path. * * The given path may both describe a file or a directory. * * \param[in] fs The FAT 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 fat_read_dir */uint8_t fat_get_dir_entry_of_path(struct fat_fs_struct* fs, const char* path, struct fat_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 = FAT_ATTRIB_DIR; while(1) { if(path[0] == '\0') return 1; struct fat_dir_struct* dd = fat_open_dir(fs, dir_entry); if(!dd) break; /* extract the next hierarchy we will search for */ const char* sub_path = strchr(path, '/'); uint8_t length_to_sep; if(sub_path) { length_to_sep = sub_path - path; ++sub_path; } else { length_to_sep = strlen(path); sub_path = path + length_to_sep; } /* read directory entries */ while(fat_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; fat_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 & FAT_ATTRIB_DIR) { /* we found a parent directory of the file we are searching for */ path = sub_path; break; } /* a parent of the file exists, but not the file itself */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -