forked from Imagelibrary/rtems
Filesystem: PR1893: Fix write and truncate handler
Space that grows due to truncate or write offsets beyond the current file size must be zero filled.
This commit is contained in:
@@ -263,6 +263,42 @@ _fat_block_write(
|
||||
return cmpltd;
|
||||
}
|
||||
|
||||
int
|
||||
_fat_block_zero(
|
||||
rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
uint32_t count)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
fat_fs_info_t *fs_info = mt_entry->fs_info;
|
||||
uint32_t blk = start;
|
||||
uint32_t ofs = offset;
|
||||
rtems_bdbuf_buffer *block = NULL;
|
||||
uint32_t c = 0;
|
||||
|
||||
while(count > 0)
|
||||
{
|
||||
c = MIN(count, (fs_info->vol.bps - ofs));
|
||||
|
||||
if (c == fs_info->vol.bps)
|
||||
rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
|
||||
else
|
||||
rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
|
||||
if (rc != RC_OK)
|
||||
return -1;
|
||||
|
||||
memset((block->buffer + ofs), 0, c);
|
||||
|
||||
fat_buf_mark_modified(fs_info);
|
||||
|
||||
count -= c;
|
||||
blk++;
|
||||
ofs = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* _fat_block_release --
|
||||
* This function works around the hack that hold a bdbuf and does
|
||||
* not release it.
|
||||
|
||||
@@ -464,6 +464,12 @@ _fat_block_write(rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
uint32_t count,
|
||||
const void *buff);
|
||||
|
||||
int
|
||||
_fat_block_zero(rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
uint32_t start,
|
||||
uint32_t offset,
|
||||
uint32_t count);
|
||||
|
||||
int
|
||||
_fat_block_release(rtems_filesystem_mount_table_entry_t *mt_entry);
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ fat_scan_fat_for_free_clusters(
|
||||
uint32_t *chain,
|
||||
uint32_t count,
|
||||
uint32_t *cls_added,
|
||||
uint32_t *last_cl
|
||||
uint32_t *last_cl,
|
||||
bool zero_fill
|
||||
)
|
||||
{
|
||||
int rc = RC_OK;
|
||||
@@ -113,14 +114,16 @@ fat_scan_fat_for_free_clusters(
|
||||
|
||||
rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
|
||||
if ( rc != RC_OK )
|
||||
{
|
||||
/* cleanup activity */
|
||||
fat_free_fat_clusters_chain(mt_entry, (*chain));
|
||||
/* trying to save last allocated cluster for future use */
|
||||
fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
|
||||
fat_buf_release(fs_info);
|
||||
return rc;
|
||||
}
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (zero_fill) {
|
||||
uint32_t sec = fat_cluster_num_to_sector_num(mt_entry,
|
||||
cl4find);
|
||||
|
||||
rc = _fat_block_zero(mt_entry, sec, 0, fs_info->vol.bpc);
|
||||
if ( rc != RC_OK )
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
save_cln = cl4find;
|
||||
@@ -150,6 +153,15 @@ fat_scan_fat_for_free_clusters(
|
||||
*last_cl = save_cln;
|
||||
fat_buf_release(fs_info);
|
||||
return RC_OK;
|
||||
|
||||
cleanup:
|
||||
|
||||
/* cleanup activity */
|
||||
fat_free_fat_clusters_chain(mt_entry, (*chain));
|
||||
/* trying to save last allocated cluster for future use */
|
||||
fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
|
||||
fat_buf_release(fs_info);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* fat_free_fat_clusters_chain --
|
||||
|
||||
@@ -43,7 +43,8 @@ fat_scan_fat_for_free_clusters(
|
||||
uint32_t *chain,
|
||||
uint32_t count,
|
||||
uint32_t *cls_added,
|
||||
uint32_t *last_cl
|
||||
uint32_t *last_cl,
|
||||
bool zero_fill
|
||||
);
|
||||
|
||||
int
|
||||
|
||||
@@ -381,18 +381,18 @@ fat_file_write(
|
||||
uint32_t sec = 0;
|
||||
uint32_t byte = 0;
|
||||
uint32_t c = 0;
|
||||
bool zero_fill = start > fat_fd->fat_file_size;
|
||||
|
||||
if ( count == 0 )
|
||||
return cmpltd;
|
||||
|
||||
if ( start > fat_fd->fat_file_size )
|
||||
rtems_set_errno_and_return_minus_one( EIO );
|
||||
if (start >= fat_fd->size_limit)
|
||||
rtems_set_errno_and_return_minus_one(EFBIG);
|
||||
|
||||
if ((count > fat_fd->size_limit) ||
|
||||
(start > fat_fd->size_limit - count))
|
||||
rtems_set_errno_and_return_minus_one( EIO );
|
||||
if (count > fat_fd->size_limit - start)
|
||||
count = fat_fd->size_limit - start;
|
||||
|
||||
rc = fat_file_extend(mt_entry, fat_fd, start + count, &c);
|
||||
rc = fat_file_extend(mt_entry, fat_fd, zero_fill, start + count, &c);
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
|
||||
@@ -475,6 +475,7 @@ int
|
||||
fat_file_extend(
|
||||
rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
fat_file_fd_t *fat_fd,
|
||||
bool zero_fill,
|
||||
uint32_t new_length,
|
||||
uint32_t *a_length
|
||||
)
|
||||
@@ -509,6 +510,27 @@ fat_file_extend(
|
||||
else
|
||||
bytes2add = 0;
|
||||
|
||||
if (zero_fill && bytes_remain > 0) {
|
||||
uint32_t start = fat_fd->fat_file_size;
|
||||
uint32_t cl_start = start >> fs_info->vol.bpc_log2;
|
||||
uint32_t ofs = start & (fs_info->vol.bpc - 1);
|
||||
uint32_t cur_cln;
|
||||
uint32_t sec;
|
||||
uint32_t byte;
|
||||
|
||||
rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
|
||||
sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
|
||||
sec += ofs >> fs_info->vol.sec_log2;
|
||||
byte = ofs & (fs_info->vol.bps - 1);
|
||||
|
||||
rc = _fat_block_zero(mt_entry, sec, byte, bytes_remain);
|
||||
if (rc != RC_OK)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* if in last cluster allocated for the file there is enough room to
|
||||
* handle extention (hence we don't need to add even one cluster to the
|
||||
@@ -520,7 +542,7 @@ fat_file_extend(
|
||||
cls2add = ((bytes2add - 1) >> fs_info->vol.bpc_log2) + 1;
|
||||
|
||||
rc = fat_scan_fat_for_free_clusters(mt_entry, &chain, cls2add,
|
||||
&cls_added, &last_cl);
|
||||
&cls_added, &last_cl, zero_fill);
|
||||
|
||||
/* this means that low level I/O error occured */
|
||||
if (rc != RC_OK)
|
||||
|
||||
@@ -158,6 +158,7 @@ fat_file_write(rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
int
|
||||
fat_file_extend(rtems_filesystem_mount_table_entry_t *mt_entry,
|
||||
fat_file_fd_t *fat_fd,
|
||||
bool zero_fill,
|
||||
uint32_t new_length,
|
||||
uint32_t *a_length);
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ msdos_file_stat(
|
||||
}
|
||||
|
||||
/* msdos_file_ftruncate --
|
||||
* Truncate the file (if new length is greater then current do nothing).
|
||||
* Truncate the file.
|
||||
*
|
||||
* PARAMETERS:
|
||||
* iop - file control block
|
||||
@@ -219,31 +219,38 @@ msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
|
||||
rtems_status_code sc = RTEMS_SUCCESSFUL;
|
||||
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
|
||||
fat_file_fd_t *fat_fd = iop->pathinfo.node_access;
|
||||
|
||||
if (length >= fat_fd->fat_file_size)
|
||||
return RC_OK;
|
||||
uint32_t old_length;
|
||||
|
||||
sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
|
||||
MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
|
||||
if (sc != RTEMS_SUCCESSFUL)
|
||||
rtems_set_errno_and_return_minus_one(EIO);
|
||||
|
||||
rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
|
||||
if (rc != RC_OK)
|
||||
{
|
||||
rtems_semaphore_release(fs_info->vol_sema);
|
||||
return rc;
|
||||
old_length = fat_fd->fat_file_size;
|
||||
if (length < old_length) {
|
||||
rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
|
||||
} else {
|
||||
uint32_t new_length;
|
||||
|
||||
rc = fat_file_extend(iop->pathinfo.mt_entry,
|
||||
fat_fd,
|
||||
true,
|
||||
length,
|
||||
&new_length);
|
||||
if (rc == RC_OK && length != new_length) {
|
||||
fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, old_length);
|
||||
errno = ENOSPC;
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fat_file_truncate do nothing if new length >= fat-file size, so update
|
||||
* file size only if length < fat-file size
|
||||
*/
|
||||
if (length < fat_fd->fat_file_size)
|
||||
if (rc == RC_OK) {
|
||||
fat_fd->fat_file_size = length;
|
||||
}
|
||||
|
||||
rtems_semaphore_release(fs_info->vol_sema);
|
||||
return RC_OK;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* msdos_file_sync --
|
||||
|
||||
@@ -1411,8 +1411,8 @@ int msdos_find_name_in_fat_file(
|
||||
#if MSDOS_FIND_PRINT
|
||||
printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
|
||||
#endif
|
||||
ret = fat_file_extend (mt_entry, fat_fd, empty_space_offset * bts2rd,
|
||||
&new_length);
|
||||
ret = fat_file_extend (mt_entry, fat_fd, false,
|
||||
empty_space_offset * bts2rd, &new_length);
|
||||
|
||||
if (ret != RC_OK)
|
||||
return ret;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
*/
|
||||
MEMFILE_STATIC int IMFS_memfile_extend(
|
||||
IMFS_jnode_t *the_jnode,
|
||||
bool zero_fill,
|
||||
off_t new_length
|
||||
);
|
||||
|
||||
@@ -195,7 +196,7 @@ int memfile_ftruncate(
|
||||
*/
|
||||
|
||||
if ( length > the_jnode->info.file.size )
|
||||
return IMFS_memfile_extend( the_jnode, length );
|
||||
return IMFS_memfile_extend( the_jnode, true, length );
|
||||
|
||||
/*
|
||||
* The in-memory files do not currently reclaim memory until the file is
|
||||
@@ -218,12 +219,14 @@ int memfile_ftruncate(
|
||||
*/
|
||||
MEMFILE_STATIC int IMFS_memfile_extend(
|
||||
IMFS_jnode_t *the_jnode,
|
||||
bool zero_fill,
|
||||
off_t new_length
|
||||
)
|
||||
{
|
||||
unsigned int block;
|
||||
unsigned int new_blocks;
|
||||
unsigned int old_blocks;
|
||||
unsigned int offset;
|
||||
|
||||
/*
|
||||
* Perform internal consistency checks
|
||||
@@ -248,12 +251,22 @@ MEMFILE_STATIC int IMFS_memfile_extend(
|
||||
*/
|
||||
new_blocks = new_length / IMFS_MEMFILE_BYTES_PER_BLOCK;
|
||||
old_blocks = the_jnode->info.file.size / IMFS_MEMFILE_BYTES_PER_BLOCK;
|
||||
offset = the_jnode->info.file.size - old_blocks * IMFS_MEMFILE_BYTES_PER_BLOCK;
|
||||
|
||||
/*
|
||||
* Now allocate each of those blocks.
|
||||
*/
|
||||
for ( block=old_blocks ; block<=new_blocks ; block++ ) {
|
||||
if ( IMFS_memfile_addblock( the_jnode, block ) ) {
|
||||
if ( !IMFS_memfile_addblock( the_jnode, block ) ) {
|
||||
if ( zero_fill ) {
|
||||
size_t count = IMFS_MEMFILE_BYTES_PER_BLOCK - offset;
|
||||
block_p *block_ptr =
|
||||
IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
|
||||
|
||||
memset( &(*block_ptr) [offset], 0, count);
|
||||
offset = 0;
|
||||
}
|
||||
} else {
|
||||
for ( ; block>=old_blocks ; block-- ) {
|
||||
IMFS_memfile_remove_block( the_jnode, block );
|
||||
}
|
||||
@@ -622,7 +635,9 @@ MEMFILE_STATIC ssize_t IMFS_memfile_write(
|
||||
|
||||
last_byte = start + my_length;
|
||||
if ( last_byte > the_jnode->info.file.size ) {
|
||||
status = IMFS_memfile_extend( the_jnode, last_byte );
|
||||
bool zero_fill = start > the_jnode->info.file.size;
|
||||
|
||||
status = IMFS_memfile_extend( the_jnode, zero_fill, last_byte );
|
||||
if ( status )
|
||||
return status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user