summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2012-05-07 16:31:15 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2012-05-11 13:58:43 +0200
commit3d0c96c7f34204aa4386cd9c1cd4a3e7977d52a0 (patch)
tree1fd0314bc888815401bead7e9c59cf9e15b7ae67
parentFilesystem: PR1871: Fix O_APPEND (diff)
downloadrtems-3d0c96c7f34204aa4386cd9c1cd4a3e7977d52a0.tar.bz2
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.
-rw-r--r--cpukit/libfs/src/dosfs/fat.c36
-rw-r--r--cpukit/libfs/src/dosfs/fat.h6
-rw-r--r--cpukit/libfs/src/dosfs/fat_fat_operations.c30
-rw-r--r--cpukit/libfs/src/dosfs/fat_fat_operations.h3
-rw-r--r--cpukit/libfs/src/dosfs/fat_file.c36
-rw-r--r--cpukit/libfs/src/dosfs/fat_file.h1
-rw-r--r--cpukit/libfs/src/dosfs/msdos_file.c37
-rw-r--r--cpukit/libfs/src/dosfs/msdos_misc.c4
-rw-r--r--cpukit/libfs/src/imfs/memfile.c21
9 files changed, 137 insertions, 37 deletions
diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
index 39a7bacb24..a7030fc78c 100644
--- a/cpukit/libfs/src/dosfs/fat.c
+++ b/cpukit/libfs/src/dosfs/fat.c
@@ -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.
diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h
index 204095cae2..e55d23d845 100644
--- a/cpukit/libfs/src/dosfs/fat.h
+++ b/cpukit/libfs/src/dosfs/fat.h
@@ -465,6 +465,12 @@ _fat_block_write(rtems_filesystem_mount_table_entry_t *mt_entry,
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);
ssize_t
diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.c b/cpukit/libfs/src/dosfs/fat_fat_operations.c
index c4f82805e8..756af99c90 100644
--- a/cpukit/libfs/src/dosfs/fat_fat_operations.c
+++ b/cpukit/libfs/src/dosfs/fat_fat_operations.c
@@ -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 --
diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.h b/cpukit/libfs/src/dosfs/fat_fat_operations.h
index d516057ad0..be997980d7 100644
--- a/cpukit/libfs/src/dosfs/fat_fat_operations.h
+++ b/cpukit/libfs/src/dosfs/fat_fat_operations.h
@@ -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
diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c
index 01dabc8f80..a10347ccc4 100644
--- a/cpukit/libfs/src/dosfs/fat_file.c
+++ b/cpukit/libfs/src/dosfs/fat_file.c
@@ -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)
diff --git a/cpukit/libfs/src/dosfs/fat_file.h b/cpukit/libfs/src/dosfs/fat_file.h
index 01ab73ef98..30614c8f46 100644
--- a/cpukit/libfs/src/dosfs/fat_file.h
+++ b/cpukit/libfs/src/dosfs/fat_file.h
@@ -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);
diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c
index 6eb9b7953a..f68e44f948 100644
--- a/cpukit/libfs/src/dosfs/msdos_file.c
+++ b/cpukit/libfs/src/dosfs/msdos_file.c
@@ -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 --
diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c
index f27b4aea9c..d11bd83f52 100644
--- a/cpukit/libfs/src/dosfs/msdos_misc.c
+++ b/cpukit/libfs/src/dosfs/msdos_misc.c
@@ -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;
diff --git a/cpukit/libfs/src/imfs/memfile.c b/cpukit/libfs/src/imfs/memfile.c
index d836172884..b2797875fc 100644
--- a/cpukit/libfs/src/imfs/memfile.c
+++ b/cpukit/libfs/src/imfs/memfile.c
@@ -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;
}