summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src')
-rw-r--r--cpukit/libfs/src/imfs/deviceio.c215
-rw-r--r--cpukit/libfs/src/imfs/imfs.h445
-rw-r--r--cpukit/libfs/src/imfs/imfs_chown.c52
-rw-r--r--cpukit/libfs/src/imfs/imfs_creat.c130
-rw-r--r--cpukit/libfs/src/imfs/imfs_debug.c160
-rw-r--r--cpukit/libfs/src/imfs/imfs_directory.c278
-rw-r--r--cpukit/libfs/src/imfs/imfs_eval.c638
-rw-r--r--cpukit/libfs/src/imfs/imfs_fchmod.c55
-rw-r--r--cpukit/libfs/src/imfs/imfs_free.c99
-rw-r--r--cpukit/libfs/src/imfs/imfs_getchild.c68
-rw-r--r--cpukit/libfs/src/imfs/imfs_gtkn.c84
-rw-r--r--cpukit/libfs/src/imfs/imfs_init.c158
-rw-r--r--cpukit/libfs/src/imfs/imfs_initsupp.c158
-rw-r--r--cpukit/libfs/src/imfs/imfs_link.c72
-rw-r--r--cpukit/libfs/src/imfs/imfs_mknod.c76
-rw-r--r--cpukit/libfs/src/imfs/imfs_mount.c49
-rw-r--r--cpukit/libfs/src/imfs/imfs_ntype.c29
-rw-r--r--cpukit/libfs/src/imfs/imfs_readlink.c40
-rw-r--r--cpukit/libfs/src/imfs/imfs_rmnod.c97
-rw-r--r--cpukit/libfs/src/imfs/imfs_stat.c59
-rw-r--r--cpukit/libfs/src/imfs/imfs_symlink.c60
-rw-r--r--cpukit/libfs/src/imfs/imfs_unlink.c67
-rw-r--r--cpukit/libfs/src/imfs/imfs_unmount.c58
-rw-r--r--cpukit/libfs/src/imfs/imfs_utime.c38
-rw-r--r--cpukit/libfs/src/imfs/ioman.c83
-rw-r--r--cpukit/libfs/src/imfs/memfile.c1000
26 files changed, 4268 insertions, 0 deletions
diff --git a/cpukit/libfs/src/imfs/deviceio.c b/cpukit/libfs/src/imfs/deviceio.c
new file mode 100644
index 0000000000..f954decf6e
--- /dev/null
+++ b/cpukit/libfs/src/imfs/deviceio.c
@@ -0,0 +1,215 @@
+/*
+ * IMFS Device Node Handlers
+ *
+ * This file contains the set of handlers used to map operations on
+ * IMFS device nodes onto calls to the RTEMS Classic API IO Manager.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+#include "imfs.h"
+
+/*
+ * device_open
+ *
+ * This handler maps an open() operation onto rtems_io_open().
+ */
+
+int device_open(
+ rtems_libio_t *iop,
+ const char *pathname,
+ unsigned32 flag,
+ unsigned32 mode
+)
+{
+ rtems_libio_open_close_args_t args;
+ rtems_status_code status;
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ args.iop = iop;
+ args.flags = iop->flags;
+ args.mode = mode;
+
+ status = rtems_io_open(
+ the_jnode->info.device.major,
+ the_jnode->info.device.minor,
+ (void *) &args
+ );
+ if ( status )
+ return RTEMS_UNSATISFIED;
+
+ return 0;
+}
+
+/*
+ * device_close
+ *
+ * This handler maps a close() operation onto rtems_io_close().
+ */
+
+int device_close(
+ rtems_libio_t *iop
+)
+{
+ rtems_libio_open_close_args_t args;
+ rtems_status_code status;
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ args.iop = iop;
+ args.flags = 0;
+ args.mode = 0;
+
+ status = rtems_io_close(
+ the_jnode->info.device.major,
+ the_jnode->info.device.minor,
+ (void *) &args
+ );
+ if ( status )
+ return RTEMS_UNSATISFIED;
+
+ return 0;
+}
+
+/*
+ * device_read
+ *
+ * This handler maps a read() operation onto rtems_io_read().
+ */
+
+int device_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ unsigned32 count
+)
+{
+ rtems_libio_rw_args_t args;
+ rtems_status_code status;
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ args.iop = iop;
+ args.offset = iop->offset;
+ args.buffer = buffer;
+ args.count = count;
+ args.flags = iop->flags;
+ args.bytes_moved = 0;
+
+ status = rtems_io_read(
+ the_jnode->info.device.major,
+ the_jnode->info.device.minor,
+ (void *) &args
+ );
+
+ if ( status )
+ return -1;
+
+ return args.bytes_moved;
+}
+
+/*
+ * device_write
+ *
+ * This handler maps a write() operation onto rtems_io_write().
+ */
+
+int device_write(
+ rtems_libio_t *iop,
+ const void *buffer,
+ unsigned32 count
+)
+{
+ rtems_libio_rw_args_t args;
+ rtems_status_code status;
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ args.iop = iop;
+ args.offset = iop->offset;
+ args.buffer = (void *) buffer;
+ args.count = count;
+ args.flags = iop->flags;
+ args.bytes_moved = 0;
+
+ status = rtems_io_write(
+ the_jnode->info.device.major,
+ the_jnode->info.device.minor,
+ (void *) &args
+ );
+
+ if ( status )
+ return -1;
+
+ return args.bytes_moved;
+}
+
+/*
+ * device_ioctl
+ *
+ * This handler maps an ioctl() operation onto rtems_io_ioctl().
+ */
+
+int device_ioctl(
+ rtems_libio_t *iop,
+ unsigned32 command,
+ void *buffer
+)
+{
+ rtems_libio_ioctl_args_t args;
+ rtems_status_code status;
+ IMFS_jnode_t *the_jnode;
+
+ args.iop = iop;
+ args.command = command;
+ args.buffer = buffer;
+
+ the_jnode = iop->file_info;
+
+ status = rtems_io_control(
+ the_jnode->info.device.major,
+ the_jnode->info.device.minor,
+ (void *) &args
+ );
+
+ if ( status )
+ return -1;
+
+ return args.ioctl_return;
+}
+
+/*
+ * device_lseek
+ *
+ * This handler eats all lseek() operations.
+ */
+
+int device_lseek(
+ rtems_libio_t *iop,
+ off_t offset,
+ int whence
+)
+{
+ return 0;
+}
+
+/*
+ * device_stat
+ *
+ * This IMFS_stat() is used.
+ */
diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h
new file mode 100644
index 0000000000..6eb535527d
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs.h
@@ -0,0 +1,445 @@
+/*
+ * Header file for the In-Memory File System
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#ifndef __IMFS_h
+#define __IMFS_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <chain.h>
+
+#include <sys/types.h>
+#include <limits.h>
+#include <rtems/libio.h>
+
+/*
+ * File name macros
+ */
+
+#define IMFS_is_valid_name_char( _ch ) ( 1 )
+
+#define IMFS_is_separator( _ch ) \
+ rtems_filesystem_is_separator( _ch )
+
+/*
+ * Data types
+ */
+
+struct IMFS_jnode_tt;
+typedef struct IMFS_jnode_tt IMFS_jnode_t;
+
+typedef struct {
+ Chain_Control Entries;
+ rtems_filesystem_mount_table_entry_t *mt_fs;
+} IMFS_directory_t;
+
+typedef struct {
+ rtems_device_major_number major;
+ rtems_device_minor_number minor;
+} IMFS_device_t;
+
+typedef struct {
+ IMFS_jnode_t *link_node;
+} IMFS_link_t;
+
+typedef struct {
+ const char *name;
+} IMFS_sym_link_t;
+
+/*
+ * IMFS "memfile" information
+ *
+ * The data structure for the in-memory "memfiles" is based on classic UNIX.
+ *
+ * block_ptr is a pointer to a block of IMFS_MEMFILE_BYTES_PER_BLOCK in
+ * length which could be data or a table of pointers to blocks.
+ */
+
+#define IMFS_MEMFILE_BYTES_PER_BLOCK 64 /* 512 */
+#define IMFS_MEMFILE_BLOCK_SLOTS \
+ (IMFS_MEMFILE_BYTES_PER_BLOCK / sizeof(void *))
+
+typedef unsigned char * block_p;
+typedef block_p *block_ptr;
+
+typedef struct {
+ off_t size; /* size of file in bytes */
+ block_ptr indirect; /* array of 128 data blocks pointers */
+ block_ptr doubly_indirect; /* 128 indirect blocks */
+ block_ptr triply_indirect; /* 128 doubly indirect blocks */
+} IMFS_memfile_t;
+
+/*
+ * Important block numbers for "memfiles"
+ */
+
+#define FIRST_INDIRECT (0)
+#define LAST_INDIRECT (IMFS_MEMFILE_BLOCK_SLOTS - 1)
+
+#define FIRST_DOUBLY_INDIRECT (LAST_INDIRECT + 1)
+#define LAST_DOUBLY_INDIRECT \
+ (LAST_INDIRECT + \
+ (IMFS_MEMFILE_BLOCK_SLOTS * IMFS_MEMFILE_BLOCK_SLOTS))
+
+#define FIRST_TRIPLY_INDIRECT (LAST_DOUBLY_INDIRECT + 1)
+#define LAST_TRIPLY_INDIRECT \
+ (LAST_DOUBLY_INDIRECT +\
+ (IMFS_MEMFILE_BLOCK_SLOTS * \
+ IMFS_MEMFILE_BLOCK_SLOTS * IMFS_MEMFILE_BLOCK_SLOTS))
+
+#define IMFS_MEMFILE_MAXIMUM_SIZE \
+ (LAST_TRIPLY_INDIRECT * IMFS_MEMFILE_BYTES_PER_BLOCK)
+
+/*
+ * What types of IMFS file systems entities there can be.
+ */
+
+#define IMFS_jnode_types_t rtems_filesystem_node_types_t
+#define IMFS_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define IMFS_DEVICE RTEMS_FILESYSTEM_DEVICE
+#define IMFS_HARD_LINK RTEMS_FILESYSTEM_HARD_LINK
+#define IMFS_SYM_LINK RTEMS_FILESYSTEM_SYM_LINK
+#define IMFS_MEMORY_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+#define IMFS_NUMBER_OF_TYPES (IMFS_MEMORY_FILE + 1)
+
+typedef union {
+ IMFS_directory_t directory;
+ IMFS_device_t device;
+ IMFS_link_t hard_link;
+ IMFS_sym_link_t sym_link;
+ IMFS_memfile_t file;
+} IMFS_types_union;
+
+/*
+ * The control structure for an IMFS jnode.
+ */
+
+struct IMFS_jnode_tt {
+ Chain_Node Node; /* for chaining them together */
+ IMFS_jnode_t *Parent; /* Parent node */
+ char name[NAME_MAX+1]; /* "basename" */
+ mode_t st_mode; /* File mode */
+ nlink_t st_nlink; /* Link count */
+ ino_t st_ino; /* inode */
+
+ uid_t st_uid; /* User ID of owner */
+ gid_t st_gid; /* Group ID of owner */
+
+ time_t st_atime; /* Time of last access */
+ time_t st_mtime; /* Time of last modification */
+ time_t st_ctime; /* Time of last status change */
+ IMFS_jnode_types_t type; /* Type of this entry */
+ IMFS_types_union info;
+};
+
+#define IMFS_update_atime( _jnode ) \
+ do { \
+ struct timeval tv; \
+ gettimeofday( &tv, 0 ); \
+ _jnode->st_atime = (time_t) tv.tv_sec; \
+ } while (0)
+
+#define IMFS_update_mtime( _jnode ) \
+ do { \
+ struct timeval tv; \
+ gettimeofday( &tv, 0 ); \
+ _jnode->st_mtime = (time_t) tv.tv_sec; \
+ } while (0)
+
+#define IMFS_update_ctime( _jnode ) \
+ do { \
+ struct timeval tv; \
+ gettimeofday( &tv, 0 ); \
+ _jnode->st_ctime = (time_t) tv.tv_sec; \
+ } while (0)
+
+#define IMFS_atime_mtime_update( _jnode ) \
+ do { \
+ struct timeval tv; \
+ gettimeofday( &tv, 0 ); \
+ _jnode->st_mtime = (time_t) tv.tv_sec; \
+ _jnode->st_atime = (time_t) tv.tv_sec; \
+ } while (0)
+
+typedef struct {
+ ino_t ino_count;
+} IMFS_fs_info_t;
+
+#define increment_and_check_linkcounts( _fs_info ) \
+ ((IMFS_fs_info_t * )_fs_info)->link_counts++; \
+ if ( ((IMFS_fs_info_t * )_fs_info)->link_counts > MAXSYMLINKS ) \
+ set_errno_and_return_minus_one( ELOOP )
+
+#define decrement_linkcounts( _fs_info ) \
+ ((IMFS_fs_info_t * )_fs_info)->link_counts--;
+
+/*
+ * Type defination for tokens returned from IMFS_get_token
+ */
+
+typedef enum {
+ IMFS_NO_MORE_PATH,
+ IMFS_CURRENT_DIR,
+ IMFS_UP_DIR,
+ IMFS_NAME,
+ IMFS_INVALID_TOKEN
+} IMFS_token_types;
+
+/*
+ * Shared Data
+ */
+
+extern rtems_filesystem_file_handlers_r device_handlers;
+extern rtems_filesystem_file_handlers_r memfile_handlers;
+extern rtems_filesystem_file_handlers_r dir_handlers;
+extern rtems_filesystem_file_handlers_r null_handlers;
+extern rtems_filesystem_operations_table IMFS_ops;
+extern rtems_filesystem_limits_and_options_t IMFS_LIMITS_AND_OPTIONS;
+
+/*
+ * Routines
+ */
+
+int IMFS_initialize(
+ rtems_filesystem_mount_table_entry_t *mt_entry
+);
+
+int IMFS_fsunmount(
+ rtems_filesystem_mount_table_entry_t *mt_entry
+);
+
+
+/*
+ * Returns the number of characters copied from path to token.
+ */
+IMFS_token_types IMFS_get_token(
+ const char *path,
+ char *token,
+ int *token_len
+);
+
+void IMFS_dump( void );
+
+void IMFS_initialize_jnode(
+ IMFS_jnode_t *the_jnode,
+ IMFS_jnode_types_t type,
+ IMFS_jnode_t *the_parent,
+ char *name,
+ mode_t mode
+);
+
+IMFS_jnode_t *IMFS_find_match_in_dir(
+ IMFS_jnode_t *directory, /* IN */
+ char *name /* IN */
+);
+
+rtems_filesystem_node_types_t IMFS_node_type(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+);
+
+int IMFS_stat(
+ rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */
+);
+
+int IMFS_evaluate_link(
+ rtems_filesystem_location_info_t *node, /* IN/OUT */
+ int flags /* IN */
+);
+
+int IMFS_eval_path(
+ const char *pathname, /* IN */
+ int flags, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */
+);
+
+
+int IMFS_link(
+ rtems_filesystem_location_info_t *to_loc, /* IN */
+ rtems_filesystem_location_info_t *parent_loc, /* IN */
+ const char *token /* IN */
+);
+
+int IMFS_unlink(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+);
+
+int IMFS_chown(
+ rtems_filesystem_location_info_t *pathloc, /* IN */
+ uid_t owner, /* IN */
+ gid_t group /* IN */
+);
+
+int IMFS_freenodinfo(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+);
+
+int IMFS_rmnod(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+);
+
+int IMFS_mknod(
+ const char *path, /* IN */
+ mode_t mode, /* IN */
+ dev_t dev, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */
+);
+
+IMFS_jnode_t *IMFS_create_node(
+ rtems_filesystem_location_info_t *parent_loc, /* IN */
+ IMFS_jnode_types_t type, /* IN */
+ char *name, /* IN */
+ mode_t mode, /* IN */
+ IMFS_types_union *info /* IN */
+);
+
+int IMFS_evaluate_for_make(
+ const char *path, /* IN */
+ rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
+ const char **name /* OUT */
+);
+
+int IMFS_mount(
+ rtems_filesystem_mount_table_entry_t *mt_entry /* IN */
+);
+
+int IMFS_unmount(
+ rtems_filesystem_mount_table_entry_t *mt_entry /* IN */
+);
+
+int IMFS_freenod(
+ rtems_filesystem_location_info_t *node /* IN/OUT */
+);
+
+int IMFS_memfile_remove(
+ IMFS_jnode_t *the_jnode /* IN/OUT */
+);
+
+int memfile_ftruncate(
+ rtems_libio_t *iop, /* IN */
+ off_t length /* IN */
+);
+int imfs_dir_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+int imfs_dir_close(
+ rtems_libio_t *iop /* IN */
+);
+int imfs_dir_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+int imfs_dir_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+int imfs_dir_fstat(
+ rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */
+);
+int memfile_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+int memfile_close(
+ rtems_libio_t *iop /* IN */
+);
+int memfile_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+int memfile_write(
+ rtems_libio_t *iop, /* IN */
+ const void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+int memfile_ioctl(
+ rtems_libio_t *iop, /* IN */
+ unsigned32 command, /* IN */
+ void *buffer /* IN */
+);
+int memfile_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+int device_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+int device_close(
+ rtems_libio_t *iop /* IN */
+);
+int device_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+int device_write(
+ rtems_libio_t *iop, /* IN */
+ const void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+int device_ioctl(
+ rtems_libio_t *iop, /* IN */
+ unsigned32 command, /* IN */
+ void *buffer /* IN */
+);
+int device_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+int IMFS_utime(
+ rtems_filesystem_location_info_t *pathloc, /* IN */
+ time_t actime, /* IN */
+ time_t modtime /* IN */
+);
+int IMFS_fchmod(
+ rtems_filesystem_location_info_t *loc,
+ mode_t mode
+);
+
+int IMFS_symlink(
+ rtems_filesystem_location_info_t *parent_loc, /* IN */
+ const char *link_name,
+ const char *node_name
+);
+
+int IMFS_readlink(
+ rtems_filesystem_location_info_t *loc, /* IN */
+ char *buf, /* OUT */
+ size_t bufsize
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* end of include file */
diff --git a/cpukit/libfs/src/imfs/imfs_chown.c b/cpukit/libfs/src/imfs/imfs_chown.c
new file mode 100644
index 0000000000..816294ee34
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_chown.c
@@ -0,0 +1,52 @@
+/*
+ * IMFS_chown
+ *
+ * This routine is the implementation of the chown() system
+ * call for the IMFS.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "libio_.h"
+#include "imfs.h"
+
+int IMFS_chown(
+ rtems_filesystem_location_info_t *pathloc, /* IN */
+ uid_t owner, /* IN */
+ gid_t group /* IN */
+)
+{
+ IMFS_jnode_t *jnode;
+#if defined(RTEMS_POSIX_API)
+ uid_t st_uid;
+#endif
+
+ jnode = (IMFS_jnode_t *) pathloc->node_access;
+
+ /*
+ * Verify I am the owner of the node or the super user.
+ */
+
+#if defined(RTEMS_POSIX_API)
+ st_uid = geteuid();
+
+ if ( ( st_uid != jnode->st_uid ) && ( st_uid != 0 ) )
+ set_errno_and_return_minus_one( EPERM );
+#endif
+
+ jnode->st_uid = owner;
+ jnode->st_gid = group;
+
+ IMFS_update_ctime( jnode );
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_creat.c b/cpukit/libfs/src/imfs/imfs_creat.c
new file mode 100644
index 0000000000..fd38e7f993
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_creat.c
@@ -0,0 +1,130 @@
+/*
+ * IMFS_create_node()
+ *
+ * Routine to create a new in memory file system node.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "imfs.h"
+#include "libio_.h"
+
+IMFS_jnode_t *IMFS_create_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ IMFS_jnode_types_t type,
+ char *name,
+ mode_t mode,
+ IMFS_types_union *info
+)
+{
+ IMFS_jnode_t *node;
+ struct timeval tv;
+ IMFS_jnode_t *parent = NULL;
+ IMFS_fs_info_t *fs_info;
+ char *sym_name;
+
+ if ( parent_loc != NULL )
+ parent = parent_loc->node_access;
+
+ /*
+ * Allocate an IMFS jnode
+ */
+
+ node = calloc( 1, sizeof( IMFS_jnode_t ) );
+ if ( !node )
+ return NULL;
+
+ /*
+ * Fill in the basic information
+ */
+
+ node->st_nlink = 1;
+ node->type = type;
+ strncpy( node->name, name, NAME_MAX );
+
+ /*
+ * Fill in the mode and permission information for the jnode structure.
+ */
+
+ node->st_mode = mode & ~rtems_filesystem_umask;
+
+#if defined(RTEMS_POSIX_API)
+ node->st_uid = geteuid();
+ node->st_gid = getegid();
+#else
+ node->st_uid = 0;
+ node->st_gid = 0;
+#endif
+
+ /*
+ * Now set all the times.
+ */
+
+ gettimeofday( &tv, 0 );
+
+ node->st_atime = (time_t) tv.tv_sec;
+ node->st_mtime = (time_t) tv.tv_sec;
+ node->st_ctime = (time_t) tv.tv_sec;
+
+ /*
+ * Set the type specific information
+ */
+
+ switch (type) {
+ case IMFS_DIRECTORY:
+ Chain_Initialize_empty(&node->info.directory.Entries);
+ break;
+
+ case IMFS_HARD_LINK:
+ node->info.hard_link.link_node = info->hard_link.link_node;
+ break;
+
+ case IMFS_SYM_LINK:
+ sym_name = calloc( 1, strlen( info->sym_link.name ) + 1 );
+ strcpy( sym_name, info->sym_link.name );
+ node->info.sym_link.name = sym_name;
+ break;
+
+ case IMFS_DEVICE:
+ node->info.device.major = info->device.major;
+ node->info.device.minor = info->device.minor;
+ break;
+
+ case IMFS_MEMORY_FILE:
+ node->info.file.size = 0;
+ node->info.file.indirect = 0;
+ node->info.file.doubly_indirect = 0;
+ node->info.file.triply_indirect = 0;
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ /*
+ * If this node has a parent, then put it in that directory list.
+ */
+
+ if ( parent ) {
+ Chain_Append( &parent->info.directory.Entries, &node->Node );
+ node->Parent = parent;
+
+ fs_info = parent_loc->mt_entry->fs_info;
+ node->st_ino = ++fs_info->ino_count;
+ }
+
+
+ return node;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_debug.c b/cpukit/libfs/src/imfs/imfs_debug.c
new file mode 100644
index 0000000000..856f21317e
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_debug.c
@@ -0,0 +1,160 @@
+/*
+ * IMFS debug support routines
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h> /* for close */
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+/*
+ * IMFS_types
+ *
+ * Printable names for each of the IMFS file system types.
+ */
+
+char *IMFS_types[ IMFS_NUMBER_OF_TYPES ] = {
+ "directory",
+ "device",
+ "link",
+ "memory file"
+};
+
+/*
+ * IMFS_print_jnode
+ *
+ * This routine prints the contents of the specified jnode.
+ */
+
+void IMFS_print_jnode(
+ IMFS_jnode_t *the_jnode
+)
+{
+ assert( the_jnode );
+
+ printf( "%s", the_jnode->name );
+ switch( the_jnode->type ) {
+ case IMFS_DIRECTORY:
+ printf( "/" );
+ break;
+
+ case IMFS_DEVICE:
+ printf( " (device %d, %d)",
+ the_jnode->info.device.major, the_jnode->info.device.minor );
+ break;
+
+ case IMFS_MEMORY_FILE:
+ printf( " (file %d %p %p %p)",
+ (int)the_jnode->info.file.size,
+ the_jnode->info.file.indirect,
+ the_jnode->info.file.doubly_indirect,
+ the_jnode->info.file.triply_indirect
+ );
+ break;
+
+ case IMFS_HARD_LINK:
+ printf( " links not printed\n" );
+ assert(0);
+ break;
+
+ case IMFS_SYM_LINK:
+ printf( " links not printed\n" );
+ assert(0);
+ break;
+
+ default:
+ printf( " bad type %d\n", the_jnode->type );
+ assert(0);
+ break;
+ }
+ puts("");
+}
+
+/*
+ * IMFS_dump_directory
+ *
+ * This routine prints the contents of a directory in the IMFS. If a
+ * directory is encountered, then this routine will recurse to process
+ * the subdirectory.
+ */
+
+void IMFS_dump_directory(
+ IMFS_jnode_t *the_directory,
+ int level
+)
+{
+ Chain_Node *the_node;
+ Chain_Control *the_chain;
+ IMFS_jnode_t *the_jnode;
+ int i;
+
+ assert( the_directory );
+
+ assert( level >= 0 );
+
+ assert( the_directory->type == IMFS_DIRECTORY );
+
+ the_chain = &the_directory->info.directory.Entries;
+
+ for ( the_node = the_chain->first;
+ !_Chain_Is_tail( the_chain, the_node );
+ the_node = the_node->next ) {
+
+ the_jnode = (IMFS_jnode_t *) the_node;
+
+ for ( i=0 ; i<=level ; i++ )
+ printf( " " );
+ IMFS_print_jnode( the_jnode );
+ if ( the_jnode->type == IMFS_DIRECTORY )
+ IMFS_dump_directory( the_jnode, level + 1 );
+ }
+}
+
+/*
+ * IMFS_dump
+ *
+ * This routine dumps the entire IMFS that is mounted at the root
+ * directory.
+ *
+ * NOTE: Assuming the "/" directory is bad.
+ * Not checking that the starting directory is in an IMFS is bad.
+ */
+
+void IMFS_dump( void )
+{
+ printf( "*************** Dump of Entire IMFS ***************\n" );
+ printf( "/\n" );
+ IMFS_dump_directory( rtems_filesystem_root.node_access, 0 );
+ printf( "*************** End of Dump ***************\n" );
+}
+
+/*
+ * IMFS_memfile_maximum_size()
+ *
+ * This routine returns the size of the largest file which can be created
+ * using the IMFS memory file type.
+ *
+ */
+
+int IMFS_memfile_maximum_size( void )
+{
+ return IMFS_MEMFILE_MAXIMUM_SIZE;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_directory.c b/cpukit/libfs/src/imfs/imfs_directory.c
new file mode 100644
index 0000000000..134204027a
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_directory.c
@@ -0,0 +1,278 @@
+/*
+ * XXX
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <chain.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <dirent.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+long getdents(
+ int dd_fd,
+ char *dd_buf,
+ int dd_len
+);
+
+/* -----------------------------------------------------------------------
+ * This rountine will verify that the node being opened as a directory is
+ * in fact a directory node. If it is then the offset into the directory
+ * will be set to 0 to position to the first directory entry.
+ */
+
+int imfs_dir_open(
+ rtems_libio_t *iop,
+ const char *pathname,
+ unsigned32 flag,
+ unsigned32 mode
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ /* Is the node a directory ? */
+ the_jnode = (IMFS_jnode_t *) iop->file_info;
+
+ if ( the_jnode->type != IMFS_DIRECTORY )
+ return -1; /* It wasn't a directory --> return error */
+
+ iop->offset = 0;
+ return 0;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * This routine will read the next directory entry based on the directory
+ * offset. The offset should be equal to -n- time the size of an individual
+ * dirent structure. If n is not an integer multiple of the sizeof a
+ * dirent structure, an integer division will be performed to determine
+ * directory entry that will be returned in the buffer. Count should reflect
+ * -m- times the sizeof dirent bytes to be placed in the buffer.
+ * If there are not -m- dirent elements from the current directory position
+ * to the end of the exisiting file, the remaining entries will be placed in
+ * the buffer and the returned value will be equal to -m actual- times the
+ * size of a directory entry.
+ */
+
+int imfs_dir_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ unsigned32 count
+)
+{
+ /*
+ * Read up to element iop->offset in the directory chain of the
+ * imfs_jnode_t struct for this file descriptor.
+ */
+ Chain_Node *the_node;
+ Chain_Control *the_chain;
+ IMFS_jnode_t *the_jnode;
+ int bytes_transferred;
+ int current_entry;
+ int first_entry;
+ int last_entry;
+ struct dirent tmp_dirent;
+
+ the_jnode = (IMFS_jnode_t *)iop->file_info;
+ the_chain = &the_jnode->info.directory.Entries;
+
+ if ( Chain_Is_empty( the_chain ) )
+ return 0;
+
+ /* Move to the first of the desired directory entries */
+ the_node = the_chain->first;
+
+ bytes_transferred = 0;
+ first_entry = iop->offset;
+ /* protect against using sizes that are not exact multiples of the */
+ /* -dirent- size. These could result in unexpected results */
+ last_entry = first_entry + (count/sizeof(struct dirent)) * sizeof(struct dirent);
+
+ /* The directory was not empty so try to move to the desired entry in chain*/
+ for(
+ current_entry = 0;
+ current_entry < last_entry;
+ current_entry = current_entry + sizeof(struct dirent) ){
+
+ if ( Chain_Is_tail( the_chain, the_node ) ){
+ /* We hit the tail of the chain while trying to move to the first */
+ /* entry in the read */
+ return bytes_transferred; /* Indicate that there are no more */
+ /* entries to return */
+ }
+
+ if( current_entry >= first_entry ) {
+ /* Move the entry to the return buffer */
+ tmp_dirent.d_ino = 1;
+ tmp_dirent.d_off = current_entry;
+ tmp_dirent.d_reclen = sizeof( struct dirent );
+ the_jnode = (IMFS_jnode_t *) the_node;
+ tmp_dirent.d_namlen = strlen( the_jnode->name );
+ sprintf( tmp_dirent.d_name, "%s", the_jnode->name );
+ memcpy(
+ buffer + bytes_transferred,
+ (void *)&tmp_dirent,
+ sizeof( struct dirent )
+ );
+ iop->offset = iop->offset + sizeof(struct dirent);
+ bytes_transferred = bytes_transferred + sizeof( struct dirent );
+ }
+
+ the_node = the_node->next;
+ }
+
+ /* Success */
+ return bytes_transferred;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * This routine will be called by the generic close routine to cleanup any
+ * resources that have been allocated for the management of the file
+ */
+
+int imfs_dir_close(
+ rtems_libio_t *iop
+)
+{
+ /* The generic close routine handles the deallocation of the file control */
+ /* and associated memory. At present the imfs_dir_close simply */
+ /* returns a successful completion status */
+
+ return 0;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * This routine will behave in one of three ways based on the state of
+ * argument whence. Based on the state of its value the offset argument will
+ * be interpreted using one of the following methods:
+ *
+ * SEEK_SET - offset is the absolute byte offset from the start of the
+ * logical start of the dirent sequence that represents the
+ * directory
+ * SEEK_CUR - offset is used as the relative byte offset from the current
+ * directory position index held in the iop structure
+ * SEEK_END - N/A --> This will cause an assert.
+ */
+
+int imfs_dir_lseek(
+ rtems_libio_t *iop,
+ off_t offset,
+ int whence
+)
+{
+ off_t normal_offset;
+
+ normal_offset = (offset/sizeof(struct dirent)) * sizeof(struct dirent);
+
+
+ switch( whence )
+ {
+ case SEEK_SET: /* absolute move from the start of the file */
+ iop->offset = normal_offset;
+ break;
+
+ case SEEK_CUR: /* relative move */
+ iop->offset = iop->offset + normal_offset;
+ break;
+
+ case SEEK_END: /* Movement past the end of the directory via lseek */
+ /* is not a permitted operation */
+ default:
+ set_errno_and_return_minus_one( EINVAL );
+ break;
+
+ }
+
+ return 0;
+}
+
+
+
+/* -----------------------------------------------------------------------
+ * This routine will obtain the following information concerning the current
+ * directory:
+ * st_dev 0ll
+ * st_ino 1
+ * st_mode mode extracted from the jnode
+ * st_nlink number of links to this node
+ * st_uid uid extracted from the jnode
+ * st_gid gid extracted from the jnode
+ * st_rdev 0ll
+ * st_size the number of bytes in the directory
+ * This is calculated by taking the number of entries
+ * in the directory and multiplying by the size of a
+ * dirent structure
+ * st_blksize 0
+ * st_blocks 0
+ * st_atime time of last access
+ * st_mtime time of last modification
+ * st_ctime time of the last change
+ *
+ * This information will be returned to the calling function in a -stat- struct
+ *
+ */
+
+int imfs_dir_fstat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+)
+{
+ Chain_Node *the_node;
+ Chain_Control *the_chain;
+ IMFS_jnode_t *the_jnode;
+
+
+ the_jnode = (IMFS_jnode_t *) loc->node_access;
+
+ buf->st_dev = 0ll;
+ buf->st_ino = the_jnode->st_ino;
+ buf->st_mode = the_jnode->st_mode;
+ buf->st_nlink = the_jnode->st_nlink;
+ buf->st_uid = the_jnode->st_uid;
+ buf->st_gid = the_jnode->st_gid;
+ buf->st_rdev = 0ll;
+ buf->st_blksize = 0;
+ buf->st_blocks = 0;
+ buf->st_atime = the_jnode->st_atime;
+ buf->st_mtime = the_jnode->st_mtime;
+ buf->st_ctime = the_jnode->st_ctime;
+
+ buf->st_size = 0;
+
+ the_chain = &the_jnode->info.directory.Entries;
+
+ /* Run through the chain and count the number of directory entries */
+ /* that are subordinate to this directory node */
+ for ( the_node = the_chain->first ;
+ !_Chain_Is_tail( the_chain, the_node ) ;
+ the_node = the_node->next ) {
+
+ buf->st_size = buf->st_size + sizeof( struct dirent );
+ }
+
+ return 0;
+}
+
+
diff --git a/cpukit/libfs/src/imfs/imfs_eval.c b/cpukit/libfs/src/imfs/imfs_eval.c
new file mode 100644
index 0000000000..eb770a58ce
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_eval.c
@@ -0,0 +1,638 @@
+/*
+ * Evaluation IMFS Node Support Routines
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+#define RTEMS_LIBIO_PERMS_RX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_READ)
+#define RTEMS_LIBIO_PERMS_WX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_WRITE)
+
+#define MAXSYMLINK 5
+
+int IMFS_Set_handlers(
+ rtems_filesystem_location_info_t *loc
+)
+{
+ IMFS_jnode_t *node = loc->node_access;
+
+ switch( node->type ) {
+ case IMFS_DIRECTORY:
+ loc->handlers = &dir_handlers;
+ break;
+ case IMFS_DEVICE:
+ loc->handlers = &device_handlers;
+ break;
+ case IMFS_SYM_LINK:
+ case IMFS_HARD_LINK:
+ loc->handlers = &null_handlers;
+ break;
+ case IMFS_MEMORY_FILE:
+ loc->handlers = &memfile_handlers;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * IMFS_evaluate_permission
+ *
+ * The following routine evaluates that we have permission
+ * to do flags on the node.
+ */
+
+int IMFS_evaluate_permission(
+ rtems_filesystem_location_info_t *node,
+ int flags
+)
+{
+ uid_t st_uid;
+ gid_t st_gid;
+ IMFS_jnode_t *jnode;
+ int flags_to_test;
+
+ if (! rtems_libio_is_valid_perms( flags ) ) {
+ assert( 0 );
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ jnode = node->node_access;
+
+#if defined(RTEMS_POSIX_API)
+ st_uid = geteuid();
+ st_gid = getegid();
+#else
+ st_uid = jnode->st_uid;
+ st_gid = jnode->st_gid;
+#endif
+
+ /*
+ * Check if I am owner or a group member or someone else.
+ */
+
+ flags_to_test = flags;
+
+ if ( st_uid == jnode->st_uid )
+ flags_to_test <<= 6;
+ else if ( st_gid == jnode->st_gid )
+ flags_to_test <<= 3;
+ else
+ /* must be other - do nothing */;
+
+ /*
+ * If all of the flags are set we have permission
+ * to do this.
+ */
+ if ( ( flags_to_test & jnode->st_mode) == flags_to_test )
+ return 1;
+
+ return 0;
+}
+
+/*
+ * IMFS_evaluate_hard_link
+ *
+ * The following routine evaluates a hardlink to the actual node.
+ */
+
+int IMFS_evaluate_hard_link(
+ rtems_filesystem_location_info_t *node, /* IN/OUT */
+ int flags /* IN */
+)
+{
+ IMFS_jnode_t *jnode = node->node_access;
+ int result = 0;
+
+ /*
+ * Check for things that should never happen.
+ */
+
+ if ( jnode->type != IMFS_HARD_LINK )
+ rtems_fatal_error_occurred (0xABCD0000);
+
+ /*
+ * Set the hard link value and the handlers.
+ */
+
+ node->node_access = jnode->info.hard_link.link_node;
+
+ IMFS_Set_handlers( node );
+
+ /*
+ * Verify we have the correct permissions for this node.
+ */
+
+ if (! IMFS_evaluate_permission( node, flags ) )
+ set_errno_and_return_minus_one( EACCES );
+
+ return result;
+}
+
+
+/*
+ * IMFS_evaluate_sym_link
+ *
+ * The following routine evaluates a symbolic link to the actual node.
+ */
+
+int IMFS_evaluate_sym_link(
+ rtems_filesystem_location_info_t *node, /* IN/OUT */
+ int flags /* IN */
+)
+{
+ IMFS_jnode_t *jnode = node->node_access;
+ int result = 0;
+ int i;
+
+ /*
+ * Check for things that should never happen.
+ */
+
+ if ( jnode->type != IMFS_SYM_LINK )
+ rtems_fatal_error_occurred (0xABCD0000);
+
+ if ( !jnode->Parent )
+ rtems_fatal_error_occurred( 0xBAD00000 );
+
+
+ /*
+ * Move the node_access to either the symbolic links parent or
+ * root depending on the symbolic links path.
+ */
+
+ node->node_access = jnode->Parent;
+
+ rtems_filesystem_get_sym_start_loc(
+ jnode->info.sym_link.name,
+ &i,
+ node
+ );
+
+ /*
+ * Use eval path to evaluate the path of the symbolic link.
+ */
+
+ result = IMFS_eval_path(
+ &jnode->info.sym_link.name[i],
+ flags,
+ node
+ );
+
+ IMFS_Set_handlers( node );
+
+ /*
+ * Verify we have the correct permissions for this node.
+ */
+
+ if (! IMFS_evaluate_permission( node, flags ) )
+ set_errno_and_return_minus_one( EACCES );
+
+ return result;
+}
+
+/*
+ * IMFS_evaluate_link
+ *
+ * The following routine returns the real node pointed to by a link.
+ */
+
+int IMFS_evaluate_link(
+ rtems_filesystem_location_info_t *node, /* IN/OUT */
+ int flags /* IN */
+)
+{
+ IMFS_jnode_t *jnode;
+ int result = 0;
+
+ do {
+ jnode = node->node_access;
+
+ /*
+ * Increment and check the link counter.
+ */
+
+ rtems_filesystem_link_counts ++;
+ if ( rtems_filesystem_link_counts > MAXSYMLINK ) {
+ rtems_filesystem_link_counts = 0;
+ set_errno_and_return_minus_one( ELOOP );
+ }
+
+ /*
+ * Follow the Link node.
+ */
+
+ if ( jnode->type == IMFS_HARD_LINK )
+ result = IMFS_evaluate_hard_link( node, flags );
+
+ else if (jnode->type == IMFS_SYM_LINK )
+ result = IMFS_evaluate_sym_link( node, flags );
+
+ } while ( ( result == 0 ) && ( ( jnode->type == IMFS_SYM_LINK ) ||
+ ( jnode->type == IMFS_HARD_LINK ) ) );
+
+ /*
+ * Clear link counter.
+ */
+
+ rtems_filesystem_link_counts = 0;
+
+ return result;
+}
+
+
+/*
+ * IMFS_evaluate_for_make
+ *
+ * The following routine evaluate path for a new node to be created.
+ * pathloc is returned with a pointer to the parent of the new node.
+ * name is returned with a pointer to the first character in the
+ * new node name. The parent node is verified to be a directory.
+ */
+
+int IMFS_evaluate_for_make(
+ const char *path, /* IN */
+ rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
+ const char **name /* OUT */
+)
+{
+ int i = 0;
+ int len;
+ IMFS_token_types type;
+ char token[ NAME_MAX + 1 ];
+ rtems_filesystem_location_info_t newloc;
+ IMFS_jnode_t *node;
+ int done = 0;
+ int result;
+
+ /*
+ * This was filled in by the caller and is valid in the
+ * mount table.
+ */
+ node = pathloc->node_access;
+
+ /*
+ * Evaluate all tokens until we are done or an error occurs.
+ */
+
+ while( !done ) {
+
+ type = IMFS_get_token( &path[i], token, &len );
+ i += len;
+
+ if ( !pathloc->node_access )
+ set_errno_and_return_minus_one( ENOENT );
+
+ /*
+ * I cannot move out of this directory without execute permission.
+ */
+
+ if ( type != IMFS_NO_MORE_PATH )
+ if ( node->type == IMFS_DIRECTORY )
+ if (! IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) )
+ set_errno_and_return_minus_one( EACCES );
+
+ node = pathloc->node_access;
+
+ switch( type ) {
+
+ case IMFS_UP_DIR:
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+
+ if (pathloc->node_access == pathloc->mt_entry->mt_fs_root.node_access){
+
+ /*
+ * Am I at the root of all filesystems?
+ */
+
+ if ( pathloc->node_access == rtems_filesystem_root.node_access ) {
+ break;
+
+ } else {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+ return (*pathloc->ops->evalformake)( &path[i-len], pathloc, name );
+ }
+ } else {
+
+ if ( !node->Parent )
+ set_errno_and_return_minus_one( ENOENT );
+
+ node = node->Parent;
+ }
+
+ pathloc->node_access = node;
+ break;
+
+ case IMFS_NAME:
+
+ if ( node->type == IMFS_HARD_LINK ) {
+
+ result = IMFS_evaluate_link( pathloc, 0 );
+ if ( result == -1 )
+ return -1;
+
+ } else if ( node->type == IMFS_SYM_LINK ) {
+
+ result = IMFS_evaluate_link( pathloc, 0 );
+
+ if ( result == -1 )
+ return -1;
+ }
+
+ node = pathloc->node_access;
+ if ( !node )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ /*
+ * Only a directory can be decended into.
+ */
+
+ if ( node->type != IMFS_DIRECTORY )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ /*
+ * If we are at a node that is a mount point. Set loc to the
+ * new fs root node and let them finish evaluating the path.
+ */
+
+ if ( node->info.directory.mt_fs != NULL ) {
+ newloc = node->info.directory.mt_fs->mt_fs_root;
+ *pathloc = newloc;
+ return (*pathloc->ops->evalformake)( &path[i-len], pathloc, name );
+ }
+
+ /*
+ * Otherwise find the token name in the present location.
+ */
+
+ node = IMFS_find_match_in_dir( node, token );
+
+ /*
+ * If there is no node we have found the name of the node we
+ * wish to create.
+ */
+
+ if ( ! node )
+ done = TRUE;
+ else
+ pathloc->node_access = node;
+
+ break;
+
+ case IMFS_NO_MORE_PATH:
+ set_errno_and_return_minus_one( EEXIST );
+ break;
+
+ case IMFS_INVALID_TOKEN:
+ set_errno_and_return_minus_one( ENAMETOOLONG );
+ break;
+
+ case IMFS_CURRENT_DIR:
+ break;
+ }
+ }
+
+ *name = &path[ i - len ];
+
+ /*
+ * We have evaluated the path as far as we can.
+ * Verify there is not any invalid stuff at the end of the name.
+ */
+
+ for( ; path[i] != '\0'; i++) {
+ if (! IMFS_is_separator( path[ i ] ) )
+ set_errno_and_return_minus_one( ENOENT );
+ }
+
+ /*
+ * Verify we can execute and write to this directory.
+ */
+
+ result = IMFS_Set_handlers( pathloc );
+
+ /*
+ * The returned node must be a directory
+ */
+ node = pathloc->node_access;
+ if ( node->type != IMFS_DIRECTORY )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ /*
+ * We must have Write and execute permission on the returned node.
+ */
+
+ if (! IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_WX ) )
+ set_errno_and_return_minus_one( EACCES );
+
+ return result;
+}
+
+
+/*
+ * IMFS_eval_path
+ *
+ * The following routine evaluate path for a node that wishes to be
+ * accessed with mode. pathloc is returned with a pointer to the
+ * node to be accessed.
+ */
+
+int IMFS_eval_path(
+ const char *pathname, /* IN */
+ int flags, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */
+)
+{
+ int i = 0;
+ int len;
+ IMFS_token_types type = IMFS_CURRENT_DIR;
+ char token[ NAME_MAX + 1 ];
+ rtems_filesystem_location_info_t newloc;
+ IMFS_jnode_t *node;
+ int result;
+
+ if (! rtems_libio_is_valid_perms( flags ) ) {
+ assert( 0 );
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ /*
+ * This was filled in by the caller and is valid in the
+ * mount table.
+ */
+
+ node = pathloc->node_access;
+
+ /*
+ * Evaluate all tokens until we are done or an error occurs.
+ */
+
+ while( (type != IMFS_NO_MORE_PATH) && (type != IMFS_INVALID_TOKEN) ) {
+
+ type = IMFS_get_token( &pathname[i], token, &len );
+ i += len;
+
+ if ( !pathloc->node_access )
+ set_errno_and_return_minus_one( ENOENT );
+
+ /*
+ * I cannot move out of this directory without execute permission.
+ */
+ if ( type != IMFS_NO_MORE_PATH )
+ if ( node->type == IMFS_DIRECTORY )
+ if (! IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) )
+ set_errno_and_return_minus_one( EACCES );
+
+ node = pathloc->node_access;
+
+ switch( type ) {
+ case IMFS_UP_DIR:
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access) {
+
+ /*
+ * Am I at the root of all filesystems?
+ */
+
+ if ( pathloc->node_access == rtems_filesystem_root.node_access ) {
+ break; /* Throw out the .. in this case */
+ } else {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+ return (*pathloc->ops->evalpath)(&(pathname[i-len]),flags,pathloc);
+ }
+ } else {
+
+ if ( !node->Parent )
+ set_errno_and_return_minus_one( ENOENT );
+
+ node = node->Parent;
+ pathloc->node_access = node;
+
+ }
+
+ pathloc->node_access = node;
+ break;
+
+ case IMFS_NAME:
+ /*
+ * If we are at a link follow it.
+ */
+
+ if ( node->type == IMFS_HARD_LINK ) {
+
+ IMFS_evaluate_hard_link( pathloc, 0 );
+
+ node = pathloc->node_access;
+ if ( !node )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ } else if ( node->type == IMFS_SYM_LINK ) {
+
+ result = IMFS_evaluate_sym_link( pathloc, 0 );
+
+ node = pathloc->node_access;
+ if ( result == -1 )
+ return -1;
+ }
+
+ /*
+ * Only a directory can be decended into.
+ */
+
+ if ( node->type != IMFS_DIRECTORY )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ /*
+ * If we are at a node that is a mount point. Set loc to the
+ * new fs root node and let them finish evaluating the path.
+ */
+
+ if ( node->info.directory.mt_fs != NULL ) {
+ newloc = node->info.directory.mt_fs->mt_fs_root;
+ *pathloc = newloc;
+ return (*pathloc->ops->evalpath)( &pathname[i-len], flags, pathloc );
+ }
+
+ /*
+ * Otherwise find the token name in the present location.
+ */
+
+ node = IMFS_find_match_in_dir( node, token );
+ if ( !node )
+ set_errno_and_return_minus_one( ENOENT );
+
+ /*
+ * Set the node access to the point we have found.
+ */
+
+ pathloc->node_access = node;
+ break;
+
+ case IMFS_NO_MORE_PATH:
+ case IMFS_CURRENT_DIR:
+ break;
+
+ case IMFS_INVALID_TOKEN:
+ set_errno_and_return_minus_one( ENAMETOOLONG );
+ break;
+
+ }
+ }
+
+ /*
+ * Only return root node if this is the base file system.
+ */
+
+ if ((pathloc->node_access == pathloc->mt_entry->mt_fs_root.node_access) &&
+ (pathloc->node_access != rtems_filesystem_root.node_access) ) {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+ }
+
+ result = IMFS_Set_handlers( pathloc );
+
+ /*
+ * Verify we have the correct permissions for this node.
+ */
+
+ if (! IMFS_evaluate_permission( pathloc, flags ) )
+ set_errno_and_return_minus_one( EACCES );
+
+ return result;
+}
+
+
+
+
+
+
+
+
+
diff --git a/cpukit/libfs/src/imfs/imfs_fchmod.c b/cpukit/libfs/src/imfs/imfs_fchmod.c
new file mode 100644
index 0000000000..06c2969100
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_fchmod.c
@@ -0,0 +1,55 @@
+/*
+ * IMFS file change mode routine.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+
+#include "libio_.h"
+#include "imfs.h"
+
+int IMFS_fchmod(
+ rtems_filesystem_location_info_t *loc,
+ mode_t mode
+)
+{
+ IMFS_jnode_t *jnode;
+#if defined(RTEMS_POSIX_API)
+ uid_t st_uid;
+#endif
+
+ jnode = loc->node_access;
+
+ /*
+ * Verify I am the owner of the node or the super user.
+ */
+#if defined(RTEMS_POSIX_API)
+ st_uid = geteuid();
+
+ if ( ( st_uid != jnode->st_uid ) && ( st_uid != 0 ) )
+ set_errno_and_return_minus_one( EPERM );
+#endif
+
+ /*
+ * Change only the RWX permissions on the jnode to mode.
+ */
+ if ( mode & (~ (S_IRWXU | S_IRWXG | S_IRWXO ) ) )
+ set_errno_and_return_minus_one( EPERM );
+
+ jnode->st_mode &= ~(S_IRWXU | S_IRWXG | S_IRWXO);
+ jnode->st_mode |= mode;
+
+ IMFS_update_ctime( jnode );
+
+ return 0;
+}
+
diff --git a/cpukit/libfs/src/imfs/imfs_free.c b/cpukit/libfs/src/imfs/imfs_free.c
new file mode 100644
index 0000000000..8216547c12
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_free.c
@@ -0,0 +1,99 @@
+/*
+ * Free IMFS Node Support Routines
+ *
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+
+#include "libio_.h"
+#include "imfs.h"
+
+/*
+ * IMFS_freenodinfo
+ *
+ * This routine is the IMFS free node handler for the file system
+ * operations table.
+ *
+ * The In Memory File System keeps its nodes in memory. This routine
+ * is for file sytems that do not.
+ */
+
+int IMFS_freenodinfo(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+)
+{
+ return 0;
+}
+
+
+/*
+ * IMFS_freenod
+ *
+ * The following routine frees a node if possible.
+ *
+ * The routine returns 0 if the node was not freed and 1 if it was.
+ *
+ * NOTE: This routine is for INTERNAL IMFS use only.
+ */
+
+int IMFS_freenod(
+ rtems_filesystem_location_info_t *pathloc
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = pathloc->node_access;
+
+ if ( the_jnode->type == IMFS_DIRECTORY ) {
+
+ /*
+ * You cannot remove a node that still has children
+ */
+
+ if ( ! Chain_Is_empty( &the_jnode->info.directory.Entries ) )
+ return ENOTEMPTY;
+
+ /*
+ * You cannot remove the file system root node.
+ */
+ if ( pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access )
+ return EBUSY;
+
+ /*
+ * You cannot remove a mountpoint.
+ */
+ if ( the_jnode->info.directory.mt_fs != NULL )
+ return EBUSY;
+ }
+
+ if ( !rtems_libio_is_file_open( the_jnode ) &&
+ (the_jnode->st_nlink < 1) ) {
+
+ /*
+ * Is the rtems_filesystem_current is this node?
+ */
+ if ( rtems_filesystem_current.node_access == pathloc->node_access ) {
+ rtems_filesystem_current.node_access = NULL;
+ }
+
+ /*
+ * Free memory associated with a memory file.
+ */
+ if ( the_jnode->type == IMFS_MEMORY_FILE )
+ IMFS_memfile_remove( the_jnode );
+
+ free( the_jnode );
+ }
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_getchild.c b/cpukit/libfs/src/imfs/imfs_getchild.c
new file mode 100644
index 0000000000..3f37738ab4
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_getchild.c
@@ -0,0 +1,68 @@
+/*
+ * IMFS_find_match_in_dir()
+ *
+ * This routine returns the child name in the given directory.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include <assert.h>
+#include "imfs.h"
+
+static char dotname[2] = ".";
+static char dotdotname[2] = "..";
+
+IMFS_jnode_t *IMFS_find_match_in_dir(
+ IMFS_jnode_t *directory,
+ char *name
+)
+{
+ Chain_Node *the_node;
+ Chain_Control *the_chain;
+ IMFS_jnode_t *the_jnode;
+
+ /*
+ * Check for fatal errors
+ */
+
+ assert( directory );
+ if ( !name )
+ return 0;
+
+ assert( name );
+ if ( !directory )
+ return 0;
+
+ /*
+ * Check for "." and ".."
+ */
+
+ if ( !strcmp( name, dotname ) )
+ return directory;
+
+ if ( !strcmp( name, dotdotname ) )
+ return directory->Parent;
+
+ the_chain = &directory->info.directory.Entries;
+
+ for ( the_node = the_chain->first;
+ !_Chain_Is_tail( the_chain, the_node );
+ the_node = the_node->next ) {
+
+ the_jnode = (IMFS_jnode_t *) the_node;
+
+ if ( !strcmp( name, the_jnode->name ) )
+ return the_jnode;
+ }
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_gtkn.c b/cpukit/libfs/src/imfs/imfs_gtkn.c
new file mode 100644
index 0000000000..052c67ceba
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_gtkn.c
@@ -0,0 +1,84 @@
+/*
+ * IMFS_get_token
+ *
+ * Routine to get a token (name or separator) from the path
+ * the length of the token is returned in token_len.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include "imfs.h"
+#include "libio_.h"
+
+IMFS_token_types IMFS_get_token(
+ const char *path,
+ char *token,
+ int *token_len
+)
+{
+ int i = 0;
+ IMFS_token_types type = IMFS_NAME;
+
+ /*
+ * Copy a name into token. (Remember NULL is a token.)
+ */
+
+ while ( !IMFS_is_separator( path[i] ) && (i <= NAME_MAX) ) {
+
+ token[i] = path[i];
+
+ if (i == NAME_MAX)
+ return IMFS_INVALID_TOKEN;
+
+ if ( !IMFS_is_valid_name_char( token[i] ) )
+ type = IMFS_INVALID_TOKEN;
+
+ i++;
+ }
+
+ /*
+ * Copy a seperator into token.
+ */
+
+ if ( i == 0 ) {
+ token[i] = path[i];
+
+ if ( token[i] != '\0' ) {
+ i++;
+ type = IMFS_CURRENT_DIR;
+ } else {
+ type = IMFS_NO_MORE_PATH;
+ }
+ } else if (token[ i-1 ] != '\0') {
+ token[i] = '\0';
+ }
+
+ /*
+ * Set token_len to the number of characters copied.
+ */
+
+ *token_len = i;
+
+ /*
+ * If we copied something that was not a seperator see if
+ * it was a special name.
+ */
+
+ if ( type == IMFS_NAME ) {
+ if ( strcmp( token, "..") == 0 )
+ type = IMFS_UP_DIR;
+ else if ( strcmp( token, "." ) == 0 )
+ type = IMFS_CURRENT_DIR;
+ }
+
+ return type;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_init.c b/cpukit/libfs/src/imfs/imfs_init.c
new file mode 100644
index 0000000000..bb3a0f9aea
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_init.c
@@ -0,0 +1,158 @@
+/*
+ * IMFS Initialization
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h> /* for mkdir */
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <assert.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+#if defined(IMFS_DEBUG)
+#include <stdio.h>
+#endif
+
+/*
+ * IMFS file system operations table
+ */
+
+rtems_filesystem_operations_table IMFS_ops = {
+ IMFS_eval_path,
+ IMFS_evaluate_for_make,
+ IMFS_link,
+ IMFS_unlink,
+ IMFS_node_type,
+ IMFS_mknod,
+ IMFS_rmnod,
+ IMFS_chown,
+ IMFS_freenodinfo,
+ IMFS_mount,
+ IMFS_initialize,
+ IMFS_unmount,
+ IMFS_fsunmount,
+ IMFS_utime,
+ IMFS_evaluate_link,
+ IMFS_symlink,
+ IMFS_readlink
+};
+
+/*
+ * IMFS_initialize
+ */
+
+int IMFS_initialize(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry
+)
+{
+ IMFS_fs_info_t *fs_info;
+ IMFS_jnode_t *jnode;
+
+ /*
+ * Create the root node
+ */
+
+ temp_mt_entry->mt_fs_root.node_access = IMFS_create_node(
+ NULL,
+ IMFS_DIRECTORY,
+ "",
+ ( S_IRWXO | S_IRWXG| S_IRWXU ),
+ NULL
+ );
+
+ temp_mt_entry->mt_fs_root.handlers = &dir_handlers;
+ temp_mt_entry->mt_fs_root.ops = &IMFS_ops;
+ temp_mt_entry->pathconf_limits_and_options = IMFS_LIMITS_AND_OPTIONS;
+
+ /*
+ * Create custom file system data.
+ */
+ fs_info = calloc( 1, sizeof( IMFS_fs_info_t ) );
+ if ( !fs_info ){
+ free(temp_mt_entry->mt_fs_root.node_access);
+ return 1;
+ }
+ temp_mt_entry->fs_info = fs_info;
+
+ /*
+ * Set st_ino for the root to 1.
+ */
+
+ fs_info->ino_count = 1;
+
+ jnode = temp_mt_entry->mt_fs_root.node_access;
+ jnode->st_ino = fs_info->ino_count;
+
+ return 0;
+}
+
+#define jnode_get_control( jnode ) \
+ (&jnode->info.directory.Entries)
+
+#define jnode_has_no_children( jnode ) \
+ Chain_Is_empty( jnode_get_control( jnode ) )
+
+#define jnode_has_children( jnode ) \
+ ( ! jnode_has_no_children( jnode ) )
+
+#define jnode_get_first_child( jnode ) \
+ ((IMFS_jnode_t *)( Chain_Head( jnode_get_control( jnode ) )->next))
+
+
+int IMFS_fsunmount(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry
+)
+{
+ IMFS_jnode_t *jnode;
+ IMFS_jnode_t *next;
+ rtems_filesystem_location_info_t loc;
+ int result = 0;
+
+ /*
+ * Traverse tree that starts at the mt_fs_root and deallocate memory
+ * associated memory space
+ */
+
+ jnode = (IMFS_jnode_t *)temp_mt_entry->mt_fs_root.node_access;
+
+ do {
+ next = jnode->Parent;
+ loc.node_access = (void *)jnode;
+
+ if ( jnode->type != IMFS_DIRECTORY ) {
+ result = IMFS_unlink( &loc );
+ if (result != 0)
+ return -1;
+ jnode = next;
+ } else if ( jnode_has_no_children( jnode ) ) {
+ result = IMFS_unlink( &loc );
+ if (result != 0)
+ return -1;
+ jnode = next;
+ }
+ if ( jnode != NULL ) {
+ if ( jnode->type == IMFS_DIRECTORY ) {
+ if ( jnode_has_children( jnode ) )
+ jnode = jnode_get_first_child( jnode );
+ }
+ }
+ } while (jnode != NULL);
+
+ return 0;
+}
+
+
+
diff --git a/cpukit/libfs/src/imfs/imfs_initsupp.c b/cpukit/libfs/src/imfs/imfs_initsupp.c
new file mode 100644
index 0000000000..bb3a0f9aea
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_initsupp.c
@@ -0,0 +1,158 @@
+/*
+ * IMFS Initialization
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h> /* for mkdir */
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <assert.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+#if defined(IMFS_DEBUG)
+#include <stdio.h>
+#endif
+
+/*
+ * IMFS file system operations table
+ */
+
+rtems_filesystem_operations_table IMFS_ops = {
+ IMFS_eval_path,
+ IMFS_evaluate_for_make,
+ IMFS_link,
+ IMFS_unlink,
+ IMFS_node_type,
+ IMFS_mknod,
+ IMFS_rmnod,
+ IMFS_chown,
+ IMFS_freenodinfo,
+ IMFS_mount,
+ IMFS_initialize,
+ IMFS_unmount,
+ IMFS_fsunmount,
+ IMFS_utime,
+ IMFS_evaluate_link,
+ IMFS_symlink,
+ IMFS_readlink
+};
+
+/*
+ * IMFS_initialize
+ */
+
+int IMFS_initialize(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry
+)
+{
+ IMFS_fs_info_t *fs_info;
+ IMFS_jnode_t *jnode;
+
+ /*
+ * Create the root node
+ */
+
+ temp_mt_entry->mt_fs_root.node_access = IMFS_create_node(
+ NULL,
+ IMFS_DIRECTORY,
+ "",
+ ( S_IRWXO | S_IRWXG| S_IRWXU ),
+ NULL
+ );
+
+ temp_mt_entry->mt_fs_root.handlers = &dir_handlers;
+ temp_mt_entry->mt_fs_root.ops = &IMFS_ops;
+ temp_mt_entry->pathconf_limits_and_options = IMFS_LIMITS_AND_OPTIONS;
+
+ /*
+ * Create custom file system data.
+ */
+ fs_info = calloc( 1, sizeof( IMFS_fs_info_t ) );
+ if ( !fs_info ){
+ free(temp_mt_entry->mt_fs_root.node_access);
+ return 1;
+ }
+ temp_mt_entry->fs_info = fs_info;
+
+ /*
+ * Set st_ino for the root to 1.
+ */
+
+ fs_info->ino_count = 1;
+
+ jnode = temp_mt_entry->mt_fs_root.node_access;
+ jnode->st_ino = fs_info->ino_count;
+
+ return 0;
+}
+
+#define jnode_get_control( jnode ) \
+ (&jnode->info.directory.Entries)
+
+#define jnode_has_no_children( jnode ) \
+ Chain_Is_empty( jnode_get_control( jnode ) )
+
+#define jnode_has_children( jnode ) \
+ ( ! jnode_has_no_children( jnode ) )
+
+#define jnode_get_first_child( jnode ) \
+ ((IMFS_jnode_t *)( Chain_Head( jnode_get_control( jnode ) )->next))
+
+
+int IMFS_fsunmount(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry
+)
+{
+ IMFS_jnode_t *jnode;
+ IMFS_jnode_t *next;
+ rtems_filesystem_location_info_t loc;
+ int result = 0;
+
+ /*
+ * Traverse tree that starts at the mt_fs_root and deallocate memory
+ * associated memory space
+ */
+
+ jnode = (IMFS_jnode_t *)temp_mt_entry->mt_fs_root.node_access;
+
+ do {
+ next = jnode->Parent;
+ loc.node_access = (void *)jnode;
+
+ if ( jnode->type != IMFS_DIRECTORY ) {
+ result = IMFS_unlink( &loc );
+ if (result != 0)
+ return -1;
+ jnode = next;
+ } else if ( jnode_has_no_children( jnode ) ) {
+ result = IMFS_unlink( &loc );
+ if (result != 0)
+ return -1;
+ jnode = next;
+ }
+ if ( jnode != NULL ) {
+ if ( jnode->type == IMFS_DIRECTORY ) {
+ if ( jnode_has_children( jnode ) )
+ jnode = jnode_get_first_child( jnode );
+ }
+ }
+ } while (jnode != NULL);
+
+ return 0;
+}
+
+
+
diff --git a/cpukit/libfs/src/imfs/imfs_link.c b/cpukit/libfs/src/imfs/imfs_link.c
new file mode 100644
index 0000000000..2232209705
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_link.c
@@ -0,0 +1,72 @@
+/*
+ * IMFS_link
+ *
+ * The following rouine creates a new link node under parent with the
+ * name given in name. The link node is set to point to the node at
+ * to_loc.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_link(
+ rtems_filesystem_location_info_t *to_loc, /* IN */
+ rtems_filesystem_location_info_t *parent_loc, /* IN */
+ const char *token /* IN */
+)
+{
+ IMFS_types_union info;
+ IMFS_jnode_t *new_node;
+ char new_name[ NAME_MAX + 1 ];
+ int i;
+
+ /*
+ * Verify this node can be linked to.
+ */
+
+ info.hard_link.link_node = to_loc->node_access;
+ if ( info.hard_link.link_node->st_nlink >= LINK_MAX )
+ set_errno_and_return_minus_one( EMLINK );
+
+ /*
+ * Remove any separators at the end of the string.
+ */
+
+ IMFS_get_token( token, new_name, &i );
+
+ /*
+ * Create a new link node.
+ */
+
+ new_node = IMFS_create_node(
+ parent_loc,
+ IMFS_HARD_LINK,
+ new_name,
+ ( S_IFLNK | ( S_IRWXU | S_IRWXG | S_IRWXO )),
+ &info
+ );
+
+ if ( !new_node )
+ set_errno_and_return_minus_one( ENOMEM );
+
+ /*
+ * Increment the link count of the node being pointed to.
+ */
+
+ info.hard_link.link_node->st_nlink++;
+ IMFS_update_ctime( info.hard_link.link_node );
+
+ return 0;
+}
+
diff --git a/cpukit/libfs/src/imfs/imfs_mknod.c b/cpukit/libfs/src/imfs/imfs_mknod.c
new file mode 100644
index 0000000000..d4feef4f36
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_mknod.c
@@ -0,0 +1,76 @@
+/*
+ * IMFS_mknod
+ *
+ * Routine to create a node in the IMFS file system.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_mknod(
+ const char *token, /* IN */
+ mode_t mode, /* IN */
+ dev_t dev, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */
+)
+{
+ IMFS_token_types type = 0;
+ IMFS_jnode_t *new_node;
+ int result;
+ char new_name[ NAME_MAX + 1 ];
+ IMFS_types_union info;
+
+ IMFS_get_token( token, new_name, &result );
+
+ /*
+ * Figure out what type of IMFS node this is.
+ */
+
+ if ( S_ISDIR(mode) )
+ type = IMFS_DIRECTORY;
+ else if ( S_ISREG(mode) )
+ type = IMFS_MEMORY_FILE;
+ else if ( S_ISBLK(mode) || S_ISCHR(mode) ) {
+ type = IMFS_DEVICE;
+ rtems_filesystem_split_dev_t( dev, info.device.major, info.device.minor );
+ } else {
+ assert( 0 );
+ set_errno_and_return_minus_one( EINVAL );
+ }
+
+ /*
+ * Allocate and fill in an IMFS jnode
+ */
+
+ new_node = IMFS_create_node(
+ pathloc,
+ type,
+ new_name,
+ mode,
+ &info
+ );
+
+ if ( !new_node )
+ set_errno_and_return_minus_one( ENOMEM );
+
+ return 0;
+}
+
diff --git a/cpukit/libfs/src/imfs/imfs_mount.c b/cpukit/libfs/src/imfs/imfs_mount.c
new file mode 100644
index 0000000000..a267b52576
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_mount.c
@@ -0,0 +1,49 @@
+/*
+ * IMFS_mount
+ *
+ * This routine will look at a mount table entry that we are going to
+ * add to the mount table. If the mount point rtems_filesystem
+ * location_info_t struct refers to a node that is a directory,
+ * the node will be marked as a mount point by setting its directory.mt_fs
+ * pointer to point to the mount table entry that we are about to add
+ * to the mount table chain.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_mount(
+ rtems_filesystem_mount_table_entry_t *mt_entry
+)
+{
+ IMFS_jnode_t *node;
+
+ node = mt_entry->mt_point_node.node_access;
+
+ /*
+ * Is the node that we are mounting onto a directory node ?
+ */
+
+ if ( node->type != IMFS_DIRECTORY )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ /*
+ * Set mt_fs pointer to point to the mount table entry for
+ * the mounted file system.
+ */
+
+ node->info.directory.mt_fs = mt_entry;
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_ntype.c b/cpukit/libfs/src/imfs/imfs_ntype.c
new file mode 100644
index 0000000000..bdf451a879
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_ntype.c
@@ -0,0 +1,29 @@
+/*
+ * IMFS_node_type
+ *
+ * The following verifies that returns the type of node that the
+ * loc refers to.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "imfs.h"
+
+rtems_filesystem_node_types_t IMFS_node_type(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+)
+{
+ IMFS_jnode_t *node;
+
+ node = pathloc->node_access;
+ return node->type;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_readlink.c b/cpukit/libfs/src/imfs/imfs_readlink.c
new file mode 100644
index 0000000000..958118f42f
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_readlink.c
@@ -0,0 +1,40 @@
+/*
+ * IMFS_readlink
+ *
+ * The following rouine puts the symblic links destination name into
+ * buff.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_readlink(
+ rtems_filesystem_location_info_t *loc,
+ char *buf, /* OUT */
+ size_t bufsize
+)
+{
+ IMFS_jnode_t *node;
+ int i;
+
+ node = loc->node_access;
+
+ if ( node->type != IMFS_SYM_LINK )
+ set_errno_and_return_minus_one( EINVAL );
+
+ for( i=0; ((i<bufsize) && (node->info.sym_link.name[i] != '\0')); i++ )
+ buf[i] = node->info.sym_link.name[i];
+
+ return i;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_rmnod.c b/cpukit/libfs/src/imfs/imfs_rmnod.c
new file mode 100644
index 0000000000..f651622de4
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_rmnod.c
@@ -0,0 +1,97 @@
+/*
+ * IMFS_rmnod
+ *
+ * This routine is available from the optable to remove a node
+ * from the IMFS file system.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "libio_.h"
+#include "imfs.h"
+
+
+int IMFS_rmnod(
+ rtems_filesystem_location_info_t *pathloc /* IN */
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = (IMFS_jnode_t *) pathloc->node_access;
+
+ if ( the_jnode->type == IMFS_DIRECTORY ) {
+
+ /*
+ * You cannot remove a node that still has children
+ */
+
+ if ( ! Chain_Is_empty( &the_jnode->info.directory.Entries ) )
+ set_errno_and_return_minus_one( ENOTEMPTY );
+
+ /*
+ * You cannot remove the file system root node.
+ */
+
+ if ( pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access )
+ set_errno_and_return_minus_one( EBUSY );
+
+ /*
+ * You cannot remove a mountpoint.
+ */
+
+ if ( the_jnode->info.directory.mt_fs != NULL )
+ set_errno_and_return_minus_one( EBUSY );
+ }
+
+ /*
+ * Take the node out of the parent's chain that contains this node
+ */
+ if ( the_jnode->Parent != NULL ) {
+ Chain_Extract( (Chain_Node *) the_jnode );
+ the_jnode->Parent = NULL;
+ }
+
+ /*
+ * Decrement the link counter and see if we can free the space.
+ */
+
+ the_jnode->st_nlink--;
+ IMFS_update_ctime( the_jnode );
+
+ /*
+ * The file cannot be open and the link must be less than 1 to free.
+ */
+
+ if ( !rtems_libio_is_file_open( the_jnode ) && (the_jnode->st_nlink < 1) ) {
+
+ /*
+ * Is the rtems_filesystem_current is this node?
+ */
+
+ if ( rtems_filesystem_current.node_access == pathloc->node_access )
+ rtems_filesystem_current.node_access = NULL;
+
+ /*
+ * Free memory associated with a memory file.
+ */
+
+ if ( the_jnode->type == IMFS_MEMORY_FILE )
+ IMFS_memfile_remove( the_jnode );
+
+ free( the_jnode );
+ }
+
+ return 0;
+
+}
+
+
diff --git a/cpukit/libfs/src/imfs/imfs_stat.c b/cpukit/libfs/src/imfs/imfs_stat.c
new file mode 100644
index 0000000000..4628736714
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_stat.c
@@ -0,0 +1,59 @@
+/*
+ * IMFS_stat
+ *
+ * This routine provides a stat for the IMFS file system.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+)
+{
+ IMFS_jnode_t *the_jnode;
+ IMFS_device_t *io;
+
+ the_jnode = loc->node_access;
+
+
+ switch ( the_jnode->type ) {
+
+ case IMFS_DEVICE:
+ io = &the_jnode->info.device;
+ buf->st_dev = rtems_filesystem_make_dev_t( io->major, io->minor );
+ break;
+
+ case IMFS_MEMORY_FILE:
+ buf->st_size = the_jnode->info.file.size;
+ break;
+
+ default:
+ set_errno_and_return_minus_one( ENOTSUP );
+ break;
+ }
+
+ buf->st_mode = the_jnode->st_mode;
+ buf->st_nlink = the_jnode->st_nlink;
+ buf->st_ino = the_jnode->st_ino;
+ buf->st_uid = the_jnode->st_uid;
+ buf->st_gid = the_jnode->st_gid;
+
+ buf->st_atime = the_jnode->st_atime;
+ buf->st_mtime = the_jnode->st_mtime;
+ buf->st_ctime = the_jnode->st_ctime;
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_symlink.c b/cpukit/libfs/src/imfs/imfs_symlink.c
new file mode 100644
index 0000000000..0d3ebbd670
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_symlink.c
@@ -0,0 +1,60 @@
+/*
+ * IMFS_symlink
+ *
+ * The following rouine creates a new symbolic link node under parent
+ * with the name given in name. The node is set to point to the node at
+ * to_loc.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_symlink(
+ rtems_filesystem_location_info_t *parent_loc,
+ const char *link_name,
+ const char *node_name
+)
+{
+ IMFS_types_union info;
+ IMFS_jnode_t *new_node;
+ char new_name[ NAME_MAX + 1 ];
+ int i;
+
+ /*
+ * Remove any separators at the end of the string.
+ */
+
+ IMFS_get_token( node_name, new_name, &i );
+
+ info.sym_link.name = link_name;
+
+ /*
+ * Create a new link node.
+ */
+
+ new_node = IMFS_create_node(
+ parent_loc,
+ IMFS_SYM_LINK,
+ new_name,
+ ( S_IFLNK | ( S_IRWXU | S_IRWXG | S_IRWXO )),
+ &info
+ );
+
+ if ( !new_node )
+ set_errno_and_return_minus_one( ENOMEM );
+
+ return 0;
+}
+
+
diff --git a/cpukit/libfs/src/imfs/imfs_unlink.c b/cpukit/libfs/src/imfs/imfs_unlink.c
new file mode 100644
index 0000000000..4e0ca26b2a
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_unlink.c
@@ -0,0 +1,67 @@
+/*
+ * IMFS_unlink
+ *
+ * Routine to remove a link node from the tree.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_unlink(
+ rtems_filesystem_location_info_t *loc /* IN */
+)
+{
+ IMFS_jnode_t *node;
+ rtems_filesystem_location_info_t the_link;
+ int result;
+
+ node = loc->node_access;
+
+ /*
+ * Decrement the link counter of node pointed to and free the
+ * space.
+ */
+
+ /*
+ * If this is the last last pointer to the node
+ * free the node.
+ */
+
+ if ( node->type == IMFS_HARD_LINK ) {
+
+ if ( !node->info.hard_link.link_node )
+ set_errno_and_return_minus_one( EINVAL );
+
+ the_link = *loc;
+ the_link.node_access = node->info.hard_link.link_node;
+
+ /*
+ * If this is the last referance to the node
+ * Free the node that the link points to.
+ */
+ node->info.hard_link.link_node->st_nlink --;
+ IMFS_update_ctime( node->info.hard_link.link_node );
+ if ( node->info.hard_link.link_node->st_nlink < 1) {
+ result = IMFS_rmnod( &the_link );
+ if ( result != 0 )
+ return -1;
+ }
+ }
+
+ result = IMFS_rmnod( loc );
+
+ return result;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_unmount.c b/cpukit/libfs/src/imfs/imfs_unmount.c
new file mode 100644
index 0000000000..f29d720ab3
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_unmount.c
@@ -0,0 +1,58 @@
+/*
+ * IMFS_unmount
+ *
+ * This routine will look at a mount table entry that we are going to
+ * add to the mount table. If the mount point
+ * rtems_filesystem_location_info_t struct refers to a node that is a
+ * directory that has a file system mounted on it, the node will be
+ * marked as a mount point by * setting its directory.mt_fs pointer
+ * to NULL. This indicates that a directory is no longer mounted on
+ * this node.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+
+#include "imfs.h"
+#include "libio_.h"
+
+int IMFS_unmount(
+ rtems_filesystem_mount_table_entry_t *mt_entry
+)
+{
+ IMFS_jnode_t *node;
+
+ node = mt_entry->mt_point_node.node_access;
+
+ /*
+ * Is the node that we are mounting onto a directory node ?
+ */
+
+ if ( node->type != IMFS_DIRECTORY )
+ set_errno_and_return_minus_one( ENOTDIR );
+
+ /*
+ * Did the node indicate that there was a directory mounted here?
+ */
+
+ if ( node->info.directory.mt_fs == NULL )
+ set_errno_and_return_minus_one( EINVAL ); /* XXX */
+
+ /*
+ * Set the mt_fs pointer to indicate that there is no longer
+ * a file system mounted to this point.
+ */
+
+ node->info.directory.mt_fs = NULL;
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/imfs_utime.c b/cpukit/libfs/src/imfs/imfs_utime.c
new file mode 100644
index 0000000000..bc2639ef8c
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_utime.c
@@ -0,0 +1,38 @@
+/*
+ * IMFS_utime
+ *
+ * This routine is the implementation of the utime() system
+ * call for the IMFS.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <errno.h>
+#include <sys/time.h>
+
+#include "libio_.h"
+#include "imfs.h"
+
+int IMFS_utime(
+ rtems_filesystem_location_info_t *pathloc, /* IN */
+ time_t actime, /* IN */
+ time_t modtime /* IN */
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = (IMFS_jnode_t *) pathloc->node_access;
+
+ the_jnode->st_atime = actime;
+ the_jnode->st_mtime = modtime;
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/imfs/ioman.c b/cpukit/libfs/src/imfs/ioman.c
new file mode 100644
index 0000000000..f8b725e987
--- /dev/null
+++ b/cpukit/libfs/src/imfs/ioman.c
@@ -0,0 +1,83 @@
+/*
+ * This file emulates the old Classic RTEMS IO manager directives
+ * which register and lookup names using the in-memory filesystem.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <assert.h>
+
+#include <rtems.h>
+#include "libio_.h"
+#include "imfs.h"
+
+/*
+ * rtems_io_register_name
+ *
+ * This assumes that all registered devices are character devices.
+ */
+
+rtems_status_code rtems_io_register_name(
+ char *device_name,
+ rtems_device_major_number major,
+ rtems_device_minor_number minor
+)
+{
+ int status;
+ dev_t dev;
+
+ dev = rtems_filesystem_make_dev_t( major, minor );
+ status = mknod( device_name, 0777 | S_IFCHR, dev );
+
+ /* this is the only error returned by the old version */
+ if ( status )
+ return RTEMS_TOO_MANY;
+
+ return RTEMS_SUCCESSFUL;
+}
+
+/*
+ * rtems_io_lookup_name
+ *
+ * This version is not reentrant.
+ */
+
+rtems_status_code rtems_io_lookup_name(
+ const char *name,
+ rtems_driver_name_t **device_info
+)
+{
+ IMFS_jnode_t *the_jnode;
+ rtems_filesystem_location_info_t temp_loc;
+ static rtems_driver_name_t device;
+ int result;
+
+ result = rtems_filesystem_evaluate_path( name, 0x00, &temp_loc, TRUE );
+ the_jnode = temp_loc.node_access;
+
+ if ( (result != 0) || the_jnode->type != IMFS_DEVICE ) {
+ *device_info = 0;
+ return RTEMS_UNSATISFIED;
+ }
+
+ device.device_name = (char *) name;
+ device.device_name_length = strlen( name );
+ device.major = the_jnode->info.device.major;
+ device.minor = the_jnode->info.device.minor;
+ *device_info = &device;
+ return RTEMS_SUCCESSFUL;
+
+}
diff --git a/cpukit/libfs/src/imfs/memfile.c b/cpukit/libfs/src/imfs/memfile.c
new file mode 100644
index 0000000000..01aee443f3
--- /dev/null
+++ b/cpukit/libfs/src/imfs/memfile.c
@@ -0,0 +1,1000 @@
+/*
+ * IMFS Device Node Handlers
+ *
+ * This file contains the set of handlers used to process operations on
+ * IMFS memory file nodes. The memory files are created in memory using
+ * malloc'ed memory. Thus any data stored in one of these files is lost
+ * at system shutdown unless special arrangements to copy the data to
+ * some type of non-volailte storage are made by the application.
+ *
+ * COPYRIGHT (c) 1989-1998.
+ * On-Line Applications Research Corporation (OAR).
+ * Copyright assigned to U.S. Government, 1994.
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include "imfs.h"
+#include "libio_.h"
+
+#define MEMFILE_STATIC
+
+/*
+ * Prototypes of private routines
+ */
+
+MEMFILE_STATIC int IMFS_memfile_extend(
+ IMFS_jnode_t *the_jnode,
+ off_t new_length
+);
+
+MEMFILE_STATIC int IMFS_memfile_addblock(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block
+);
+
+MEMFILE_STATIC int IMFS_memfile_remove_block(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block
+);
+
+MEMFILE_STATIC block_p *IMFS_memfile_get_block_pointer(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block,
+ int malloc_it
+);
+
+MEMFILE_STATIC int IMFS_memfile_read(
+ IMFS_jnode_t *the_jnode,
+ off_t start,
+ unsigned char *destination,
+ unsigned int length
+);
+
+MEMFILE_STATIC int IMFS_memfile_write(
+ IMFS_jnode_t *the_jnode,
+ off_t start,
+ const unsigned char *source,
+ unsigned int length
+);
+
+void *memfile_alloc_block(void);
+
+void memfile_free_block(
+ void *memory
+);
+
+/*
+ * memfile_open
+ *
+ * This routine processes the open() system call. Note that there is
+ * nothing special to be done at open() time.
+ */
+
+int memfile_open(
+ rtems_libio_t *iop,
+ const char *pathname,
+ unsigned32 flag,
+ unsigned32 mode
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ return 0;
+}
+
+/*
+ * memfile_close
+ *
+ * This routine processes the close() system call. Note that there is
+ * nothing to flush or memory to free at this point.
+ */
+
+int memfile_close(
+ rtems_libio_t *iop
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ return 0;
+}
+
+/*
+ * memfile_read
+ *
+ * This routine processes the read() system call.
+ */
+
+int memfile_read(
+ rtems_libio_t *iop,
+ void *buffer,
+ unsigned32 count
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ return IMFS_memfile_read( the_jnode, iop->offset, buffer, count );
+}
+
+/*
+ * memfile_write
+ *
+ * This routine processes the write() system call.
+ */
+
+int memfile_write(
+ rtems_libio_t *iop,
+ const void *buffer,
+ unsigned32 count
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ return IMFS_memfile_write( the_jnode, iop->offset, buffer, count );
+}
+
+/*
+ * memfile_ioctl
+ *
+ * This routine processes the ioctl() system call.
+ *
+ * NOTE: No ioctl()'s are supported for in-memory files.
+ */
+
+int memfile_ioctl(
+ rtems_libio_t *iop,
+ unsigned32 command,
+ void *buffer
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ return 0;
+}
+
+/*
+ * memfile_lseek
+ *
+ * This routine processes the lseek() system call.
+ */
+
+int memfile_lseek(
+ rtems_libio_t *iop,
+ off_t offset,
+ int whence
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ if (IMFS_memfile_extend( the_jnode, iop->offset ))
+ set_errno_and_return_minus_one( ENOSPC );
+
+ return 0;
+}
+
+/*
+ * memfile_stat
+ *
+ * This IMFS_stat() can be used.
+ */
+
+/*
+ * memfile_ftruncate
+ *
+ * This routine processes the ftruncate() system call.
+ */
+
+int memfile_ftruncate(
+ rtems_libio_t *iop,
+ off_t length
+)
+{
+ IMFS_jnode_t *the_jnode;
+
+ the_jnode = iop->file_info;
+
+ /*
+ * POSIX 1003.1b does not specify what happens if you truncate a file
+ * and the new length is greater than the current size. We treat this
+ * as an extend operation.
+ */
+
+ if ( length > the_jnode->info.file.size )
+ return IMFS_memfile_extend( the_jnode, length );
+
+ /*
+ * The in-memory files do not currently reclaim memory until the file is
+ * deleted. So we leave the previously allocated blocks in place for
+ * future use and just set the length.
+ */
+
+ the_jnode->info.file.size = length;
+
+ IMFS_update_atime( the_jnode );
+
+ return 0;
+}
+
+/*
+ * IMFS_memfile_extend
+ *
+ * This routine insures that the in-memory file is of the length
+ * specified. If necessary, it will allocate memory blocks to
+ * extend the file.
+ */
+
+MEMFILE_STATIC int IMFS_memfile_extend(
+ IMFS_jnode_t *the_jnode,
+ off_t new_length
+)
+{
+ unsigned int block;
+ unsigned int new_blocks;
+ unsigned int old_blocks;
+
+ /*
+ * Perform internal consistency checks
+ */
+
+ assert( the_jnode );
+ if ( !the_jnode )
+ set_errno_and_return_minus_one( EIO );
+
+ assert( the_jnode->type == IMFS_MEMORY_FILE );
+ if ( the_jnode->type != IMFS_MEMORY_FILE )
+ set_errno_and_return_minus_one( EIO );
+
+ if ( new_length >= IMFS_MEMFILE_MAXIMUM_SIZE )
+ set_errno_and_return_minus_one( EINVAL );
+
+ if ( new_length <= the_jnode->info.file.size )
+ return 0;
+
+ /*
+ * Calculate the number of range of blocks to allocate
+ */
+
+ new_blocks = new_length / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ old_blocks = the_jnode->info.file.size / IMFS_MEMFILE_BYTES_PER_BLOCK;
+
+ /*
+ * Now allocate each of those blocks.
+ */
+
+ for ( block=old_blocks ; block<=new_blocks ; block++ ) {
+ if ( IMFS_memfile_addblock( the_jnode, block ) ) {
+ for ( ; block>=old_blocks ; block-- ) {
+ IMFS_memfile_remove_block( the_jnode, block );
+ }
+ set_errno_and_return_minus_one( ENOSPC );
+ }
+ }
+
+ /*
+ * Set the new length of the file.
+ */
+
+ the_jnode->info.file.size = new_length;
+ return 0;
+}
+
+/*
+ * IMFS_memfile_addblock
+ *
+ * This routine adds a single block to the specified in-memory file.
+ */
+
+MEMFILE_STATIC int IMFS_memfile_addblock(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block
+)
+{
+ block_p memory;
+ block_p *block_entry_ptr;
+
+ assert( the_jnode );
+ if ( !the_jnode )
+ set_errno_and_return_minus_one( EIO );
+
+ assert( the_jnode->type == IMFS_MEMORY_FILE );
+ if ( the_jnode->type != IMFS_MEMORY_FILE )
+ set_errno_and_return_minus_one( EIO );
+
+ block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 1 );
+ if ( *block_entry_ptr )
+ return 0;
+
+#if 0
+ printf( "%d %p", block, block_entry_ptr );
+ fflush(stdout);
+#endif
+
+ memory = memfile_alloc_block();
+ assert( memory );
+ if ( !memory )
+ return 1;
+ *block_entry_ptr = memory;
+
+ return 0;
+}
+
+/*
+ * IMFS_memfile_remove_block
+ *
+ * This routine removes the specified block from the in-memory file.
+ *
+ * NOTE: This is a support routine and is called only to remove
+ * the last block or set of blocks in a file. Removing a
+ * block from the middle of a file would be exceptionally
+ * dangerous and the results unpredictable.
+ */
+
+MEMFILE_STATIC int IMFS_memfile_remove_block(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block
+)
+{
+ block_p *block_entry_ptr;
+ block_p ptr;
+
+ block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ ptr = *block_entry_ptr;
+ *block_entry_ptr = 0;
+
+ memfile_free_block( ptr );
+
+ return 1;
+}
+
+/*
+ * memfile_free_blocks_in_table
+ *
+ * This is a support routine for IMFS_memfile_remove. It frees all the
+ * blocks in one of the indirection tables.
+ */
+
+void memfile_free_blocks_in_table(
+ block_p **block_table,
+ int entries
+)
+{
+ int i;
+ block_p *b;
+
+ /*
+ * Perform internal consistency checks
+ */
+
+ assert( block_table );
+ if ( !block_table )
+ return;
+
+ /*
+ * Now go through all the slots in the table and free the memory.
+ */
+
+ b = *block_table;
+
+ for ( i=0 ; i<entries ; i++ ) {
+ if ( b[i] ) {
+ memfile_free_block( b[i] );
+ b[i] = 0;
+ }
+ }
+
+ /*
+ * Now that all the blocks in the block table are free, we can
+ * free the block table itself.
+ */
+
+ memfile_free_block( *block_table );
+ *block_table = 0;
+}
+
+/*
+ * IMFS_memfile_remove
+ *
+ * This routine frees all memory associated with an in memory file.
+ *
+ * NOTE: This is an exceptionally conservative implementation.
+ * It will check EVERY pointer which is non-NULL and insure
+ * any child non-NULL pointers are freed. Optimistically, all that
+ * is necessary is to scan until a NULL pointer is found. There
+ * should be no allocated data past that point.
+ *
+ * In experimentation on the powerpc simulator, it was noted
+ * that using blocks which held 128 slots versus 16 slots made
+ * a significant difference in the performance of this routine.
+ *
+ * Regardless until the IMFS implementation is proven, it
+ * is better to stick to simple, easy to understand algorithms.
+ */
+
+int IMFS_memfile_remove(
+ IMFS_jnode_t *the_jnode
+)
+{
+ IMFS_memfile_t *info;
+ int i;
+ int j;
+ unsigned int to_free;
+ block_p *p;
+
+ /*
+ * Perform internal consistency checks
+ */
+
+ assert( the_jnode );
+ if ( !the_jnode )
+ set_errno_and_return_minus_one( EIO );
+
+ assert( the_jnode->type == IMFS_MEMORY_FILE );
+ if ( the_jnode->type != IMFS_MEMORY_FILE )
+ set_errno_and_return_minus_one( EIO );
+
+ /*
+ * Eventually this could be set smarter at each call to
+ * memfile_free_blocks_in_table to greatly speed this up.
+ */
+
+ to_free = IMFS_MEMFILE_BLOCK_SLOTS;
+
+ /*
+ * Now start freeing blocks in this order:
+ * + indirect
+ * + doubly indirect
+ * + triply indirect
+ */
+
+ info = &the_jnode->info.file;
+
+ if ( info->indirect ) {
+ memfile_free_blocks_in_table( &info->indirect, to_free );
+ }
+
+ if ( info->doubly_indirect ) {
+
+ for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
+ if ( info->doubly_indirect[i] ) {
+ memfile_free_blocks_in_table(
+ (block_p **)&info->doubly_indirect[i], to_free );
+ }
+ }
+ memfile_free_blocks_in_table( &info->doubly_indirect, to_free );
+
+ }
+
+ if ( info->triply_indirect ) {
+ for ( i=0 ; i<IMFS_MEMFILE_BLOCK_SLOTS ; i++ ) {
+ p = (block_p *) info->triply_indirect[i];
+ for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) {
+ if ( p[j] ) {
+ memfile_free_blocks_in_table( (block_p **)&p[j], to_free);
+ }
+ }
+ memfile_free_blocks_in_table(
+ (block_p **)&info->triply_indirect[i], to_free );
+ }
+ memfile_free_blocks_in_table(
+ (block_p **)&info->triply_indirect, to_free );
+ }
+
+ return 0;
+}
+
+/*
+ * IMFS_memfile_read
+ *
+ * This routine read from memory file pointed to by the_jnode into
+ * the specified data buffer specified by destination. The file
+ * is NOT extended. An offset greater than the length of the file
+ * is considered an error. Read from an offset for more bytes than
+ * are between the offset and the end of the file will result in
+ * reading the data between offset and the end of the file (truncated
+ * read).
+ */
+
+MEMFILE_STATIC int IMFS_memfile_read(
+ IMFS_jnode_t *the_jnode,
+ off_t start,
+ unsigned char *destination,
+ unsigned int length
+)
+{
+ block_p *block_ptr;
+ unsigned int block;
+ unsigned int my_length;
+ unsigned int to_copy = 0;
+ unsigned int last_byte;
+ unsigned int copied;
+ unsigned int start_offset;
+ unsigned char *dest;
+
+ dest = destination;
+
+ /*
+ * Perform internal consistency checks
+ */
+
+ assert( the_jnode );
+ if ( !the_jnode )
+ set_errno_and_return_minus_one( EIO );
+
+ assert( the_jnode->type == IMFS_MEMORY_FILE );
+ if ( the_jnode->type != IMFS_MEMORY_FILE )
+ set_errno_and_return_minus_one( EIO );
+
+ /*
+ * Error checks on arguments
+ */
+
+ assert( dest );
+ if ( !dest )
+ set_errno_and_return_minus_one( EINVAL );
+
+ /*
+ * If there is nothing to read, then quick exit.
+ */
+
+ my_length = length;
+ if ( !my_length )
+ set_errno_and_return_minus_one( EINVAL );
+
+ /*
+ * If the last byte we are supposed to read is past the end of this
+ * in memory file, then shorten the length to read.
+ */
+
+ last_byte = start + length;
+ if ( last_byte > the_jnode->info.file.size )
+ my_length = the_jnode->info.file.size - start;
+
+ copied = 0;
+
+ /*
+ * Three phases to the read:
+ * + possibly the last part of one block
+ * + all of zero of more blocks
+ * + possibly the first part of one block
+ */
+
+ /*
+ * Phase 1: possibly the last part of one block
+ */
+
+ start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
+ block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ if ( start_offset ) {
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
+ if ( to_copy > my_length )
+ to_copy = my_length;
+ block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ assert( block_ptr );
+ if ( !block_ptr )
+ return copied;
+ memcpy( dest, &(*block_ptr)[ start_offset ], to_copy );
+ dest += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 2: all of zero of more blocks
+ */
+
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
+ while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
+ block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ assert( block_ptr );
+ if ( !block_ptr )
+ return copied;
+ memcpy( dest, &(*block_ptr)[ 0 ], to_copy );
+ dest += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 3: possibly the first part of one block
+ */
+
+ assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
+
+ if ( my_length ) {
+ block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ assert( block_ptr );
+ if ( !block_ptr )
+ return copied;
+ memcpy( dest, &(*block_ptr)[ 0 ], my_length );
+ copied += my_length;
+ }
+
+ IMFS_update_atime( the_jnode );
+
+ return copied;
+}
+
+/*
+ * IMFS_memfile_write
+ *
+ * This routine writes the specified data buffer into the in memory
+ * file pointed to by the_jnode. The file is extended as needed.
+ */
+
+MEMFILE_STATIC int IMFS_memfile_write(
+ IMFS_jnode_t *the_jnode,
+ off_t start,
+ const unsigned char *source,
+ unsigned int length
+)
+{
+ block_p *block_ptr;
+ unsigned int block;
+ int status;
+ unsigned int my_length;
+ unsigned int to_copy = 0;
+ unsigned int last_byte;
+ unsigned int start_offset;
+ int copied;
+ const unsigned char *src;
+
+ src = source;
+
+ /*
+ * Perform internal consistency checks
+ */
+
+ assert( the_jnode );
+ if ( !the_jnode )
+ set_errno_and_return_minus_one( EIO );
+
+ assert( the_jnode->type == IMFS_MEMORY_FILE );
+ if ( the_jnode->type != IMFS_MEMORY_FILE )
+ set_errno_and_return_minus_one( EIO );
+
+ /*
+ * Error check arguments
+ */
+
+ assert( source );
+ if ( !source )
+ set_errno_and_return_minus_one( EINVAL );
+
+
+ /*
+ * If there is nothing to write, then quick exit.
+ */
+
+ my_length = length;
+ if ( !my_length )
+ set_errno_and_return_minus_one( EINVAL );
+
+ /*
+ * If the last byte we are supposed to write is past the end of this
+ * in memory file, then extend the length.
+ */
+
+ last_byte = start + length;
+ if ( last_byte > the_jnode->info.file.size ) {
+ status = IMFS_memfile_extend( the_jnode, last_byte );
+ if ( status )
+ set_errno_and_return_minus_one( ENOSPC );
+ }
+
+ copied = 0;
+
+ /*
+ * Three phases to the write:
+ * + possibly the last part of one block
+ * + all of zero of more blocks
+ * + possibly the first part of one block
+ */
+
+ /*
+ * Phase 1: possibly the last part of one block
+ */
+
+ start_offset = start % IMFS_MEMFILE_BYTES_PER_BLOCK;
+ block = start / IMFS_MEMFILE_BYTES_PER_BLOCK;
+ if ( start_offset ) {
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK - start_offset;
+ if ( to_copy > my_length )
+ to_copy = my_length;
+ block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ assert( block_ptr );
+ if ( !block_ptr )
+ return copied;
+ memcpy( &(*block_ptr)[ start_offset ], src, to_copy );
+ src += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 2: all of zero of more blocks
+ */
+
+ to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK;
+ while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) {
+ block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ assert( block_ptr );
+ if ( !block_ptr )
+ return copied;
+ memcpy( &(*block_ptr)[ 0 ], src, to_copy );
+ src += to_copy;
+ block++;
+ my_length -= to_copy;
+ copied += to_copy;
+ }
+
+ /*
+ * Phase 3: possibly the first part of one block
+ */
+
+ assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK );
+
+ to_copy = my_length;
+ if ( my_length ) {
+ block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 );
+ assert( block_ptr );
+ if ( !block_ptr )
+ return copied;
+ memcpy( &(*block_ptr)[ 0 ], src, my_length );
+ my_length = 0;
+ copied += to_copy;
+ }
+
+ IMFS_atime_mtime_update( the_jnode );
+
+ return copied;
+}
+
+/*
+ * IMFS_memfile_get_block_pointer
+ *
+ * This routine looks up the block pointer associated with the given block
+ * number. If that block has not been allocated and "malloc_it" is
+ * TRUE, then the block is allocated. Otherwise, it is an error.
+ */
+
+block_p *IMFS_memfile_get_block_pointer(
+ IMFS_jnode_t *the_jnode,
+ unsigned int block,
+ int malloc_it
+)
+{
+ unsigned int my_block;
+ IMFS_memfile_t *info;
+ unsigned int singly;
+ unsigned int doubly;
+ unsigned int triply;
+ block_p *p;
+ block_p *p1;
+ block_p *p2;
+
+ /*
+ * Perform internal consistency checks
+ */
+
+ assert( the_jnode );
+ if ( !the_jnode )
+ return NULL;
+
+ assert( the_jnode->type == IMFS_MEMORY_FILE );
+ if ( the_jnode->type != IMFS_MEMORY_FILE )
+ return NULL;
+
+ info = &the_jnode->info.file;
+
+ my_block = block;
+
+ /*
+ * Is the block number in the simple indirect portion?
+ */
+
+ if ( my_block <= LAST_INDIRECT ) {
+#if 0
+printf( "(s %d) ", block );
+fflush(stdout);
+#endif
+ p = info->indirect;
+
+ if ( malloc_it ) {
+
+ if ( !p ) {
+ p = memfile_alloc_block();
+ if ( !p )
+ return 0;
+ info->indirect = p;
+ }
+ return &info->indirect[ my_block ];
+ }
+
+ if ( !p )
+ return 0;
+
+ return &info->indirect[ my_block ];
+ }
+
+ /*
+ * Is the block number in the doubly indirect portion?
+ */
+
+ if ( my_block <= LAST_DOUBLY_INDIRECT ) {
+#if 0
+printf( "(d %d) ", block );
+fflush(stdout);
+#endif
+
+ my_block -= FIRST_DOUBLY_INDIRECT;
+
+ singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
+ doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
+
+ p = info->doubly_indirect;
+ if ( malloc_it ) {
+
+ if ( !p ) {
+ p = memfile_alloc_block();
+ if ( !p )
+ return 0;
+ info->doubly_indirect = p;
+ }
+
+ p1 = (block_p *)p[ doubly ];
+ if ( !p1 ) {
+ p1 = memfile_alloc_block();
+ if ( !p1 )
+ return 0;
+ p[ doubly ] = (block_p) p1;
+ }
+
+ return (block_p *)&p[ singly ];
+ }
+
+ if ( !p )
+ return 0;
+
+ p = (block_p *)p[ doubly ];
+ if ( !p )
+ return 0;
+
+#if 0
+printf( "(d %d %d %d %d %p %p) ", block, my_block, doubly,
+ singly, p, &p[singly] );
+fflush(stdout);
+#endif
+ return (block_p *)&p[ singly ];
+ }
+
+#if 0
+printf( "(t %d) ", block );
+fflush(stdout);
+#endif
+ /*
+ * Is the block number in the triply indirect portion?
+ */
+
+ if ( my_block <= LAST_TRIPLY_INDIRECT ) {
+ my_block -= FIRST_TRIPLY_INDIRECT;
+
+ singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS;
+ doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS;
+ triply = doubly / IMFS_MEMFILE_BLOCK_SLOTS;
+ doubly %= IMFS_MEMFILE_BLOCK_SLOTS;
+
+ p = info->triply_indirect;
+
+ if ( malloc_it ) {
+ if ( !p ) {
+ p = memfile_alloc_block();
+ if ( !p )
+ return 0;
+ info->triply_indirect = p;
+ }
+
+ p1 = (block_p *) p[ triply ];
+ if ( !p1 ) {
+ p1 = memfile_alloc_block();
+ if ( !p1 )
+ return 0;
+ p[ triply ] = (block_p) p1;
+ }
+
+ p2 = (block_p *)p1[ doubly ];
+ if ( !p2 ) {
+ p2 = memfile_alloc_block();
+ if ( !p2 )
+ return 0;
+ p1[ doubly ] = (block_p) p2;
+ }
+ return (block_p *)&p2[ singly ];
+ }
+
+ if ( !p )
+ return 0;
+
+#if 0
+printf( "(t %d %d %d %d %d) ", block, my_block, triply, doubly, singly );
+fflush(stdout);
+#endif
+ p1 = (block_p *) p[ triply ];
+ if ( !p1 )
+ return 0;
+
+ p2 = (block_p *)p1[ doubly ];
+ if ( !p )
+ return 0;
+
+ return (block_p *)&p2[ singly ];
+ }
+
+ /*
+ * This means the requested block number is out of range.
+ */
+
+ return 0;
+}
+
+/*
+ * memfile_alloc_block
+ *
+ * Allocate a block for an in-memory file.
+ */
+
+int memfile_blocks_allocated = 0;
+
+void *memfile_alloc_block(void)
+{
+ void *memory;
+
+ memory = (void *)calloc(1, IMFS_MEMFILE_BYTES_PER_BLOCK);
+ if ( memory )
+ memfile_blocks_allocated++;
+
+ return memory;
+}
+
+/*
+ * memfile_free_blocK
+ *
+ * Free a block from an in-memory file.
+ */
+
+void memfile_free_block(
+ void *memory
+)
+{
+#if 0
+printf( "(d %p) ", memory );
+fflush(stdout);
+#endif
+ free(memory);
+ memfile_blocks_allocated--;
+}
+