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:
Sebastian Huber
2012-05-07 16:31:15 +02:00
parent d61b0a5abf
commit 3d0c96c7f3
9 changed files with 137 additions and 37 deletions

View File

@@ -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.

View File

@@ -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);

View File

@@ -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 --

View File

@@ -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

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 --

View File

@@ -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;

View File

@@ -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;
}