📄 fat16.c
字号:
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->dir_entry.cluster; uint16_t buffer_left = buffer_len; uint16_t first_cluster_offset; /* find cluster in which to start reading */ if(cluster_num) { 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; } first_cluster_offset = pos; } else { return -1; } /* read data */ while(1) { /* calculate data size to copy from cluster */ uint32_t cluster_offset = fd->fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * cluster_size + 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; /* check if we are done */ if(buffer_left == 0) break; /* we are on a cluster boundary, so get the next cluster */ if((cluster_num = fat16_get_next_cluster(fd->fs, cluster_num))) first_cluster_offset = 0; else return buffer_len - buffer_left; } return buffer_len;}/** * \ingroup fat16_file * Writes data to a file. * * The data is written to the current file location. * * \param[in] fd The file handle of the file to which to write. * \param[in] buffer The buffer from which to read the data to be written. * \param[in] buffer_len The amount of data to write. * \returns The number of bytes written, 0 on disk full, or -1 on failure. * \see fat16_read_file */int16_t fat16_write_file(struct fat16_file_struct* fd, const uint8_t* buffer, uint16_t buffer_len){#if FAT16_WRITE_SUPPORT /* check arguments */ if(!fd || !buffer || buffer_len < 1) return -1; if(fd->pos > fd->dir_entry.file_size) return -1; uint16_t cluster_size = fd->fs->header.cluster_size; uint16_t cluster_num = fd->dir_entry.cluster; uint16_t buffer_left = buffer_len; uint16_t first_cluster_offset = 0; /* find cluster in which to start writing */ if(cluster_num) { 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 && pos == 0) /* the file exactly ends on a cluster boundary, and we append to it */ cluster_num = fat16_append_cluster(fd->fs, cluster_num); if(!cluster_num) return -1; } first_cluster_offset = pos; } else { fd->dir_entry.cluster = cluster_num = fat16_append_cluster(fd->fs, 0); if(!cluster_num) return -1; } /* write data */ while(1) { /* calculate data size to write to cluster */ uint32_t cluster_offset = fd->fs->header.cluster_zero_offset + (uint32_t) (cluster_num - 2) * cluster_size + first_cluster_offset; uint16_t write_length = cluster_size - first_cluster_offset; if(write_length > buffer_left) write_length = buffer_left; /* write data which fits into the current cluster */ if(!fd->fs->partition->device_write(cluster_offset, buffer, write_length)) break; /* calculate new file position */ buffer += write_length; buffer_left -= write_length; fd->pos += write_length; /* check if we are done */ if(buffer_left == 0) break; /* we are on a cluster boundary, so get the next cluster */ uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num); if(!cluster_num_next) { cluster_num_next = fat16_append_cluster(fd->fs, cluster_num); if(!cluster_num_next) break; } cluster_num = cluster_num_next; first_cluster_offset = 0; } /* update directory entry */ if(fd->pos > fd->dir_entry.file_size) { uint32_t size_old = fd->dir_entry.file_size; /* update file size */ fd->dir_entry.file_size = fd->pos; /* write directory entry */ if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry)) { /* We do not return an error here since we actually wrote * some data to disk. So we calculate the amount of data * we wrote to disk and which lies within the old file size. */ buffer_left = fd->pos - size_old; fd->pos = size_old; } } return buffer_len - buffer_left;#else return -1;#endif}/** * \ingroup fat16_file * Repositions the read/write file offset. * * Changes the file offset where the next call to fat16_read_file() * or fat16_write_file() starts reading/writing. * * If the new offset is beyond the end of the file, fat16_resize_file() * is implicitly called, i.e. the file is expanded. * * The new offset can be given in different ways determined by * the \c whence parameter: * - \b FAT16_SEEK_SET: \c *offset is relative to the beginning of the file. * - \b FAT16_SEEK_CUR: \c *offset is relative to the current file position. * - \b FAT16_SEEK_END: \c *offset is relative to the end of the file. * * The resulting absolute offset is written to the location the \c offset * parameter points to. * * \param[in] fd The file decriptor of the file on which to seek. * \param[in,out] offset A pointer to the new offset, as affected by the \c whence * parameter. The function writes the new absolute offset * to this location before it returns. * \param[in] whence Affects the way \c offset is interpreted, see above. * \returns 0 on failure, 1 on success. */uint8_t fat16_seek_file(struct fat16_file_struct* fd, int32_t* offset, uint8_t whence){ if(!fd || !offset) return 0; uint32_t new_pos = fd->pos; switch(whence) { case FAT16_SEEK_SET: new_pos = *offset; break; case FAT16_SEEK_CUR: new_pos += *offset; break; case FAT16_SEEK_END: new_pos = fd->dir_entry.file_size + *offset; break; default: return 0; } if(new_pos > fd->dir_entry.file_size && !fat16_resize_file(fd, new_pos)) return 0; fd->pos = new_pos; *offset = new_pos; return 1;}/** * \ingroup fat16_file * Resizes a file to have a specific size. * * Enlarges or shrinks the file pointed to by the file descriptor to have * exactly the specified size. * * If the file is truncated, all bytes having an equal or larger offset * than the given size are lost. If the file is expanded, the additional * bytes are allocated, but they keep their values. * * \param[in] fd The file decriptor of the file which to resize. * \param[in] size The new size of the file. * \returns 0 on failure, 1 on success. */uint8_t fat16_resize_file(struct fat16_file_struct* fd, uint32_t size){ if(!fd) return 0; uint16_t cluster_num = fd->dir_entry.cluster; uint16_t cluster_size = fd->fs->header.cluster_size; uint32_t size_new = size; if(fd->dir_entry.file_size < size) { /* check if the file owns a cluster */ if(cluster_num == 0) { /* allocate first cluster */ if(!(cluster_num = fat16_append_cluster(fd->fs, cluster_num))) return 0; fd->dir_entry.cluster = cluster_num; } else { /* get last cluster of file */ uint16_t cluster_num_next; while((cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num))) { cluster_num = cluster_num_next; size_new -= cluster_size; } } /* append new clusters as needed */ if(size_new > cluster_size) { while(1) { if(!(cluster_num = fat16_append_cluster(fd->fs, cluster_num))) return 0; if(size_new <= cluster_size) break; size_new -= cluster_size; } } /* write new directory entry */ fd->dir_entry.file_size = size; if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry)) return 0; } else if(fd->dir_entry.file_size > size) { /* write new directory entry */ fd->dir_entry.file_size = size; if(size == 0) fd->dir_entry.cluster = 0; if(!fat16_write_dir_entry(fd->fs, &fd->dir_entry)) return 0; /* get cluster where the file is cut off */ while(size_new > cluster_size) { if(!(cluster_num = fat16_get_next_cluster(fd->fs, cluster_num))) return 0; size_new -= cluster_size; } /* free all clusters no longer needed */ if(size == 0 || (cluster_num = fat16_get_next_cluster(fd->fs, cluster_num))) { while(cluster_num) { /* get next cluster before freeing the previous one */ uint16_t cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num); /* delete cluster */ fat16_free_cluster(fd->fs, cluster_num); cluster_num = cluster_num_next; } } } return 1;}/** * \ingroup fat16_dir * Opens a directory. * * \param[in] fs The filesystem on which the directory to open resides. * \param[in] dir_entry The directory entry which stands for the directory to open. * \returns An opaque directory descriptor on success, 0 on failure. * \see fat16_close_dir */struct fat16_dir_struct* fat16_open_dir(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; struct fat16_dir_struct* dd = malloc(sizeof(*dd)); if(!dd) return 0; memcpy(&dd->dir_entry, dir_entry, sizeof(*dir_entry)); dd->fs = fs; dd->entry_next = 0; return dd;}/** * \ingroup fat16_dir * Closes a directory descriptor. * * This function destroys a directory descriptor which was * previously obtained by calling fat16_open_dir(). When this * function returns, the given descriptor will be invalid. * * \param[in] dd The directory descriptor to close. * \see fat16_open_dir */void fat16_close_dir(struct fat16_dir_struct* dd){ if(dd) free(dd);}/** * \ingroup fat16_dir * Reads the next directory entry contained within a parent directory. * * \param[in] dd The descriptor of the parent directory from which to read the entry. * \param[out] dir_entry Pointer to a buffer into which to write the directory entry information. * \returns 0 on failure, 1 on success. * \see fat16_reset_dir */uint8_t fat16_read_dir(struct fat16_dir_struct* dd, struct fat16_dir_entry_struct* dir_entry){ if(!dd || !dir_entry) return 0; if(dd->dir_entry.cluster == 0) { /* read entry from root directory */ if(fat16_read_root_dir_entry(dd->fs, dd->entry_next, dir_entry)) { ++dd->entry_next; return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -