summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/dosfs
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src/dosfs')
-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
8 files changed, 119 insertions, 34 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;