📄 fat16.c
字号:
return 1; if(dir_entry->attributes & FAT16_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 */ 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){ if(!fs || cluster_num < 2) return 0; /* read appropriate fat entry */ uint8_t fat_entry[2]; 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 if(!fs) return 0; device_read_t device_read = fs->partition->device_read; device_write_t device_write = fs->partition->device_write; uint32_t fat_offset = fs->header.fat_offset; uint16_t cluster_max = fs->header.fat_size / 2; uint16_t cluster_next = 0; uint16_t count_left = count; uint8_t buffer[2]; for(uint16_t 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 if(!fs || cluster_num < 2) return 0; uint32_t fat_offset = fs->header.fat_offset; uint8_t buffer[2]; 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 */ uint16_t 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 if(!fs || cluster_num < 2) return 0; /* fetch next cluster before overwriting the cluster entry */ uint16_t cluster_num_next = fat16_get_next_cluster(fs, cluster_num); /* mark cluster as the last one */ uint8_t buffer[2]; 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 if(cluster_num < 2) return 0; uint32_t cluster_offset = fat16_cluster_offset(fs, cluster_num); uint8_t zero[16]; return fs->partition->device_write_interval(cluster_offset, zero, fs->header.cluster_size, fat16_clear_cluster_callback, 0 );#else return 0;#endif}/** * \ingroup fat16_fs * Callback function for clearing a cluster. */uint16_t fat16_clear_cluster_callback(uint8_t* buffer, uint32_t offset, void* p){#if FAT16_WRITE_SUPPORT memset(buffer, 0, 16); return 16;#else return 0;#endif}/** * \ingroup fat16_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. */uint32_t fat16_cluster_offset(const struct fat16_fs_struct* fs, uint16_t cluster_num){ if(!fs || cluster_num < 2) return 0; return fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * fs->header.cluster_size;}/** * \ingroup fat16_file * Opens a file on a FAT16 filesystem. * * \param[in] fs The filesystem on which the file to open lies. * \param[in] dir_entry The directory entry of the file to open. * \returns The file handle, or 0 on failure. * \see fat16_close_file */struct fat16_file_struct* fat16_open_file(struct fat16_fs_struct* fs, const struct fat16_dir_entry_struct* dir_entry){ if(!fs || !dir_entry || (dir_entry->attributes & FAT16_ATTRIB_DIR)) return 0;#if USE_DYNAMIC_MEMORY struct fat16_file_struct* fd = malloc(sizeof(*fd)); if(!fd) return 0;#else struct fat16_file_struct* fd = fat16_file_handles; uint8_t i; for(i = 0; i < FAT16_FILE_COUNT; ++i) { if(!fd->fs) break; ++fd; } if(i >= FAT16_FILE_COUNT) return 0;#endif memcpy(&fd->dir_entry, dir_entry, sizeof(*dir_entry)); fd->fs = fs; fd->pos = 0; fd->pos_cluster = dir_entry->cluster; return fd;}/** * \ingroup fat16_file * Closes a file. * * \param[in] fd The file handle of the file to close. * \see fat16_open_file */void fat16_close_file(struct fat16_file_struct* fd){ if(fd)#if USE_DYNAMIC_MEMORY free(fd);#else fd->fs = 0;#endif}/** * \ingroup fat16_file * Reads data from a file. * * The data requested is read from the current file location. * * \param[in] fd The file handle of the file from which to read. * \param[out] buffer The buffer into which to write. * \param[in] buffer_len The amount of data to read. * \returns The number of bytes read, 0 on end of file, or -1 on failure. * \see fat16_write_file */int16_t fat16_read_file(struct fat16_file_struct* fd, uint8_t* buffer, uint16_t buffer_len){ /* check arguments */ if(!fd || !buffer || buffer_len < 1) return -1; /* determine number of bytes to read */ if(fd->pos + buffer_len > fd->dir_entry.file_size) buffer_len = fd->dir_entry.file_size - fd->pos; if(buffer_len == 0) return 0; uint16_t cluster_size = fd->fs->header.cluster_size; uint16_t cluster_num = fd->pos_cluster; uint16_t buffer_left = buffer_len; uint16_t first_cluster_offset = fd->pos % cluster_size; /* find cluster in which to start reading */ if(!cluster_num) { cluster_num = fd->dir_entry.cluster; if(!cluster_num) { if(!fd->pos) return 0; else return -1; } if(fd->pos) { uint32_t pos = fd->pos; while(pos >= cluster_size) { pos -= cluster_size; cluster_num = fat16_get_next_cluster(fd->fs, cluster_num); if(!cluster_num) return -1; } } } /* read data */ do { /* calculate data size to copy from cluster */ uint32_t cluster_offset = fat16_cluster_offset(fd->fs, cluster_num) + first_cluster_offset; uint16_t copy_length = cluster_size - first_cluster_offset; if(copy_length > buffer_left) copy_length = buffer_left; /* read data */ if(!fd->fs->partition->device_read(cluster_offset, buffer, copy_length)) return buffer_len - buffer_left; /* calculate new file position */ buffer += copy_length; buffer_left -= copy_length; fd->pos += copy_length;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -