[PATCH 2/7] IMFS: Split linfile and memfile modules
Sebastian Huber
sebastian.huber at embedded-brains.de
Mon Feb 9 20:35:52 UTC 2015
Make several functions static.
---
cpukit/libfs/Makefile.am | 7 +-
cpukit/libfs/src/imfs/imfs.h | 62 +-
cpukit/libfs/src/imfs/imfs_handlers_memfile.c | 87 ---
cpukit/libfs/src/imfs/imfs_linfile.c | 97 +++
cpukit/libfs/src/imfs/imfs_memfile.c | 860 +++++++++++++++++++++++++
cpukit/libfs/src/imfs/imfs_stat_file.c | 33 +
cpukit/libfs/src/imfs/memfile.c | 893 --------------------------
7 files changed, 1004 insertions(+), 1035 deletions(-)
delete mode 100644 cpukit/libfs/src/imfs/imfs_handlers_memfile.c
create mode 100644 cpukit/libfs/src/imfs/imfs_linfile.c
create mode 100644 cpukit/libfs/src/imfs/imfs_memfile.c
create mode 100644 cpukit/libfs/src/imfs/imfs_stat_file.c
delete mode 100644 cpukit/libfs/src/imfs/memfile.c
diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am
index 4bff8cf..3c454e7 100644
--- a/cpukit/libfs/Makefile.am
+++ b/cpukit/libfs/Makefile.am
@@ -49,13 +49,14 @@ libimfs_a_SOURCES += src/imfs/deviceio.c \
src/imfs/imfs_fsunmount.c \
src/imfs/imfs_handlers_device.c \
src/imfs/imfs_handlers_directory.c \
- src/imfs/imfs_handlers_memfile.c src/imfs/imfs_init.c \
+ src/imfs/imfs_init.c \
src/imfs/imfs_initsupp.c src/imfs/imfs_link.c src/imfs/imfs_load_tar.c \
+ src/imfs/imfs_linfile.c \
src/imfs/imfs_mknod.c src/imfs/imfs_mount.c \
src/imfs/imfs_rename.c src/imfs/imfs_rmnod.c \
- src/imfs/imfs_stat.c src/imfs/imfs_symlink.c \
+ src/imfs/imfs_stat.c src/imfs/imfs_stat_file.c src/imfs/imfs_symlink.c \
src/imfs/imfs_unmount.c src/imfs/imfs_utime.c src/imfs/ioman.c \
- src/imfs/memfile.c src/imfs/miniimfs_init.c src/imfs/imfs.h
+ src/imfs/imfs_memfile.c src/imfs/miniimfs_init.c src/imfs/imfs.h
# POSIX FIFO/pipe
libimfs_a_SOURCES += src/pipe/fifo.c src/pipe/pipe.c src/pipe/pipe.h
diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h
index f69408a..12881c4 100644
--- a/cpukit/libfs/src/imfs/imfs.h
+++ b/cpukit/libfs/src/imfs/imfs.h
@@ -511,6 +511,11 @@ extern int IMFS_stat(
struct stat *buf
);
+extern int IMFS_stat_file(
+ const rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+);
+
/**
* @brief IMFS evaluation node support.
*/
@@ -711,20 +716,6 @@ extern int IMFS_unmount(
rtems_filesystem_mount_table_entry_t *mt_entry /* IN */
);
-extern void IMFS_memfile_remove(
- IMFS_jnode_t *the_jnode /* IN/OUT */
-);
-
-/**
- * @brief Truncate a memory file.
- *
- * This routine processes the ftruncate() system call.
- */
-extern int memfile_ftruncate(
- rtems_libio_t *iop, /* IN */
- off_t length /* IN */
-);
-
/**
* @brief Read the next directory of the IMFS.
*
@@ -756,44 +747,11 @@ extern ssize_t imfs_dir_read(
*/
/**@{*/
-/**
- * @brief Open a linear file.
- *
- * Transforms the file into a memfile if opened for writing.
- */
-extern int IMFS_linfile_open(
- rtems_libio_t *iop, /* IN */
- const char *pathname, /* IN */
- int oflag, /* IN */
- mode_t mode /* IN */
-);
-
-extern ssize_t IMFS_linfile_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-);
-
-/**
- * @brief Read a memory file.
- *
- * This routine processes the read() system call.
- */
-extern ssize_t memfile_read(
- rtems_libio_t *iop, /* IN */
- void *buffer, /* IN */
- size_t count /* IN */
-);
-
-/**
- * @brief Write a memory file.
- *
- * This routine processes the write() system call.
- */
-extern ssize_t memfile_write(
- rtems_libio_t *iop, /* IN */
- const void *buffer, /* IN */
- size_t count /* IN */
+extern ssize_t IMFS_memfile_write(
+ IMFS_memfile_t *memfile,
+ off_t start,
+ const unsigned char *source,
+ unsigned int length
);
/** @} */
diff --git a/cpukit/libfs/src/imfs/imfs_handlers_memfile.c b/cpukit/libfs/src/imfs/imfs_handlers_memfile.c
deleted file mode 100644
index 1e5dba2..0000000
--- a/cpukit/libfs/src/imfs/imfs_handlers_memfile.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * @file
- *
- * @brief Memfile Operations Tables
- * @ingroup IMFS
- */
-
-/*
- * COPYRIGHT (c) 1989-1999.
- * On-Line Applications Research Corporation (OAR).
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#if HAVE_CONFIG_H
- #include "config.h"
-#endif
-
-#include "imfs.h"
-
-static int IMFS_stat_file(
- const rtems_filesystem_location_info_t *loc,
- struct stat *buf
-)
-{
- const IMFS_file_t *file = loc->node_access;
-
- buf->st_size = file->File.size;
- buf->st_blksize = imfs_rq_memfile_bytes_per_block;
-
- return IMFS_stat( loc, buf );
-}
-
-static const rtems_filesystem_file_handlers_r IMFS_memfile_handlers = {
- .open_h = rtems_filesystem_default_open,
- .close_h = rtems_filesystem_default_close,
- .read_h = memfile_read,
- .write_h = memfile_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = rtems_filesystem_default_lseek_file,
- .fstat_h = IMFS_stat_file,
- .ftruncate_h = memfile_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
-
-static const rtems_filesystem_file_handlers_r IMFS_linfile_handlers = {
- .open_h = IMFS_linfile_open,
- .close_h = rtems_filesystem_default_close,
- .read_h = IMFS_linfile_read,
- .write_h = rtems_filesystem_default_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = rtems_filesystem_default_lseek_file,
- .fstat_h = IMFS_stat_file,
- .ftruncate_h = rtems_filesystem_default_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
-
-const IMFS_mknod_control IMFS_mknod_control_memfile = {
- {
- .handlers = &IMFS_memfile_handlers,
- .node_initialize = IMFS_node_initialize_default,
- .node_remove = IMFS_node_remove_default,
- .node_destroy = IMFS_memfile_remove
- },
- .node_size = sizeof( IMFS_file_t )
-};
-
-const IMFS_node_control IMFS_node_control_linfile = {
- .handlers = &IMFS_linfile_handlers,
- .node_initialize = IMFS_node_initialize_default,
- .node_remove = IMFS_node_remove_default,
- .node_destroy = IMFS_node_destroy_default
-};
diff --git a/cpukit/libfs/src/imfs/imfs_linfile.c b/cpukit/libfs/src/imfs/imfs_linfile.c
new file mode 100644
index 0000000..8a14866
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_linfile.c
@@ -0,0 +1,97 @@
+/**
+ * @file
+ *
+ * @ingroup IMFS
+ */
+
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "imfs.h"
+
+static ssize_t IMFS_linfile_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ size_t count
+)
+{
+ IMFS_file_t *file = IMFS_iop_to_file( iop );
+ off_t start = iop->offset;
+ size_t size = file->File.size;
+ const unsigned char *data = file->Linearfile.direct;
+
+ if (count > size - start)
+ count = size - start;
+
+ IMFS_update_atime( &file->Node );
+ iop->offset = start + count;
+ memcpy(buffer, &data[start], count);
+
+ return (ssize_t) count;
+}
+
+static int IMFS_linfile_open(
+ rtems_libio_t *iop,
+ const char *pathname,
+ int oflag,
+ mode_t mode
+)
+{
+ IMFS_file_t *file;
+
+ file = iop->pathinfo.node_access;
+
+ /*
+ * Perform 'copy on write' for linear files
+ */
+ if ((iop->flags & LIBIO_FLAGS_WRITE) != 0) {
+ uint32_t count = file->File.size;
+ const unsigned char *buffer = file->Linearfile.direct;
+
+ file->Node.control = &IMFS_mknod_control_memfile.node_control;
+ file->File.size = 0;
+ file->Memfile.indirect = 0;
+ file->Memfile.doubly_indirect = 0;
+ file->Memfile.triply_indirect = 0;
+ if ((count != 0)
+ && (IMFS_memfile_write(&file->Memfile, 0, buffer, count) == -1))
+ return -1;
+ }
+
+ return 0;
+}
+
+static const rtems_filesystem_file_handlers_r IMFS_linfile_handlers = {
+ .open_h = IMFS_linfile_open,
+ .close_h = rtems_filesystem_default_close,
+ .read_h = IMFS_linfile_read,
+ .write_h = rtems_filesystem_default_write,
+ .ioctl_h = rtems_filesystem_default_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek_file,
+ .fstat_h = IMFS_stat_file,
+ .ftruncate_h = rtems_filesystem_default_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};
+
+const IMFS_node_control IMFS_node_control_linfile = {
+ .handlers = &IMFS_linfile_handlers,
+ .node_initialize = IMFS_node_initialize_default,
+ .node_remove = IMFS_node_remove_default,
+ .node_destroy = IMFS_node_destroy_default
+};
diff --git a/cpukit/libfs/src/imfs/imfs_memfile.c b/cpukit/libfs/src/imfs/imfs_memfile.c
new file mode 100644
index 0000000..2b6a496
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_memfile.c
@@ -0,0 +1,860 @@
+/**
+ * @file
+ *
+ * @brief IMFS Memory File Handlers
+ * @ingroup IMFS
+ */
+
+/*
+ * COPYRIGHT (c) 1989-2010.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "imfs.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Prototypes of private routines
+ */
+static int IMFS_memfile_extend(
+ IMFS_memfile_t *memfile,
+ bool zero_fill,
+ off_t new_length
+);
+
+static int IMFS_memfile_addblock(
+ IMFS_memfile_t *memfile,
+ unsigned int block
+);
+
+static void IMFS_memfile_remove_block(
+ IMFS_memfile_t *memfile,
+ unsigned int block
+);
+
+static block_p *IMFS_memfile_get_block_pointer(
+ IMFS_memfile_t *memfile,
+ unsigned int block,
+ int malloc_it
+);
+
+static ssize_t IMFS_memfile_read(
+ IMFS_file_t *file,
+ off_t start,
+ unsigned char *destination,
+ unsigned int length
+);
+
+static void *memfile_alloc_block(void);
+
+static void memfile_free_block(
+ void *memory
+);
+
+static ssize_t memfile_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ size_t count
+)
+{
+ IMFS_file_t *file = IMFS_iop_to_file( iop );
+ ssize_t status;
+
+ status = IMFS_memfile_read( file, iop->offset, buffer, count );
+
+ if ( status > 0 )
+ iop->offset += status;
+
+ return status;
+}
+
+static ssize_t memfile_write(
+ rtems_libio_t *iop,
+ const void *buffer,
+ size_t count
+)
+{
+ IMFS_memfile_t *memfile = IMFS_iop_to_memfile( iop );
+ ssize_t status;
+
+ if ((iop->flags & LIBIO_FLAGS_APPEND) != 0)
+ iop->offset = memfile->File.size;
+
+ status = IMFS_memfile_write( memfile, iop->offset, buffer, count );
+
+ if ( status > 0 )
+ iop->offset += status;
+
+ return status;
+}
+
+/*
+ * memfile_stat
+ *
+ * This IMFS_stat() can be used.
+ */
+
+static int memfile_ftruncate(
+ rtems_libio_t *iop,
+ off_t length
+)
+{
+ IMFS_memfile_t *memfile = IMFS_iop_to_memfile( iop );
+
+ /*
+ * POSIX 1003.1b does not specify what happens if you truncate a file
+ * and the new length is greater than the current size. We treat this
+ * as an extend operation.
+ */
+
+ if ( length > memfile->File.size )
+ return IMFS_memfile_extend( memfile, true, length );
+
+ /*
+ * The in-memory files do not currently reclaim memory until the file is
+ * deleted. So we leave the previously allocated blocks in place for
+ * future use and just set the length.
+ */
+ memfile->File.size = length;
+
+ IMFS_mtime_ctime_update( &memfile->File.Node );
+
+ return 0;
+}
+
+/*
+ * IMFS_memfile_extend
+ *
+ * This routine insures that the in-memory file is of the length
+ * specified. If necessary, it will allocate memory blocks to
+ * extend the file.
+ */
+static int IMFS_memfile_extend(
+ IMFS_memfile_t *memfile,
+ 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
+ */
+ IMFS_assert( memfile );
+
+ /*
+ * Verify new file size is supported
+ */
+ if ( new_length >= IMFS_MEMFILE_MAXIMUM_SIZE )
+ rtems_set_errno_and_return_minus_one( EFBIG );
+
+ /*
+ * Verify new file size is actually larger than current size
+ */
+ if ( new_length <= memfile->File.size )
+ return 0;
+
+ /*
+ * Calculate the number of range of blocks to allocate
+ */
+ new_blocks = new_length / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ old_blocks = memfile->File.size / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ offset = memfile->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( memfile, block ) ) {
+ if ( zero_fill ) {
+ size_t count = IMFS_MEMFILE_BYTES_PER_BLOCK - offset;
+ block_p *block_ptr =
+ IMFS_memfile_get_block_pointer( memfile, block, 0 );
+
+ memset( &(*block_ptr) [offset], 0, count);
+ offset = 0;
+ }
+ } else {
+ for ( ; block>=old_blocks ; block-- ) {
+ IMFS_memfile_remove_block( memfile, block );
+ }
+ rtems_set_errno_and_return_minus_one( ENOSPC );
+ }
+ }
+
+ /*
+ * Set the new length of the file.
+ */
+ memfile->File.size = new_length;
+
+ IMFS_mtime_ctime_update( &memfile->File.Node );
+
+ return 0;
+}
+
+/*
+ * IMFS_memfile_addblock
+ *
+ * This routine adds a single block to the specified in-memory file.
+ */
+static int IMFS_memfile_addblock(
+ IMFS_memfile_t *memfile,
+ unsigned int block
+)
+{
+ block_p memory;
+ block_p *block_entry_ptr;
+
+ IMFS_assert( memfile );
+
+ /*
+ * Obtain the pointer for the specified block number
+ */
+ block_entry_ptr = IMFS_memfile_get_block_pointer( memfile, block, 1 );
+ if ( !block_entry_ptr )
+ return 1;
+
+ if ( *block_entry_ptr )
+ return 0;
+
+ /*
+ * There is no memory for this block number so allocate it.
+ */
+ memory = memfile_alloc_block();
+ if ( !memory )
+ return 1;
+
+ *block_entry_ptr = memory;
+ return 0;
+}
+
+/*
+ * IMFS_memfile_remove_block
+ *
+ * This routine removes the specified block from the in-memory file.
+ *
+ * NOTE: This is a support routine and is called only to remove
+ * the last block or set of blocks in a file. Removing a
+ * block from the middle of a file would be exceptionally
+ * dangerous and the results unpredictable.
+ */
+static void IMFS_memfile_remove_block(
+ IMFS_memfile_t *memfile,
+ unsigned int block
+)
+{
+ block_p *block_ptr;
+ block_p ptr;
+
+ block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
+ if ( block_ptr ) {
+ ptr = *block_ptr;
+ *block_ptr = 0;
+ memfile_free_block( ptr );
+ }
+}
+
+/*
+ * memfile_free_blocks_in_table
+ *
+ * This is a support routine for IMFS_memfile_remove. It frees all the
+ * blocks in one of the indirection tables.
+ */
+static void memfile_free_blocks_in_table(
+ block_p **block_table,
+ int entries
+)
+{
+ int i;
+ block_p *b;
+
+ /*
+ * Perform internal consistency checks
+ */
+ IMFS_assert( block_table );
+
+ /*
+ * Now go through all the slots in the table and free the memory.
+ */
+ b = *block_table;
+
+ for ( i=0 ; i<entries ; i++ ) {
+ if ( b[i] ) {
+ memfile_free_block( b[i] );
+ b[i] = 0;
+ }
+ }
+
+ /*
+ * Now that all the blocks in the block table are free, we can
+ * free the block table itself.
+ */
+ memfile_free_block( *block_table );
+ *block_table = 0;
+}
+
+/*
+ * IMFS_memfile_destroy
+ *
+ * This routine frees all memory associated with an in memory file.
+ *
+ * NOTE: This is an exceptionally conservative implementation.
+ * It will check EVERY pointer which is non-NULL and insure
+ * any child non-NULL pointers are freed. Optimistically, all that
+ * is necessary is to scan until a NULL pointer is found. There
+ * should be no allocated data past that point.
+ *
+ * In experimentation on the powerpc simulator, it was noted
+ * that using blocks which held 128 slots versus 16 slots made
+ * a significant difference in the performance of this routine.
+ *
+ * Regardless until the IMFS implementation is proven, it
+ * is better to stick to simple, easy to understand algorithms.
+ */
+static void IMFS_memfile_destroy(
+ IMFS_jnode_t *the_jnode
+)
+{
+ IMFS_memfile_t *memfile;
+ int i;
+ int j;
+ unsigned int to_free;
+ block_p *p;
+
+ memfile = (IMFS_memfile_t *) the_jnode;
+
+ /*
+ * Perform internal consistency checks
+ */
+ IMFS_assert( memfile );
+
+ /*
+ * Eventually this could be set smarter at each call to
+ * memfile_free_blocks_in_table to greatly speed this up.
+ */
+ to_free = IMFS_MEMFILE_BLOCK_SLOTS;
+
+ /*
+ * Now start freeing blocks in this order:
+ * + indirect
+ * + doubly indirect
+ * + triply indirect
+ */
+
+ if ( memfile->indirect ) {
+ memfile_free_blocks_in_table( &memfile->indirect, to_free );
+ }
+
+ if ( memfile->doubly_indirect ) {
+ for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
+ if ( memfile->doubly_indirect[i] ) {
+ memfile_free_blocks_in_table(
+ (block_p **)&memfile->doubly_indirect[i], to_free );
+ }
+ }
+ memfile_free_blocks_in_table( &memfile->doubly_indirect, to_free );
+
+ }
+
+ if ( memfile->triply_indirect ) {
+ for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
+ p = (block_p *) memfile->triply_indirect[i];
+ if ( !p ) /* ensure we have a valid pointer */
+ break;
+ for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) {
+ if ( p[j] ) {
+ memfile_free_blocks_in_table( (block_p **)&p[j], to_free);
+ }
+ }
+ memfile_free_blocks_in_table(
+ (block_p **)&memfile->triply_indirect[i], to_free );
+ }
+ memfile_free_blocks_in_table(
+ (block_p **)&memfile->triply_indirect, to_free );
+ }
+
+ IMFS_node_destroy_default( the_jnode );
+}
+
+/*
+ * IMFS_memfile_read
+ *
+ * This routine read from memory file pointed to by the_jnode into
+ * the specified data buffer specified by destination. The file
+ * is NOT extended. An offset greater than the length of the file
+ * is considered an error. Read from an offset for more bytes than
+ * are between the offset and the end of the file will result in
+ * reading the data between offset and the end of the file (truncated
+ * read).
+ */
+static ssize_t IMFS_memfile_read(
+ IMFS_file_t *file,
+ off_t start,
+ unsigned char *destination,
+ unsigned int length
+)
+{
+ block_p *block_ptr;
+ unsigned int block;
+ unsigned int my_length;
+ unsigned int to_copy = 0;
+ unsigned int last_byte;
+ unsigned int copied;
+ unsigned int start_offset;
+ unsigned char *dest;
+
+ dest = destination;
+
+ /*
+ * Perform internal consistency checks
+ */
+ IMFS_assert( file );
+ IMFS_assert( dest );
+
+ /*
+ * Linear files (as created from a tar file are easier to handle
+ * than block files).
+ */
+ my_length = length;
+
+ /*
+ * If the last byte we are supposed to read is past the end of this
+ * in memory file, then shorten the length to read.
+ */
+ last_byte = start + length;
+ if ( last_byte > file->Memfile.File.size )
+ my_length = file->Memfile.File.size - start;
+
+ copied = 0;
+
+ /*
+ * Three phases to the read:
+ * + possibly the last part of one block
+ * + all of zero of more blocks
+ * + possibly the first part of one block
+ */
+
+ /*
+ * Phase 1: possibly the last part of one block
+ */
+ start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
+ block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ if ( start_offset ) {
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
+ if ( to_copy > my_length )
+ to_copy = my_length;
+ block_ptr = IMFS_memfile_get_block_pointer( &file->Memfile, block, 0 );
+ if ( !block_ptr )
+ return copied;
+ memcpy( dest, &(*block_ptr)[ start_offset ], to_copy );
+ dest += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 2: all of zero of more blocks
+ */
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
+ while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
+ block_ptr = IMFS_memfile_get_block_pointer( &file->Memfile, block, 0 );
+ if ( !block_ptr )
+ return copied;
+ memcpy( dest, &(*block_ptr)[ 0 ], to_copy );
+ dest += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 3: possibly the first part of one block
+ */
+ IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
+
+ if ( my_length ) {
+ block_ptr = IMFS_memfile_get_block_pointer( &file->Memfile, block, 0 );
+ if ( !block_ptr )
+ return copied;
+ memcpy( dest, &(*block_ptr)[ 0 ], my_length );
+ copied += my_length;
+ }
+
+ IMFS_update_atime( &file->Node );
+
+ return copied;
+}
+
+/*
+ * IMFS_memfile_write
+ *
+ * This routine writes the specified data buffer into the in memory
+ * file pointed to by memfile. The file is extended as needed.
+ */
+ssize_t IMFS_memfile_write(
+ IMFS_memfile_t *memfile,
+ off_t start,
+ const unsigned char *source,
+ unsigned int length
+)
+{
+ block_p *block_ptr;
+ unsigned int block;
+ int status;
+ unsigned int my_length;
+ unsigned int to_copy = 0;
+ unsigned int last_byte;
+ unsigned int start_offset;
+ int copied;
+ const unsigned char *src;
+
+ src = source;
+
+ /*
+ * Perform internal consistency checks
+ */
+ IMFS_assert( source );
+ IMFS_assert( memfile );
+
+ my_length = length;
+ /*
+ * If the last byte we are supposed to write is past the end of this
+ * in memory file, then extend the length.
+ */
+
+ last_byte = start + my_length;
+ if ( last_byte > memfile->File.size ) {
+ bool zero_fill = start > memfile->File.size;
+
+ status = IMFS_memfile_extend( memfile, zero_fill, last_byte );
+ if ( status )
+ return status;
+ }
+
+ copied = 0;
+
+ /*
+ * Three phases to the write:
+ * + possibly the last part of one block
+ * + all of zero of more blocks
+ * + possibly the first part of one block
+ */
+
+ /*
+ * Phase 1: possibly the last part of one block
+ */
+ start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
+ block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ if ( start_offset ) {
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
+ if ( to_copy > my_length )
+ to_copy = my_length;
+ block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
+ if ( !block_ptr )
+ return copied;
+ #if 0
+ fprintf(
+ stderr,
+ "write %d at %d in %d: %*s\n",
+ to_copy,
+ start_offset,
+ block,
+ to_copy,
+ src
+ );
+ #endif
+ memcpy( &(*block_ptr)[ start_offset ], src, to_copy );
+ src += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 2: all of zero of more blocks
+ */
+
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
+ while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
+ block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
+ if ( !block_ptr )
+ return copied;
+ #if 0
+ fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
+ #endif
+ memcpy( &(*block_ptr)[ 0 ], src, to_copy );
+ src += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 3: possibly the first part of one block
+ */
+ IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
+
+ to_copy = my_length;
+ if ( my_length ) {
+ block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
+ if ( !block_ptr )
+ return copied;
+ #if 0
+ fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
+ #endif
+ memcpy( &(*block_ptr)[ 0 ], src, my_length );
+ my_length = 0;
+ copied += to_copy;
+ }
+
+ IMFS_mtime_ctime_update( &memfile->File.Node );
+
+ return copied;
+}
+
+/*
+ * IMFS_memfile_get_block_pointer
+ *
+ * This routine looks up the block pointer associated with the given block
+ * number. If that block has not been allocated and "malloc_it" is
+ * TRUE, then the block is allocated. Otherwise, it is an error.
+ */
+#if 0
+block_p *IMFS_memfile_get_block_pointer_DEBUG(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block,
+ int malloc_it
+);
+
+block_p *IMFS_memfile_get_block_pointer(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block,
+ int malloc_it
+)
+{
+ block_p *p;
+
+ p = IMFS_memfile_get_block_pointer_DEBUG( the_jnode, block, malloc_it );
+ fprintf(stdout, "(%d -> %p) ", block, p );
+ return p;
+}
+
+block_p *IMFS_memfile_get_block_pointer_DEBUG(
+#else
+block_p *IMFS_memfile_get_block_pointer(
+#endif
+ IMFS_memfile_t *memfile,
+ unsigned int block,
+ int malloc_it
+)
+{
+ unsigned int my_block;
+ unsigned int singly;
+ unsigned int doubly;
+ unsigned int triply;
+ block_p *p;
+ block_p *p1;
+ block_p *p2;
+
+ /*
+ * Perform internal consistency checks
+ */
+ IMFS_assert( memfile );
+
+ my_block = block;
+
+ /*
+ * Is the block number in the simple indirect portion?
+ */
+ if ( my_block <= LAST_INDIRECT ) {
+ p = memfile->indirect;
+
+ if ( malloc_it ) {
+
+ if ( !p ) {
+ p = memfile_alloc_block();
+ if ( !p )
+ return 0;
+ memfile->indirect = p;
+ }
+ return &memfile->indirect[ my_block ];
+ }
+
+ if ( !p )
+ return 0;
+
+ return &memfile->indirect[ my_block ];
+ }
+
+ /*
+ * Is the block number in the doubly indirect portion?
+ */
+
+ if ( my_block <= LAST_DOUBLY_INDIRECT ) {
+ my_block -= FIRST_DOUBLY_INDIRECT;
+
+ singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
+ doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
+
+ p = memfile->doubly_indirect;
+ if ( malloc_it ) {
+
+ if ( !p ) {
+ p = memfile_alloc_block();
+ if ( !p )
+ return 0;
+ memfile->doubly_indirect = p;
+ }
+
+ p1 = (block_p *)p[ doubly ];
+ if ( !p1 ) {
+ p1 = memfile_alloc_block();
+ if ( !p1 )
+ return 0;
+ p[ doubly ] = (block_p) p1;
+ }
+
+ return (block_p *)&p1[ singly ];
+ }
+
+ if ( !p )
+ return 0;
+
+ p = (block_p *)p[ doubly ];
+ if ( !p )
+ return 0;
+
+ return (block_p *)&p[ singly ];
+ }
+
+ /*
+ * Is the block number in the triply indirect portion?
+ */
+ if ( my_block <= LAST_TRIPLY_INDIRECT ) {
+ my_block -= FIRST_TRIPLY_INDIRECT;
+
+ singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
+ doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
+ triply = doubly / IMFS_MEMFILE_BLOCK_SLOTS;
+ doubly %= IMFS_MEMFILE_BLOCK_SLOTS;
+
+ p = memfile->triply_indirect;
+
+ if ( malloc_it ) {
+ if ( !p ) {
+ p = memfile_alloc_block();
+ if ( !p )
+ return 0;
+ memfile->triply_indirect = p;
+ }
+
+ p1 = (block_p *) p[ triply ];
+ if ( !p1 ) {
+ p1 = memfile_alloc_block();
+ if ( !p1 )
+ return 0;
+ p[ triply ] = (block_p) p1;
+ }
+
+ p2 = (block_p *)p1[ doubly ];
+ if ( !p2 ) {
+ p2 = memfile_alloc_block();
+ if ( !p2 )
+ return 0;
+ p1[ doubly ] = (block_p) p2;
+ }
+ return (block_p *)&p2[ singly ];
+ }
+
+ if ( !p )
+ return 0;
+
+ p1 = (block_p *) p[ triply ];
+ if ( !p1 )
+ return 0;
+
+ p2 = (block_p *)p1[ doubly ];
+ if ( !p2 )
+ return 0;
+
+ return (block_p *)&p2[ singly ];
+ }
+
+ /*
+ * This means the requested block number is out of range.
+ */
+ return 0;
+}
+
+/*
+ * memfile_alloc_block
+ *
+ * Allocate a block for an in-memory file.
+ */
+int memfile_blocks_allocated = 0;
+
+void *memfile_alloc_block(void)
+{
+ void *memory;
+
+ memory = (void *)calloc(1, IMFS_MEMFILE_BYTES_PER_BLOCK);
+ if ( memory )
+ memfile_blocks_allocated++;
+
+ return memory;
+}
+
+/*
+ * memfile_free_block
+ *
+ * Free a block from an in-memory file.
+ */
+void memfile_free_block(
+ void *memory
+)
+{
+ free(memory);
+ memfile_blocks_allocated--;
+}
+
+static const rtems_filesystem_file_handlers_r IMFS_memfile_handlers = {
+ .open_h = rtems_filesystem_default_open,
+ .close_h = rtems_filesystem_default_close,
+ .read_h = memfile_read,
+ .write_h = memfile_write,
+ .ioctl_h = rtems_filesystem_default_ioctl,
+ .lseek_h = rtems_filesystem_default_lseek_file,
+ .fstat_h = IMFS_stat_file,
+ .ftruncate_h = memfile_ftruncate,
+ .fsync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
+ .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync_success,
+ .fcntl_h = rtems_filesystem_default_fcntl,
+ .kqfilter_h = rtems_filesystem_default_kqfilter,
+ .poll_h = rtems_filesystem_default_poll,
+ .readv_h = rtems_filesystem_default_readv,
+ .writev_h = rtems_filesystem_default_writev
+};
+
+const IMFS_mknod_control IMFS_mknod_control_memfile = {
+ {
+ .handlers = &IMFS_memfile_handlers,
+ .node_initialize = IMFS_node_initialize_default,
+ .node_remove = IMFS_node_remove_default,
+ .node_destroy = IMFS_memfile_destroy
+ },
+ .node_size = sizeof( IMFS_file_t )
+};
diff --git a/cpukit/libfs/src/imfs/imfs_stat_file.c b/cpukit/libfs/src/imfs/imfs_stat_file.c
new file mode 100644
index 0000000..2302705
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_stat_file.c
@@ -0,0 +1,33 @@
+/**
+ * @file
+ *
+ * @ingroup IMFS
+ */
+
+/*
+ * COPYRIGHT (c) 1989-1999.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+ #include "config.h"
+#endif
+
+#include "imfs.h"
+
+int IMFS_stat_file(
+ const rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+)
+{
+ const IMFS_file_t *file = loc->node_access;
+
+ buf->st_size = file->File.size;
+ buf->st_blksize = imfs_rq_memfile_bytes_per_block;
+
+ return IMFS_stat( loc, buf );
+}
diff --git a/cpukit/libfs/src/imfs/memfile.c b/cpukit/libfs/src/imfs/memfile.c
deleted file mode 100644
index 59da9a6..0000000
--- a/cpukit/libfs/src/imfs/memfile.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/**
- * @file
- *
- * @brief IMFS Memory File Handlers
- * @ingroup IMFS
- */
-
-/*
- * COPYRIGHT (c) 1989-2010.
- * On-Line Applications Research Corporation (OAR).
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#if HAVE_CONFIG_H
- #include "config.h"
-#endif
-
-#include "imfs.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#define MEMFILE_STATIC
-
-/*
- * Prototypes of private routines
- */
-MEMFILE_STATIC int IMFS_memfile_extend(
- IMFS_memfile_t *memfile,
- bool zero_fill,
- off_t new_length
-);
-
-MEMFILE_STATIC int IMFS_memfile_addblock(
- IMFS_memfile_t *memfile,
- unsigned int block
-);
-
-MEMFILE_STATIC void IMFS_memfile_remove_block(
- IMFS_memfile_t *memfile,
- unsigned int block
-);
-
-MEMFILE_STATIC block_p *IMFS_memfile_get_block_pointer(
- IMFS_memfile_t *memfile,
- unsigned int block,
- int malloc_it
-);
-
-MEMFILE_STATIC ssize_t IMFS_memfile_read(
- IMFS_file_t *file,
- off_t start,
- unsigned char *destination,
- unsigned int length
-);
-
-ssize_t IMFS_memfile_write( /* cannot be static as used in imfs_fchmod.c */
- IMFS_memfile_t *memfile,
- off_t start,
- const unsigned char *source,
- unsigned int length
-);
-
-void *memfile_alloc_block(void);
-
-void memfile_free_block(
- void *memory
-);
-
-int IMFS_linfile_open(
- rtems_libio_t *iop,
- const char *pathname,
- int oflag,
- mode_t mode
-)
-{
- IMFS_file_t *file;
-
- file = iop->pathinfo.node_access;
-
- /*
- * Perform 'copy on write' for linear files
- */
- if ((iop->flags & LIBIO_FLAGS_WRITE) != 0) {
- uint32_t count = file->File.size;
- const unsigned char *buffer = file->Linearfile.direct;
-
- file->Node.control = &IMFS_mknod_control_memfile.node_control;
- file->File.size = 0;
- file->Memfile.indirect = 0;
- file->Memfile.doubly_indirect = 0;
- file->Memfile.triply_indirect = 0;
- if ((count != 0)
- && (IMFS_memfile_write(&file->Memfile, 0, buffer, count) == -1))
- return -1;
- }
-
- return 0;
-}
-
-ssize_t IMFS_linfile_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-)
-{
- IMFS_file_t *file = IMFS_iop_to_file( iop );
- off_t start = iop->offset;
- size_t size = file->File.size;
- const unsigned char *data = file->Linearfile.direct;
-
- if (count > size - start)
- count = size - start;
-
- IMFS_update_atime( &file->Node );
- iop->offset = start + count;
- memcpy(buffer, &data[start], count);
-
- return (ssize_t) count;
-}
-
-ssize_t memfile_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-)
-{
- IMFS_file_t *file = IMFS_iop_to_file( iop );
- ssize_t status;
-
- status = IMFS_memfile_read( file, iop->offset, buffer, count );
-
- if ( status > 0 )
- iop->offset += status;
-
- return status;
-}
-
-ssize_t memfile_write(
- rtems_libio_t *iop,
- const void *buffer,
- size_t count
-)
-{
- IMFS_memfile_t *memfile = IMFS_iop_to_memfile( iop );
- ssize_t status;
-
- if ((iop->flags & LIBIO_FLAGS_APPEND) != 0)
- iop->offset = memfile->File.size;
-
- status = IMFS_memfile_write( memfile, iop->offset, buffer, count );
-
- if ( status > 0 )
- iop->offset += status;
-
- return status;
-}
-
-/*
- * memfile_stat
- *
- * This IMFS_stat() can be used.
- */
-
-int memfile_ftruncate(
- rtems_libio_t *iop,
- off_t length
-)
-{
- IMFS_memfile_t *memfile = IMFS_iop_to_memfile( iop );
-
- /*
- * POSIX 1003.1b does not specify what happens if you truncate a file
- * and the new length is greater than the current size. We treat this
- * as an extend operation.
- */
-
- if ( length > memfile->File.size )
- return IMFS_memfile_extend( memfile, true, length );
-
- /*
- * The in-memory files do not currently reclaim memory until the file is
- * deleted. So we leave the previously allocated blocks in place for
- * future use and just set the length.
- */
- memfile->File.size = length;
-
- IMFS_mtime_ctime_update( &memfile->File.Node );
-
- return 0;
-}
-
-/*
- * IMFS_memfile_extend
- *
- * This routine insures that the in-memory file is of the length
- * specified. If necessary, it will allocate memory blocks to
- * extend the file.
- */
-MEMFILE_STATIC int IMFS_memfile_extend(
- IMFS_memfile_t *memfile,
- 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
- */
- IMFS_assert( memfile );
-
- /*
- * Verify new file size is supported
- */
- if ( new_length >= IMFS_MEMFILE_MAXIMUM_SIZE )
- rtems_set_errno_and_return_minus_one( EFBIG );
-
- /*
- * Verify new file size is actually larger than current size
- */
- if ( new_length <= memfile->File.size )
- return 0;
-
- /*
- * Calculate the number of range of blocks to allocate
- */
- new_blocks = new_length / IMFS_MEMFILE_BYTES_PER_BLOCK;
- old_blocks = memfile->File.size / IMFS_MEMFILE_BYTES_PER_BLOCK;
- offset = memfile->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( memfile, block ) ) {
- if ( zero_fill ) {
- size_t count = IMFS_MEMFILE_BYTES_PER_BLOCK - offset;
- block_p *block_ptr =
- IMFS_memfile_get_block_pointer( memfile, block, 0 );
-
- memset( &(*block_ptr) [offset], 0, count);
- offset = 0;
- }
- } else {
- for ( ; block>=old_blocks ; block-- ) {
- IMFS_memfile_remove_block( memfile, block );
- }
- rtems_set_errno_and_return_minus_one( ENOSPC );
- }
- }
-
- /*
- * Set the new length of the file.
- */
- memfile->File.size = new_length;
-
- IMFS_mtime_ctime_update( &memfile->File.Node );
-
- return 0;
-}
-
-/*
- * IMFS_memfile_addblock
- *
- * This routine adds a single block to the specified in-memory file.
- */
-MEMFILE_STATIC int IMFS_memfile_addblock(
- IMFS_memfile_t *memfile,
- unsigned int block
-)
-{
- block_p memory;
- block_p *block_entry_ptr;
-
- IMFS_assert( memfile );
-
- /*
- * Obtain the pointer for the specified block number
- */
- block_entry_ptr = IMFS_memfile_get_block_pointer( memfile, block, 1 );
- if ( !block_entry_ptr )
- return 1;
-
- if ( *block_entry_ptr )
- return 0;
-
- /*
- * There is no memory for this block number so allocate it.
- */
- memory = memfile_alloc_block();
- if ( !memory )
- return 1;
-
- *block_entry_ptr = memory;
- return 0;
-}
-
-/*
- * IMFS_memfile_remove_block
- *
- * This routine removes the specified block from the in-memory file.
- *
- * NOTE: This is a support routine and is called only to remove
- * the last block or set of blocks in a file. Removing a
- * block from the middle of a file would be exceptionally
- * dangerous and the results unpredictable.
- */
-MEMFILE_STATIC void IMFS_memfile_remove_block(
- IMFS_memfile_t *memfile,
- unsigned int block
-)
-{
- block_p *block_ptr;
- block_p ptr;
-
- block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
- if ( block_ptr ) {
- ptr = *block_ptr;
- *block_ptr = 0;
- memfile_free_block( ptr );
- }
-}
-
-/*
- * memfile_free_blocks_in_table
- *
- * This is a support routine for IMFS_memfile_remove. It frees all the
- * blocks in one of the indirection tables.
- */
-static void memfile_free_blocks_in_table(
- block_p **block_table,
- int entries
-)
-{
- int i;
- block_p *b;
-
- /*
- * Perform internal consistency checks
- */
- IMFS_assert( block_table );
-
- /*
- * Now go through all the slots in the table and free the memory.
- */
- b = *block_table;
-
- for ( i=0 ; i<entries ; i++ ) {
- if ( b[i] ) {
- memfile_free_block( b[i] );
- b[i] = 0;
- }
- }
-
- /*
- * Now that all the blocks in the block table are free, we can
- * free the block table itself.
- */
- memfile_free_block( *block_table );
- *block_table = 0;
-}
-
-/*
- * IMFS_memfile_remove
- *
- * This routine frees all memory associated with an in memory file.
- *
- * NOTE: This is an exceptionally conservative implementation.
- * It will check EVERY pointer which is non-NULL and insure
- * any child non-NULL pointers are freed. Optimistically, all that
- * is necessary is to scan until a NULL pointer is found. There
- * should be no allocated data past that point.
- *
- * In experimentation on the powerpc simulator, it was noted
- * that using blocks which held 128 slots versus 16 slots made
- * a significant difference in the performance of this routine.
- *
- * Regardless until the IMFS implementation is proven, it
- * is better to stick to simple, easy to understand algorithms.
- */
-void IMFS_memfile_remove(
- IMFS_jnode_t *the_jnode
-)
-{
- IMFS_memfile_t *memfile;
- int i;
- int j;
- unsigned int to_free;
- block_p *p;
-
- memfile = (IMFS_memfile_t *) the_jnode;
-
- /*
- * Perform internal consistency checks
- */
- IMFS_assert( memfile );
-
- /*
- * Eventually this could be set smarter at each call to
- * memfile_free_blocks_in_table to greatly speed this up.
- */
- to_free = IMFS_MEMFILE_BLOCK_SLOTS;
-
- /*
- * Now start freeing blocks in this order:
- * + indirect
- * + doubly indirect
- * + triply indirect
- */
-
- if ( memfile->indirect ) {
- memfile_free_blocks_in_table( &memfile->indirect, to_free );
- }
-
- if ( memfile->doubly_indirect ) {
- for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
- if ( memfile->doubly_indirect[i] ) {
- memfile_free_blocks_in_table(
- (block_p **)&memfile->doubly_indirect[i], to_free );
- }
- }
- memfile_free_blocks_in_table( &memfile->doubly_indirect, to_free );
-
- }
-
- if ( memfile->triply_indirect ) {
- for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
- p = (block_p *) memfile->triply_indirect[i];
- if ( !p ) /* ensure we have a valid pointer */
- break;
- for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) {
- if ( p[j] ) {
- memfile_free_blocks_in_table( (block_p **)&p[j], to_free);
- }
- }
- memfile_free_blocks_in_table(
- (block_p **)&memfile->triply_indirect[i], to_free );
- }
- memfile_free_blocks_in_table(
- (block_p **)&memfile->triply_indirect, to_free );
- }
-
- IMFS_node_destroy_default( the_jnode );
-}
-
-/*
- * IMFS_memfile_read
- *
- * This routine read from memory file pointed to by the_jnode into
- * the specified data buffer specified by destination. The file
- * is NOT extended. An offset greater than the length of the file
- * is considered an error. Read from an offset for more bytes than
- * are between the offset and the end of the file will result in
- * reading the data between offset and the end of the file (truncated
- * read).
- */
-MEMFILE_STATIC ssize_t IMFS_memfile_read(
- IMFS_file_t *file,
- off_t start,
- unsigned char *destination,
- unsigned int length
-)
-{
- block_p *block_ptr;
- unsigned int block;
- unsigned int my_length;
- unsigned int to_copy = 0;
- unsigned int last_byte;
- unsigned int copied;
- unsigned int start_offset;
- unsigned char *dest;
-
- dest = destination;
-
- /*
- * Perform internal consistency checks
- */
- IMFS_assert( file );
- IMFS_assert( dest );
-
- /*
- * Linear files (as created from a tar file are easier to handle
- * than block files).
- */
- my_length = length;
-
- /*
- * If the last byte we are supposed to read is past the end of this
- * in memory file, then shorten the length to read.
- */
- last_byte = start + length;
- if ( last_byte > file->Memfile.File.size )
- my_length = file->Memfile.File.size - start;
-
- copied = 0;
-
- /*
- * Three phases to the read:
- * + possibly the last part of one block
- * + all of zero of more blocks
- * + possibly the first part of one block
- */
-
- /*
- * Phase 1: possibly the last part of one block
- */
- start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
- block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
- if ( start_offset ) {
- to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
- if ( to_copy > my_length )
- to_copy = my_length;
- block_ptr = IMFS_memfile_get_block_pointer( &file->Memfile, block, 0 );
- if ( !block_ptr )
- return copied;
- memcpy( dest, &(*block_ptr)[ start_offset ], to_copy );
- dest += to_copy;
- block++;
- my_length -= to_copy;
- copied += to_copy;
- }
-
- /*
- * Phase 2: all of zero of more blocks
- */
- to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
- while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
- block_ptr = IMFS_memfile_get_block_pointer( &file->Memfile, block, 0 );
- if ( !block_ptr )
- return copied;
- memcpy( dest, &(*block_ptr)[ 0 ], to_copy );
- dest += to_copy;
- block++;
- my_length -= to_copy;
- copied += to_copy;
- }
-
- /*
- * Phase 3: possibly the first part of one block
- */
- IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
-
- if ( my_length ) {
- block_ptr = IMFS_memfile_get_block_pointer( &file->Memfile, block, 0 );
- if ( !block_ptr )
- return copied;
- memcpy( dest, &(*block_ptr)[ 0 ], my_length );
- copied += my_length;
- }
-
- IMFS_update_atime( &file->Node );
-
- return copied;
-}
-
-/*
- * IMFS_memfile_write
- *
- * This routine writes the specified data buffer into the in memory
- * file pointed to by memfile. The file is extended as needed.
- */
-MEMFILE_STATIC ssize_t IMFS_memfile_write(
- IMFS_memfile_t *memfile,
- off_t start,
- const unsigned char *source,
- unsigned int length
-)
-{
- block_p *block_ptr;
- unsigned int block;
- int status;
- unsigned int my_length;
- unsigned int to_copy = 0;
- unsigned int last_byte;
- unsigned int start_offset;
- int copied;
- const unsigned char *src;
-
- src = source;
-
- /*
- * Perform internal consistency checks
- */
- IMFS_assert( source );
- IMFS_assert( memfile );
-
- my_length = length;
- /*
- * If the last byte we are supposed to write is past the end of this
- * in memory file, then extend the length.
- */
-
- last_byte = start + my_length;
- if ( last_byte > memfile->File.size ) {
- bool zero_fill = start > memfile->File.size;
-
- status = IMFS_memfile_extend( memfile, zero_fill, last_byte );
- if ( status )
- return status;
- }
-
- copied = 0;
-
- /*
- * Three phases to the write:
- * + possibly the last part of one block
- * + all of zero of more blocks
- * + possibly the first part of one block
- */
-
- /*
- * Phase 1: possibly the last part of one block
- */
- start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
- block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
- if ( start_offset ) {
- to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
- if ( to_copy > my_length )
- to_copy = my_length;
- block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
- if ( !block_ptr )
- return copied;
- #if 0
- fprintf(
- stderr,
- "write %d at %d in %d: %*s\n",
- to_copy,
- start_offset,
- block,
- to_copy,
- src
- );
- #endif
- memcpy( &(*block_ptr)[ start_offset ], src, to_copy );
- src += to_copy;
- block++;
- my_length -= to_copy;
- copied += to_copy;
- }
-
- /*
- * Phase 2: all of zero of more blocks
- */
-
- to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
- while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
- block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
- if ( !block_ptr )
- return copied;
- #if 0
- fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
- #endif
- memcpy( &(*block_ptr)[ 0 ], src, to_copy );
- src += to_copy;
- block++;
- my_length -= to_copy;
- copied += to_copy;
- }
-
- /*
- * Phase 3: possibly the first part of one block
- */
- IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
-
- to_copy = my_length;
- if ( my_length ) {
- block_ptr = IMFS_memfile_get_block_pointer( memfile, block, 0 );
- if ( !block_ptr )
- return copied;
- #if 0
- fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src );
- #endif
- memcpy( &(*block_ptr)[ 0 ], src, my_length );
- my_length = 0;
- copied += to_copy;
- }
-
- IMFS_mtime_ctime_update( &memfile->File.Node );
-
- return copied;
-}
-
-/*
- * IMFS_memfile_get_block_pointer
- *
- * This routine looks up the block pointer associated with the given block
- * number. If that block has not been allocated and "malloc_it" is
- * TRUE, then the block is allocated. Otherwise, it is an error.
- */
-#if 0
-block_p *IMFS_memfile_get_block_pointer_DEBUG(
- IMFS_jnode_t *the_jnode,
- unsigned int block,
- int malloc_it
-);
-
-block_p *IMFS_memfile_get_block_pointer(
- IMFS_jnode_t *the_jnode,
- unsigned int block,
- int malloc_it
-)
-{
- block_p *p;
-
- p = IMFS_memfile_get_block_pointer_DEBUG( the_jnode, block, malloc_it );
- fprintf(stdout, "(%d -> %p) ", block, p );
- return p;
-}
-
-block_p *IMFS_memfile_get_block_pointer_DEBUG(
-#else
-block_p *IMFS_memfile_get_block_pointer(
-#endif
- IMFS_memfile_t *memfile,
- unsigned int block,
- int malloc_it
-)
-{
- unsigned int my_block;
- unsigned int singly;
- unsigned int doubly;
- unsigned int triply;
- block_p *p;
- block_p *p1;
- block_p *p2;
-
- /*
- * Perform internal consistency checks
- */
- IMFS_assert( memfile );
-
- my_block = block;
-
- /*
- * Is the block number in the simple indirect portion?
- */
- if ( my_block <= LAST_INDIRECT ) {
- p = memfile->indirect;
-
- if ( malloc_it ) {
-
- if ( !p ) {
- p = memfile_alloc_block();
- if ( !p )
- return 0;
- memfile->indirect = p;
- }
- return &memfile->indirect[ my_block ];
- }
-
- if ( !p )
- return 0;
-
- return &memfile->indirect[ my_block ];
- }
-
- /*
- * Is the block number in the doubly indirect portion?
- */
-
- if ( my_block <= LAST_DOUBLY_INDIRECT ) {
- my_block -= FIRST_DOUBLY_INDIRECT;
-
- singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
- doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
-
- p = memfile->doubly_indirect;
- if ( malloc_it ) {
-
- if ( !p ) {
- p = memfile_alloc_block();
- if ( !p )
- return 0;
- memfile->doubly_indirect = p;
- }
-
- p1 = (block_p *)p[ doubly ];
- if ( !p1 ) {
- p1 = memfile_alloc_block();
- if ( !p1 )
- return 0;
- p[ doubly ] = (block_p) p1;
- }
-
- return (block_p *)&p1[ singly ];
- }
-
- if ( !p )
- return 0;
-
- p = (block_p *)p[ doubly ];
- if ( !p )
- return 0;
-
- return (block_p *)&p[ singly ];
- }
-
- /*
- * Is the block number in the triply indirect portion?
- */
- if ( my_block <= LAST_TRIPLY_INDIRECT ) {
- my_block -= FIRST_TRIPLY_INDIRECT;
-
- singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
- doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
- triply = doubly / IMFS_MEMFILE_BLOCK_SLOTS;
- doubly %= IMFS_MEMFILE_BLOCK_SLOTS;
-
- p = memfile->triply_indirect;
-
- if ( malloc_it ) {
- if ( !p ) {
- p = memfile_alloc_block();
- if ( !p )
- return 0;
- memfile->triply_indirect = p;
- }
-
- p1 = (block_p *) p[ triply ];
- if ( !p1 ) {
- p1 = memfile_alloc_block();
- if ( !p1 )
- return 0;
- p[ triply ] = (block_p) p1;
- }
-
- p2 = (block_p *)p1[ doubly ];
- if ( !p2 ) {
- p2 = memfile_alloc_block();
- if ( !p2 )
- return 0;
- p1[ doubly ] = (block_p) p2;
- }
- return (block_p *)&p2[ singly ];
- }
-
- if ( !p )
- return 0;
-
- p1 = (block_p *) p[ triply ];
- if ( !p1 )
- return 0;
-
- p2 = (block_p *)p1[ doubly ];
- if ( !p2 )
- return 0;
-
- return (block_p *)&p2[ singly ];
- }
-
- /*
- * This means the requested block number is out of range.
- */
- return 0;
-}
-
-/*
- * memfile_alloc_block
- *
- * Allocate a block for an in-memory file.
- */
-int memfile_blocks_allocated = 0;
-
-void *memfile_alloc_block(void)
-{
- void *memory;
-
- memory = (void *)calloc(1, IMFS_MEMFILE_BYTES_PER_BLOCK);
- if ( memory )
- memfile_blocks_allocated++;
-
- return memory;
-}
-
-/*
- * memfile_free_block
- *
- * Free a block from an in-memory file.
- */
-void memfile_free_block(
- void *memory
-)
-{
- free(memory);
- memfile_blocks_allocated--;
-}
--
2.1.4
More information about the devel
mailing list