📄 fat16.c
字号:
/* 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
*/
u8 fat16_free_clusters(const struct fat16_fs_struct* fs, u16 cluster_num)
{
#if FAT16_WRITE_SUPPORT
if(!fs || cluster_num < 2)
return 0;
u32 fat_offset = fs->header.fat_offset;
u8 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 */
u16 cluster_num_next = ((u16) buffer[0]) |
((u16) 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
*/
u8 fat16_terminate_clusters(const struct fat16_fs_struct* fs, u16 cluster_num)
{
#if FAT16_WRITE_SUPPORT
if(!fs || cluster_num < 2)
return 0;
/* fetch next cluster before overwriting the cluster entry */
u16 cluster_num_next = fat16_get_next_cluster(fs, cluster_num);
/* mark cluster as the last one */
u8 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.
*/
u8 fat16_clear_cluster(const struct fat16_fs_struct* fs, u16 cluster_num)
{
#if FAT16_WRITE_SUPPORT
if(cluster_num < 2)
return 0;
u32 cluster_offset = fs->header.cluster_zero_offset +
(u32) (cluster_num - 2) * fs->header.cluster_size;
u8 zero[CLUSTER_BUFFER_SIZE];
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.
*/
u16 fat16_clear_cluster_callback(u8* buffer, u32 offset, void* p)
{
#if FAT16_WRITE_SUPPORT
memset(buffer, 0, CLUSTER_BUFFER_SIZE);
return CLUSTER_BUFFER_SIZE;
#else
return 0;
#endif
}
/**
* \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_handlers;
u8 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
*/
s16 fat16_read_file(struct fat16_file_struct* fd, u8* buffer, u16 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;
u16 cluster_size = fd->fs->header.cluster_size;
u16 cluster_num = fd->pos_cluster;
u16 buffer_left = buffer_len;
u16 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)
{
u32 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 */
u32 cluster_offset = fd->fs->header.cluster_zero_offset +
(u32) (cluster_num - 2) * cluster_size + first_cluster_offset;
u16 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;
if(first_cluster_offset + copy_length >= cluster_size)
{
/* 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
{
fd->pos_cluster = 0;
return buffer_len - buffer_left;
}
}
fd->pos_cluster = cluster_num;
} while(buffer_left > 0); /* check if we are done */
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
*/
s16 fat16_write_file(struct fat16_file_struct* fd, const u8* buffer, u16 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;
u16 cluster_size = fd->fs->header.cluster_size;
u16 cluster_num = fd->pos_cluster;
u16 buffer_left = buffer_len;
u16 first_cluster_offset = fd->pos % cluster_size;
/* find cluster in which to start writing */
if(!cluster_num)
{
cluster_num = fd->dir_entry.cluster;
if(!cluster_num)
{
if(!fd->pos)
{
/* empty file */
fd->dir_entry.cluster = cluster_num = fat16_append_clusters(fd->fs, 0, 1);
if(!cluster_num)
return -1;
}
else
{
return -1;
}
}
if(fd->pos)
{
u32 pos = fd->pos;
u16 cluster_num_next;
while(pos >= cluster_size)
{
pos -= cluster_size;
cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num);
if(!cluster_num_next && pos == 0)
/* the file exactly ends on a cluster boundary, and we append to it */
cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1);
if(!cluster_num_next)
return -1;
cluster_num = cluster_num_next;
}
}
}
/* write data */
do
{
/* calculate data size to write to cluster */
u32 cluster_offset = fd->fs->header.cluster_zero_offset +
(u32) (cluster_num - 2) * cluster_size + first_cluster_offset;
u16 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;
if(first_cluster_offset + write_length >= cluster_size)
{
/* we are on a cluster boundary, so get the next cluster */
u16 cluster_num_next = fat16_get_next_cluster(fd->fs, cluster_num);
if(!cluster_num_next && buffer_left > 0)
/* we reached the last cluster, append a new one */
cluster_num_next = fat16_append_clusters(fd->fs, cluster_num, 1);
if(!cluster_num_next)
{
fd->pos_cluster = 0;
break;
}
cluster_num = cluster_num_next;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -