diff options
Diffstat (limited to 'c/src/libfs/src/imfs')
26 files changed, 4268 insertions, 0 deletions
diff --git a/c/src/libfs/src/imfs/deviceio.c b/c/src/libfs/src/imfs/deviceio.c new file mode 100644 index 0000000000..f954decf6e --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs.h b/c/src/libfs/src/imfs/imfs.h new file mode 100644 index 0000000000..6eb535527d --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_chown.c b/c/src/libfs/src/imfs/imfs_chown.c new file mode 100644 index 0000000000..816294ee34 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_creat.c b/c/src/libfs/src/imfs/imfs_creat.c new file mode 100644 index 0000000000..fd38e7f993 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_debug.c b/c/src/libfs/src/imfs/imfs_debug.c new file mode 100644 index 0000000000..856f21317e --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_directory.c b/c/src/libfs/src/imfs/imfs_directory.c new file mode 100644 index 0000000000..134204027a --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_eval.c b/c/src/libfs/src/imfs/imfs_eval.c new file mode 100644 index 0000000000..eb770a58ce --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_fchmod.c b/c/src/libfs/src/imfs/imfs_fchmod.c new file mode 100644 index 0000000000..06c2969100 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_free.c b/c/src/libfs/src/imfs/imfs_free.c new file mode 100644 index 0000000000..8216547c12 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_getchild.c b/c/src/libfs/src/imfs/imfs_getchild.c new file mode 100644 index 0000000000..3f37738ab4 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_gtkn.c b/c/src/libfs/src/imfs/imfs_gtkn.c new file mode 100644 index 0000000000..052c67ceba --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_init.c b/c/src/libfs/src/imfs/imfs_init.c new file mode 100644 index 0000000000..bb3a0f9aea --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_initsupp.c b/c/src/libfs/src/imfs/imfs_initsupp.c new file mode 100644 index 0000000000..bb3a0f9aea --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_link.c b/c/src/libfs/src/imfs/imfs_link.c new file mode 100644 index 0000000000..2232209705 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_mknod.c b/c/src/libfs/src/imfs/imfs_mknod.c new file mode 100644 index 0000000000..d4feef4f36 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_mount.c b/c/src/libfs/src/imfs/imfs_mount.c new file mode 100644 index 0000000000..a267b52576 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_ntype.c b/c/src/libfs/src/imfs/imfs_ntype.c new file mode 100644 index 0000000000..bdf451a879 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_readlink.c b/c/src/libfs/src/imfs/imfs_readlink.c new file mode 100644 index 0000000000..958118f42f --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_rmnod.c b/c/src/libfs/src/imfs/imfs_rmnod.c new file mode 100644 index 0000000000..f651622de4 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_stat.c b/c/src/libfs/src/imfs/imfs_stat.c new file mode 100644 index 0000000000..4628736714 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_symlink.c b/c/src/libfs/src/imfs/imfs_symlink.c new file mode 100644 index 0000000000..0d3ebbd670 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_unlink.c b/c/src/libfs/src/imfs/imfs_unlink.c new file mode 100644 index 0000000000..4e0ca26b2a --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_unmount.c b/c/src/libfs/src/imfs/imfs_unmount.c new file mode 100644 index 0000000000..f29d720ab3 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/imfs_utime.c b/c/src/libfs/src/imfs/imfs_utime.c new file mode 100644 index 0000000000..bc2639ef8c --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/ioman.c b/c/src/libfs/src/imfs/ioman.c new file mode 100644 index 0000000000..f8b725e987 --- /dev/null +++ b/c/src/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/c/src/libfs/src/imfs/memfile.c b/c/src/libfs/src/imfs/memfile.c new file mode 100644 index 0000000000..01aee443f3 --- /dev/null +++ b/c/src/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--; +} + |