summaryrefslogtreecommitdiff
path: root/cesar/ecos/packages/fs
diff options
context:
space:
mode:
authorsave2008-04-07 14:17:42 +0000
committersave2008-04-07 14:17:42 +0000
commit3d58a62727346b7ac1a6cb36fed1a06ed72228dd (patch)
treed7788c3cf9f76426aef0286d0202e2097f0fa0eb /cesar/ecos/packages/fs
parent095dca4b0a8d4924093bab424f71f588fdd84613 (diff)
Moved the complete svn base into the cesar directory.
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@1769 017c9cb6-072f-447c-8318-d5b54f68fe89
Diffstat (limited to 'cesar/ecos/packages/fs')
-rw-r--r--cesar/ecos/packages/fs/ram/current/ChangeLog118
-rw-r--r--cesar/ecos/packages/fs/ram/current/cdl/ramfs.cdl193
-rw-r--r--cesar/ecos/packages/fs/ram/current/src/ramfs.c2396
-rw-r--r--cesar/ecos/packages/fs/ram/current/tests/ramfs1.c654
-rw-r--r--cesar/ecos/packages/fs/ram/current/tests/ramfs2.c174
-rw-r--r--cesar/ecos/packages/fs/rom/current/ChangeLog165
-rw-r--r--cesar/ecos/packages/fs/rom/current/cdl/romfs.cdl133
-rw-r--r--cesar/ecos/packages/fs/rom/current/doc/mk_romfs.txt94
-rw-r--r--cesar/ecos/packages/fs/rom/current/doc/romfs.txt12
-rw-r--r--cesar/ecos/packages/fs/rom/current/src/romfs.c1100
-rw-r--r--cesar/ecos/packages/fs/rom/current/support/Makefile39
-rwxr-xr-xcesar/ecos/packages/fs/rom/current/support/file2c.tcl124
-rw-r--r--cesar/ecos/packages/fs/rom/current/support/mk_romfs.c734
-rw-r--r--cesar/ecos/packages/fs/rom/current/tests/romfs1.c388
-rw-r--r--cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/hosts0
-rw-r--r--cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/inetd0
-rw-r--r--cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/passwd32
-rw-r--r--cesar/ecos/packages/fs/rom/current/tests/testromfs/mnt/thing1
-rw-r--r--cesar/ecos/packages/fs/rom/current/tests/testromfs/var/foobar1
19 files changed, 6358 insertions, 0 deletions
diff --git a/cesar/ecos/packages/fs/ram/current/ChangeLog b/cesar/ecos/packages/fs/ram/current/ChangeLog
new file mode 100644
index 0000000000..c32390010d
--- /dev/null
+++ b/cesar/ecos/packages/fs/ram/current/ChangeLog
@@ -0,0 +1,118 @@
+2005-03-27 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * tests/ramfs1.c (SHOW_RESULT): Fixed compiler warning about format
+ not matching type.
+
+2004-12-13 John Dallaway <jld@ecoscentric.com>
+
+ * tests/fileio1.c: Rename to ramfs1.c. eCos test names should be
+ unique.
+ * tests/fseek1.c: Rename to ramfs2.c:
+ * cdl/ramfs.cdl: Build the renamed tests.
+
+2004-03-29 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * test/fseek1.c: Test the fseek/ftell functions
+ * cdl/ramfs.cdl: Added a fseek1 test to the build
+
+2004-03-15 Sebastien Couret <sebastien.couret@elios-informatique.fr>
+
+ * src/ramfs.c (block_init): Fixed compiler warning.
+
+2004-02-20 Vincent Catros <Vincent.Catros@elios-informatique.fr>
+
+ * src/ramfs.c :
+ (ramfs_find) Policy to skip path separator is no longer
+ "if '/' then skip" but "while '/' then skip" allowing
+ multi '/' separators (i.e : /tmp////foo).
+ (find_entry) Policy to detect end of path is no longer
+ "if '\0' then end_of_path"
+ but "while '/' skip it and then if '\0' then end_of_path"
+ allowing path terminated with any number of '/'
+ (i.e : chdir(/tmp///)).
+
+2004-02-25 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * src/ramfs.c (findbuffer_node): If pos larger than even INDIRECT2_MAX
+ then return ENOSPC, not EINVAL. Thanks to Vincent Catros for spotting
+ this.
+
+2004-01-08 Vincent Catros <Vincent.Catros@elios-informatique.fr>
+
+ * src/ramfs.c (ramfs_fo_write): Return ENOSPC when the filesystem
+ is full.
+
+2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/ramfs.cdl: Fix doc link.
+
+2002-12-06 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * cdl/ramfs.cdl: Implements the CYGINT_IO_FILEIO_FS interface
+
+2002-01-25 Jonathan Larmour <jlarmour@redhat.com>
+
+ * tests/fileio1.c (main): Check in listdir that the number of
+ dirents is correct.
+
+2001-07-26 Jonathan Larmour <jlarmour@redhat.com>
+
+ * src/ramfs.c (findbuffer_indirect1): Determine correct offset in
+ indirect block list.
+ (findbuffer_indirect2): Ditto.
+ (findbuffer_direct): Compare block index with number of blocks
+ correctly.
+
+2000-10-05 Nick Garnett <nickg@cygnus.co.uk>
+
+ * tests/fileio1.c:
+ Extended to check getcwd() and chdir() functionality more fully.
+
+2000-08-18 Nick Garnett <nickg@cygnus.co.uk>
+
+ * cdl/ramfs.cdl:
+ * src/ramfs.c:
+ * tests/fileio1.c:
+ Created this example RAM filesystem both as a usable filesystem
+ and as an example of how to build filesystems for the fileio
+ infrastructure.
+
+
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
+
+
diff --git a/cesar/ecos/packages/fs/ram/current/cdl/ramfs.cdl b/cesar/ecos/packages/fs/ram/current/cdl/ramfs.cdl
new file mode 100644
index 0000000000..be6a00e915
--- /dev/null
+++ b/cesar/ecos/packages/fs/ram/current/cdl/ramfs.cdl
@@ -0,0 +1,193 @@
+# ====================================================================
+#
+# ramfs.cdl
+#
+# RAM Filesystem configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+## Copyright (C) 2004 eCosCentric Limited
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): nickg
+# Original data: nickg
+# Contributors:
+# Date: 2000-08-01
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_FS_RAM {
+ display "RAM filesystem"
+ doc ref/fileio.html
+ include_dir cyg/ramfs
+
+ requires CYGPKG_IO_FILEIO
+
+ requires CYGPKG_ISOINFRA
+ requires CYGPKG_ERROR
+ requires CYGINT_ISO_ERRNO
+ requires CYGINT_ISO_ERRNO_CODES
+
+ implements CYGINT_IO_FILEIO_FS
+
+ compile -library=libextras.a ramfs.c
+
+ # ----------------------------------------------------------------------
+ # Simple allocation mechanism using malloc()
+
+ cdl_component CYGPKG_FS_RAM_SIMPLE {
+ display "Simple, malloc() based, implementation"
+ requires { CYGINT_ISO_MALLOC != 0 }
+ default_value 1
+ active_if !CYGPKG_FS_RAM_BLOCKS
+
+ cdl_option CYGNUM_RAMFS_REALLOC_INCREMENT {
+ display "Size of file data storage increment"
+ flavor data
+ default_value 256
+ legal_values 64 to 32768
+ description "This option controls the size of the increment to a file data
+ storage block."
+ }
+
+ }
+
+ # ----------------------------------------------------------------------
+ # Block based allocation, using either malloc() or a private block
+ # pool.
+
+ cdl_component CYGPKG_FS_RAM_BLOCKS {
+ display "Block-based RAM filesystem allocation"
+ default_value 0
+ active_if !CYGPKG_FS_RAM_SIMPLE
+
+
+ cdl_option CYGNUM_RAMFS_BLOCK_SIZE {
+ display "Size of file data storage block"
+ flavor data
+ default_value 256
+ legal_values 64 to 32768
+ description "This option controls the size of a data storage block."
+ }
+
+ cdl_option CYGNUM_RAMFS_BLOCKS_DIRECT {
+ display "Directly referenced data storage blocks"
+ flavor data
+ default_value 8
+ legal_values 0 to 32
+ description "This option controls the number of data storage blocks that
+ are referenced directly from a file or directory node."
+ }
+
+ cdl_option CYGNUM_RAMFS_BLOCKS_INDIRECT1 {
+ display "Single level indirect data storage blocks"
+ flavor data
+ default_value 1
+ legal_values 0 to 32
+ description "This option controls the number of single level indirect storage
+ blocks that are referenced from a file or directory node."
+ }
+
+ cdl_option CYGNUM_RAMFS_BLOCKS_INDIRECT2 {
+ display "Two level indirect data storage blocks"
+ flavor data
+ default_value 1
+ legal_values 0 to 32
+ description "This option controls the number of two level indirect storage
+ blocks that are referenced from a file or directory node."
+ }
+
+ cdl_component CYGPKG_FS_RAM_BLOCKS_ARRAY {
+ display "Use block array rather than malloc()"
+ default_value 0
+ description "This option controls whether the blocks are allocated from
+ an array of blocks rather from the heap using malloc()."
+
+ cdl_option CYGPKG_FS_RAM_BLOCKS_ARRAY_EXTERN {
+ display "Block array is external"
+ default_value 0
+ description "This option controls whether the block array is
+ defined by the RAMFS package or whether it is provided
+ by an external component. The latter option may be
+ useful when the RAM file system is to be put into a
+ special memory area."
+ }
+
+ cdl_option CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME {
+ display "Name of external block array"
+ active_if CYGPKG_FS_RAM_BLOCKS_ARRAY_EXTERN
+ flavor data
+ default_value "cyg_ramfs_block_array"
+ description "This option controls what the symbol name of the external
+ block array will be."
+ }
+
+ cdl_option CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE {
+ display "Size of blocks array"
+ flavor data
+ default_value 128
+ legal_values 1 to 9999999999
+ description "The number of blocks in the array. The total size of
+ the array will be this value times the block size."
+ }
+ }
+ }
+
+ cdl_option CYGNUM_RAMFS_DIRENT_SIZE {
+ display "Directory entry size"
+ flavor data
+ default_value 32
+ legal_values 16 to { CYGNUM_RAMFS_BLOCK_SIZE ? CYGNUM_RAMFS_BLOCK_SIZE : 128 }
+ description "This option controls the number of two level indirect storage
+ blocks that are referenced from a file or directory node."
+ }
+
+ # ----------------------------------------------------------------
+ # Tests
+
+ cdl_option CYGPKG_FS_RAM_TESTS {
+ display "RAM FS tests"
+ flavor data
+ no_define
+ calculated { "tests/ramfs1 tests/ramfs2" }
+ description "
+ This option specifies the set of tests for the RAM FS package."
+ }
+
+}
+
+# End of ramfs.cdl
diff --git a/cesar/ecos/packages/fs/ram/current/src/ramfs.c b/cesar/ecos/packages/fs/ram/current/src/ramfs.c
new file mode 100644
index 0000000000..b1d456f747
--- /dev/null
+++ b/cesar/ecos/packages/fs/ram/current/src/ramfs.c
@@ -0,0 +1,2396 @@
+//==========================================================================
+//
+// ramfs.c
+//
+// RAM file system
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg
+// Contributors: nickg
+// Date: 2000-07-25
+// Purpose: RAM file system
+// Description: This is a RAM filesystem for eCos. It attempts to
+// provide full POSIX-compatible filesystem behaviour
+// while at the same time being efficient in terms of
+// time and space used.
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+//
+// General Description
+// ===================
+//
+// This is an implementation of a RAM filesystem for eCos. Its goal is
+// to provide a working example of a filesystem that provides most of
+// the required POSIX functionality. And obviously it may also be
+// useful in its own right.
+//
+//
+// Nodes
+// -----
+//
+// All files and directories are represented by node objects. Each
+// ramfs_node structure contains the following fields:
+//
+// mode - Node type, file or directory.
+// refcnt - Number of references to this node. For files each open counts as
+// a reference and for directories a node is referenced when it is made
+// current directory, or is opened for reading.
+// nlink - Number of links to this node. Each directory entry that references
+// this node is a link.
+// size - Size of the data in this node in bytes.
+// atime - Last time this node was accessed.
+// mtime - Last time the data in this node was modified.
+// ctime - Last time the status information in this node was changed.
+//
+// The data storage in a node is controlled by the configuration and
+// can take two forms. These will be described later.
+//
+// Directories
+// -----------
+//
+// A directory is a node whose data is a list of directory entries. To
+// simplify management of these, long directory entries are split into
+// a chain of fixed size ramfs_dirent structures. These contain the
+// following fields:
+//
+// node - Pointer to node referenced by this entry. This is present in
+// every directory entry fragment
+// inuse - Set to 1 if this entry is in use, zero if it is free.
+// first - Set to 1 if this is the first fragment of a directory entry.
+// last - Set to 1 if this is the last fragment of a directory entry.
+// namelen - The size of the whole file name.
+// fraglen - The number of bytes of the file name that are stored in this
+// fragment.
+// next - The offset of the next fragment of this directory entry.
+// name - The characters of the fragment of the file name stored in this
+// entry.
+//
+// Small file names are stored in a single fragment. Longer names are
+// stored in a chain of fragments.
+//
+// Data Storage
+// ------------
+//
+// Two data storage mechanisms may be configured, the SIMPLE and the
+// BLOCKS mechanisms.
+//
+// SIMPLE Data Storage
+// ~~~~~~~~~~~~~~~~~~~
+//
+// This mechanism simply uses malloc() and free() to allocate the
+// memory for both nodes and file data. File data is stored in a
+// single malloced vector that is realloced as necessary to acquire
+// more space.
+//
+// The advantage of this approach is that the RAM filesystem only uses
+// as much memory as it needs, the rest is available for use by other
+// components. It also requires much simpler data structures and code
+// in the filesystem to manage. However, if any files get to be a
+// significant proportion of the size of the heap, there is the danger
+// that fragmentation will prevent any further extension of some
+// files, even if there is enough memory in total. It also requires an
+// implementation of malloc() to be present. If this needs to be
+// present for other components,then this is not a significant
+// overhead, but including it just for use by this filesystem
+// represents a major addition of code and data structures.
+//
+//
+// BLOCKS Data Storage
+// ~~~~~~~~~~~~~~~~~~~
+//
+// This mechanism divides the memory used for file storage into fixed
+// sized blocks. These blocks may either be allocated using
+// malloc()/free(), or may be obtained from a array of blocks reserved
+// for the purpose. Configuration allows the block size to be
+// selected, as well as the allocation mechanism, and in the case of a
+// block array, whether it is defined here or by an external
+// component.
+//
+// Data storage in nodes is arranges in three arrays of pointers to
+// blocks. The first array points directly to data blocks, the second
+// to blocks which themselves contain pointers to data blocks, and the
+// third to blocks which contain pointers to blocks which contain
+// pointers to data blocks. In the default configuration These last
+// two arrays have only one element each.
+//
+// The following shows how the data is arranged in a fully populated
+// file with a 256 byte block size using the default configuration.
+//
+// Node
+// ~ ~
+// | |
+// | |
+// +------------+
+// | *------+--------> data block 0
+// +------------+
+// | *------+--------> data block 1
+// +------------+
+// | *------+--------> data block 2
+// +------------+
+// | *------+--------> data block 3
+// +------------+
+// | *------+--------> data block 4
+// +------------+
+// | *------+--------> data block 5
+// +------------+
+// | *------+--------> data block 6
+// +------------+
+// | *------+--------> data block 7
+// +------------+
+// | *------+--------> +------------+
+// +------------+ | *------+--------> data block 8
+// | *------+----+ +------------+
+// +------------+ | | |
+// | ~ ~
+// | | |
+// | +------------+
+// | | *------+--------> data block 71
+// | +------------+
+// |
+// +---->+------------+ +------------+
+// | *------+-------->| *------+---->data block 72
+// +------------+ +------------+
+// | | | |
+// ~ ~ ~ ~
+// | | | |
+// +------------+ +------------+
+// | *------+---+ | *------+----> data block 135
+// +------------+ | +------------+
+// |
+// | +------------+
+// +---->| *------+----> data block 4104
+// +------------+
+// | |
+// ~ ~
+// | |
+// +------------+
+// | *------+----> data block 4167
+// +------------+
+//
+//
+//
+// The advantages of this approach are that, first, memory usage is
+// divided into discreet fixed size blocks which are easier to
+// manage. When using malloc() to allocate them, they will fit into
+// any free memory of at least the right size. Using the block array
+// option removes the need to have a malloc() implementation at all.
+//
+// The disadvantages of this mechanism are that, first, when using
+// malloc() to allocate blocks, the per-block memory allocator
+// overhead is paid for each block, rather than per file. This may
+// result in less memory overall being available for data
+// storage. When using the block array, it is permanently reserved for
+// use by the ram filesystem, and is not available for use by other
+// components.
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+#include <pkgconf/fs_ram.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/kernel/kapi.h>
+#include <cyg/infra/diag.h>
+
+//==========================================================================
+// Sizes derived from configuration
+
+// -------------------------------------------------------------------------
+// Simple malloc based allocator parameters
+
+#ifdef CYGPKG_FS_RAM_SIMPLE
+
+#define RAMFS_FILESIZE_MAX UINT_MAX
+
+#else
+
+// -------------------------------------------------------------------------
+// Block allocator parameters
+
+// The number of nodes per block
+#define RAMFS_NODES_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_node))
+
+// The number of indirect pointers that can be stored in a single data block
+#define RAMFS_INDIRECT_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_block *))
+
+// The number of directory entries that can be stored in a single data block
+#define RAMFS_DIRENT_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_dirent))
+
+// Number of bytes contained in a one level indirect block
+#define RAMFS_INDIRECT1_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
+ CYGNUM_RAMFS_BLOCK_SIZE)
+
+// number of bytes contained in a two level indirect block
+#define RAMFS_INDIRECT2_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
+ RAMFS_INDIRECT_PER_BLOCK* \
+ CYGNUM_RAMFS_BLOCK_SIZE)
+
+// The maximum data offset for data directly accessed from the node
+#define RAMFS_DIRECT_MAX (CYGNUM_RAMFS_BLOCKS_DIRECT*CYGNUM_RAMFS_BLOCK_SIZE)
+
+// The maximum data offset for data accessed from the single level indirect blocks
+#define RAMFS_INDIRECT1_MAX (RAMFS_DIRECT_MAX+ \
+ (CYGNUM_RAMFS_BLOCKS_INDIRECT1* \
+ RAMFS_INDIRECT1_BLOCK_EXTENT))
+
+// The maximum data offset for data accessed from the two level indirect blocks
+#define RAMFS_INDIRECT2_MAX (RAMFS_INDIRECT1_MAX+ \
+ (CYGNUM_RAMFS_BLOCKS_INDIRECT2* \
+ RAMFS_INDIRECT2_BLOCK_EXTENT))
+
+// The maximum size of a file
+#define RAMFS_FILESIZE_MAX RAMFS_INDIRECT2_MAX
+
+#endif
+
+//==========================================================================
+// Forward definitions
+
+// Filesystem operations
+static int ramfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
+static int ramfs_umount ( cyg_mtab_entry *mte );
+static int ramfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int mode, cyg_file *fte );
+static int ramfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
+static int ramfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
+static int ramfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
+static int ramfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
+ cyg_dir dir2, const char *name2 );
+static int ramfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
+ cyg_dir dir2, const char *name2, int type );
+static int ramfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_file *fte );
+static int ramfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_dir *dir_out );
+static int ramfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ struct stat *buf);
+static int ramfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len );
+static int ramfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len );
+
+// File operations
+static int ramfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+static int ramfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+static int ramfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
+static int ramfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
+ CYG_ADDRWORD data);
+static int ramfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode );
+static int ramfs_fo_close (struct CYG_FILE_TAG *fp);
+static int ramfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
+static int ramfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
+static int ramfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
+
+// Directory operations
+static int ramfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+static int ramfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
+
+
+//==========================================================================
+// Filesystem table entries
+
+// -------------------------------------------------------------------------
+// Fstab entry.
+// This defines the entry in the filesystem table.
+// For simplicity we use _FILESYSTEM synchronization for all accesses since
+// we should never block in any filesystem operations.
+
+FSTAB_ENTRY( ramfs_fste, "ramfs", 0,
+ CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
+ ramfs_mount,
+ ramfs_umount,
+ ramfs_open,
+ ramfs_unlink,
+ ramfs_mkdir,
+ ramfs_rmdir,
+ ramfs_rename,
+ ramfs_link,
+ ramfs_opendir,
+ ramfs_chdir,
+ ramfs_stat,
+ ramfs_getinfo,
+ ramfs_setinfo);
+
+// -------------------------------------------------------------------------
+// File operations.
+// This set of file operations are used for normal open files.
+
+static cyg_fileops ramfs_fileops =
+{
+ ramfs_fo_read,
+ ramfs_fo_write,
+ ramfs_fo_lseek,
+ ramfs_fo_ioctl,
+ cyg_fileio_seltrue,
+ ramfs_fo_fsync,
+ ramfs_fo_close,
+ ramfs_fo_fstat,
+ ramfs_fo_getinfo,
+ ramfs_fo_setinfo
+};
+
+// -------------------------------------------------------------------------
+// Directory file operations.
+// This set of operations are used for open directories. Most entries
+// point to error-returning stub functions. Only the read, lseek and
+// close entries are functional.
+
+static cyg_fileops ramfs_dirops =
+{
+ ramfs_fo_dirread,
+ (cyg_fileop_write *)cyg_fileio_enosys,
+ ramfs_fo_dirlseek,
+ (cyg_fileop_ioctl *)cyg_fileio_enosys,
+ cyg_fileio_seltrue,
+ (cyg_fileop_fsync *)cyg_fileio_enosys,
+ ramfs_fo_close,
+ (cyg_fileop_fstat *)cyg_fileio_enosys,
+ (cyg_fileop_getinfo *)cyg_fileio_enosys,
+ (cyg_fileop_setinfo *)cyg_fileio_enosys
+};
+
+//==========================================================================
+// Data typedefs
+// Some forward typedefs for the main data structures.
+
+struct ramfs_node;
+typedef struct ramfs_node ramfs_node;
+
+struct ramfs_dirent;
+typedef struct ramfs_dirent ramfs_dirent;
+
+#ifndef CYGPKG_FS_RAM_SIMPLE
+
+typedef cyg_uint8 ramfs_block[CYGNUM_RAMFS_BLOCK_SIZE];
+
+#endif
+
+//==========================================================================
+// File and directory node
+// This data structure represents a file or directory.
+
+struct ramfs_node
+{
+ mode_t mode; // node type
+ cyg_ucount32 refcnt; // open file/current dir references
+ nlink_t nlink; // number of links to this node
+ size_t size; // size of file in bytes
+ time_t atime; // last access time
+ time_t mtime; // last modified time
+ time_t ctime; // last changed status time
+
+#ifdef CYGPKG_FS_RAM_SIMPLE
+
+ // The data storage in this case consists of a single
+ // malloced memory block, together with its size.
+
+ size_t datasize; // size of data block
+ cyg_uint8 *data; // malloced data buffer
+
+#else
+
+ // The data storage in this case consists of arrays of pointers
+ // to data blocks.
+
+#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
+ // Directly accessible blocks from the inode.
+ ramfs_block *direct[CYGNUM_RAMFS_BLOCKS_DIRECT];
+#endif
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
+ // Single level indirection
+ ramfs_block **indirect1[CYGNUM_RAMFS_BLOCKS_INDIRECT1];
+#endif
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
+ // Two level indirection
+ ramfs_block ***indirect2[CYGNUM_RAMFS_BLOCKS_INDIRECT2];
+#endif
+
+#endif
+
+};
+
+//==========================================================================
+// Directory entry.
+// Fixed sized entry containing a fragment of the name of a file/directory.
+
+struct ramfs_dirent
+{
+ ramfs_node *node; // pointer to node
+ unsigned int inuse:1, // entry in use?
+ first:1, // first directory entry fragment?
+ last:1, // last directory entry fragment?
+ namelen:8, // bytes in whole name
+ fraglen:8; // bytes in name fragment
+ off_t next; // offset of next dirent
+
+ // Name fragment, fills rest of entry.
+ char name[CYGNUM_RAMFS_DIRENT_SIZE-
+ sizeof(ramfs_node *)-
+ sizeof( cyg_uint32)-
+ sizeof(off_t)];
+};
+
+//==========================================================================
+// Directory search data
+// Parameters for a directory search. The fields of this structure are
+// updated as we follow a pathname through the directory tree.
+
+struct ramfs_dirsearch
+{
+ ramfs_node *dir; // directory to search
+ const char *path; // path to follow
+ ramfs_node *node; // Node found
+ const char *name; // last name fragment used
+ int namelen; // name fragment length
+ cyg_bool last; // last name in path?
+};
+
+typedef struct ramfs_dirsearch ramfs_dirsearch;
+
+//==========================================================================
+// Forward defs
+
+static int del_direntry( ramfs_node *dir, const char *name, int namelen );
+
+
+//==========================================================================
+// Block array
+// This is used for block allocation when malloc is not being used.
+
+#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
+
+# ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY_EXTERN
+
+// Array is defined externally with a user-supplied name
+
+__externC ramfs_block CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
+
+// Translate into a usable common name
+#define ramfs_block_array CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME
+
+# else
+
+// Array is defined here
+
+static ramfs_block cyg_ramfs_block_array[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
+
+#define ramfs_block_array cyg_ramfs_block_array
+
+# endif
+
+// Pointer to list of free blocks
+static ramfs_block *block_free_list = NULL;
+
+#endif
+
+//==========================================================================
+// Block allocation
+
+#ifndef CYGPKG_FS_RAM_SIMPLE
+
+// -------------------------------------------------------------------------
+// block_init()
+// Initialize the block allocator by chaining them all together on
+// block_free_list.
+
+#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
+
+static void block_init(void)
+{
+ static cyg_bool initialized = false;
+ int i;
+
+ if( !initialized )
+ {
+ for( i = 0; i < CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE; i++ )
+ {
+ ramfs_block *b = &ramfs_block_array[i];
+ *(ramfs_block **)b = block_free_list;
+ block_free_list = b;
+ }
+ initialized = true;
+ }
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// block_alloc()
+// Allocate a block for data storage.
+// If we have a block array, just pick the first off the free list.
+// If we are mallocing, call malloc() to get it.
+
+static ramfs_block *block_alloc(void)
+{
+ ramfs_block *b;
+
+#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
+
+ block_init(); // Check blocks are initialized
+
+ // pick first block off free list.
+ b = block_free_list;
+
+ // and advance list
+ if( b != NULL )
+ block_free_list = *(ramfs_block **)b;
+
+#else
+
+ b = malloc(CYGNUM_RAMFS_BLOCK_SIZE);
+
+#endif
+
+ // Clear the block to zero if it was allocated
+ if( b != NULL )
+ memset( b, 0, CYGNUM_RAMFS_BLOCK_SIZE );
+
+ return b;
+
+}
+
+// -------------------------------------------------------------------------
+// block_free()
+// Free a block. Depending on the configuration send it back to the
+// heap or put it back on free list.
+
+static void block_free( ramfs_block *b )
+{
+#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
+
+ // Put the block back on the free list
+
+ *(ramfs_block **)b = block_free_list;
+ block_free_list = b;
+
+#else
+
+ // Call free() to return it to the memory pool
+
+ free( b );
+
+#endif
+}
+
+#endif
+
+//==========================================================================
+// Node buffer management
+// There are two versions of this, one for the _SIMPLE variant and one for
+// the _BLOCKS variant. In both cases the interface to this code is via the
+// findbuffer_node() and freebuffer_node() functions.
+
+#ifdef CYGPKG_FS_RAM_SIMPLE
+
+//==========================================================================
+// SIMPLE buffer management.
+// Each node has a data buffer pointer and a size. This buffer is
+// realloc()ed as needed.
+
+// -------------------------------------------------------------------------
+// findbuffer_node()
+// return a pointer to the data at the indicated file position, extending
+// the buffer if required.
+
+static int findbuffer_node( ramfs_node *node, // node pointer
+ off_t pos, // data position to get
+ cyg_uint8 **buffer, // returned buffer pointer
+ size_t *size, // returned buffer size
+ cyg_bool alloc) // extend allocation?
+{
+ if( alloc && (pos == node->datasize || node->datasize == 0) )
+ {
+ // If we are allowed to alloc new data, and we are at the end of the
+ // current data allocation, or there is no data present, allocate or
+ // extend the data buffer.
+
+ cyg_uint8 *newdata;
+
+ if( node->data == NULL )
+ newdata = malloc( CYGNUM_RAMFS_REALLOC_INCREMENT );
+ else
+ newdata = realloc( node->data, pos+CYGNUM_RAMFS_REALLOC_INCREMENT );
+
+ if( newdata == NULL ) return ENOSPC;
+ else memset( newdata+pos, 0, CYGNUM_RAMFS_REALLOC_INCREMENT );
+
+ node->data = newdata;
+ node->datasize = pos+CYGNUM_RAMFS_REALLOC_INCREMENT;
+ }
+ else if( pos > node->datasize )
+ {
+ // Indicate end of data.
+ *size = 0;
+ return ENOERR;
+ }
+
+ *buffer = node->data+pos;
+ *size = node->datasize-pos;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// freebuffer_node()
+// Empty out the data storage from the node.
+
+static int freebuffer_node( ramfs_node *node )
+{
+ if( node->data != NULL )
+ {
+ free( node->data );
+ }
+
+ node->data = NULL;
+ node->datasize = 0;
+
+ return ENOERR;
+}
+
+//==========================================================================
+
+#else
+
+//==========================================================================
+// _BLOCKS storage management.
+// Data storage in the node is by means of a set of arrays of pointers to
+// blocks. The first array points directly to the data blocks. Subsequent
+// arrays point to single and double indirect blocks respectively.
+
+// -------------------------------------------------------------------------
+// findbuffer_direct()
+// Indexes into an array of block pointers and extracts a pointer to the
+// data at offset _pos_, allocating new blocks if required.
+
+static int findbuffer_direct( off_t pos,
+ ramfs_block **blocks,
+ int nblocks,
+ cyg_uint8 **buffer,
+ size_t *size,
+ cyg_bool alloc)
+{
+ int bi = pos / CYGNUM_RAMFS_BLOCK_SIZE;
+ int bpos = pos % CYGNUM_RAMFS_BLOCK_SIZE;
+ ramfs_block *b;
+
+ *buffer = NULL;
+ *size = 0;
+
+ if( bi >= nblocks )
+ return ENOERR;
+
+ b = blocks[bi];
+
+ if( b == NULL )
+ {
+ // There is no block there. If _alloc_ is true we can fill the
+ // slot in with a new block. If it is false, we indicate end of
+ // data with a zero size result.
+ if( alloc )
+ {
+ b = block_alloc();
+ if( b == NULL )
+ return ENOSPC;
+ blocks[bi] = b;
+ }
+ else return ENOERR;
+ }
+
+ *buffer = &((*b)[bpos]);
+ *size = CYGNUM_RAMFS_BLOCK_SIZE - bpos;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// findbuffer_indirect1()
+// Indexes into an array of pointers to blocks containing pointers to
+// blocks and extracts a pointer to the data at offset _pos_,
+// allocating new blocks if required.
+
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
+
+static int findbuffer_indirect1( off_t pos,
+ ramfs_block ***blocks,
+ int nblocks,
+ cyg_uint8 **buffer,
+ size_t *size,
+ cyg_bool alloc)
+{
+
+ int bi = pos / RAMFS_INDIRECT1_BLOCK_EXTENT;
+ int bpos = pos % RAMFS_INDIRECT1_BLOCK_EXTENT;
+ int err;
+ cyg_uint8 *b;
+ size_t sz;
+
+ // Use findbuffer_direct() to index and allocate
+ // the first level indirect block.
+
+ err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
+ (ramfs_block **)blocks,
+ nblocks,
+ &b,
+ &sz,
+ alloc);
+
+ if( err != ENOERR )
+ return err;
+
+ if( sz == 0 )
+ {
+ *size = 0;
+ return ENOERR;
+ }
+
+ // Use findbuffer_direct() on the first level indirect
+ // block to allocate and return the data pointer.
+
+ return findbuffer_direct( bpos,
+ blocks[bi],
+ RAMFS_INDIRECT_PER_BLOCK,
+ buffer,
+ size,
+ alloc);
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// findbuffer_indirect1()
+// Indexes into an array of pointers to blocks containing pointers to
+// blocks containing pointers to blocks (!) and extracts a pointer to
+// the data at offset _pos_, allocating new blocks if required.
+
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
+
+static int findbuffer_indirect2( off_t pos,
+ ramfs_block ****blocks,
+ int nblocks,
+ cyg_uint8 **buffer,
+ size_t *size,
+ cyg_bool alloc)
+{
+ int bi = pos / RAMFS_INDIRECT2_BLOCK_EXTENT;
+ int bpos = pos % RAMFS_INDIRECT2_BLOCK_EXTENT;
+ int err;
+ cyg_uint8 *b;
+ size_t sz;
+
+ // Use findbuffer_direct() to index and allocate
+ // the first level indirect block.
+
+ err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
+ (ramfs_block **)blocks,
+ nblocks,
+ &b,
+ &sz,
+ alloc);
+
+ if( err != ENOERR )
+ return err;
+
+ if( sz == 0 )
+ {
+ *size = 0;
+ return ENOERR;
+ }
+
+ // Use findbuffer_indirect1() on the first level indirect block to
+ // index and allocate the next level indirect block and the data
+ // block.
+
+ return findbuffer_indirect1( bpos,
+ blocks[bi],
+ RAMFS_INDIRECT_PER_BLOCK,
+ buffer,
+ size,
+ alloc);
+}
+
+#endif
+
+// -------------------------------------------------------------------------
+// findbuffer_node()
+// Depending on the offset and configuration, call the appropriate
+// function to get the buffer pointer.
+
+static int findbuffer_node( ramfs_node *node,
+ off_t pos,
+ cyg_uint8 **buffer,
+ size_t *size,
+ cyg_bool alloc)
+{
+#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
+ if( pos < RAMFS_DIRECT_MAX )
+ return findbuffer_direct( pos,
+ node->direct,
+ CYGNUM_RAMFS_BLOCKS_DIRECT,
+ buffer,
+ size,
+ alloc);
+#endif
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
+ if( pos < RAMFS_INDIRECT1_MAX )
+ return findbuffer_indirect1( pos - RAMFS_DIRECT_MAX,
+ node->indirect1,
+ CYGNUM_RAMFS_BLOCKS_INDIRECT1,
+ buffer,
+ size,
+ alloc);
+#endif
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
+ if( pos < RAMFS_INDIRECT2_MAX )
+ return findbuffer_indirect2( pos - RAMFS_INDIRECT1_MAX,
+ node->indirect2,
+ CYGNUM_RAMFS_BLOCKS_INDIRECT2,
+ buffer,
+ size,
+ alloc);
+#endif
+
+ return ENOSPC;
+}
+
+// -------------------------------------------------------------------------
+// freeblock_list()
+// Free a list of data blocks.
+
+static void freeblock_list( ramfs_block *blocks[],int nblocks )
+{
+ int i;
+ for( i = 0; i < nblocks ; i++ )
+ {
+ if( blocks[i] != NULL )
+ {
+ block_free( blocks[i] );
+ blocks[i] = NULL;
+ }
+ }
+}
+
+// -------------------------------------------------------------------------
+// freebuffer_node()
+// Free all the data blocks in the node and clear the pointers.
+
+static int freebuffer_node( ramfs_node *node )
+{
+#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
+ freeblock_list( node->direct, CYGNUM_RAMFS_BLOCKS_DIRECT );
+#endif
+
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
+ {
+ int i;
+ for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT1 ; i++ )
+ {
+ if( node->indirect1[i] != NULL )
+ {
+ freeblock_list( (ramfs_block **)node->indirect1[i], RAMFS_INDIRECT_PER_BLOCK );
+ block_free( (ramfs_block *)node->indirect1[i] );
+ node->indirect1[i] = NULL;
+ }
+ }
+ }
+#endif
+
+#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
+ {
+ int i;
+ for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT2 ; i++ )
+ {
+ if( node->indirect2[i] != NULL )
+ {
+ ramfs_block ***b = node->indirect2[i];
+ int j;
+ for( j = 0; j < RAMFS_INDIRECT_PER_BLOCK ; j++ )
+ {
+ if( b[j] != NULL )
+ {
+ freeblock_list( (ramfs_block **)b[j], RAMFS_INDIRECT_PER_BLOCK );
+ block_free( (ramfs_block *)b[j] );
+ b[j] = NULL;
+ }
+ }
+ block_free( (ramfs_block *)node->indirect2[i] );
+ node->indirect2[i] = NULL;
+ }
+ }
+ }
+#endif
+
+ return ENOERR;
+}
+
+//==========================================================================
+
+#endif
+
+//==========================================================================
+// Node allocation
+
+// -------------------------------------------------------------------------
+// alloc_node()
+// Allocate a node and initialize it.
+// For the _SIMPLE allocation option, we just malloc it. For the
+// _BLOCKS option we allocate a block and use that. In theory we could
+// pack several nodes into a single block, but we don't at present due
+// to sheer lazyness.
+
+static ramfs_node *alloc_node( mode_t mode )
+{
+#ifdef CYGPKG_FS_RAM_SIMPLE
+ ramfs_node *node = malloc( sizeof( ramfs_node ) );
+
+ if( node == NULL )
+ return NULL;
+
+#else
+ ramfs_block *b = block_alloc();
+ ramfs_node *node;
+
+ if( b == NULL )
+ return NULL;
+
+ node = (ramfs_node *)b;
+
+#endif
+
+ memset( node, 0, sizeof(ramfs_node) );
+
+ node->mode = mode;
+ node->refcnt = 0;
+ node->nlink = 0;
+ node->size = 0;
+ node->atime =
+ node->mtime =
+ node->ctime = cyg_timestamp();
+
+#ifdef CYGPKG_FS_RAM_SIMPLE
+ node->datasize = 0;
+ node->data = NULL;
+#else
+
+ // The node is already all zero
+
+#endif
+ return node;
+}
+
+// -------------------------------------------------------------------------
+// free_node()
+// Release a node either back to the free pool or back into the block
+// pool.
+
+static void free_node( ramfs_node *node )
+{
+#ifdef CYGPKG_FS_RAM_SIMPLE
+
+ free( node );
+
+#else
+
+ block_free( (ramfs_block *)node );
+
+#endif
+
+}
+
+
+//==========================================================================
+// Ref count and nlink management
+
+// -------------------------------------------------------------------------
+// dec_refcnt()
+// Decrment the reference count on a node. If this makes the ref count
+// zero, and the number of links is either zero for a file or one for
+// a node, then this node is detached from the directory tree and can
+// be freed.
+
+static int dec_refcnt( ramfs_node *node )
+{
+ int err = ENOERR;
+ node->refcnt--;
+
+ if( node->refcnt == 0 &&
+ ((S_ISREG(node->mode) && node->nlink == 0 ) ||
+ (S_ISDIR(node->mode) && node->nlink == 1) )
+ )
+ {
+ // This node it now totally detached from the directory tree,
+ // so delete it.
+
+ if( S_ISDIR(node->mode) )
+ {
+ del_direntry( node, ".", 1 );
+ del_direntry( node, "..", 2 );
+ }
+
+ err = freebuffer_node( node );
+
+ if( err == ENOERR )
+ free_node( node );
+ }
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// dec_nlink()
+// Decrement a node's link count. Since this has to do all the same
+// work as dec_refcnt() we implement this using that function by
+// essentially transferring the count to refcnt and then decrement
+// that.
+
+static int dec_nlink( ramfs_node *node )
+{
+ node->refcnt++;
+
+ node->nlink--;
+
+ return dec_refcnt( node );
+}
+
+//==========================================================================
+// Directory operations
+
+// -------------------------------------------------------------------------
+// add_direntry()
+// Add an entry to a directory. This is added as a chain of entry
+// fragments until the name is exhausted.
+
+static int add_direntry( ramfs_node *dir, // dir to add to
+ const char *name, // name to add
+ int namelen, // length of name
+ ramfs_node *node // node to reference
+ )
+{
+ off_t pos = 0;
+ ramfs_dirent *d = NULL, *dp = NULL;
+ cyg_bool isfirst = true;
+
+ // Loop inserting fragments of the name into the directory until we
+ // have found a home for them all.
+
+ while( namelen > 0 )
+ {
+ int fraglen = namelen;
+
+ if( fraglen > sizeof(d->name) )
+ fraglen = sizeof(d->name);
+
+ // Find a free fragment
+ for(;;)
+ {
+ cyg_uint8 *buf;
+ size_t size;
+ int err = findbuffer_node( dir, pos, &buf, &size, true );
+ if( err != ENOERR ) return err;
+
+ d = (ramfs_dirent *)buf;
+
+ if( size < sizeof(ramfs_dirent) || d->inuse )
+ {
+ pos += sizeof(ramfs_dirent);
+ continue;
+ }
+
+ break;
+ }
+
+ // d now points to a free dirent structure
+
+ d->node = node;
+ d->inuse = 1;
+ d->first = isfirst;
+ d->namelen = namelen;
+ d->fraglen = fraglen;
+ if( dp ) dp->next = pos;
+
+ memcpy( d->name, name, fraglen );
+
+ name += fraglen;
+ namelen -= fraglen;
+ pos += sizeof(ramfs_dirent);
+ dp = d;
+ isfirst = false;
+
+ }
+
+
+ d->last = 1; // Mark last fragment
+
+ // Update directory times
+ dir->mtime =
+ dir->ctime = cyg_timestamp();
+
+ // Extend dir size if necessary
+ if( pos > dir->size )
+ dir->size = pos;
+
+ // Count the new link
+ node->nlink++;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// find_direntry()
+// Find a directory entry for the name and return a pointer to the first
+// entry fragment.
+
+static ramfs_dirent *find_direntry( ramfs_node *dir, const char *name, int namelen )
+{
+ ramfs_dirent *first = NULL;
+ off_t pos = 0;
+ int err;
+
+ // Loop over all the entries until a match is found or we run out
+ // of data.
+ while( pos < dir->size )
+ {
+ const char *frag = name;
+ ramfs_dirent *d;
+ cyg_uint8 *buf;
+ size_t size;
+
+ // look for a first name fragment
+ for(;;)
+ {
+ err = findbuffer_node( dir, pos, &buf, &size, false );
+ if( err != ENOERR || size == 0)
+ return NULL;
+
+ d = (ramfs_dirent *)buf;
+
+ if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
+ {
+ pos += sizeof(ramfs_dirent);
+ continue;
+ }
+
+ break;
+ }
+
+ // Here we have got a first fragment of a name, check it
+ // against the name we are looking for. First check that they
+ // are the same length.
+
+ if( d->namelen == namelen )
+ {
+ // We have a potential candidate here...
+
+ first = d; // Save it for later
+
+ // Now check that all the name fragments match
+ for(;;)
+ {
+ int fraglen = namelen-(frag-name);
+
+ if( fraglen > d->fraglen )
+ fraglen = d->fraglen;
+
+ // compare strings, if different, look for another
+ if( memcmp( frag, d->name, fraglen ) != 0 )
+ break;
+
+ frag += fraglen;
+
+ // If we are at the last fragment, then the whole name string
+ // has matched and we have a successful search.
+
+ if( d->last )
+ return first;
+
+ // Otherwise move on to next entry in chain
+ err = findbuffer_node( dir, d->next, &buf, &size, false );
+ if( err != ENOERR )
+ return NULL;
+
+ d = (ramfs_dirent *)buf;
+
+ }
+ }
+
+ pos += sizeof(ramfs_dirent);
+ }
+
+ return NULL;
+}
+
+// -------------------------------------------------------------------------
+// del_direntry()
+// Delete a named directory entry. Find it and then follow the chain
+// deleting the fragments as we go.
+
+static int del_direntry( ramfs_node *dir, const char *name, int namelen )
+{
+ ramfs_dirent *d = find_direntry( dir, name, namelen );
+
+ if( d == NULL )
+ return ENOENT;
+
+ for(;;)
+ {
+ int err;
+ cyg_uint8 *buf;
+ size_t size;
+
+ d->inuse = 0;
+ if( d->last ) break;
+
+ err = findbuffer_node( dir, d->next, &buf, &size, false );
+ if( err != ENOERR )
+ return ENOENT;
+
+ d = (ramfs_dirent *)buf;
+ }
+
+ dec_nlink( d->node );
+
+ return ENOERR;
+}
+
+//==========================================================================
+// Directory search
+
+// -------------------------------------------------------------------------
+// init_dirsearch()
+// Initialize a dirsearch object to start a search
+
+static void init_dirsearch( ramfs_dirsearch *ds,
+ ramfs_node *dir,
+ const char *name)
+{
+ ds->dir = dir;
+ ds->path = name;
+ ds->node = dir;
+ ds->name = name;
+ ds->namelen = 0;
+ ds->last = false;
+}
+
+// -------------------------------------------------------------------------
+// find_entry()
+// Search a single directory for the next name in a path and update the
+// dirsearch object appropriately.
+
+static int find_entry( ramfs_dirsearch *ds )
+{
+ ramfs_node *dir = ds->dir;
+ const char *name = ds->path;
+ const char *n = name;
+ char namelen = 0;
+ ramfs_dirent *d;
+
+ // check that we really have a directory
+ if( !S_ISDIR(dir->mode) )
+ return ENOTDIR;
+
+ // Isolate the next element of the path name.
+ while( *n != '\0' && *n != '/' )
+ n++, namelen++;
+
+ // Check if this is the last path element.
+ while( *n == '/') n++;
+ if( *n == '\0' )
+ ds->last = true;
+
+ // update name in dirsearch object
+ ds->name = name;
+ ds->namelen = namelen;
+
+ // Here we have the name and its length set up.
+ // Search the directory for a matching entry
+
+ d = find_direntry( dir, name, namelen );
+
+ if( d == NULL )
+ return ENOENT;
+
+ // pass back the node we have found
+ ds->node = d->node;
+
+ return ENOERR;
+
+}
+
+// -------------------------------------------------------------------------
+// ramfs_find()
+// Main interface to directory search code. This is used in all file
+// level operations to locate the object named by the pathname.
+
+static int ramfs_find( ramfs_dirsearch *d )
+{
+ int err;
+
+ // Short circuit empty paths
+ if( *(d->path) == '\0' )
+ return ENOERR;
+
+ // iterate down directory tree until we find the object
+ // we want.
+ for(;;)
+ {
+ err = find_entry( d );
+
+ if( err != ENOERR )
+ return err;
+
+ if( d->last )
+ return ENOERR;
+
+ // Update dirsearch object to search next directory.
+ d->dir = d->node;
+ d->path += d->namelen;
+ while( *(d->path) == '/' ) d->path++; // skip dirname separators
+ }
+}
+
+//==========================================================================
+// Pathconf support
+// This function provides support for pathconf() and fpathconf().
+
+static int ramfs_pathconf( ramfs_node *node, struct cyg_pathconf_info *info )
+{
+ int err = ENOERR;
+
+ switch( info->name )
+ {
+ case _PC_LINK_MAX:
+ info->value = LINK_MAX;
+ break;
+
+ case _PC_MAX_CANON:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_MAX_INPUT:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_NAME_MAX:
+ info->value = NAME_MAX;
+ break;
+
+ case _PC_PATH_MAX:
+ info->value = PATH_MAX;
+ break;
+
+ case _PC_PIPE_BUF:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+
+ case _PC_ASYNC_IO:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_CHOWN_RESTRICTED:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_NO_TRUNC:
+ info->value = 0;
+ break;
+
+ case _PC_PRIO_IO:
+ info->value = 0;
+ break;
+
+ case _PC_SYNC_IO:
+ info->value = 0;
+ break;
+
+ case _PC_VDISABLE:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ default:
+ err = EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+//==========================================================================
+// Filesystem operations
+
+// -------------------------------------------------------------------------
+// ramfs_mount()
+// Process a mount request. This mainly creates a root for the
+// filesystem.
+
+static int ramfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
+{
+ ramfs_node *root;
+ int err;
+
+ // Allocate a node to be the root of this filesystem and initialize it.
+
+ root = alloc_node(__stat_mode_DIR);
+
+ if( root == NULL )
+ return ENOSPC;
+
+ // Add . and .. entries back to self.
+
+ err = add_direntry( root, ".", 1, root );
+ if( err == ENOERR )
+ err = add_direntry( root, "..", 2, root );
+
+ if( err != ENOERR )
+ {
+ free_node( root );
+ return err;
+ }
+
+ mte->root = (cyg_dir)root;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_umount()
+// Unmount the filesystem. This will currently only succeed if the
+// filesystem is empty.
+
+static int ramfs_umount ( cyg_mtab_entry *mte )
+{
+ ramfs_node *root = (ramfs_node *)mte->root;
+
+ // Check for open/inuse root
+ if( root->refcnt != 0 )
+ return EBUSY;
+
+ // Check that root directory is clear of extra links.
+ if( root->nlink != 2 )
+ return EBUSY;
+
+ // Just return it to free pool
+ free_node( root );
+
+ // Clear root pointer
+ mte->root = CYG_DIR_NULL;
+
+ // That's all folks.
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_open()
+// Open a file for reading or writing.
+
+static int ramfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int mode, cyg_file *file )
+{
+
+ ramfs_dirsearch ds;
+ ramfs_node *node = NULL;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err == ENOENT )
+ {
+ if( ds.last && (mode & O_CREAT) )
+ {
+ // No node there, if the O_CREAT bit is set then we must
+ // create a new one. The dir and name fields of the dirsearch
+ // object will have been updated so we know where to put it.
+
+ node = alloc_node( __stat_mode_REG );
+
+ if( node == NULL )
+ return ENOSPC;
+
+ err = add_direntry( ds.dir, ds.name, ds.namelen, node );
+
+ if( err != ENOERR )
+ {
+ free_node( node );
+ return err;
+ }
+
+ err = ENOERR;
+ }
+ }
+ else if( err == ENOERR )
+ {
+ // The node exists. If the O_CREAT and O_EXCL bits are set, we
+ // must fail the open.
+
+ if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
+ err = EEXIST;
+ else node = ds.node;
+ }
+
+ if( err == ENOERR && (mode & O_TRUNC ) )
+ {
+ // If the O_TRUNC bit is set we must clean out the file data.
+
+ err = freebuffer_node( node );
+ node->size = 0;
+
+ // Update file times
+ node->ctime =
+ node->mtime = cyg_timestamp();
+ }
+
+ if( err != ENOERR ) return err;
+
+ // Check that we actually have a file here
+ if( S_ISDIR(node->mode) ) return EISDIR;
+
+ node->refcnt++; // Count successful open
+
+ // Initialize the file object
+
+ file->f_flag |= mode & CYG_FILE_MODE_MASK;
+ file->f_type = CYG_FILE_TYPE_FILE;
+ file->f_ops = &ramfs_fileops;
+ file->f_offset = (mode&O_APPEND) ? node->size : 0;
+ file->f_data = (CYG_ADDRWORD)node;
+ file->f_xops = 0;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_unlink()
+// Remove a file link from its directory.
+
+static int ramfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
+{
+ ramfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // Cannot unlink directories, use rmdir() instead
+ if( S_ISDIR(ds.node->mode) )
+ return EPERM;
+
+ // Delete it from its directory
+ err = del_direntry( ds.dir, ds.name, ds.namelen );
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_mkdir()
+// Create a new directory.
+
+static int ramfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
+{
+ ramfs_dirsearch ds;
+ ramfs_node *node = NULL;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err == ENOENT )
+ {
+ if( ds.last )
+ {
+ // The entry does not exist, and it is the last element in
+ // the pathname, so we can create it here.
+ int doterr, dotdoterr, direrr;
+
+ node = alloc_node( __stat_mode_DIR );
+
+ if( node == NULL )
+ return ENOSPC;
+
+ // Add "." and ".." entries.
+ doterr = add_direntry( node, ".", 1, node );
+ dotdoterr = add_direntry( node, "..", 2, ds.dir );
+
+ // And add to parent directory.
+ direrr = add_direntry( ds.dir, ds.name, ds.namelen, node );
+
+ // check for any errors in that...
+ if( doterr+dotdoterr+direrr != ENOERR )
+ {
+ // For each of the add_direntry() calls that succeeded,
+ // we must now undo it.
+
+ if( doterr == ENOERR )
+ del_direntry( node, ".", 1 );
+ else err = doterr;
+
+ if( dotdoterr == ENOERR )
+ del_direntry( node, "..", 2 );
+ else err = dotdoterr;
+
+ if( direrr == ENOERR )
+ del_direntry( ds.dir, ds.name, ds.namelen );
+ else err = direrr;
+
+ // Free the data and the node itself.
+ freebuffer_node( node );
+ free_node( node );
+ }
+ else err = ENOERR;
+ }
+ // If this was not the last element, then and intermediate
+ // directory does not exist.
+ }
+ else
+ {
+ // If there we no error, something already exists with that
+ // name, so we cannot create another one.
+
+ if( err == ENOERR )
+ err = EEXIST;
+ }
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_rmdir()
+// Remove a directory.
+
+static int ramfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name )
+{
+ ramfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // Check that this is actually a directory.
+ if( !S_ISDIR(ds.node->mode) )
+ return EPERM;
+
+ // Delete the entry. This will adjust the link values
+ // accordingly and if the directory is now unreferenced,
+ // will cause it to be deleted.
+
+ err = del_direntry( ds.dir, ds.name, ds.namelen );
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_rename()
+// Rename a file/dir.
+
+static int ramfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
+ cyg_dir dir2, const char *name2 )
+{
+ ramfs_dirsearch ds1, ds2;
+ int err;
+
+ init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
+
+ err = ramfs_find( &ds1 );
+
+ if( err != ENOERR ) return err;
+
+ init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
+
+ err = ramfs_find( &ds2 );
+
+ // Allow through renames to non-existent objects.
+ if( ds2.last && err == ENOENT )
+ ds2.node = NULL, err = ENOERR;
+
+ if( err != ENOERR ) return err;
+
+ // Null rename, just return
+ if( ds1.node == ds2.node )
+ return ENOERR;
+
+ // First deal with any entry that is at the destination
+ if( ds2.node )
+ {
+ // Check that we are renaming like-for-like
+
+ if( !S_ISDIR(ds1.node->mode) && S_ISDIR(ds2.node->mode) )
+ return EISDIR;
+
+ if( S_ISDIR(ds1.node->mode) && !S_ISDIR(ds2.node->mode) )
+ return ENOTDIR;
+
+ // Now delete the destination directory entry
+
+ err = del_direntry( ds2.dir, ds2.name, ds2.namelen );
+
+ if( err != ENOERR ) return err;
+
+ }
+
+ // Now we know that there is no clashing node at the destination,
+ // make a new direntry at the destination and delete the old entry
+ // at the source.
+
+ err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
+
+ if( err == ENOERR )
+ err = del_direntry( ds1.dir, ds1.name, ds1.namelen );
+
+ // Update directory times
+ if( err == ENOERR )
+ ds1.dir->ctime =
+ ds1.dir->mtime =
+ ds2.dir->ctime =
+ ds2.dir->mtime = cyg_timestamp();
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_link()
+// Make a new directory entry for a file.
+
+static int ramfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
+ cyg_dir dir2, const char *name2, int type )
+{
+ ramfs_dirsearch ds1, ds2;
+ int err;
+
+ // Only do hard links for now in this filesystem
+ if( type != CYG_FSLINK_HARD )
+ return EINVAL;
+
+ init_dirsearch( &ds1, (ramfs_node *)dir1, name1 );
+
+ err = ramfs_find( &ds1 );
+
+ if( err != ENOERR ) return err;
+
+ init_dirsearch( &ds2, (ramfs_node *)dir2, name2 );
+
+ err = ramfs_find( &ds2 );
+
+ // Don't allow links to existing objects
+ if( err == ENOERR ) return EEXIST;
+
+ // Allow through links to non-existing terminal objects
+ if( ds2.last && err == ENOENT )
+ ds2.node = NULL, err = ENOERR;
+
+ if( err != ENOERR ) return err;
+
+ // Now we know that there is no existing node at the destination,
+ // make a new direntry at the destination.
+
+ err = add_direntry( ds2.dir, ds2.name, ds2.namelen, ds1.node );
+
+ if( err == ENOERR )
+ ds1.node->ctime =
+ ds2.dir->ctime =
+ ds2.dir->mtime = cyg_timestamp();
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_opendir()
+// Open a directory for reading.
+
+static int ramfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_file *file )
+{
+ ramfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // check it is really a directory.
+ if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
+
+ ds.node->refcnt++; // Count successful open
+
+ // Initialize the file object, setting the f_ops field to a
+ // special set of file ops.
+
+ file->f_type = CYG_FILE_TYPE_FILE;
+ file->f_ops = &ramfs_dirops;
+ file->f_offset = 0;
+ file->f_data = (CYG_ADDRWORD)ds.node;
+ file->f_xops = 0;
+
+ return ENOERR;
+
+}
+
+// -------------------------------------------------------------------------
+// ramfs_chdir()
+// Change directory support.
+
+static int ramfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_dir *dir_out )
+{
+ if( dir_out != NULL )
+ {
+ // This is a request to get a new directory pointer in
+ // *dir_out.
+
+ ramfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // check it is a directory
+ if( !S_ISDIR(ds.node->mode) )
+ return ENOTDIR;
+
+ // Increment ref count to keep this directory in existent
+ // while it is the current cdir.
+ ds.node->refcnt++;
+
+ // Pass it out
+ *dir_out = (cyg_dir)ds.node;
+ }
+ else
+ {
+ // If no output dir is required, this means that the mte and
+ // dir arguments are the current cdir setting and we should
+ // forget this fact.
+
+ ramfs_node *node = (ramfs_node *)dir;
+
+ // Just decrement directory reference count.
+ dec_refcnt( node );
+ }
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_stat()
+// Get struct stat info for named object.
+
+static int ramfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ struct stat *buf)
+{
+ ramfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // Fill in the status
+ buf->st_mode = ds.node->mode;
+ buf->st_ino = (ino_t)ds.node;
+ buf->st_dev = 0;
+ buf->st_nlink = ds.node->nlink;
+ buf->st_uid = 0;
+ buf->st_gid = 0;
+ buf->st_size = ds.node->size;
+ buf->st_atime = ds.node->atime;
+ buf->st_mtime = ds.node->mtime;
+ buf->st_ctime = ds.node->ctime;
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_getinfo()
+// Getinfo. Currently only support pathconf().
+
+static int ramfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len )
+{
+ ramfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (ramfs_node *)dir, name );
+
+ err = ramfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ switch( key )
+ {
+ case FS_INFO_CONF:
+ err = ramfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_setinfo()
+// Setinfo. Nothing to support here at present.
+
+static int ramfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len )
+{
+ // No setinfo keys supported at present
+
+ return EINVAL;
+}
+
+
+//==========================================================================
+// File operations
+
+// -------------------------------------------------------------------------
+// ramfs_fo_read()
+// Read data from the file.
+
+static int ramfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+{
+ ramfs_node *node = (ramfs_node *)fp->f_data;
+ int i;
+ off_t pos = fp->f_offset;
+ ssize_t resid = uio->uio_resid;
+
+ // Loop over the io vectors until there are none left
+ for( i = 0; i < uio->uio_iovcnt; i++ )
+ {
+ cyg_iovec *iov = &uio->uio_iov[i];
+ char *buf = (char *)iov->iov_base;
+ off_t len = iov->iov_len;
+
+ // Loop over each vector filling it with data from the file.
+ while( len > 0 && pos < node->size )
+ {
+ cyg_uint8 *fbuf;
+ size_t bsize;
+ off_t l = len;
+ int err;
+
+ // Get a pointer to the data at offset _pos_.
+ err = findbuffer_node( node, pos, &fbuf, &bsize, false );
+
+ if( err != ENOERR )
+ return err;
+
+ // adjust size to end of file if necessary
+ if( l > node->size-pos )
+ l = node->size-pos;
+
+ // adjust size to the amount of contiguous data we can see
+ // at present.
+ if( l > bsize )
+ l = bsize;
+
+ // copy data out
+ memcpy( buf, fbuf, l );
+
+ // Update working vars
+ len -= l;
+ buf += l;
+ pos += l;
+ resid -= l;
+ }
+ }
+
+ // We successfully read some data, update the node's access time
+ // and update the file offset and transfer residue.
+
+ node->atime = cyg_timestamp();
+
+ uio->uio_resid = resid;
+ fp->f_offset = pos;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_write()
+// Write data to file.
+
+static int ramfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+{
+ ramfs_node *node = (ramfs_node *)fp->f_data;
+ off_t pos = fp->f_offset;
+ ssize_t resid = uio->uio_resid;
+ int err = ENOERR;
+ int i;
+
+ // If the APPEND mode bit was supplied, force all writes to
+ // the end of the file.
+ if( fp->f_flag & CYG_FAPPEND )
+ pos = fp->f_offset = node->size;
+
+ // Check that pos is within current file size, or at the very end.
+ if( pos < 0 || pos > node->size )
+ return EINVAL;
+
+ // Now loop over the iovecs until they are all done, or
+ // we get an error.
+ for( i = 0; i < uio->uio_iovcnt; i++ )
+ {
+ cyg_iovec *iov = &uio->uio_iov[i];
+ char *buf = (char *)iov->iov_base;
+ off_t len = iov->iov_len;
+
+ // loop over the vector writing it to the file until it has
+ // all been done.
+ while( len > 0 )
+ {
+ cyg_uint8 *fbuf;
+ size_t bsize;
+ off_t l = len;
+
+ err = findbuffer_node( node, pos, &fbuf, &bsize, true );
+
+ // Stop writing if there is no more space in the file and
+ // indicate end of data.
+ if( err == ENOSPC )
+ break;
+
+ if( err != ENOERR )
+ return err;
+
+ // adjust size to this block
+ if( l > bsize )
+ l = bsize;
+
+ // copy data in
+ memcpy( fbuf, buf, l );
+
+ // Update working vars
+ len -= l;
+ buf += l;
+ pos += l;
+ resid -= l;
+ }
+ }
+
+ // We wrote some data successfully, update the modified and access
+ // times of the node, increase its size appropriately, and update
+ // the file offset and transfer residue.
+ node->mtime =
+ node->ctime = cyg_timestamp();
+ if( pos > node->size )
+ node->size = pos;
+
+ uio->uio_resid = resid;
+ fp->f_offset = pos;
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_lseek()
+// Seek to a new file position.
+
+static int ramfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
+{
+ ramfs_node *node = (ramfs_node *)fp->f_data;
+ off_t pos = *apos;
+
+ switch( whence )
+ {
+ case SEEK_SET:
+ // Pos is already where we want to be.
+ break;
+
+ case SEEK_CUR:
+ // Add pos to current offset.
+ pos += fp->f_offset;
+ break;
+
+ case SEEK_END:
+ // Add pos to file size.
+ pos += node->size;
+ break;
+
+ default:
+ return EINVAL;
+ }
+
+ // Check that pos is still within current file size, or at the
+ // very end.
+ if( pos < 0 || pos > node->size )
+ return EINVAL;
+
+ // All OK, set fp offset and return new position.
+ *apos = fp->f_offset = pos;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_ioctl()
+// Handle ioctls. Currently none are defined.
+
+static int ramfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
+ CYG_ADDRWORD data)
+{
+ // No Ioctls currenly defined.
+
+ return EINVAL;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_fsync().
+// Force the file out to data storage.
+
+static int ramfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode )
+{
+ // Data is always permanently where it belongs, nothing to do
+ // here.
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_close()
+// Close a file. We just decrement the refcnt and let it go away if
+// that is all that is keeping it here.
+
+static int ramfs_fo_close (struct CYG_FILE_TAG *fp)
+{
+ ramfs_node *node = (ramfs_node *)fp->f_data;
+
+ dec_refcnt( node );
+
+ fp->f_data = 0; // zero data pointer
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+//ramfs_fo_fstat()
+// Get file status.
+
+static int ramfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
+{
+ ramfs_node *node = (ramfs_node *)fp->f_data;
+
+ // Fill in the status
+ buf->st_mode = node->mode;
+ buf->st_ino = (ino_t)node;
+ buf->st_dev = 0;
+ buf->st_nlink = node->nlink;
+ buf->st_uid = 0;
+ buf->st_gid = 0;
+ buf->st_size = node->size;
+ buf->st_atime = node->atime;
+ buf->st_mtime = node->mtime;
+ buf->st_ctime = node->ctime;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_getinfo()
+// Get info. Currently only supports fpathconf().
+
+static int ramfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
+{
+ ramfs_node *node = (ramfs_node *)fp->f_data;
+ int err;
+
+ switch( key )
+ {
+ case FS_INFO_CONF:
+ err = ramfs_pathconf( node, (struct cyg_pathconf_info *)buf );
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_setinfo()
+// Set info. Nothing supported here.
+
+static int ramfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
+{
+ // No setinfo key supported at present
+
+ return ENOERR;
+}
+
+
+//==========================================================================
+// Directory operations
+
+// -------------------------------------------------------------------------
+// ramfs_fo_dirread()
+// Read a single directory entry from a file.
+
+static int ramfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+{
+ ramfs_node *dir = (ramfs_node *)fp->f_data;
+ off_t pos = fp->f_offset;
+ int err = ENOERR;
+ struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
+ char *nbuf = ent->d_name;
+ int nlen = sizeof(ent->d_name)-1;
+ off_t len = uio->uio_iov[0].iov_len;
+ ramfs_dirent *d = NULL;
+ cyg_uint8 *buf;
+ size_t size;
+
+ if( len < sizeof(struct dirent) )
+ return EINVAL;
+
+ // look for a first name fragment
+
+ while( pos < dir->size )
+ {
+ err = findbuffer_node( dir, pos, &buf, &size, false );
+ if( err != ENOERR || size == 0)
+ break;
+
+ d = (ramfs_dirent *)buf;
+
+ if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
+ {
+ pos += sizeof(ramfs_dirent);
+ continue;
+ }
+
+ break;
+ }
+
+ // Check we have not exceeded the size of the directory.
+ if( pos == dir->size )
+ return err;
+
+ // Here we have the first fragment of a directory entry.
+
+ for(;;)
+ {
+ int fraglen = d->fraglen;
+
+ // adjust to allow for remaining space in dirent struct
+ if( fraglen > nlen )
+ fraglen = nlen;
+
+ memcpy( nbuf, d->name, fraglen);
+ nbuf += fraglen;
+ nlen -= fraglen;
+
+ // if we hit the last entry, we have a successful transfer
+ if( d->last || nlen == 0)
+ break;
+
+ // Otherwise move on to next entry in chain
+ err = findbuffer_node( dir, d->next, &buf, &size, false );
+ if( err != ENOERR )
+ return err;
+
+ d = (ramfs_dirent *)buf;
+ }
+
+ // A successful read. Terminate the entry name with a NUL, set the
+ // residue and set the file offset to restart at the next
+ // directory entry.
+
+ *nbuf = '\0';
+ uio->uio_resid -= sizeof(struct dirent);
+ fp->f_offset = pos+sizeof(ramfs_dirent);
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// ramfs_fo_dirlseek()
+// Seek directory to start.
+
+static int ramfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
+{
+ // Only allow SEEK_SET to zero
+
+ if( whence != SEEK_SET || *pos != 0)
+ return EINVAL;
+
+ *pos = fp->f_offset = 0;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// EOF ramfs.c
diff --git a/cesar/ecos/packages/fs/ram/current/tests/ramfs1.c b/cesar/ecos/packages/fs/ram/current/tests/ramfs1.c
new file mode 100644
index 0000000000..42fdbc1cd2
--- /dev/null
+++ b/cesar/ecos/packages/fs/ram/current/tests/ramfs1.c
@@ -0,0 +1,654 @@
+//==========================================================================
+//
+// ramfs1.c
+//
+// Test fileio system
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg
+// Contributors: nickg
+// Date: 2000-05-25
+// Purpose: Test fileio system
+// Description: This test uses the testfs to check out the initialization
+// and basic operation of the fileio system
+//
+//
+//
+//
+//
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h> // HAL polled output
+
+//==========================================================================
+
+#if 0
+MTAB_ENTRY( ramfs_mte1,
+ "/",
+ "ramfs",
+ "",
+ 0);
+#endif
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res ) \
+diag_printf("<FAIL>: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):"");
+
+//==========================================================================
+
+#define IOSIZE 100
+
+#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1"
+#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2"
+
+
+//==========================================================================
+
+#ifndef CYGPKG_LIBC_STRING
+
+char *strcat( char *s1, const char *s2 )
+{
+ char *s = s1;
+ while( *s1 ) s1++;
+ while( (*s1++ = *s2++) != 0);
+ return s;
+}
+
+#endif
+
+//==========================================================================
+
+static void listdir( char *name, int statp, int numexpected, int *numgot )
+{
+ int err;
+ DIR *dirp;
+ int num=0;
+
+ diag_printf("<INFO>: reading directory %s\n",name);
+
+ dirp = opendir( name );
+ if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+ for(;;)
+ {
+ struct dirent *entry = readdir( dirp );
+
+ if( entry == NULL )
+ break;
+ num++;
+ diag_printf("<INFO>: entry %14s",entry->d_name);
+ if( statp )
+ {
+ char fullname[PATH_MAX];
+ struct stat sbuf;
+
+ if( name[0] )
+ {
+ strcpy(fullname, name );
+ if( !(name[0] == '/' && name[1] == 0 ) )
+ strcat(fullname, "/" );
+ }
+ else fullname[0] = 0;
+
+ strcat(fullname, entry->d_name );
+
+ err = stat( fullname, &sbuf );
+ if( err < 0 )
+ {
+ if( errno == ENOSYS )
+ diag_printf(" <no status available>");
+ else SHOW_RESULT( stat, err );
+ }
+ else
+ {
+ diag_printf(" [mode %08x ino %08x nlink %d size %ld]",
+ sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,
+ (unsigned long) sbuf.st_size);
+ }
+ }
+
+ diag_printf("\n");
+ }
+
+ err = closedir( dirp );
+ if( err < 0 ) SHOW_RESULT( stat, err );
+ if (numexpected >= 0 && num != numexpected)
+ CYG_TEST_FAIL("Wrong number of dir entries\n");
+ if ( numgot != NULL )
+ *numgot = num;
+}
+
+//==========================================================================
+
+static void createfile( char *name, size_t size )
+{
+ char buf[IOSIZE];
+ int fd;
+ ssize_t wrote;
+ int i;
+ int err;
+
+ diag_printf("<INFO>: create file %s size %d\n",name,size);
+
+ err = access( name, F_OK );
+ if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+ for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+
+ fd = open( name, O_WRONLY|O_CREAT );
+ if( fd < 0 ) SHOW_RESULT( open, fd );
+
+ while( size > 0 )
+ {
+ ssize_t len = size;
+ if ( len > IOSIZE ) len = IOSIZE;
+
+ wrote = write( fd, buf, len );
+ if( wrote != len ) SHOW_RESULT( write, wrote );
+
+ size -= wrote;
+ }
+
+ err = close( fd );
+ if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+#if 0
+static void maxfile( char *name )
+{
+ char buf[IOSIZE];
+ int fd;
+ ssize_t wrote;
+ int i;
+ int err;
+ size_t size = 0;
+
+ diag_printf("<INFO>: create maximal file %s\n",name);
+
+ err = access( name, F_OK );
+ if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+ for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256;
+
+ fd = open( name, O_WRONLY|O_CREAT );
+ if( fd < 0 ) SHOW_RESULT( open, fd );
+
+ do
+ {
+ wrote = write( fd, buf, IOSIZE );
+ if( wrote < 0 ) SHOW_RESULT( write, wrote );
+
+ size += wrote;
+
+ } while( wrote == IOSIZE );
+
+ diag_printf("<INFO>: file size == %d\n",size);
+
+ err = close( fd );
+ if( err < 0 ) SHOW_RESULT( close, err );
+}
+#endif
+
+//==========================================================================
+
+static void checkfile( char *name )
+{
+ char buf[IOSIZE];
+ int fd;
+ ssize_t done;
+ int i;
+ int err;
+ off_t pos = 0;
+
+ diag_printf("<INFO>: check file %s\n",name);
+
+ err = access( name, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ fd = open( name, O_RDONLY );
+ if( fd < 0 ) SHOW_RESULT( open, fd );
+
+ for(;;)
+ {
+ done = read( fd, buf, IOSIZE );
+ if( done < 0 ) SHOW_RESULT( read, done );
+
+ if( done == 0 ) break;
+
+ for( i = 0; i < done; i++ )
+ if( buf[i] != i%256 )
+ {
+ diag_printf("buf[%ld+%d](%02x) != %02x\n",
+ (unsigned long)pos,i,buf[i],i%256);
+ CYG_TEST_FAIL("Data read not equal to data written\n");
+ }
+
+ pos += done;
+ }
+
+ err = close( fd );
+ if( err < 0 ) SHOW_RESULT( close, err );
+}
+
+//==========================================================================
+
+static void copyfile( char *name2, char *name1 )
+{
+
+ int err;
+ char buf[IOSIZE];
+ int fd1, fd2;
+ ssize_t done, wrote;
+
+ diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
+
+ err = access( name1, F_OK );
+ if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+ err = access( name2, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ fd1 = open( name1, O_WRONLY|O_CREAT );
+ if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+ fd2 = open( name2, O_RDONLY );
+ if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+
+ for(;;)
+ {
+ done = read( fd2, buf, IOSIZE );
+ if( done < 0 ) SHOW_RESULT( read, done );
+
+ if( done == 0 ) break;
+
+ wrote = write( fd1, buf, done );
+ if( wrote != done ) SHOW_RESULT( write, wrote );
+
+ if( wrote != done ) break;
+ }
+
+ err = close( fd1 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+ err = close( fd2 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+}
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1 )
+{
+ int err;
+ char buf1[IOSIZE];
+ char buf2[IOSIZE];
+ int fd1, fd2;
+ ssize_t done1, done2;
+ int i;
+
+ diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
+
+ err = access( name1, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ err = access( name1, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ fd1 = open( name1, O_RDONLY );
+ if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+ fd2 = open( name2, O_RDONLY );
+ if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+
+ for(;;)
+ {
+ done1 = read( fd1, buf1, IOSIZE );
+ if( done1 < 0 ) SHOW_RESULT( read, done1 );
+
+ done2 = read( fd2, buf2, IOSIZE );
+ if( done2 < 0 ) SHOW_RESULT( read, done2 );
+
+ if( done1 != done2 )
+ diag_printf("Files different sizes\n");
+
+ if( done1 == 0 ) break;
+
+ for( i = 0; i < done1; i++ )
+ if( buf1[i] != buf2[i] )
+ {
+ diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+ CYG_TEST_FAIL("Data in files not equal\n");
+ }
+ }
+
+ err = close( fd1 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+ err = close( fd2 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+}
+
+//==========================================================================
+
+void checkcwd( const char *cwd )
+{
+ static char cwdbuf[PATH_MAX];
+ char *ret;
+
+ ret = getcwd( cwdbuf, sizeof(cwdbuf));
+ if( ret == NULL ) SHOW_RESULT( getcwd, ret );
+
+ if( strcmp( cwdbuf, cwd ) != 0 )
+ {
+ diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd );
+ CYG_TEST_FAIL( "Current directory mismatch");
+ }
+}
+
+//==========================================================================
+// main
+
+int main( int argc, char **argv )
+{
+ int err;
+ int existingdirents=-1;
+
+ CYG_TEST_INIT();
+
+ // --------------------------------------------------------------
+
+ err = mount( "", "/", "ramfs" );
+ if( err < 0 ) SHOW_RESULT( mount, err );
+
+ err = chdir( "/" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ checkcwd( "/" );
+
+ listdir( "/", true, -1, &existingdirents );
+ if ( existingdirents < 2 )
+ CYG_TEST_FAIL("Not enough dir entries\n");
+
+ // --------------------------------------------------------------
+
+ createfile( "/foo", 202 );
+ checkfile( "foo" );
+ copyfile( "foo", "fee");
+ checkfile( "fee" );
+ comparefiles( "foo", "/fee" );
+ diag_printf("<INFO>: mkdir bar\n");
+ err = mkdir( "/bar", 0 );
+ if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+ listdir( "/" , true, existingdirents+3, NULL );
+
+ copyfile( "fee", "/bar/fum" );
+ checkfile( "bar/fum" );
+ comparefiles( "/fee", "bar/fum" );
+
+ diag_printf("<INFO>: cd bar\n");
+ err = chdir( "bar" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ checkcwd( "/bar" );
+
+ diag_printf("<INFO>: rename /foo bundy\n");
+ err = rename( "/foo", "bundy" );
+ if( err < 0 ) SHOW_RESULT( rename, err );
+
+ listdir( "/", true, existingdirents+2, NULL );
+ listdir( "" , true, 4, NULL );
+
+ checkfile( "/bar/bundy" );
+ comparefiles("/fee", "bundy" );
+
+ // --------------------------------------------------------------
+
+ createfile( LONGNAME1, 123 );
+ checkfile( LONGNAME1 );
+ copyfile( LONGNAME1, LONGNAME2 );
+
+ listdir( "", false, 6, NULL );
+
+ diag_printf("<INFO>: unlink " LONGNAME1 "\n");
+ err = unlink( LONGNAME1 );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: unlink " LONGNAME2 "\n");
+ err = unlink( LONGNAME2 );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+
+ // --------------------------------------------------------------
+
+ diag_printf("<INFO>: unlink fee\n");
+ err = unlink( "/fee" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: unlink fum\n");
+ err = unlink( "fum" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: unlink /bar/bundy\n");
+ err = unlink( "/bar/bundy" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: cd /\n");
+ err = chdir( "/" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ checkcwd( "/" );
+
+ diag_printf("<INFO>: rmdir /bar\n");
+ err = rmdir( "/bar" );
+ if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+ listdir( "/", false, existingdirents, NULL );
+
+ // --------------------------------------------------------------
+
+ diag_printf("<INFO>: mount /ram \n");
+ err = mount( "", "/ram", "ramfs" );
+ if( err < 0 ) SHOW_RESULT( mount, err );
+
+ createfile( "/ram/tinky", 456 );
+ copyfile( "/ram/tinky", "/ram/laalaa" );
+ checkfile( "/ram/tinky");
+ checkfile( "/ram/laalaa");
+ comparefiles( "/ram/tinky", "/ram/laalaa" );
+
+ diag_printf("<INFO>: cd /ram\n");
+ err = chdir( "/ram" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ checkcwd( "/ram" );
+
+ diag_printf("<INFO>: mkdir noonoo\n");
+ err = mkdir( "noonoo", 0 );
+ if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+ listdir( "." , true, existingdirents+3, NULL);
+
+ diag_printf("<INFO>: cd noonoo\n");
+ err = chdir( "noonoo" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ checkcwd( "/ram/noonoo" );
+
+ createfile( "tinky", 678 );
+ checkfile( "tinky" );
+
+ createfile( "dipsy", 3456 );
+ checkfile( "dipsy" );
+ copyfile( "dipsy", "po" );
+ checkfile( "po" );
+ comparefiles( "dipsy", "po" );
+
+ listdir( ".", true, 5, NULL );
+ listdir( "", true, 5, NULL );
+ listdir( "..", true, existingdirents+3, NULL );
+
+ // --------------------------------------------------------------
+
+ diag_printf("<INFO>: unlink tinky\n");
+ err = unlink( "tinky" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: unlink dipsy\n");
+ err = unlink( "dipsy" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: unlink po\n");
+ err = unlink( "po" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: cd ..\n");
+ err = chdir( ".." );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/ram" );
+
+ diag_printf("<INFO>: rmdir noonoo\n");
+ err = rmdir( "noonoo" );
+ if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+ // --------------------------------------------------------------
+
+ err = mkdir( "x", 0 );
+ if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+ err = mkdir( "x/y", 0 );
+ if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+ err = mkdir( "x/y/z", 0 );
+ if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+ err = mkdir( "x/y/z/w", 0 );
+ if( err < 0 ) SHOW_RESULT( mkdir, err );
+
+ diag_printf("<INFO>: cd /ram/x/y/z/w\n");
+ err = chdir( "/ram/x/y/z/w" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/ram/x/y/z/w" );
+
+ diag_printf("<INFO>: cd ..\n");
+ err = chdir( ".." );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/ram/x/y/z" );
+
+ diag_printf("<INFO>: cd .\n");
+ err = chdir( "." );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/ram/x/y/z" );
+
+ diag_printf("<INFO>: cd ../../y\n");
+ err = chdir( "../../y" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/ram/x/y" );
+
+ diag_printf("<INFO>: cd ../..\n");
+ err = chdir( "../.." );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/ram" );
+
+ diag_printf("<INFO>: rmdir x/y/z/w\n");
+ err = rmdir( "x/y/z/w" );
+ if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+ diag_printf("<INFO>: rmdir x/y/z\n");
+ err = rmdir( "x/y/z" );
+ if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+ diag_printf("<INFO>: rmdir x/y\n");
+ err = rmdir( "x/y" );
+ if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+ diag_printf("<INFO>: rmdir x\n");
+ err = rmdir( "x" );
+ if( err < 0 ) SHOW_RESULT( rmdir, err );
+
+ // --------------------------------------------------------------
+
+ diag_printf("<INFO>: unlink tinky\n");
+ err = unlink( "tinky" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: unlink laalaa\n");
+ err = unlink( "laalaa" );
+ if( err < 0 ) SHOW_RESULT( unlink, err );
+
+ diag_printf("<INFO>: cd /\n");
+ err = chdir( "/" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+ checkcwd( "/" );
+
+ diag_printf("<INFO>: umount /ram\n");
+ err = umount( "/ram" );
+ if( err < 0 ) SHOW_RESULT( umount, err );
+
+ CYG_TEST_PASS_FINISH("ramfs1");
+}
+
+// -------------------------------------------------------------------------
+// EOF ramfs1.c
diff --git a/cesar/ecos/packages/fs/ram/current/tests/ramfs2.c b/cesar/ecos/packages/fs/ram/current/tests/ramfs2.c
new file mode 100644
index 0000000000..d287b08533
--- /dev/null
+++ b/cesar/ecos/packages/fs/ram/current/tests/ramfs2.c
@@ -0,0 +1,174 @@
+//==========================================================================
+//
+// ramfs2.c
+//
+// Test fseek on a filesystem
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2004 Andrew Lunn
+// Copyright (C) 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): asl
+// Contributors: asl
+// Date: 2004-03-29
+// Purpose: Test fseek on a filesystem
+// Description: This test uses the ramfs to check out the fseek
+// operation on a filesystem.
+//
+//
+//
+//
+//
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h> // HAL polled output
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res ) \
+diag_printf("FAIL: " #_fn "() returned %ld %s\n", (long)_res, _res<0?strerror(errno):"");
+
+//==========================================================================
+
+char buf[1024];
+char buf1[1024];
+
+//==========================================================================
+// main
+
+int main( int argc, char **argv )
+{
+ int err;
+ FILE *stream;
+ long pos;
+ int i;
+
+ CYG_TEST_INIT();
+
+ // --------------------------------------------------------------
+
+ CYG_TEST_INFO("mount /");
+ err = mount( "", "/", "ramfs" );
+ if( err < 0 ) SHOW_RESULT( mount, err );
+
+ CYG_TEST_INFO("creating /fseek");
+ stream = fopen("/fseek","w+");
+ if (!stream) {
+ diag_printf("FAIL: fopen() returned NULL, %s\n", strerror(errno));
+ CYG_TEST_FINISH("done"); \
+ }
+
+ /* Write a buffer full of cyclic numbers */
+ for (i = 0; i < sizeof(buf); i++) {
+ buf[i] = i % 256;
+ }
+
+ CYG_TEST_INFO("writing test pattern");
+ err=fwrite(buf,sizeof(buf), 1, stream);
+ if ( err < 0 ) SHOW_RESULT( fwrite, err );
+
+ /* The current position should be the same size as the buffer */
+ pos = ftell(stream);
+
+ if (pos < 0) SHOW_RESULT( ftell, pos );
+ if (pos != sizeof(buf))
+ diag_printf("<FAIL>: ftell is not telling the truth.");
+
+ CYG_TEST_INFO("fseek()ing to beginning and writing");
+
+ /* Seek back to the beginning of the file */
+ err = fseek(stream, 0, SEEK_SET);
+ if ( err < 0 ) SHOW_RESULT( fwrite, err );
+
+ pos = ftell(stream);
+
+ if (pos < 0) SHOW_RESULT( ftell, pos );
+ if (pos != 0) CYG_TEST_FAIL("ftell is not telling the truth");
+
+ /* Write 4 zeros to the beginning of the file */
+ for (i = 0; i < 4; i++) {
+ buf[i] = 0;
+ }
+
+ err = fwrite(buf, 4, 1, stream);
+ if ( err < 0 ) SHOW_RESULT( fwrite, err );
+
+ /* Check the pointer is at 4 */
+ pos = ftell(stream);
+
+ if (pos < 0) SHOW_RESULT( ftell, pos );
+ if (pos != 4) CYG_TEST_FAIL("ftell is not telling the truth");
+
+ CYG_TEST_INFO("closing file");
+
+ /* Close the file, open it up again and read it back */
+ err = fclose(stream);
+ if (err != 0) SHOW_RESULT( fclose, err );
+
+ CYG_TEST_INFO("open file /fseek");
+ stream = fopen("/fseek", "r+");
+ if (!stream) {
+ diag_printf("<FAIL>: fopen() returned NULL, %s\n", strerror(errno));
+ }
+
+ err = fread(buf1,sizeof(buf1),1, stream);
+ if (err != 1) SHOW_RESULT( fread, err );
+
+ CYG_TEST_INFO("Comparing contents");
+ if (memcmp(buf, buf1, sizeof(buf1))) {
+ CYG_TEST_FAIL("File contents inconsistent");
+ }
+
+ err = fclose(stream);
+ if (err != 0) SHOW_RESULT( fclose, err );
+
+ CYG_TEST_INFO("umount /");
+ err = umount( "/" );
+ if( err < 0 ) SHOW_RESULT( umount, err );
+
+ CYG_TEST_PASS_FINISH("ramfs2");
+}
diff --git a/cesar/ecos/packages/fs/rom/current/ChangeLog b/cesar/ecos/packages/fs/rom/current/ChangeLog
new file mode 100644
index 0000000000..349ce2d935
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/ChangeLog
@@ -0,0 +1,165 @@
+2005-07-08 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * cdl/romfs.cdl: Allow mk_romfs to be build even when the tests
+ are disabled. It is generally useful and other tests programs may
+ want it.
+
+2004-12-13 John Dallaway <jld@ecoscentric.com>
+
+ * tests/fileio1.c: Rename to romfs1.c. eCos test names should be
+ unique.
+ * cdl/romfs.cdl: Build the romfs1 test.
+
+2004-10-04 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * src/romfs.c (romfs_mount): Avoid a compiler warning about punned
+ types.
+
+2004-08-08 Bart Veer <bartv@ecoscentric.com>
+
+ * cdl/romfs.cdl: generate both little-endian and big-endian image
+ files.
+
+ * tests/fileio1.c: include either a little-endian or a big-endian
+ image. Totally fail the test early on if the file system cannot be
+ mounted.
+
+2004-06-14 John Dallaway <jld@ecoscentric.com>
+
+ * cdl/romfs.cdl: Specify the test executable file name for
+ compatibility with the eCos Configuration Tool.
+
+2004-02-20 Vincent Catros <Vincent.Catros@elios-informatique.fr>
+
+ * src/fs-ecos.c :
+ (jffs2_find) Policy to skip path separator is no longer
+ "if '/' then skip" but "while '/' then skip" allowing
+ multi '/' separators (i.e : /tmp////foo).
+ (find_entry) Policy to detect end of path is no longer
+ "if '\0' then end_of_path"
+ but "while '/' skip it and then if '\0' then end_of_path"
+ allowing path terminated with any number of '/'
+ (i.e : chdir(/tmp///)).
+
+2003-12-11 Sandeep Kumar <sandeep@codito.com>
+
+ * src/romfs.c (romfs_mount) : function wrongly returns ENOENT even
+ if fste->data isn't NULL.
+
+2003-09-25 Oyvind Harboe <oyvind.harboe@zylin.com>
+
+ * src/romfs.c (romfs_mount): If a mount fails, make sure we leave
+ all state information in such a way we can try again.
+
+2003-07-10 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * support/mk_romfs.c: S_I[RWX]{USR|GRP|OTH} etc changed to match
+ the changes in sys/stat.h
+
+2003-02-24 Jonathan Larmour <jifl@eCosCentric.com>
+
+ * cdl/romfs.cdl: Fix doc link.
+
+2003-01-30 Andrew Lunn <andrew.lunn@ascom.ch>
+
+ * cdl/romfs.cdl: Implements the CYGINT_IO_FILEIO_FS interface.
+
+2003-01-29 John Dallaway <jld@ecoscentric.com>
+
+ * support/file2c.tcl: Accommodate latest Cygwin Tcl shell
+ (tclsh83.exe)
+
+2002-04-15 Bart Veer <bartv@redhat.com>
+
+ * support/file2c.tcl:
+ Do not use an alignment attribute, since it is not honoured on
+ all targets.
+
+ * src/romfs.c:
+ Remove alignment restrictions, since they are not actually needed
+ yet and alignment is hard to guarantee on all targets.
+
+2002-01-21 Jonathan Larmour <jlarmour@redhat.com>
+
+ * support/mk_romfs.c: Open image file in binary mode (for cygwin).
+ Spotted by Warren Jasper.
+
+2001-11-23 Jonathan Larmour <jlarmour@redhat.com>
+
+ * cdl/romfs.cdl (CYGTST_ROMFS_BUILD_TESTS): Try gcc and cc if $HOST_CC
+ doesn't exist or has a problem.
+
+2001-11-22 Jesper Skov <jskov@redhat.com>
+
+ * cdl/romfs.cdl: Use HOST_CC instead of 'cc'.
+
+2001-10-17 Drew Moseley <dmoseley@redhat.com>
+2001-10-17 Jonathan Larmour <jlarmour@redhat.com>
+
+ * support/mk_romfs.c: Open input files in binary mode (for cygwin).
+ * cdl/romfs.cdl: Work around cygwin path problems by copying files
+ into build tree.
+
+2001-07-20 Jonathan Larmour <jlarmour@redhat.com>
+
+ * tests/fileio1.c (main): Get this to actually pass! Remove
+ kernel dependency.
+ * cdl/fileio.cdl: Get CDL dependencies better. Don't use
+ fixed base address. Make test building an option. Build mk_romfs
+ and use it to construct a test romfs.
+ * support/mk_romfs.c: fix trivial typo
+ * tests/testromfs: Directory hierarchy added for constructing test
+ ROMFS.
+
+2001-07-13 Richard Panton (richard.panton@3glab.com)
+
+ * support/mk_romfs.c: Convert between host FS file modes and eCos
+ ones.
+
+2000-10-25 Richard Panton (richard.panton@3glab.com)
+
+ * cdl/romfs.cdl:
+ * src/romfs.c:
+ * support/mk_romfs.c:
+ * tests/fileio1.c:
+ A sample ROM filesystem implementation
+
+
+
+//===========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//===========================================================================
+
+
diff --git a/cesar/ecos/packages/fs/rom/current/cdl/romfs.cdl b/cesar/ecos/packages/fs/rom/current/cdl/romfs.cdl
new file mode 100644
index 0000000000..f65991aa27
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/cdl/romfs.cdl
@@ -0,0 +1,133 @@
+# ====================================================================
+#
+# romfs.cdl
+#
+# ROM Filesystem configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+## Copyright (C) 2004 eCosCentric Limited
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): nickg
+# Original data: nickg
+# Contributors: richard.panton@3glab.com
+# Date: 2000-08-01
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_FS_ROM {
+ display "ROM filesystem"
+ doc ref/fileio.html
+ include_dir cyg/romfs
+
+ requires CYGPKG_IO_FILEIO
+
+ requires CYGPKG_ISOINFRA
+ requires CYGINT_ISO_ERRNO
+ requires CYGINT_ISO_ERRNO_CODES
+
+ implements CYGINT_IO_FILEIO_FS
+
+ compile -library=libextras.a romfs.c
+
+ cdl_option CYGBLD_FS_ROMFS_MK_ROMFS {
+ display "Build the tool used to build filesystems"
+ flavor bool
+ default_value 1
+
+ # FIXME: host compiler/flags should be provided by config system
+ make -priority 100 {
+ <PREFIX>/bin/mk_romfs: <PACKAGE>/support/mk_romfs.c <PREFIX>/bin/file2c.tcl
+ @mkdir -p "$(dir $@)"
+ @$(HOST_CC) -g -O2 -o $@ $< || cc -g -O2 -o $@ $< || gcc -g -O2 -o $@ $<
+ @cp $(REPOSITORY)/$(PACKAGE)/support/file2c.tcl $(PREFIX)/bin
+ }
+
+ description "
+ When enabled this option will build a host tool which can be
+ used to create a rom filesystem image."
+ }
+
+ # ----------------------------------------------------------------
+ # Tests
+
+ cdl_component CYGTST_ROMFS_BUILD_TESTS {
+ display "Build ROM filesystem tests"
+ flavor bool
+ no_define
+ default_value 0
+ requires CYGINT_LIBC_STARTUP_CONTEXT
+ requires CYGINT_ISO_STDIO_FORMATTED_IO
+ requires CYGINT_ISO_STRERROR
+ requires CYGBLD_FS_ROMFS_MK_ROMFS
+ description "
+ This option enables the building of the ROM filesystem tests."
+
+ make -priority 100 {
+ <PREFIX>/include/cyg/romfs/testromfs_le.h : $(PREFIX)/bin/mk_romfs <PACKAGE>/support/file2c.tcl
+ $(PREFIX)/bin/mk_romfs $(REPOSITORY)/$(PACKAGE)/tests/testromfs testromfs_le.bin
+ @mkdir -p "$(dir $@)"
+ # work around cygwin path problems by copying to build dir
+ @cp $(REPOSITORY)/$(PACKAGE)/support/file2c.tcl .
+ sh file2c.tcl testromfs_le.bin testromfs_le.h
+ @rm -f $@ file2c.tcl
+ @cp testromfs_le.h $@
+ }
+
+ make -priority 100 {
+ <PREFIX>/include/cyg/romfs/testromfs_be.h : $(PREFIX)/bin/mk_romfs <PACKAGE>/support/file2c.tcl
+ $(PREFIX)/bin/mk_romfs -b $(REPOSITORY)/$(PACKAGE)/tests/testromfs testromfs_be.bin
+ @mkdir -p "$(dir $@)"
+ # work around cygwin path problems by copying to bin dir
+ @cp $(REPOSITORY)/$(PACKAGE)/support/file2c.tcl $(PREFIX)/bin/
+ sh $(PREFIX)/bin/file2c.tcl testromfs_be.bin testromfs_be.h
+ @cp testromfs_be.h $@
+ }
+
+ cdl_option CYGPKG_FS_ROM_TESTS {
+ display "ROM filesystem tests"
+ flavor data
+ no_define
+ calculated { "tests/romfs1" }
+ description "
+ This option specifies the set of tests for the ROM filesystem package."
+ }
+ }
+}
+
+# End of romfs.cdl
diff --git a/cesar/ecos/packages/fs/rom/current/doc/mk_romfs.txt b/cesar/ecos/packages/fs/rom/current/doc/mk_romfs.txt
new file mode 100644
index 0000000000..3671bbcb60
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/doc/mk_romfs.txt
@@ -0,0 +1,94 @@
+MK_ROMFS - Make a ROMFS image
+=============================
+
+This program creates a ROMFS image that can be read by eCos.
+
+mk_romfs - Create an eCos ROMFS disk image from the files
+ contained under a specified directory
+
+Usage: ../support/mk_romfs [options] <fs_root> <fs_file>
+ fs_root is the directory containing the files to package into the ROMFS image
+ fs_file is the name of the ROMFS image file to create
+ Options include:
+ -v / -q increase / decrease verbosity
+ -n do everything EXCEPT creating the output file
+ -b write a big-endian image (default is little endian)
+ -l collapse hard links to a single node
+
+-----------
+How to use.
+-----------
+
+For example, suppose you wish to access the following directories and files:
+ /
+ /etc passwd, group
+ /dev
+ /mnt
+ /tmp (for a RAMFS)
+ /var (for a RAMFS)
+
+1. Create the required directories and files under a suitable root, eg. under
+ ~/rom:
+ $ mkdir ~/rom
+ $ cd ~/rom
+ $ mkdir etc dev mnt tmp var
+ $ cp /etc/passwd /etc/group etc/
+ ( remembering to edit these files....;-)
+
+2. Make the romfs image in a suitable place, eg /tftpboot for direct upload to
+ the RedBoot monitor.
+ $ mk_romfs -v . /tftpboot/romfs.img
+ mk_romfs: Verbosity 2 little endian
+ Phase 1 - Build file list
+ Phase 2 - Calculate space allocation
+ Phase 2a - * Directories
+ Phase 2b - * Regular files
+ Phase 2c - * Executable files
+ Phase 3 - Construct ROMFS image file (3 kb)
+ Phase 3a - * Node table
+ Phase 3b - * Data blocks
+ /tftpboot/romfs.img completed
+
+3. Connect to your target RedBoot monitor, and load the romfs image. You will
+ need to determine a suitable place in RAM to load the image into.
+ $ telnet xxx.xxx.xxx.xxx 1000
+ Trying xxx.xxx.xxx.xxx...
+ Connected to xxx.xxx.xxx.xxx.
+ Escape character is '^]'.
+ RedBoot> load romfs.img -r -v -b 0x1000000
+ Raw file loaded 0x01000000-0x0100093e
+ RedBoot>
+
+4. Determine where to load the romfs image in the ROM. See what's there...
+ RedBoot> fis list
+ Name FLASH addr Mem addr Length Entry point
+ RedBoot 0x50000000 0x50000000 0x020000 0x00000000
+ RedBoot[backup] 0x50020000 0x50020000 0x020000 0x00000000
+ RedBoot config 0x503C0000 0x503C0000 0x020000 0x00000000
+ FIS directory 0x503E0000 0x503E0000 0x020000 0x00000000
+ RedBoot> fis free
+ 0x50040000 .. 0x503C0000
+ RedBoot>
+ We can see that a suitable place would be 0x50040000.
+ Alternatively, you can let RedBoot determine the address itself...
+
+5. Copy the image from RAM to ROM...
+ RedBoot> fis create -b 0x1000000 -l 0x940 RomFs
+ ... Erase from 0x50040000-0x50040940: .
+ ... Program from 0x01000000-0x01000940 at 0x50040000: .
+ ... Erase from 0x503e0000-0x50400000: .
+ ... Program from 0x01fd0000-0x01ff0000 at 0x503e0000: .
+ RedBoot> fis list
+ Name FLASH addr Mem addr Length Entry point
+ RedBoot 0x50000000 0x50000000 0x020000 0x00000000
+ RedBoot[backup] 0x50020000 0x50020000 0x020000 0x00000000
+ RedBoot config 0x503C0000 0x503C0000 0x020000 0x00000000
+ FIS directory 0x503E0000 0x503E0000 0x020000 0x00000000
+ RomFs 0x50040000 0x01000000 0x000940 0x00000000
+ RedBoot>
+
+6. MAKE A NOTE OF THE ADDRESS IN FLASH THAT THE IMAGE IS LOADED AT.
+ The ROMFS option 'CYGNUM_FS_ROM_BASE_ADDRESS' needs to be set to this
+ value in order to access the filesystem.
+
+
diff --git a/cesar/ecos/packages/fs/rom/current/doc/romfs.txt b/cesar/ecos/packages/fs/rom/current/doc/romfs.txt
new file mode 100644
index 0000000000..7b34a13398
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/doc/romfs.txt
@@ -0,0 +1,12 @@
+ROMFS - A rom filesystem plug-in module for eCos
+================================================
+
+You can use this module if you have flash ROM available to install the
+filesystem into. Instructions are given for creating and installing a
+rom filesystem into a RedBoot monitor.
+
+See mk_romfs for instructions for making the filesystem.
+
+See romfs.c for comments about the filesystem structure.
+
+
diff --git a/cesar/ecos/packages/fs/rom/current/src/romfs.c b/cesar/ecos/packages/fs/rom/current/src/romfs.c
new file mode 100644
index 0000000000..0c8599516b
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/src/romfs.c
@@ -0,0 +1,1100 @@
+//==========================================================================
+//
+// romfs.c
+//
+// ROM file system
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg
+// Contributors: nickg, richard.panton@3glab.com
+// Date: 2000-07-25
+// Purpose: ROM file system
+// Description: This is a ROM filesystem for eCos. It attempts to
+// provide full POSIX-compatible filesystem behaviour
+// while at the same time being efficient in terms of
+// time and space used.
+//
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+//
+// General Description
+// ===================
+//
+// This is an implementation of a ROM filesystem for eCos. Its goal is
+// to provide a working example of a filesystem that provides most of
+// the required POSIX functionality. And obviously it may also be
+// useful in its own right.
+//
+//
+// Header
+// ------
+//
+// There is a single header that describes the overall format of the ROMFS
+// disk. The address of this header is used as the base for all offsets used
+// in the node and directory structures. It contains the following fields:
+//
+// label - A human readable label for various purposes
+// fssize - The size in bytes of the entire ROMFS disk
+// nodes - A count of the nodes in the disk
+//
+// Immediately following thisin memory is the node table, consisting of
+// 'nodes' repetitions of the node object.
+//
+// Nodes
+// -----
+//
+// All files and directories are represented by node objects. Each
+// romfs_node structure contains the following fields:
+//
+// mode - Node type, file or directory.
+// nlink - Number of links to this node. Each directory entry that references
+// this node is a link.
+// size - Size of the data in this node in bytes.
+// ctime - Creation time of the file (NOT the ROMFS)
+// data - Offset of the first data byte for this node from the header
+//
+// Directories
+// -----------
+//
+// A directory is a node whose data is a list of directory entries.
+// These contain the
+// following fields:
+//
+// node - Index of the node in the romfs_disk table that is referenced by
+// this entry. This is present in every directory entry fragment.
+// next - Offset of the next name entry.
+// name - The filename associated with this link to the node.
+//
+// Data Storage
+// ------------
+//
+// Each file has its data stored in a single contiguous memory block
+// referenced by the offset in the node.
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/hal.h>
+#include <pkgconf/kernel.h>
+#include <pkgconf/io_fileio.h>
+#include <pkgconf/fs_rom.h>
+
+#include <cyg/kernel/ktypes.h> // base kernel types
+#include <cyg/infra/cyg_trac.h> // tracing macros
+#include <cyg/infra/cyg_ass.h> // assertion macros
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/kernel/kapi.h>
+#include <cyg/infra/diag.h>
+
+//==========================================================================
+// Eventually we want to eXecute In Place from the ROM in a protected
+// environment, so we'll need executables to be aligned to a boundary
+// suitable for MMU protection. A suitable boundary would be the 4k
+// boundary in all the CPU architectures I am currently aware of.
+
+// Forward definitions
+
+// Filesystem operations
+static int romfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
+static int romfs_umount ( cyg_mtab_entry *mte );
+static int romfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int mode, cyg_file *fte );
+static int romfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_file *fte );
+static int romfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_dir *dir_out );
+static int romfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ struct stat *buf);
+static int romfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len );
+static int romfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len );
+
+// File operations
+static int romfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+static int romfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
+static int romfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
+ CYG_ADDRWORD data);
+static int romfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode );
+static int romfs_fo_close (struct CYG_FILE_TAG *fp);
+static int romfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
+static int romfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
+static int romfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
+
+// Directory operations
+static int romfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
+static int romfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
+
+
+//==========================================================================
+// Filesystem table entries
+
+// -------------------------------------------------------------------------
+// Fstab entry.
+// This defines the entry in the filesystem table.
+// For simplicity we use _FILESYSTEM synchronization for all accesses since
+// we should never block in any filesystem operations.
+
+FSTAB_ENTRY( romfs_fste, "romfs", 0,
+ CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
+ romfs_mount,
+ romfs_umount,
+ romfs_open,
+ (cyg_fsop_unlink *)cyg_fileio_erofs,
+ (cyg_fsop_mkdir *)cyg_fileio_erofs,
+ (cyg_fsop_rmdir *)cyg_fileio_erofs,
+ (cyg_fsop_rename *)cyg_fileio_erofs,
+ (cyg_fsop_link *)cyg_fileio_erofs,
+ romfs_opendir,
+ romfs_chdir,
+ romfs_stat,
+ romfs_getinfo,
+ romfs_setinfo);
+
+// -------------------------------------------------------------------------
+// mtab entry.
+// This defines a single ROMFS loaded into ROM at the configured address
+//
+// MTAB_ENTRY( rom_mte, // structure name
+// "/rom", // mount point
+// "romfs", // FIlesystem type
+// "", // hardware device
+// (CYG_ADDRWORD) CYGNUM_FS_ROM_BASE_ADDRESS // Address in ROM
+// );
+
+
+// -------------------------------------------------------------------------
+// File operations.
+// This set of file operations are used for normal open files.
+
+static cyg_fileops romfs_fileops =
+{
+ romfs_fo_read,
+ (cyg_fileop_write *)cyg_fileio_erofs,
+ romfs_fo_lseek,
+ romfs_fo_ioctl,
+ cyg_fileio_seltrue,
+ romfs_fo_fsync,
+ romfs_fo_close,
+ romfs_fo_fstat,
+ romfs_fo_getinfo,
+ romfs_fo_setinfo
+};
+
+// -------------------------------------------------------------------------
+// Directory file operations.
+// This set of operations are used for open directories. Most entries
+// point to error-returning stub functions. Only the read, lseek and
+// close entries are functional.
+
+static cyg_fileops romfs_dirops =
+{
+ romfs_fo_dirread,
+ (cyg_fileop_write *)cyg_fileio_enosys,
+ romfs_fo_dirlseek,
+ (cyg_fileop_ioctl *)cyg_fileio_enosys,
+ cyg_fileio_seltrue,
+ (cyg_fileop_fsync *)cyg_fileio_enosys,
+ romfs_fo_close,
+ (cyg_fileop_fstat *)cyg_fileio_enosys,
+ (cyg_fileop_getinfo *)cyg_fileio_enosys,
+ (cyg_fileop_setinfo *)cyg_fileio_enosys
+};
+
+//==========================================================================
+// Data typedefs
+// Some forward typedefs for the main data structures.
+
+struct romfs_disk;
+typedef struct romfs_disk romfs_disk;
+
+struct romfs_node;
+typedef struct romfs_node romfs_node;
+
+struct romfs_dirent;
+typedef struct romfs_dirent romfs_dirent;
+
+//==========================================================================
+// File and directory node
+// This data structure represents a file or directory.
+
+struct romfs_node
+{
+ cyg_uint32 mode; // 0-3 node type
+ cyg_ucount32 nlink; // 4-7 number of links to this node
+ cyg_uint16 uid; // 8-9 Owner id
+ cyg_uint16 gid; // 10-11 Group id
+ cyg_uint32 size; // 12-15 size of file in bytes
+ cyg_uint32 ctime; // 16-19 creation status time
+ cyg_uint32 offset; // 20-23 offset of data from start of ROMFS
+ cyg_uint32 pad[2]; // 24-31 padding to align to 32byte boundary
+};
+
+//==========================================================================
+// Directory entry.
+// Variable sized entry containing the name and node of a directory entry
+
+struct romfs_dirent
+{
+ cyg_ucount32 node; // Index of node in romfs_disk structure
+ cyg_uint32 next; // Offset from start of directory of
+ // a) the next entry, or
+ // b) the end of the directory data
+ char name[0]; // The name, NUL terminated
+};
+
+//==========================================================================
+// ROMFS header
+// This data structure contains overall information on the ROMFS
+
+struct romfs_disk
+{
+ cyg_uint32 magic; // 0-3 Marks a valid ROMFS entry
+ cyg_ucount32 nodecount; // 4-7 Count of nodes in this filesystem
+ cyg_ucount32 disksize; // 8-11 Count of bytes in this filesystem
+ cyg_uint32 dev_id; // 12-15 ID of disk (put into stat.st_dev)
+ char name[16]; // 16-31 Name - pads to 32 bytes
+ romfs_node node[0];
+};
+
+#define ROMFS_MAGIC 0x526f6d2e // The magic signature word for a romfs
+#define ROMFS_CIGAM 0x2e6d6f52 // The byte sex is wrong if you see this
+
+//==========================================================================
+// Directory search data
+// Parameters for a directory search. The fields of this structure are
+// updated as we follow a pathname through the directory tree.
+
+struct romfs_dirsearch
+{
+ romfs_disk *disk; // disk structure
+ romfs_node *dir; // directory to search
+ const char *path; // path to follow
+ romfs_node *node; // Node found
+ const char *name; // last name used
+ int namelen; // name fragment length
+ cyg_bool last; // last name in path?
+};
+
+typedef struct romfs_dirsearch romfs_dirsearch;
+
+//==========================================================================
+// This seems to be the only string function referenced. Define as static
+// here to avoid having to load the string library
+
+static bool match( const char *a, const char *b, int len )
+{
+ for ( ; len > 0 && *a && *b && *a == *b ; a++, b++, len-- )
+ ;
+ return ( len == 0 );
+}
+
+
+//==========================================================================
+// SIMPLE buffer management.
+// Each node has a data buffer pointer and a size.
+
+// -------------------------------------------------------------------------
+// findbuffer_node()
+// return a pointer to the data at the indicated file position.
+
+static int findbuffer_node( romfs_disk *disk, // header pointer
+ romfs_node *node, // node pointer
+ off_t pos, // data position to get
+ cyg_uint8 **buffer, // returned buffer pointer
+ size_t *size) // returned buffer size
+{
+ if ( pos >= node->size || node->size == 0 )
+ {
+ // Indicate end of data.
+ *size = 0;
+ } else {
+
+ // Calculate the buffer position
+ *buffer = (cyg_uint8*)disk + node->offset + pos;
+ *size = node->size-pos;
+ }
+
+ return ENOERR;
+}
+
+//==========================================================================
+// Directory operations
+
+
+// -------------------------------------------------------------------------
+// find_direntry()
+// Find a directory entry for the name and return a pointer to the first
+// entry fragment.
+
+static romfs_dirent *find_direntry( romfs_disk *disk, romfs_node *dir, const char *name, int namelen )
+{
+ off_t pos = 0;
+ int err;
+
+ // Loop over all the entries until a match is found or we run out
+ // of data.
+ while( pos < dir->size )
+ {
+ romfs_dirent *d;
+ cyg_uint8 *buf;
+ size_t size;
+
+ err = findbuffer_node( disk, dir, pos, &buf, &size );
+ if( err != ENOERR || size == 0)
+ return NULL;
+
+ d = (romfs_dirent *)buf;
+
+ // Is this the directory entry we're looking for?
+ if ( match( d->name, name, namelen ) )
+ return d;
+
+ // Otherwise move on to next entry in chain
+ pos = d->next;
+ }
+
+ return NULL;
+}
+
+//==========================================================================
+// Directory search
+
+// -------------------------------------------------------------------------
+// init_dirsearch()
+// Initialize a dirsearch object to start a search
+
+static void init_dirsearch( romfs_dirsearch *ds,
+ romfs_disk *disk,
+ romfs_node *dir,
+ const char *name)
+{
+ ds->disk = disk;
+ ds->dir = dir;
+ ds->path = name;
+ ds->node = dir;
+ ds->name = name;
+ ds->namelen = 0;
+ ds->last = false;
+}
+
+// -------------------------------------------------------------------------
+// find_entry()
+// Search a single directory for the next name in a path and update the
+// dirsearch object appropriately.
+
+static int find_entry( romfs_dirsearch *ds )
+{
+ romfs_node *dir = ds->dir;
+ const char *name = ds->path;
+ const char *n = name;
+ int namelen = 0;
+ romfs_dirent *d;
+
+ // check that we really have a directory
+ if( !S_ISDIR(dir->mode) )
+ return ENOTDIR;
+
+ // Isolate the next element of the path name.
+ while( *n != '\0' && *n != '/' )
+ n++, namelen++;
+
+ // Check if this is the last path element.
+ while( *n == '/') n++;
+ if( *n == '\0' )
+ ds->last = true;
+
+ // update name in dirsearch object
+ ds->name = name;
+ ds->namelen = namelen;
+
+ // Here we have the name and its length set up.
+ // Search the directory for a matching entry
+
+ d = find_direntry( ds->disk, dir, name, namelen );
+
+ if( d == NULL )
+ return ENOENT;
+
+ // pass back the node we have found
+ ds->node = &ds->disk->node[d->node];
+
+ return ENOERR;
+
+}
+
+// -------------------------------------------------------------------------
+// romfs_find()
+// Main interface to directory search code. This is used in all file
+// level operations to locate the object named by the pathname.
+
+static int romfs_find( romfs_dirsearch *d )
+{
+ int err;
+
+ // Short circuit empty paths
+ if( *(d->path) == '\0' )
+ return ENOERR;
+
+ // iterate down directory tree until we find the object
+ // we want.
+ for(;;)
+ {
+ err = find_entry( d );
+
+ if( err != ENOERR )
+ return err;
+
+ if( d->last )
+ return ENOERR;
+
+ // Update dirsearch object to search next directory.
+ d->dir = d->node;
+ d->path += d->namelen;
+ while( *(d->path) == '/' ) d->path++; // skip dirname separators
+ }
+}
+
+//==========================================================================
+// Pathconf support
+// This function provides support for pathconf() and fpathconf().
+
+static int romfs_pathconf( romfs_node *node, struct cyg_pathconf_info *info )
+{
+ int err = ENOERR;
+
+ switch( info->name )
+ {
+ case _PC_LINK_MAX:
+ info->value = LINK_MAX;
+ break;
+
+ case _PC_MAX_CANON:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_MAX_INPUT:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_NAME_MAX:
+ info->value = NAME_MAX;
+ break;
+
+ case _PC_PATH_MAX:
+ info->value = PATH_MAX;
+ break;
+
+ case _PC_PIPE_BUF:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+
+ case _PC_ASYNC_IO:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_CHOWN_RESTRICTED:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ case _PC_NO_TRUNC:
+ info->value = 0;
+ break;
+
+ case _PC_PRIO_IO:
+ info->value = 0;
+ break;
+
+ case _PC_SYNC_IO:
+ info->value = 0;
+ break;
+
+ case _PC_VDISABLE:
+ info->value = -1; // not supported
+ err = EINVAL;
+ break;
+
+ default:
+ err = EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+//==========================================================================
+// Filesystem operations
+
+// -------------------------------------------------------------------------
+// romfs_mount()
+// Process a mount request. This mainly finds root for the
+// filesystem.
+
+static int romfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte )
+{
+ romfs_disk *disk=NULL;
+
+ if ( !mte->data ) {
+ // If the image address was not in the MTE data word,
+ if ( mte->devname && mte->devname[0] ) {
+ char *addr;
+ // And there's something in the 'hardware device' field,
+ // then read the address from there.
+ sscanf( mte->devname, "%p", &addr );
+ disk = (romfs_disk *) addr;
+ }
+ } else {
+ disk = (romfs_disk *)mte->data;
+ }
+
+ if ( !disk ) {
+ // If still no address, try the FSTAB entry data word
+ disk = (romfs_disk *)fste->data;
+ }
+
+ if ( !disk ) {
+ // If still no address, give up...
+ return ENOENT;
+ }
+
+
+
+ // Check the ROMFS magic number to ensure that there's really an fs.
+ if ( disk->magic == ROMFS_CIGAM ) {
+ // The disk image has the wrong byte sex!!!
+ return EIO;
+ } else if ( disk->magic != ROMFS_MAGIC || disk->nodecount == 0 ) {
+ // No image found
+ return ENOENT;
+ }
+
+ mte->root = (cyg_dir)&disk->node[0];
+
+ mte->data = (CYG_ADDRWORD)disk;
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_umount()
+// Unmount the filesystem. This will currently always succeed.
+
+static int romfs_umount ( cyg_mtab_entry *mte )
+{
+ // Clear root pointer
+ mte->root = CYG_DIR_NULL;
+
+ // That's all folks.
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_open()
+// Open a file for reading
+
+static int romfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int mode, cyg_file *file )
+{
+
+ romfs_dirsearch ds;
+ romfs_node *node = NULL;
+ int err;
+
+ init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
+
+ err = romfs_find( &ds );
+
+ if( err == ENOENT )
+ {
+ return ENOENT;
+ }
+ else if( err == ENOERR )
+ {
+ // The node exists. If the O_CREAT and O_EXCL bits are set, we
+ // must fail the open.
+
+ if( (mode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) )
+ err = EEXIST;
+ else node = ds.node;
+ }
+
+ if( err == ENOERR && (mode & O_TRUNC ) )
+ {
+ // If the O_TRUNC bit is set we must fail the open
+
+ err = EPERM;
+ }
+
+ if( err != ENOERR ) return err;
+
+ // Check that we actually have a file here
+ if( S_ISDIR(node->mode) ) return EISDIR;
+
+ // Initialize the file object
+
+ file->f_flag |= mode & CYG_FILE_MODE_MASK;
+ file->f_type = CYG_FILE_TYPE_FILE;
+ file->f_ops = &romfs_fileops;
+ file->f_offset = 0;
+ file->f_data = (CYG_ADDRWORD)node;
+ file->f_xops = 0;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_opendir()
+// Open a directory for reading.
+
+static int romfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_file *file )
+{
+ romfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
+
+ err = romfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // check it is really a directory.
+ if( !S_ISDIR(ds.node->mode) ) return ENOTDIR;
+
+ // Initialize the file object, setting the f_ops field to a
+ // special set of file ops.
+
+ file->f_type = CYG_FILE_TYPE_FILE;
+ file->f_ops = &romfs_dirops;
+ file->f_offset = 0;
+ file->f_data = (CYG_ADDRWORD)ds.node;
+ file->f_xops = 0;
+
+ return ENOERR;
+
+}
+
+// -------------------------------------------------------------------------
+// romfs_chdir()
+// Change directory support.
+
+static int romfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ cyg_dir *dir_out )
+{
+ if( dir_out != NULL )
+ {
+ // This is a request to get a new directory pointer in
+ // *dir_out.
+
+ romfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
+
+ err = romfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // check it is a directory
+ if( !S_ISDIR(ds.node->mode) )
+ return ENOTDIR;
+
+ // Pass it out
+ *dir_out = (cyg_dir)ds.node;
+ }
+ // If no output dir is required, this means that the mte and
+ // dir arguments are the current cdir setting and we should
+ // forget this fact. Do nothing in ROMFS.
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_stat()
+// Get struct stat info for named object.
+
+static int romfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ struct stat *buf)
+{
+ romfs_dirsearch ds;
+ int err;
+ romfs_disk *disk = (romfs_disk *)mte->data;
+
+ init_dirsearch( &ds, disk, (romfs_node *)dir, name );
+
+ err = romfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ // Fill in the status
+ buf->st_mode = ds.node->mode;
+ buf->st_ino = (ino_t)(ds.node - &disk->node[0]);
+ buf->st_dev = (dev_t)disk->dev_id;
+ buf->st_nlink = ds.node->nlink;
+ buf->st_uid = ds.node->uid;
+ buf->st_gid = ds.node->gid;
+ buf->st_size = ds.node->size;
+ buf->st_atime = ds.node->ctime;
+ buf->st_mtime = ds.node->ctime;
+ buf->st_ctime = ds.node->ctime;
+
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// romfs_getinfo()
+// Getinfo. Currently only support pathconf().
+
+static int romfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len )
+{
+ romfs_dirsearch ds;
+ int err;
+
+ init_dirsearch( &ds, (romfs_disk *)mte->data, (romfs_node *)dir, name );
+
+ err = romfs_find( &ds );
+
+ if( err != ENOERR ) return err;
+
+ switch( key )
+ {
+ case FS_INFO_CONF:
+ err = romfs_pathconf( ds.node, (struct cyg_pathconf_info *)buf );
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// romfs_setinfo()
+// Setinfo. Nothing to support here at present.
+
+static int romfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
+ int key, void *buf, int len )
+{
+ // No setinfo keys supported at present
+
+ return EINVAL;
+}
+
+
+//==========================================================================
+// File operations
+
+// -------------------------------------------------------------------------
+// romfs_fo_read()
+// Read data from the file.
+
+static int romfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+{
+ romfs_node *node = (romfs_node *)fp->f_data;
+ int i;
+ off_t pos = fp->f_offset;
+ ssize_t resid = uio->uio_resid;
+
+ // Loop over the io vectors until there are none left
+ for( i = 0; i < uio->uio_iovcnt; i++ )
+ {
+ cyg_iovec *iov = &uio->uio_iov[i];
+ char *buf = (char *)iov->iov_base;
+ off_t len = iov->iov_len;
+
+ // Loop over each vector filling it with data from the file.
+ while( len > 0 && pos < node->size )
+ {
+ cyg_uint8 *fbuf;
+ size_t bsize;
+ off_t l = len;
+ int err;
+
+ // Get a pointer to the data at offset _pos_.
+ err = findbuffer_node( (romfs_disk *)fp->f_mte->data, node, pos, &fbuf, &bsize );
+
+ if( err != ENOERR )
+ return err;
+
+ // adjust size to end of file if necessary
+ if( l > node->size-pos )
+ l = node->size-pos;
+
+ // adjust size to the amount of contiguous data we can see
+ // at present.
+ if( l > bsize )
+ l = bsize;
+
+ // copy data out
+ memcpy( buf, fbuf, l );
+
+ // Update working vars
+ len -= l;
+ buf += l;
+ pos += l;
+ resid -= l;
+ }
+ }
+
+ // We successfully read some data
+ // Update the file offset and transfer residue.
+
+ uio->uio_resid = resid;
+ fp->f_offset = pos;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_lseek()
+// Seek to a new file position.
+
+static int romfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *apos, int whence )
+{
+ romfs_node *node = (romfs_node *)fp->f_data;
+ off_t pos = *apos;
+
+ switch( whence )
+ {
+ case SEEK_SET:
+ // Pos is already where we want to be.
+ break;
+
+ case SEEK_CUR:
+ // Add pos to current offset.
+ pos += fp->f_offset;
+ break;
+
+ case SEEK_END:
+ // Add pos to file size.
+ pos += node->size;
+ break;
+
+ default:
+ return EINVAL;
+ }
+
+ // Check that pos is still within current file size, or at the
+ // very end.
+ if( pos < 0 || pos > node->size )
+ return EINVAL;
+
+ // All OK, set fp offset and return new position.
+ *apos = fp->f_offset = pos;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_ioctl()
+// Handle ioctls. Currently none are defined.
+
+static int romfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
+ CYG_ADDRWORD data)
+{
+ // No Ioctls currenly defined.
+
+ return EINVAL;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_fsync().
+// Force the file out to data storage.
+
+static int romfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode )
+{
+ // Data is always permanently where it belongs, nothing to do
+ // here.
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_close()
+// Close a file. We just clear out the data pointer.
+
+static int romfs_fo_close (struct CYG_FILE_TAG *fp)
+{
+ fp->f_data = 0; // zero data pointer
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+//romfs_fo_fstat()
+// Get file status.
+
+static int romfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf )
+{
+ romfs_node *node = (romfs_node *)fp->f_data;
+ romfs_disk *disk = (romfs_disk*)(fp->f_mte->data);
+
+ // Fill in the status
+ buf->st_mode = node->mode;
+ buf->st_ino = (ino_t)(node - &disk->node[0]);
+ buf->st_dev = disk->dev_id;
+ buf->st_nlink = node->nlink;
+ buf->st_uid = node->uid;
+ buf->st_gid = node->gid;
+ buf->st_size = node->size;
+ buf->st_atime = node->ctime;
+ buf->st_mtime = node->ctime;
+ buf->st_ctime = node->ctime;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_getinfo()
+// Get info. Currently only supports fpathconf().
+
+static int romfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
+{
+ romfs_node *node = (romfs_node *)fp->f_data;
+ int err;
+
+ switch( key )
+ {
+ case FS_INFO_CONF:
+ err = romfs_pathconf( node, (struct cyg_pathconf_info *)buf );
+ break;
+
+ default:
+ err = EINVAL;
+ }
+ return err;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_setinfo()
+// Set info. Nothing supported here.
+
+static int romfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len )
+{
+ // No setinfo key supported at present
+
+ return ENOERR;
+}
+
+
+//==========================================================================
+// Directory operations
+
+// -------------------------------------------------------------------------
+// romfs_fo_dirread()
+// Read a single directory entry from a file.
+
+static int romfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
+{
+ romfs_node *dir = (romfs_node *)fp->f_data;
+ off_t pos = fp->f_offset;
+ int err = ENOERR;
+ struct dirent *ent = (struct dirent *)uio->uio_iov[0].iov_base;
+ char *nbuf = ent->d_name;
+ int nlen = sizeof(ent->d_name)-1;
+ off_t len = uio->uio_iov[0].iov_len;
+ romfs_dirent *d = NULL;
+ cyg_uint8 *buf;
+ size_t size;
+ int i;
+
+ if( len < sizeof(struct dirent) )
+ return EINVAL;
+
+ // Get the next entry
+ err = findbuffer_node( (romfs_disk *)fp->f_mte->data, dir, pos, &buf, &size );
+ if( err != ENOERR || size == 0 || pos >= dir->size )
+ return err;
+
+ d = (romfs_dirent *)buf;
+
+ for ( i = 0 ; i < nlen && d->name[i] ; i++, nbuf++ )
+ *nbuf = d->name[i];
+
+ // A successful read. Terminate the entry name with a NUL, set the
+ // residue and set the file offset to restart at the next
+ // directory entry.
+
+ *nbuf = '\0';
+ uio->uio_resid -= sizeof(struct dirent);
+ fp->f_offset = d->next;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// romfs_fo_dirlseek()
+// Seek directory to start.
+
+static int romfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence )
+{
+ // Only allow SEEK_SET to zero
+
+ if( whence != SEEK_SET || *pos != 0)
+ return EINVAL;
+
+ *pos = fp->f_offset = 0;
+
+ return ENOERR;
+}
+
+// -------------------------------------------------------------------------
+// EOF romfs.c
diff --git a/cesar/ecos/packages/fs/rom/current/support/Makefile b/cesar/ecos/packages/fs/rom/current/support/Makefile
new file mode 100644
index 0000000000..e61080ef70
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/support/Makefile
@@ -0,0 +1,39 @@
+#==========================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+#==========================================================================
+
+CC = gcc
+CFLAGS = -ggdb -Wall
+
+mk_romfs:
diff --git a/cesar/ecos/packages/fs/rom/current/support/file2c.tcl b/cesar/ecos/packages/fs/rom/current/support/file2c.tcl
new file mode 100755
index 0000000000..f40b4a0da1
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/support/file2c.tcl
@@ -0,0 +1,124 @@
+#!/bin/bash
+# restart using a Tcl shell \
+ exec sh -c 'for tclshell in tclsh tclsh83 cygtclsh80 ; do \
+ ( echo | $tclshell ) 2> /dev/null && exec $tclshell "`( cygpath -w \"$0\" ) 2> /dev/null || echo $0`" "$@" ; \
+ done ; \
+ echo "file2c.tcl: cannot find Tcl shell" ; exit 1' "$0" "$@"
+
+#===============================================================================
+#
+# file2c.tcl
+#
+# Convert a file into a header that can be #included from C.
+#
+#===============================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+## at http://sources.redhat.com/ecos/ecos-license/
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+#===============================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s): jlarmour,bartv
+# Contact(s):
+# Date: 2001-07-20
+# Purpose:
+# Description:
+# Usage: file2c.tcl <file to encode> <output C header file>
+#
+#####DESCRIPTIONEND####
+#===============================================================================
+
+
+
+if { $argc != 2 } {
+ puts "Usage: file2c.tcl <file to encode> <output C header file>"
+ exit 1
+}
+set infile [lindex $argv 0]
+set outfile [lindex $argv 1]
+
+set status [ catch {
+ set infilefd [open $infile "r"]
+ fconfigure $infilefd -translation binary
+ set data [read $infilefd]
+ close $infilefd
+} message]
+
+if { $status != 0 } {
+ error "Unable to read file $infile: $message"
+}
+
+set result ""
+
+set status [ catch {
+ set outfilefd [ open $outfile "w" ]
+} message ]
+
+if { $status != 0 } {
+ error "Unable to create file $outfile: $message"
+}
+
+append result "/* This is a generated file. Do not edit. */\n\n"
+append result "static const unsigned char filedata\[\] = {\n"
+
+set datalength [ string length $data ]
+
+set aligned_datalength [expr $datalength - ($datalength % 8)]
+
+for { set i 0 } {$i < $aligned_datalength} {incr i 8} {
+ binary scan $data "@[set i]H16" var0
+ append result [format " 0x%2s, 0x%2s, 0x%2s, 0x%2s, 0x%2s, 0x%2s, 0x%2s, 0x%2s,\n" \
+ [string range $var0 0 1] \
+ [string range $var0 2 3] \
+ [string range $var0 4 5] \
+ [string range $var0 6 7] \
+ [string range $var0 8 9] \
+ [string range $var0 10 11] \
+ [string range $var0 12 13] \
+ [string range $var0 14 15]]
+}
+
+if { $aligned_datalength != $datalength } {
+ append result " "
+ for { set i $aligned_datalength } {$i < $datalength} {incr i} {
+ binary scan $data "@[set i]H2" var0
+ append result [format "0x%2s, " $var0]
+ }
+}
+
+# Remove either comma+newline or comma+space from the end
+set result [string range $result 0 [expr [string length $result] - 3]]
+
+append result "\n};"
+
+puts $outfilefd $result
+close $outfilefd
diff --git a/cesar/ecos/packages/fs/rom/current/support/mk_romfs.c b/cesar/ecos/packages/fs/rom/current/support/mk_romfs.c
new file mode 100644
index 0000000000..45921a7d2a
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/support/mk_romfs.c
@@ -0,0 +1,734 @@
+//==========================================================================
+//
+// mk_romfs.c
+//
+// Create ROM file system image
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): richard.panton@3glab.com
+// Contributors: richard.panton@3glab.com
+// Date: 2000-07-25
+// Purpose: ROM file system
+// Description: This program creates a ROM file system image, suitable
+// for use with the sample ROM file system implemented by
+// this package.
+// * CAUTION! * This is host code and can only be built
+// in a host, e.g. Linux, environment.
+//
+//####DESCRIPTIONEND####
+//==========================================================================
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+//==========================================================================
+//
+// CONFIGURABLE ITEMS HERE
+//
+//==========================================================================
+
+// define LONG to be a four byte unsigned integer on the host
+#define LONG unsigned long
+
+// define SHORT to be a two byte unsigned integer on the host
+#define SHORT unsigned short
+
+// All data files should be aligned to this sized boundary (minimum probably 32)
+#define DATA_ALIGN 32
+
+// The data stored in a directory should be aligned to this size boundary
+#define DIRECTORY_ALIGN 32
+
+// All executable files should be aligned to this sized boundary (minimum probably 32)
+#define EXEC_ALIGN 32
+
+// Undefine this if the host filesystem does not support lstat()
+#define HAS_LSTAT
+
+//==========================================================================
+
+// Return (n) aligned to the next (b) byte boundary
+#define ALIGN_TO( n, b ) (( (n) + (b)-1 ) & ~((b)-1))
+
+// Set the stat call to use
+#ifdef HAS_LSTAT
+#define get_status( p, b ) lstat( (p), (b) )
+#else
+#define get_status( p, b ) stat( (p), (b) )
+#endif
+
+// This is how we identify a directory from its mode
+#define IS_DIRECTORY( m ) (S_ISDIR(m))
+
+// This is how we identify a data file from its mode
+#define IS_DATAFILE( m ) (S_ISREG(m) && ((m)&S_IXUSR) == 0 )
+
+// This is how we identify an executable from its mode
+#define IS_EXECUTABLE( m ) (S_ISREG(m) && ((m)&S_IXUSR) != 0 )
+
+// This is how we identify a symbolic link from its mode
+#define IS_SYMLINK( m ) (S_ISLNK(m))
+
+#define ROMFS_MAGIC 0x526f6d2e
+
+//=========================================================================
+// EXIT CODES
+#define EXIT_SUCCESS 0
+#define EXIT_ARGS 1
+#define EXIT_MALLOC 2
+#define EXIT_FILESYS 3
+#define EXIT_WRITE 4
+#define EXIT_SEEK 5
+#define EXIT_COMPILE 6
+#define EXIT_BUG 7
+
+
+
+// These are the structures we will build into the ROMFS image.
+// The sizes of these structures should be fixed for all architectures
+typedef struct romfs_dirent {
+ LONG node; // 4
+ LONG next; // 8
+ char name[0]; // 8 + strlen(name) + 1
+} romfs_dirent; // Aligns to next 32 byte boundary
+
+typedef struct romfs_node {
+ LONG mode; // 4
+ LONG nlink; // 8
+ SHORT uid; // 10
+ SHORT gid; // 12
+ LONG size; // 16
+ LONG ctime; // 20
+ LONG data_offset; // 24
+ char pad[8]; // 32
+} romfs_node; // Next node begins here
+
+typedef struct romfs_disk {
+ LONG magic; // 4
+ LONG nodecount; // 8
+ LONG disksize; // 12
+ LONG dev_id; // 16
+ char name[16]; // 32
+} romfs_disk; // Nodes start here
+
+// This is the holding structure for a node
+typedef struct node {
+ const char *path; // Filename (inc. path) of a link to this node
+ size_t size; // Size of file/directory/link
+ mode_t st_mode; // Type and permissions
+ uid_t uid; // Owner id
+ gid_t gid; // Group id
+ time_t ctime; // File creation time
+ int nodenum; // Nodenumber of this node in the ROMFS image
+ dev_t device; // Device (for hardlink check)
+ ino_t inode; // Inode (for hardlink check)
+ int nlink; // [DIRECTORIES] Number of sub-directories [FILES] hard links
+ romfs_dirent *entry; // [DIRECTORIES] Points to an array of directory entries
+ int entry_size; // Size to be allocated to file (includes alignment bytes)
+ unsigned long offset; // Offset within ROMFS image of data
+ struct node *sibling; // Points to the next entry in this directory
+ struct node *child; // [DIRECTORIES] Points to any subdirectories
+ struct node *next_in_rom; // Next in ROMFS write order
+ struct node *next_multilink;// Next node that is multilinked
+} node;
+
+static int nodes = 0;
+static char *prog;
+static int verbose = 1;
+static int dowrite = 1;
+static int bigendian = 0;
+static int hardlinks = 0;
+static unsigned long coffset = 0;
+static node * first = NULL;
+static node ** last_p = &first;
+static node * first_multilink = NULL;
+static node ** last_multilink_p = &first_multilink;
+static int fd = -1;
+
+#define VERB_NONE 0
+#define VERB_MINIMUM 1
+#define VERB_SUB 2
+#define VERB_MAX 3
+#define VERB_EXCESSIVE 4
+
+// Use gcc format argument checking on this function, which cannot return
+static void fatal_error( int exitcode, const char *fmt, ... ) \
+ __attribute__ (( noreturn,format (printf, 2, 3) ));
+
+// Use gcc format argument checking on this function
+static void verb_printf( int level, const char *fmt, ... ) \
+ __attribute__ ((format (printf, 2, 3) ));
+
+static void fatal_error( int exitcode, const char *fmt, ... ) {
+ va_list v;
+
+ va_start( v, fmt );
+ vfprintf( stderr, fmt, v );
+
+ exit(exitcode);
+}
+
+static void verb_printf( int level, const char *fmt, ... ){
+ if ( level <= verbose ) {
+ va_list v;
+ va_start( v,fmt );
+ vprintf(fmt, v);
+ }
+}
+
+static void *mymalloc( size_t size ) {
+ void *p = malloc(size);
+ if ( !p ) {
+ fatal_error( EXIT_MALLOC, "Out of memory allocating %d bytes\n", size );
+ }
+ return p;
+}
+
+static void myrealloc( void **o, size_t newsize ) {
+ if ( *o == NULL )
+ *o = mymalloc( newsize );
+ else if ( !(*o = realloc( *o, newsize )) ) {
+ fatal_error( EXIT_MALLOC, "Out of memory re-allocating %d bytes\n", newsize );
+ }
+}
+
+static void outputlong( unsigned char *b, unsigned long w ) {
+ if ( bigendian ) {
+ b[0] = (w>>24) & 0xff;
+ b[1] = (w>>16) & 0xff;
+ b[2] = (w>> 8) & 0xff;
+ b[3] = (w ) & 0xff;
+ } else {
+ b[3] = (w>>24) & 0xff;
+ b[2] = (w>>16) & 0xff;
+ b[1] = (w>> 8) & 0xff;
+ b[0] = (w ) & 0xff;
+ }
+}
+
+static void outputshort( unsigned char *b, unsigned short w ) {
+ if ( bigendian ) {
+ b[0] = (w>> 8) & 0xff;
+ b[1] = (w ) & 0xff;
+ } else {
+ b[1] = (w>> 8) & 0xff;
+ b[0] = (w ) & 0xff;
+ }
+}
+
+static unsigned long ConvertMode( unsigned long posix_mode ) {
+ unsigned long result = 0;
+ if ( S_ISDIR( posix_mode ) ) result |= 1<<0;
+ if ( S_ISCHR( posix_mode ) ) result |= 1<<1;
+ if ( S_ISBLK( posix_mode ) ) result |= 1<<2;
+ if ( S_ISREG( posix_mode ) ) result |= 1<<3;
+ if ( S_ISFIFO(posix_mode ) ) result |= 1<<4;
+ // We cannot create MQ, SEM, or SHM entries here
+ if ( posix_mode & S_IRUSR ) result |= 1<<16;
+ if ( posix_mode & S_IWUSR ) result |= 1<<17;
+ if ( posix_mode & S_IXUSR ) result |= 1<<18;
+ if ( posix_mode & S_IRGRP ) result |= 1<<19;
+ if ( posix_mode & S_IWGRP ) result |= 1<<20;
+ if ( posix_mode & S_IXGRP ) result |= 1<<21;
+ if ( posix_mode & S_IROTH ) result |= 1<<22;
+ if ( posix_mode & S_IWOTH ) result |= 1<<23;
+ if ( posix_mode & S_IXOTH ) result |= 1<<24;
+ if ( posix_mode & S_ISUID ) result |= 1<<25;
+ if ( posix_mode & S_ISGID ) result |= 1<<26;
+ return result;
+}
+
+static const char *AddDirEntry( const char *name, node *parent_node, int node_num ) {
+ int this_size = ((strlen(name) + 4 + 4 + 1) + 31) & ~31;
+ int start = parent_node->size;
+ romfs_dirent *g;
+ myrealloc( (void**)&parent_node->entry, (parent_node->size += this_size) );
+ g = (romfs_dirent *)((unsigned char *)parent_node->entry + start);
+ memset( (void*)g, '\0', this_size );
+ outputlong( (char*)&g->node, node_num);
+ outputlong( (char*)&g->next, parent_node->size);
+ strcpy(g->name,name);
+ verb_printf( VERB_MAX, "\t%s --> node %d\n", name, node_num );
+ return (const char *)g->name;
+}
+
+extern int errno;
+
+static node * FindLink( dev_t d, ino_t i ) {
+ // See if the node has been previously included by checking the device/inode
+ // combinations of all known multi-linked nodes
+ node *np = first_multilink;
+
+ for ( ; np ; np = np->next_multilink ) {
+ if ( np->device == d && np->inode == i )
+ return np;
+ }
+ return NULL;
+}
+
+static node * GetNodeInfo( const char *path, const char *name, int *hlink ) {
+ char newpath[1024];
+ node *node, *lnode;
+ struct stat stbuff;
+
+ sprintf(newpath,"%s/%s",path,name);
+ if ( (get_status(newpath,&stbuff)) < 0 ) {
+ fatal_error(EXIT_FILESYS, "stat(%s) failed: %s\n", newpath, strerror(errno));
+ }
+ if ( !(stbuff.st_mode & S_IRUSR) ) {
+ fatal_error(EXIT_FILESYS, "\"%s\" is not readable\n", newpath );
+ }
+ if ( hardlinks && S_ISREG( stbuff.st_mode ) && stbuff.st_nlink > 1 ) {
+
+ // See if this node has already been loaded
+ lnode = FindLink( stbuff.st_dev, stbuff.st_ino );
+
+ if ( lnode ) {
+ lnode->nlink++;
+ *hlink = 1;
+ return lnode; // Return the found link instead
+ }
+
+ // Create a new node
+ node = mymalloc( sizeof(struct node) );
+
+ // Incorporate the new link into the 'multi-linked' node list
+ *last_multilink_p = node;
+ last_multilink_p = &node->next_multilink;
+ } else {
+ // Create a new node
+ node = mymalloc( sizeof(struct node) );
+ }
+ node->path = strdup( newpath );
+ // We re-calculate the size for directories
+ node->size = IS_DIRECTORY( stbuff.st_mode ) ? 0 : stbuff.st_size;
+ node->st_mode = stbuff.st_mode;
+ node->uid = stbuff.st_uid;
+ node->gid = stbuff.st_gid;
+ node->ctime = stbuff.st_ctime;
+ node->nodenum = nodes++;
+ node->device = stbuff.st_dev;
+ node->inode = stbuff.st_ino;
+ // We always re-calculate the number of links
+ node->nlink = IS_DIRECTORY( stbuff.st_mode ) ? 2 : 1;
+ node->entry = NULL;
+ node->entry_size = 0;
+ node->offset = 0;
+ node->sibling = NULL;
+ node->child = NULL;
+ node->next_in_rom = NULL;
+ node->next_multilink = NULL;
+ *hlink = 0;
+ return node;
+}
+
+static void ScanDirectory(node *mynode, int p_node) {
+
+ DIR *dh;
+ struct dirent *e;
+ node **last_p = &mynode->child;
+ node *th;
+ int was_hardlinked;
+
+ if ( (dh = opendir( mynode->path )) == NULL ) {
+ perror(mynode->path);
+ return;
+ }
+
+ verb_printf(VERB_EXCESSIVE, "Construct directory '%s'(%d):\n",
+ mynode->path, mynode->nodenum );
+
+ // Add . & .. here because they MUST be present in the image
+ AddDirEntry( ".", mynode, mynode->nodenum );
+ AddDirEntry( "..", mynode, p_node );
+
+ while ( (e = readdir( dh )) ) {
+ // Ignore . & .. here because they MAY NOT be in the host filesystem
+ if ( strcmp(e->d_name,".") && strcmp(e->d_name,"..") ) {
+
+
+ th = GetNodeInfo( mynode->path, e->d_name, &was_hardlinked );
+ AddDirEntry( e->d_name, mynode, th->nodenum );
+
+ if ( !was_hardlinked ) {
+ verb_printf( VERB_EXCESSIVE, "\t\tNew node %d for entry '%s'\n", th->nodenum, e->d_name);
+ *last_p = th;
+ last_p = &th->sibling;
+ } else {
+ verb_printf( VERB_EXCESSIVE, "\t\tRe-used node %d for entry '%s'\n", th->nodenum, e->d_name);
+ }
+ }
+ }
+ closedir( dh );
+ verb_printf(VERB_EXCESSIVE,"Completed '%s'. Checking for child directories...\n", mynode->path);
+
+ for ( th = mynode->child ; th ; th = th->sibling ) {
+ if ( IS_DIRECTORY( th->st_mode ) ) {
+ mynode->nlink++;
+ ScanDirectory( th, mynode->nodenum );
+ }
+ }
+}
+
+static void AllocateSpaceToDirectories( node *first ) {
+ node *np;
+
+ for ( np = first ; np ; np = np->sibling ) {
+ if ( IS_DIRECTORY( np->st_mode ) ) {
+ // The first node is a directory. Add its data
+ np->offset = coffset;
+ np->entry_size = ALIGN_TO( np->size, DIRECTORY_ALIGN );
+ coffset += np->entry_size;
+
+ verb_printf( VERB_MAX, "\t\tnode %5d : 0x%06lX (+0x%05X)\n",
+ np->nodenum, np->offset, np->entry_size );
+
+ // Link this node into the write order chain.
+ // For node 0 (the root), this will overwrite the first pointer with itself
+ *last_p = np;
+ last_p = &np->next_in_rom;
+ }
+ }
+
+ // Now add any child directories
+ for ( np = first ; np ; np = np->sibling ) {
+ if ( IS_DIRECTORY( np->st_mode ) && np->child )
+ AllocateSpaceToDirectories( np->child );
+ }
+}
+
+static void AllocateSpaceToDataFiles( node *first ) {
+ node *np;
+
+ // There are two loops below. It CAN be done in just one, but this re-orders
+ // the file positions in relation to their inode numbers. To keep it simple
+ // to check, allocation takes place in the first loop, recursion in the second
+
+ // Search for child data files
+ for ( np = first->child ; np ; np = np->sibling ) {
+ if ( IS_DATAFILE( np->st_mode ) || IS_SYMLINK( np->st_mode ) ) {
+ np->offset = coffset;
+ np->entry_size = ALIGN_TO( np->size, DATA_ALIGN );
+ coffset += np->entry_size;
+
+ // Link in to the rom write order list
+ *last_p = np;
+ last_p = &np->next_in_rom;
+
+ verb_printf( VERB_MAX, "\t\tnode %5d : 0x%06lX (+0x%05X)\n",
+ np->nodenum, np->offset, np->entry_size );
+ }
+ }
+
+ // Recurse into sub-directories
+ for ( np = first->child ; np ; np = np->sibling ) {
+ if ( IS_DIRECTORY( np->st_mode ) ) {
+ AllocateSpaceToDataFiles( np );
+ }
+ }
+}
+
+static void AllocateSpaceToExecutables( node *first ) {
+ node *np;
+
+ // The first node is a directory. Don't bother with that...
+
+ // Search for child executables
+ for ( np = first->child ; np ; np = np->sibling ) {
+ if ( IS_EXECUTABLE( np->st_mode ) ) {
+ np->offset = coffset;
+ np->entry_size = ALIGN_TO( np->size, EXEC_ALIGN );
+ coffset += np->entry_size;
+
+ // Link in to the rom write order list
+ *last_p = np;
+ last_p = &np->next_in_rom;
+
+ verb_printf( VERB_MAX, "\t\tnode %5d : 0x%06lX (+0x%05X)\n",
+ np->nodenum, np->offset, np->entry_size );
+ }
+ }
+
+ // Recurse into sub-directories
+ for ( np = first->child ; np ; np = np->sibling ) {
+ if ( IS_DIRECTORY( np->st_mode ) ) {
+ AllocateSpaceToExecutables( np );
+ }
+ }
+}
+
+static void WriteNode( int fd, node *np ) {
+ romfs_node anode;
+ char padhere[9];
+ outputlong( (char*) &anode.mode, ConvertMode( np->st_mode ) );
+ outputlong( (char*) &anode.nlink, np->nlink );
+ outputshort((char*) &anode.uid, np->uid );
+ outputshort((char*) &anode.gid, np->gid );
+ outputlong( (char*) &anode.size, np->size );
+ outputlong( (char*) &anode.ctime, np->ctime );
+ outputlong( (char*) &anode.data_offset, np->offset );
+ sprintf( padhere, "<%6d>", np->nodenum );
+ memcpy( anode.pad, padhere, 8 );
+ if ( dowrite && write( fd, (void*)&anode, sizeof(anode) ) != sizeof(anode) )
+ fatal_error(EXIT_WRITE, "Error writing node %d (%s): %s\n", np->nodenum, np->path, strerror(errno) );
+}
+
+static int WriteNodeAndSiblings( int fd, int nodenum, node *first ) {
+ node *np;
+
+ for ( np = first ; np ; np = np->sibling ) {
+ if ( np->nodenum != nodenum++ ) {
+ fatal_error(EXIT_BUG, "BUG: Out of sequence node number; got %d, expected %d\n", np->nodenum, nodenum-1);
+ }
+ WriteNode( fd, np );
+ }
+
+ for ( np = first ; np ; np = np->sibling ) {
+ if ( IS_DIRECTORY( np->st_mode ) && np->child ) {
+ nodenum = WriteNodeAndSiblings( fd, nodenum, np->child );
+ }
+ }
+ return nodenum;
+}
+
+static void WriteNodeTable( int fd ) {
+ romfs_disk header;
+ int wnodes;
+
+ outputlong( (char*) &header.magic, ROMFS_MAGIC );
+ outputlong( (char*) &header.nodecount, nodes );
+ outputlong( (char*) &header.disksize, coffset );
+ outputlong( (char*) &header.dev_id, 0x01020304 );
+ strcpy( header.name, "ROMFS v1.0" );
+ if ( dowrite && write( fd, (void*)&header, sizeof(header) ) != sizeof(header) )
+ fatal_error(EXIT_WRITE, "Error writing ROMFS header: %s\n", strerror(errno) );
+
+ if ( (wnodes = WriteNodeAndSiblings( fd, 0, first )) != nodes ) {
+ fatal_error(EXIT_BUG, "BUG: Lost/gained some nodes; wrote %d, expected %d\n", wnodes, nodes );
+ }
+}
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static void WriteData( int fd, node *np ) {
+ char newpath[1024];
+ int ffd;
+ unsigned long todo;
+
+ if ( IS_SYMLINK( np->st_mode ) ) {
+ if ( (ffd = readlink( np->path, newpath, sizeof(newpath) )) < 0 )
+ fatal_error(EXIT_FILESYS, "Error reading symlink \"%s\": %s\n", np->path, strerror(errno) );
+
+ if ( !dowrite ) return;
+
+ if ( lseek( fd, np->offset, SEEK_SET ) != np->offset )
+ fatal_error(EXIT_SEEK, "Error seeking to offset 0x%lX: %s\n", np->offset, strerror(errno) );
+
+ if ( write( fd, newpath, ffd ) != ffd )
+ fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
+
+ return;
+ }
+
+ if ( (ffd=open(np->path, O_RDONLY | O_BINARY )) < 0 )
+ fatal_error(EXIT_FILESYS, "Error opening \"%s\": %s\n", np->path, strerror(errno) );
+
+ if ( dowrite && lseek( fd, np->offset, SEEK_SET ) != np->offset )
+ fatal_error(EXIT_SEEK, "Error seeking to offset 0x%lX: %s\n", np->offset, strerror(errno) );
+
+ todo = np->size;
+ while ( todo >= 1024 ) {
+ if ( read( ffd, newpath, 1024 ) != 1024 )
+ fatal_error(EXIT_FILESYS, "Error reading file \"%s\" at offset 0x%lX: %s\n", np->path, np->size - todo, strerror(errno) );
+ if ( dowrite && write( fd, newpath, 1024 ) != 1024 )
+ fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
+ todo -= 1024;
+ }
+
+ if ( todo ) {
+ if ( read( ffd, newpath, todo ) != todo )
+ fatal_error(EXIT_FILESYS, "Error reading file \"%s\" at offset 0x%lX: %s\n", np->path, np->size - todo, strerror(errno) );
+ if ( dowrite && write( fd, newpath, todo ) != todo )
+ fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
+ }
+
+ close(ffd);
+
+}
+
+static void WriteDataBlocks( int fd, node *first ) {
+ for ( ; first ; first = first->next_in_rom ) {
+ if ( dowrite && lseek( fd, first->offset, SEEK_SET ) != first->offset )
+ fatal_error(EXIT_SEEK, "Error seeking to offset 0x%lX: %s\n", first->offset, strerror(errno) );
+ if ( IS_DIRECTORY( first->st_mode ) ) {
+ if ( dowrite && write( fd, first->entry, first->size ) != first->size )
+ fatal_error(EXIT_WRITE, "Write error: %s\n", strerror(errno) );
+ } else {
+ WriteData( fd, first );
+ }
+ }
+}
+
+static void usage(void) {
+ fprintf(stderr,"\n%s - Create an eCos ROMFS disk image from the files\n",prog);
+ fprintf(stderr,"%*s contained under a specified directory\n\n", strlen(prog), "");
+ fprintf(stderr,"Usage: %s [options] <fs_root> <fs_file>\n", prog);
+ fprintf(stderr," fs_root is the directory containing the files to package into the ROMFS image\n");
+ fprintf(stderr," fs_file is the name of the ROMFS image file to create\n");
+ fprintf(stderr," Options include:\n");
+ fprintf(stderr," -v / -q increase / decrease verbosity\n");
+ fprintf(stderr," -n do everything EXCEPT creating the output file\n");
+ fprintf(stderr," -b write a big-endian image (default is little endian)\n");
+ fprintf(stderr," -l collapse hard links to a single node\n");
+ fprintf(stderr,"\n");
+ exit(EXIT_ARGS);
+}
+
+int main(int ac, char *av[]) {
+ int dummy;
+
+ prog = av[0];
+
+ // Check structure sizes
+ if (sizeof(romfs_node) != 32) {
+ fatal_error(EXIT_COMPILE , "Size of romfs_node is %d, NOT 32\n", sizeof(romfs_node) );
+ } else if (sizeof(romfs_dirent) != 8) {
+ fatal_error(EXIT_COMPILE , "Size of romfs_dirent is %d, NOT 8\n", sizeof(romfs_dirent) );
+ } else if (sizeof(romfs_disk) != 32) {
+ fatal_error(EXIT_COMPILE , "Size of romfs_disk is %d, NOT 32\n", sizeof(romfs_disk) );
+ }
+
+ // Parse option arguments
+ while ( ac > 1 && av[1][0] == '-' ) {
+ char *o = &av[1][1];
+ for ( ; *o ; o++ ) {
+ switch ( *o ) {
+ case 'q' :
+ verbose--;
+ break;
+ case 'v' :
+ verbose++;
+ break;
+ case 'n' :
+ dowrite = 0;
+ break;
+ case 'b' :
+ bigendian = 1;
+ break;
+ case 'l' :
+ hardlinks = 1;
+ break;
+ default :
+ fprintf(stderr,"%s: Invalid flag -%c\n", prog, *o );
+ usage();
+ }
+ }
+ av++; ac--;
+ }
+
+ // Check remaining arguments
+ if ( ac != 3 ) usage();
+
+
+ verb_printf( VERB_MINIMUM, "%s: Verbosity %d %s%s endian\n",
+ prog, verbose,
+ dowrite ? "" : "no write, ",
+ bigendian ? "big" : "little" );
+
+ // Phase 1. Recursively scan the root directory for files and directories.
+ verb_printf(VERB_MINIMUM, "Phase 1 - Build file list\n");
+
+ first = GetNodeInfo( av[1], ".", &dummy ); // Initialize the root node entry.
+ ScanDirectory( first, 0 );
+
+ // Phase 2. Work out space allocations for filesystem
+ verb_printf(VERB_MINIMUM, "Phase 2 - Calculate space allocation\n");
+ coffset = sizeof(romfs_disk) + nodes * sizeof(romfs_node);
+ verb_printf(VERB_MAX,"\t\tnode table : 0x000000 (+0x%05lX) %d nodes\n", coffset, nodes );
+
+ // Phase 2a. Work out space allocations for the directories of the filesystem
+ verb_printf(VERB_SUB,"Phase 2a - * Directories\n");
+ coffset = ALIGN_TO( coffset, DIRECTORY_ALIGN );
+ AllocateSpaceToDirectories( first );
+
+ // Phase 2b. Work out space allocations for the data files of the filesystem
+ verb_printf(VERB_SUB,"Phase 2b - * Regular files\n");
+ coffset = ALIGN_TO( coffset, DATA_ALIGN );
+ AllocateSpaceToDataFiles( first );
+
+ // Phase 2c. Work out space allocations for the executable files of the filesystem
+ verb_printf(VERB_SUB,"Phase 2c - * Executable files\n");
+ coffset = ALIGN_TO( coffset, EXEC_ALIGN );
+ AllocateSpaceToExecutables( first );
+
+ // Round off the image size...
+ coffset = ALIGN_TO( coffset, EXEC_ALIGN );
+
+ // Phase 3. Write out the image file
+ verb_printf(VERB_MINIMUM, "Phase 3 - Construct ROMFS image file (%ld kb)\n", ALIGN_TO( coffset, 1024 )/1024);
+
+ if ( dowrite ) {
+ if ( (fd = open( av[2], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666 )) < 0 ) {
+ fatal_error(EXIT_WRITE,"Failed to open output file '%s', errno=%d\n", av[2], errno );
+ }
+ } else {
+ verb_printf(VERB_NONE," (No image is being written)\n");
+ }
+
+ verb_printf(VERB_SUB,"Phase 3a - * Node table\n");
+ WriteNodeTable( fd );
+
+ verb_printf(VERB_SUB,"Phase 3b - * Data blocks\n");
+ WriteDataBlocks( fd, first );
+
+ if ( fd >= 0 ) close(fd);
+
+ verb_printf(VERB_MINIMUM, "%s completed\n", av[2] );
+
+ return 0;
+}
diff --git a/cesar/ecos/packages/fs/rom/current/tests/romfs1.c b/cesar/ecos/packages/fs/rom/current/tests/romfs1.c
new file mode 100644
index 0000000000..1d32bb0421
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/tests/romfs1.c
@@ -0,0 +1,388 @@
+//==========================================================================
+//
+// romfs1.c
+//
+// Test fileio system
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2004 eCosCentric Limited
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
+// at http://sources.redhat.com/ecos/ecos-license/
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s): nickg
+// Contributors: nickg, richard.panton@3glab.com, jlarmour
+// Date: 2000-05-25
+// Purpose: Test fileio system
+// Description: This test uses the testfs to check out the initialization
+// and basic operation of the fileio system
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/hal.h>
+#include <pkgconf/io_fileio.h>
+#include <pkgconf/isoinfra.h>
+#include <pkgconf/system.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <dirent.h>
+#include <stdio.h>
+
+#include <cyg/fileio/fileio.h>
+
+#include <cyg/infra/cyg_type.h>
+#include <cyg/infra/testcase.h>
+#include <cyg/infra/diag.h> // HAL polled output
+
+// Test ROMFS data. Two example data files are generated so that
+// the test will work on both big-endian and little-endian targets.
+#if (CYG_BYTEORDER == CYG_LSBFIRST)
+# include <cyg/romfs/testromfs_le.h>
+#else
+# include <cyg/romfs/testromfs_be.h>
+#endif
+
+//==========================================================================
+
+MTAB_ENTRY( romfs_mte1,
+ "/",
+ "romfs",
+ "",
+ (CYG_ADDRWORD) &filedata[0] );
+
+
+//==========================================================================
+
+#define SHOW_RESULT( _fn, _res ) \
+diag_printf("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):"");
+
+#define CHKFAIL_TYPE( _fn, _res, _type ) { \
+if ( _res != -1 ) \
+ diag_printf("<FAIL>: " #_fn "() returned %d (expected -1)\n", _res); \
+else if ( errno != _type ) \
+ diag_printf("<FAIL>: " #_fn "() failed with errno %d (%s),\n expected %d (%s)\n", errno, strerror(errno), _type, strerror(_type) ); \
+}
+
+//==========================================================================
+
+#define IOSIZE 100
+
+#define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1"
+#define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2"
+
+
+//==========================================================================
+
+#ifndef CYGINT_ISO_STRING_STRFUNCS
+
+char *strcat( char *s1, const char *s2 )
+{
+ char *s = s1;
+ while( *s1 ) s1++;
+ while( (*s1++ = *s2++) != 0);
+ return s;
+}
+
+#endif
+
+//==========================================================================
+
+static void listdir( char *name, int statp )
+{
+ int err;
+ DIR *dirp;
+
+ diag_printf("<INFO>: reading directory %s\n",name);
+
+ dirp = opendir( name );
+ if( dirp == NULL ) SHOW_RESULT( opendir, -1 );
+
+ for(;;)
+ {
+ struct dirent *entry = readdir( dirp );
+
+ if( entry == NULL )
+ break;
+
+ diag_printf("<INFO>: entry %14s",entry->d_name);
+ if( statp )
+ {
+ char fullname[PATH_MAX];
+ struct stat sbuf;
+
+ if( name[0] )
+ {
+ strcpy(fullname, name );
+ if( !(name[0] == '/' && name[1] == 0 ) )
+ strcat(fullname, "/" );
+ }
+ else fullname[0] = 0;
+
+ strcat(fullname, entry->d_name );
+
+ err = stat( fullname, &sbuf );
+ if( err < 0 )
+ {
+ if( errno == ENOSYS )
+ diag_printf(" <no status available>");
+ else SHOW_RESULT( stat, err );
+ }
+ else
+ {
+ diag_printf(" [mode %08x ino %08x nlink %d size %d]",
+ sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,sbuf.st_size);
+ }
+ }
+
+ diag_printf("\n");
+ }
+
+ err = closedir( dirp );
+ if( err < 0 ) SHOW_RESULT( stat, err );
+}
+
+//==========================================================================
+
+#ifdef CYGPKG_FS_RAM
+static void copyfile( char *name2, char *name1 )
+{
+
+ int err;
+ char buf[IOSIZE];
+ int fd1, fd2;
+ ssize_t done, wrote;
+
+ diag_printf("<INFO>: copy file %s -> %s\n",name2,name1);
+
+ err = access( name1, F_OK );
+ if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err );
+
+ err = access( name2, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ fd1 = open( name1, O_WRONLY|O_CREAT );
+ if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+ fd2 = open( name2, O_RDONLY );
+ if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+
+ for(;;)
+ {
+ done = read( fd2, buf, IOSIZE );
+ if( done < 0 ) SHOW_RESULT( read, done );
+
+ if( done == 0 ) break;
+
+ wrote = write( fd1, buf, done );
+ if( wrote != done ) SHOW_RESULT( write, wrote );
+
+ if( wrote != done ) break;
+ }
+
+ err = close( fd1 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+ err = close( fd2 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+}
+#endif
+
+//==========================================================================
+
+static void comparefiles( char *name2, char *name1 )
+{
+ int err;
+ char buf1[IOSIZE];
+ char buf2[IOSIZE];
+ int fd1, fd2;
+ ssize_t done1, done2;
+ int i;
+
+ diag_printf("<INFO>: compare files %s == %s\n",name2,name1);
+
+ err = access( name1, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ err = access( name1, F_OK );
+ if( err != 0 ) SHOW_RESULT( access, err );
+
+ fd1 = open( name1, O_RDONLY );
+ if( fd1 < 0 ) SHOW_RESULT( open, fd1 );
+
+ fd2 = open( name2, O_RDONLY );
+ if( fd2 < 0 ) SHOW_RESULT( open, fd2 );
+
+ for(;;)
+ {
+ done1 = read( fd1, buf1, IOSIZE );
+ if( done1 < 0 ) SHOW_RESULT( read, done1 );
+
+ done2 = read( fd2, buf2, IOSIZE );
+ if( done2 < 0 ) SHOW_RESULT( read, done2 );
+
+ if( done1 != done2 )
+ diag_printf("Files different sizes\n");
+
+ if( done1 == 0 ) break;
+
+ for( i = 0; i < done1; i++ )
+ if( buf1[i] != buf2[i] )
+ {
+ diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]);
+ CYG_TEST_FAIL("Data in files not equal\n");
+ }
+ }
+
+ err = close( fd1 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+ err = close( fd2 );
+ if( err < 0 ) SHOW_RESULT( close, err );
+
+}
+
+//==========================================================================
+// main
+
+int main( int argc, char **argv )
+{
+ int err;
+ char address[16];
+
+ CYG_TEST_INIT();
+
+ // --------------------------------------------------------------
+
+ diag_printf("<INFO>: ROMFS root follows\n");
+ listdir( "/", true );
+
+ diag_printf("<INFO>: cd /etc\n" );
+ err = chdir( "/etc" );
+ if ( err < 0 ) {
+ SHOW_RESULT( chdir, err );
+ CYG_TEST_FAIL_FINISH("romfs1");
+ }
+
+ diag_printf("<INFO>: ROMFS list of '' follows\n");
+ listdir( "", true );
+
+ diag_printf("<INFO>: ROMFS list of /etc follows\n");
+ listdir( "/etc", true );
+
+ diag_printf("<INFO>: ROMFS list of . follows\n");
+ listdir( ".", true );
+
+#ifdef CYGPKG_FS_RAM
+ err = mount( "", "/var", "ramfs" );
+ if( err < 0 ) SHOW_RESULT( mount, err );
+
+ copyfile( "/etc/passwd", "/var/passwd_copy" );
+
+ comparefiles( "/etc/passwd", "/var/passwd_copy" );
+#endif
+
+ diag_printf("<INFO>: ROMFS list of / follows\n");
+#ifdef CYGPKG_FS_RAM
+ diag_printf("<INFO>: Note that /var now gives stat() info for RAMFS\n");
+#endif
+ listdir( "/", true );
+
+ diag_printf("<INFO>: Mount ROMFS again onto /mnt\n");
+ sprintf( address, "%p", (void*)&filedata[0] );
+ err = mount( address, "/mnt", "romfs" );
+ if( err < 0 ) SHOW_RESULT( mount, err );
+
+ comparefiles( "/etc/passwd", "/mnt/etc/passwd" );
+
+
+ err = mkdir( "/foo", 0 );
+ CHKFAIL_TYPE( mkdir, err, EROFS );
+
+ err = rename( "/var", "/tmp" ); // RAMFS is mounted here
+#ifdef CYGPKG_FS_RAM
+ CHKFAIL_TYPE( rename, err, EXDEV );
+#else
+ CHKFAIL_TYPE( rename, err, EROFS );
+#endif
+
+ err = rename( "/var/passwd_copy", "/mnt/etc/passwd_copy" );
+ CHKFAIL_TYPE( rename, err, EXDEV );
+
+ err = rename( "/etc", "/tmp" );
+ CHKFAIL_TYPE( rename, err, EROFS );
+
+ diag_printf("<INFO>: cd /etc\n");
+ err = chdir( "/etc" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ err = chdir( "/mnt/etc" );
+ if( err < 0 ) SHOW_RESULT( chdir, err );
+
+ listdir( ".", true );
+
+ diag_printf("<INFO>: unlink /tmp\n");
+ err = unlink( "/tmp" );
+ CHKFAIL_TYPE( unlink, err, EROFS );
+
+ diag_printf("<INFO>: mount random area\n");
+ sprintf(address, "%p", (void*)(&filedata[0] + 0x100));
+ err = mount( address, "/tmp", "romfs" );
+ CHKFAIL_TYPE( mount, err, ENOENT );
+
+ err = umount( "/mnt" );
+ if( err < 0 ) SHOW_RESULT( umount, err );
+
+ err = umount( "/var" );
+#ifdef CYGPKG_FS_RAM
+ if( err < 0 ) SHOW_RESULT( umount, err );
+#else
+ CHKFAIL_TYPE( umount, err, EINVAL );
+#endif
+
+ err = umount( "/" );
+ if( err < 0 ) SHOW_RESULT( umount, err );
+
+
+ CYG_TEST_PASS_FINISH("romfs1");
+}
+
+// -------------------------------------------------------------------------
+// EOF romfs1.c
diff --git a/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/hosts b/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/hosts
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/hosts
diff --git a/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/inetd b/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/inetd
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/inetd
diff --git a/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/passwd b/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/passwd
new file mode 100644
index 0000000000..85aa954e56
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/tests/testromfs/etc/passwd
@@ -0,0 +1,32 @@
+root:x:0:0:root:/root:/bin/bash
+daemon:x:1:1:daemon:/usr/sbin:/bin/sh
+bin:x:2:2:bin:/bin:/bin/sh
+sys:x:3:3:sys:/dev:/bin/sh
+sync:x:4:100:sync:/bin:/bin/sync
+games:x:5:100:games:/usr/games:/bin/sh
+man:x:6:100:man:/var/cache/man:/bin/sh
+lp:x:7:7:lp:/var/spool/lpd:/bin/sh
+mail:x:8:8:mail:/var/spool/mail:/bin/sh
+news:x:9:9:news:/var/spool/news:/bin/sh
+uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
+proxy:x:13:13:proxy:/bin:/bin/sh
+majordom:x:30:31:Majordomo:/usr/lib/majordomo:/bin/sh
+postgres:x:31:32:postgres:/var/lib/postgres:/bin/sh
+www-data:x:33:33:www-data:/var/www:/bin/sh
+backup:x:34:34:backup:/var/backups:/bin/sh
+msql:x:36:36:Mini SQL Database Manager:/var/lib/msql:/bin/sh
+operator:x:37:37:Operator:/var:/bin/sh
+list:x:38:38:SmartList:/var/list:/bin/sh
+irc:x:39:39:ircd:/var:/bin/sh
+gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats/gnats-db:/bin/sh
+alias:x:70:65534:qmail alias:/var/qmail/alias:/bin/sh
+qmaild:x:71:65534:qmail daemon:/var/qmail:/bin/sh
+qmails:x:72:70:qmail send:/var/qmail:/bin/sh
+qmailr:x:73:70:qmail remote:/var/qmail:/bin/sh
+qmailq:x:74:70:qmail queue:/var/qmail:/bin/sh
+qmaill:x:75:65534:qmail log:/var/qmail:/bin/sh
+qmailp:x:76:65534:qmail pw:/var/qmail:/bin/sh
+ftp:x:60000:65534::/lhome/ftp:/bin/false
+nobody:x:65534:65534:nobody:/home:/bin/sh
+identd:x:60001:65534::/var/run/identd:/bin/false
+telnetd:x:60002:60002::/usr/lib/telnetd:/bin/false
diff --git a/cesar/ecos/packages/fs/rom/current/tests/testromfs/mnt/thing b/cesar/ecos/packages/fs/rom/current/tests/testromfs/mnt/thing
new file mode 100644
index 0000000000..45b983be36
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/tests/testromfs/mnt/thing
@@ -0,0 +1 @@
+hi
diff --git a/cesar/ecos/packages/fs/rom/current/tests/testromfs/var/foobar b/cesar/ecos/packages/fs/rom/current/tests/testromfs/var/foobar
new file mode 100644
index 0000000000..9cbcf6fc1a
--- /dev/null
+++ b/cesar/ecos/packages/fs/rom/current/tests/testromfs/var/foobar
@@ -0,0 +1 @@
+flibble