diff options
Diffstat (limited to 'cpukit/libfs/src/imfs')
39 files changed, 5246 insertions, 0 deletions
diff --git a/cpukit/libfs/src/imfs/.cvsignore b/cpukit/libfs/src/imfs/.cvsignore new file mode 100644 index 0000000000..c62d89f265 --- /dev/null +++ b/cpukit/libfs/src/imfs/.cvsignore @@ -0,0 +1,5 @@ +config.h +config.h.in +stamp-h +stamp-h.in +stamp-h1.in diff --git a/cpukit/libfs/src/imfs/deviceerrno.c b/cpukit/libfs/src/imfs/deviceerrno.c new file mode 100644 index 0000000000..396df7619d --- /dev/null +++ b/cpukit/libfs/src/imfs/deviceerrno.c @@ -0,0 +1,73 @@ +/* + * 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-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include <rtems.h> +#include <rtems/libio.h> + +static const int status_code_to_errno [RTEMS_STATUS_CODES_LAST + 1] = { + [RTEMS_SUCCESSFUL] = 0, + [RTEMS_TASK_EXITTED] = EIO, + [RTEMS_MP_NOT_CONFIGURED] = EIO, + [RTEMS_INVALID_NAME] = EINVAL, + [RTEMS_INVALID_ID] = EIO, + [RTEMS_TOO_MANY] = EIO, + [RTEMS_TIMEOUT] = ETIMEDOUT, + [RTEMS_OBJECT_WAS_DELETED] = EIO, + [RTEMS_INVALID_SIZE] = EIO, + [RTEMS_INVALID_ADDRESS] = EIO, + [RTEMS_INVALID_NUMBER] = EBADF, + [RTEMS_NOT_DEFINED] = EIO, + [RTEMS_RESOURCE_IN_USE] = EBUSY, + [RTEMS_UNSATISFIED] = ENODEV, + [RTEMS_INCORRECT_STATE] = EIO, + [RTEMS_ALREADY_SUSPENDED] = EIO, + [RTEMS_ILLEGAL_ON_SELF] = EIO, + [RTEMS_ILLEGAL_ON_REMOTE_OBJECT] = EIO, + [RTEMS_CALLED_FROM_ISR] = EIO, + [RTEMS_INVALID_PRIORITY] = EIO, + [RTEMS_INVALID_CLOCK] = EINVAL, + [RTEMS_INVALID_NODE] = EINVAL, + [RTEMS_NOT_CONFIGURED] = ENOSYS, + [RTEMS_NOT_OWNER_OF_RESOURCE] = EPERM, + [RTEMS_NOT_IMPLEMENTED] = ENOSYS, + [RTEMS_INTERNAL_ERROR] = EIO, + [RTEMS_NO_MEMORY] = ENOMEM, + [RTEMS_IO_ERROR] = EIO, + [RTEMS_PROXY_BLOCKING] = EIO +}; + +int rtems_deviceio_errno(rtems_status_code sc) +{ + if (sc == RTEMS_SUCCESSFUL) { + return 0; + } else { + int eno = EINVAL; + + if ((unsigned) sc <= RTEMS_STATUS_CODES_LAST) { + eno = status_code_to_errno [sc]; + } + + errno = eno; + + return -1; + } +} diff --git a/cpukit/libfs/src/imfs/deviceio.c b/cpukit/libfs/src/imfs/deviceio.c new file mode 100644 index 0000000000..ff6cf2a01e --- /dev/null +++ b/cpukit/libfs/src/imfs/deviceio.c @@ -0,0 +1,233 @@ +/* + * 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-2008. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/devfs.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, + uint32_t flag, + uint32_t mode +) +{ + rtems_libio_open_close_args_t args; + rtems_status_code status; + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + 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 + ); + + return rtems_deviceio_errno( status ); +} + +/* + * 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->pathinfo.node_access; + + 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 + ); + + IMFS_check_node_remove( the_jnode ); + + return rtems_deviceio_errno( status ); +} + +/* + * device_read + * + * This handler maps a read() operation onto rtems_io_read(). + */ + +ssize_t device_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + rtems_libio_rw_args_t args; + rtems_status_code status; + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + 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 rtems_deviceio_errno(status); + + return (ssize_t) args.bytes_moved; +} + +/* + * device_write + * + * This handler maps a write() operation onto rtems_io_write(). + */ + +ssize_t device_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + rtems_libio_rw_args_t args; + rtems_status_code status; + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + 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 rtems_deviceio_errno(status); + + return (ssize_t) args.bytes_moved; +} + +/* + * device_ioctl + * + * This handler maps an ioctl() operation onto rtems_io_ioctl(). + */ + +int device_ioctl( + rtems_libio_t *iop, + uint32_t 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->pathinfo.node_access; + + status = rtems_io_control( + the_jnode->info.device.major, + the_jnode->info.device.minor, + (void *) &args + ); + + if ( status ) + return rtems_deviceio_errno(status); + + return args.ioctl_return; +} + +/* + * device_lseek + * + * This handler eats all lseek() operations and does not create + * an error. It assumes all devices can handle the seek. The + * writes fail. + */ + +rtems_off64_t device_lseek( + rtems_libio_t *iop, + rtems_off64_t offset, + int whence +) +{ + return offset; +} + +/* + * device_stat + * + * The IMFS_stat() is used. + */ + +/* + * device_rmnod + * + * The IMFS_rmnod() is used. + */ + +int device_ftruncate( + rtems_libio_t *iop, + rtems_off64_t length +) +{ + return 0; +} diff --git a/cpukit/libfs/src/imfs/fifoimfs_init.c b/cpukit/libfs/src/imfs/fifoimfs_init.c new file mode 100644 index 0000000000..13dc373eec --- /dev/null +++ b/cpukit/libfs/src/imfs/fifoimfs_init.c @@ -0,0 +1,61 @@ +/** + * @file + * + * @ingroup LibFSIMFS + * + * @brief IMFS without fifo support initialization. + */ + +/* + * Copyright (c) 2010 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imfs.h" + +const rtems_filesystem_operations_table fifoIMFS_ops = { + .evalpath_h = IMFS_eval_path, + .evalformake_h = IMFS_evaluate_for_make, + .link_h = IMFS_link, + .unlink_h = IMFS_unlink, + .node_type_h = IMFS_node_type, + .mknod_h = IMFS_mknod, + .chown_h = IMFS_chown, + .freenod_h = rtems_filesystem_default_freenode, + .mount_h = IMFS_mount, + .fsmount_me_h = fifoIMFS_initialize, + .unmount_h = IMFS_unmount, + .fsunmount_me_h = IMFS_fsunmount, + .utime_h = IMFS_utime, + .eval_link_h = IMFS_evaluate_link, + .symlink_h = IMFS_symlink, + .readlink_h = IMFS_readlink, + .rename_h = IMFS_rename, + .statvfs_h = rtems_filesystem_default_statvfs +}; + +int fifoIMFS_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) +{ + return IMFS_initialize_support( + mt_entry, + &fifoIMFS_ops, + &IMFS_memfile_handlers, + &IMFS_directory_handlers, + &IMFS_fifo_handlers + ); +} diff --git a/cpukit/libfs/src/imfs/imfs.h b/cpukit/libfs/src/imfs/imfs.h new file mode 100644 index 0000000000..aec8febdc5 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs.h @@ -0,0 +1,574 @@ +/* + * Header file for the In-Memory File System + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#ifndef _RTEMS_IMFS_H +#define _RTEMS_IMFS_H + +#include <rtems.h> +#include <rtems/chain.h> + +#include <sys/types.h> +#include <limits.h> +#include <rtems/libio.h> + +#include <rtems/pipe.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * 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 { + rtems_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 { + char *name; +} IMFS_sym_link_t; + +typedef struct { + pipe_control_t *pipe; +} IMFS_fifo_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. + * + * Setting IMFS_MEMFILE_BYTES_PER_BLOCK to different values has a significant + * impact on the maximum file size supported as well as the amount of + * memory wasted due to internal file fragmentation. The following + * is a list of maximum file sizes based on various settings + * + * max_filesize with blocks of 16 is 1,328 + * max_filesize with blocks of 32 is 18,656 + * max_filesize with blocks of 64 is 279,488 + * max_filesize with blocks of 128 is 4,329,344 + * max_filesize with blocks of 256 is 68,173,568 + * max_filesize with blocks of 512 is 1,082,195,456 + */ + +#define IMFS_MEMFILE_DEFAULT_BYTES_PER_BLOCK 128 + extern int imfs_rq_memfile_bytes_per_block; + extern int imfs_memfile_bytes_per_block; + +#define IMFS_MEMFILE_BYTES_PER_BLOCK imfs_memfile_bytes_per_block +#define IMFS_MEMFILE_BLOCK_SLOTS \ + (IMFS_MEMFILE_BYTES_PER_BLOCK / sizeof(void *)) + +typedef uint8_t *block_p; +typedef block_p *block_ptr; + +typedef struct { + rtems_off64_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; + +typedef struct { + rtems_off64_t size; /* size of file in bytes */ + block_p direct; /* pointer to file image */ +} IMFS_linearfile_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. + */ + +typedef enum { + IMFS_DIRECTORY = RTEMS_FILESYSTEM_DIRECTORY, + IMFS_DEVICE = RTEMS_FILESYSTEM_DEVICE, + IMFS_HARD_LINK = RTEMS_FILESYSTEM_HARD_LINK, + IMFS_SYM_LINK = RTEMS_FILESYSTEM_SYM_LINK, + IMFS_MEMORY_FILE = RTEMS_FILESYSTEM_MEMORY_FILE, + IMFS_LINEAR_FILE, + IMFS_FIFO +} IMFS_jnode_types_t; + +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_linearfile_t linearfile; + IMFS_fifo_t fifo; +} IMFS_types_union; + +/* + * Major device number for the IMFS. This is not a real device number because + * the IMFS is just a file system and does not have a driver. + */ +#define IMFS_DEVICE_MAJOR_NUMBER (0xfffe) + +/* + * Maximum length of a "basename" of an IMFS file/node. + */ + +#define IMFS_NAME_MAX 32 + +/* + * The control structure for an IMFS jnode. + */ + +struct IMFS_jnode_tt { + rtems_chain_node Node; /* for chaining them together */ + IMFS_jnode_t *Parent; /* Parent node */ + char name[IMFS_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 stat_atime; /* Time of last access */ + time_t stat_mtime; /* Time of last modification */ + time_t stat_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->stat_atime = (time_t) tv.tv_sec; \ + } while (0) + +#define IMFS_update_mtime( _jnode ) \ + do { \ + struct timeval tv; \ + gettimeofday( &tv, 0 ); \ + _jnode->stat_mtime = (time_t) tv.tv_sec; \ + } while (0) + +#define IMFS_update_ctime( _jnode ) \ + do { \ + struct timeval tv; \ + gettimeofday( &tv, 0 ); \ + _jnode->stat_ctime = (time_t) tv.tv_sec; \ + } while (0) + +#define IMFS_mtime_ctime_update( _jnode ) \ + do { \ + struct timeval tv; \ + gettimeofday( &tv, 0 ); \ + _jnode->stat_mtime = (time_t) tv.tv_sec; \ + _jnode->stat_ctime = (time_t) tv.tv_sec; \ + } while (0) + +typedef struct { + int instance; + ino_t ino_count; + const rtems_filesystem_file_handlers_r *memfile_handlers; + const rtems_filesystem_file_handlers_r *directory_handlers; + const rtems_filesystem_file_handlers_r *fifo_handlers; +} IMFS_fs_info_t; + +/* + * 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 const rtems_filesystem_file_handlers_r IMFS_directory_handlers; +extern const rtems_filesystem_file_handlers_r IMFS_device_handlers; +extern const rtems_filesystem_file_handlers_r IMFS_link_handlers; +extern const rtems_filesystem_file_handlers_r IMFS_memfile_handlers; +extern const rtems_filesystem_file_handlers_r IMFS_fifo_handlers; +extern const rtems_filesystem_operations_table IMFS_ops; +extern const rtems_filesystem_operations_table fifoIMFS_ops; +extern const rtems_filesystem_limits_and_options_t IMFS_LIMITS_AND_OPTIONS; + +/* + * Routines + */ + +extern int IMFS_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +); + +extern int fifoIMFS_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +); + +extern int miniIMFS_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +); + +extern int IMFS_initialize_support( + rtems_filesystem_mount_table_entry_t *mt_entry, + const rtems_filesystem_operations_table *op_table, + const rtems_filesystem_file_handlers_r *memfile_handlers, + const rtems_filesystem_file_handlers_r *directory_handlers, + const rtems_filesystem_file_handlers_r *fifo_handlers +); + +extern int IMFS_fsunmount( + rtems_filesystem_mount_table_entry_t *mt_entry +); + +extern int rtems_tarfs_load( + char *mountpoint, + uint8_t *tar_image, + size_t tar_size +); + +/* + * Returns the number of characters copied from path to token. + */ +extern IMFS_token_types IMFS_get_token( + const char *path, + int pathlen, + char *token, + int *token_len +); + +extern void IMFS_dump( void ); + +extern void IMFS_initialize_jnode( + IMFS_jnode_t *the_jnode, + IMFS_jnode_types_t type, + IMFS_jnode_t *the_parent, + char *name, + mode_t mode +); + +extern IMFS_jnode_t *IMFS_find_match_in_dir( + IMFS_jnode_t *directory, /* IN */ + char *name /* IN */ +); + +extern rtems_filesystem_node_types_t IMFS_node_type( + rtems_filesystem_location_info_t *pathloc /* IN */ +); + +extern int IMFS_stat( + rtems_filesystem_location_info_t *loc, /* IN */ + struct stat *buf /* OUT */ +); + +extern int IMFS_Set_handlers( + rtems_filesystem_location_info_t *loc +); + +extern int IMFS_evaluate_link( + rtems_filesystem_location_info_t *node, /* IN/OUT */ + int flags /* IN */ +); + +extern int IMFS_eval_path( + const char *pathname, /* IN */ + size_t pathnamelen, /* IN */ + int flags, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN/OUT */ +); + +extern int IMFS_link( + rtems_filesystem_location_info_t *to_loc, /* IN */ + rtems_filesystem_location_info_t *parent_loc, /* IN */ + const char *token /* IN */ +); + +extern int IMFS_unlink( + rtems_filesystem_location_info_t *parent_pathloc, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN */ +); + +extern int IMFS_chown( + rtems_filesystem_location_info_t *pathloc, /* IN */ + uid_t owner, /* IN */ + gid_t group /* IN */ +); + +extern int IMFS_mknod( + const char *path, /* IN */ + mode_t mode, /* IN */ + dev_t dev, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN/OUT */ +); + +extern IMFS_jnode_t *IMFS_allocate_node( + IMFS_jnode_types_t type, /* IN */ + const char *name, /* IN */ + mode_t mode /* IN */ +); + +extern IMFS_jnode_t *IMFS_create_root_node(void); + +extern IMFS_jnode_t *IMFS_create_node( + rtems_filesystem_location_info_t *parent_loc, /* IN */ + IMFS_jnode_types_t type, /* IN */ + const char *name, /* IN */ + mode_t mode, /* IN */ + const IMFS_types_union *info /* IN */ +); + +extern int IMFS_evaluate_for_make( + const char *path, /* IN */ + rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ + const char **name /* OUT */ +); + +extern int IMFS_mount( + rtems_filesystem_mount_table_entry_t *mt_entry /* IN */ +); + +extern int IMFS_unmount( + rtems_filesystem_mount_table_entry_t *mt_entry /* IN */ +); + +extern int IMFS_memfile_remove( + IMFS_jnode_t *the_jnode /* IN/OUT */ +); + +extern int memfile_ftruncate( + rtems_libio_t *iop, /* IN */ + rtems_off64_t length /* IN */ +); + +extern int imfs_dir_open( + rtems_libio_t *iop, /* IN */ + const char *pathname, /* IN */ + uint32_t flag, /* IN */ + uint32_t mode /* IN */ +); + +extern int imfs_dir_close( + rtems_libio_t *iop /* IN */ +); + +extern ssize_t imfs_dir_read( + rtems_libio_t *iop, /* IN */ + void *buffer, /* IN */ + size_t count /* IN */ +); + +extern rtems_off64_t imfs_dir_lseek( + rtems_libio_t *iop, /* IN */ + rtems_off64_t offset, /* IN */ + int whence /* IN */ +); + +extern int imfs_dir_fstat( + rtems_filesystem_location_info_t *loc, /* IN */ + struct stat *buf /* OUT */ +); + +extern int imfs_dir_rmnod( + rtems_filesystem_location_info_t *parent_pathloc, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN */ +); + +extern int memfile_open( + rtems_libio_t *iop, /* IN */ + const char *pathname, /* IN */ + uint32_t flag, /* IN */ + uint32_t mode /* IN */ +); + +extern int memfile_close( + rtems_libio_t *iop /* IN */ +); + +extern ssize_t memfile_read( + rtems_libio_t *iop, /* IN */ + void *buffer, /* IN */ + size_t count /* IN */ +); + +extern ssize_t memfile_write( + rtems_libio_t *iop, /* IN */ + const void *buffer, /* IN */ + size_t count /* IN */ +); + +extern int memfile_ioctl( + rtems_libio_t *iop, /* IN */ + uint32_t command, /* IN */ + void *buffer /* IN */ +); + +extern rtems_off64_t memfile_lseek( + rtems_libio_t *iop, /* IN */ + rtems_off64_t offset, /* IN */ + int whence /* IN */ +); + +extern int device_open( + rtems_libio_t *iop, /* IN */ + const char *pathname, /* IN */ + uint32_t flag, /* IN */ + uint32_t mode /* IN */ +); + +extern int device_close( + rtems_libio_t *iop /* IN */ +); + +extern ssize_t device_read( + rtems_libio_t *iop, /* IN */ + void *buffer, /* IN */ + size_t count /* IN */ +); + +extern ssize_t device_write( + rtems_libio_t *iop, /* IN */ + const void *buffer, /* IN */ + size_t count /* IN */ +); + +extern int device_ioctl( + rtems_libio_t *iop, /* IN */ + uint32_t command, /* IN */ + void *buffer /* IN */ +); + +extern rtems_off64_t device_lseek( + rtems_libio_t *iop, /* IN */ + rtems_off64_t offset, /* IN */ + int whence /* IN */ +); + +extern int device_ftruncate( + rtems_libio_t *iop, /* IN */ + rtems_off64_t length /* IN */ +); + +extern int IMFS_utime( + rtems_filesystem_location_info_t *pathloc, /* IN */ + time_t actime, /* IN */ + time_t modtime /* IN */ +); + +extern int IMFS_fchmod( + rtems_filesystem_location_info_t *loc, + mode_t mode +); + +extern int IMFS_symlink( + rtems_filesystem_location_info_t *parent_loc, /* IN */ + const char *link_name, + const char *node_name +); + +extern ssize_t IMFS_readlink( + rtems_filesystem_location_info_t *loc, /* IN */ + char *buf, /* OUT */ + size_t bufsize +); + +extern int IMFS_rename( + rtems_filesystem_location_info_t *old_loc, /* IN */ + rtems_filesystem_location_info_t *old_parent_loc, /* IN */ + rtems_filesystem_location_info_t *new_parent_loc, /* IN */ + const char *new_name /* IN */ +); + +extern int IMFS_fdatasync( + rtems_libio_t *iop +); + +extern void IMFS_create_orphan( + IMFS_jnode_t *jnode +); + +extern void IMFS_check_node_remove( + IMFS_jnode_t *jnode +); + +extern int IMFS_rmnod( + rtems_filesystem_location_info_t *parent_pathloc, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN */ +); + +/* + * Turn on IMFS assertions when RTEMS_DEBUG is defined. + */ +#ifdef RTEMS_DEBUG + #include <assert.h> + + #define IMFS_assert(_x) assert(_x) +#else + #define IMFS_assert(_x) +#endif + +#ifdef __cplusplus +} +#endif + +#endif +/* end of include file */ diff --git a/cpukit/libfs/src/imfs/imfs_chown.c b/cpukit/libfs/src/imfs/imfs_chown.c new file mode 100644 index 0000000000..7f0c7b5688 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_chown.c @@ -0,0 +1,56 @@ +/* + * IMFS_chown + * + * This routine is the implementation of the chown() system + * call for the IMFS. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <rtems/libio_.h> +#include <rtems/seterr.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 ) ) + rtems_set_errno_and_return_minus_one( EPERM ); +#endif + + jnode->st_uid = owner; + jnode->st_gid = group; + + IMFS_update_ctime( jnode ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_config.c b/cpukit/libfs/src/imfs/imfs_config.c new file mode 100644 index 0000000000..78f947e81f --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_config.c @@ -0,0 +1,35 @@ +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems.h> +#include <rtems/libio_.h> +#include "imfs.h" + +/* XXX this structure should use real constants */ + +const rtems_filesystem_limits_and_options_t IMFS_LIMITS_AND_OPTIONS = { + 5, /* link_max */ + 6, /* max_canon */ + 7, /* max_input */ + IMFS_NAME_MAX, /* name_max */ + 255, /* path_max */ + 2, /* pipe_buf */ + 1, /* posix_async_io */ + 2, /* posix_chown_restrictions */ + 3, /* posix_no_trunc */ + 4, /* posix_prio_io */ + 5, /* posix_sync_io */ + 6 /* posix_vdisable */ +}; diff --git a/cpukit/libfs/src/imfs/imfs_creat.c b/cpukit/libfs/src/imfs/imfs_creat.c new file mode 100644 index 0000000000..3b602d0c14 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_creat.c @@ -0,0 +1,170 @@ +/* + * IMFS_create_node() + * + * Routine to create a new in memory file system node. + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include "imfs.h" +#include <rtems/libio_.h> + +/* + * Create an IMFS filesystem node of an arbitrary type that is NOT + * the root directory node. + */ +IMFS_jnode_t *IMFS_create_node( + rtems_filesystem_location_info_t *parent_loc, + IMFS_jnode_types_t type, + const char *name, + mode_t mode, + const IMFS_types_union *info +) +{ + IMFS_jnode_t *node; + IMFS_jnode_t *parent; + IMFS_fs_info_t *fs_info; + + /* + * MUST have a parent node to call this routine. + */ + if ( parent_loc == NULL ) + return NULL; + + parent = parent_loc->node_access; + fs_info = parent_loc->mt_entry->fs_info; + + /* + * Reject creation of FIFOs if support is disabled. + */ + if ( type == IMFS_FIFO && + fs_info->fifo_handlers == &rtems_filesystem_handlers_default ) + return NULL; + + /* + * Allocate filesystem node and fill in basic information + */ + node = IMFS_allocate_node( type, name, mode & ~rtems_filesystem_umask ); + if ( !node ) + return NULL; + + /* + * Set the type specific information + */ + if ( type == IMFS_DIRECTORY ) { + rtems_chain_initialize_empty(&node->info.directory.Entries); + } else if ( type == IMFS_HARD_LINK ) { + node->info.hard_link.link_node = info->hard_link.link_node; + } else if ( type == IMFS_SYM_LINK ) { + node->info.sym_link.name = info->sym_link.name; + } else if ( type == IMFS_DEVICE ) { + node->info.device.major = info->device.major; + node->info.device.minor = info->device.minor; + } else if ( type == IMFS_LINEAR_FILE ) { + node->info.linearfile.size = 0; + node->info.linearfile.direct = 0; + } else if ( type == 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; + } else if ( type == IMFS_FIFO ) { + node->info.fifo.pipe = NULL; + } else { + IMFS_assert(0); + } + + /* + * This node MUST have a parent, so put it in that directory list. + */ + node->Parent = parent; + node->st_ino = ++fs_info->ino_count; + + rtems_chain_append( &parent->info.directory.Entries, &node->Node ); + + return node; +} + +/* + * Allocate filesystem node and fill in basic information + */ +IMFS_jnode_t *IMFS_allocate_node( + IMFS_jnode_types_t type, + const char *name, + mode_t mode +) +{ + IMFS_jnode_t *node; + struct timeval tv; + + /* + * 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, IMFS_NAME_MAX ); + + /* + * Fill in the mode and permission information for the jnode structure. + */ + node->st_mode = mode; + #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->stat_atime = (time_t) tv.tv_sec; + node->stat_mtime = (time_t) tv.tv_sec; + node->stat_ctime = (time_t) tv.tv_sec; + + return node; +} + +IMFS_jnode_t *IMFS_create_root_node(void) +{ + IMFS_jnode_t *node; + + /* + * Allocate filesystem node and fill in basic information + */ + node = IMFS_allocate_node( IMFS_DIRECTORY, "", (S_IFDIR | 0755) ); + if ( !node ) + return NULL; + + /* + * Set the type specific information + * + * NOTE: Root node is always a directory. + */ + rtems_chain_initialize_empty(&node->info.directory.Entries); + + return node; +} diff --git a/cpukit/libfs/src/imfs/imfs_debug.c b/cpukit/libfs/src/imfs/imfs_debug.c new file mode 100644 index 0000000000..0a4e3a9bba --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_debug.c @@ -0,0 +1,159 @@ +/* + * IMFS debug support routines + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> /* for close */ +#include <inttypes.h> + +#include <stdio.h> +#include <sys/stat.h> + +#include "imfs.h" +#include <rtems/libio_.h> + +/* + * IMFS_print_jnode + * + * This routine prints the contents of the specified jnode. + */ +void IMFS_print_jnode( + IMFS_jnode_t *the_jnode +) +{ + IMFS_assert( the_jnode ); + + fprintf(stdout, "%s", the_jnode->name ); + switch( the_jnode->type ) { + case IMFS_DIRECTORY: + fprintf(stdout, "/" ); + break; + + case IMFS_DEVICE: + fprintf(stdout, " (device %" PRId32 ", %" PRId32 ")", + the_jnode->info.device.major, the_jnode->info.device.minor ); + break; + + case IMFS_LINEAR_FILE: + fprintf(stdout, " (file %" PRId32 " %p)", + (uint32_t)the_jnode->info.linearfile.size, + the_jnode->info.linearfile.direct + ); + break; + + case IMFS_MEMORY_FILE: + /* Useful when debugging .. varies between targets */ +#if 0 + fprintf(stdout, " (file %" PRId32 " %p %p %p)", + (uint32_t)the_jnode->info.file.size, + the_jnode->info.file.indirect, + the_jnode->info.file.doubly_indirect, + the_jnode->info.file.triply_indirect + ); +#else + fprintf(stdout, " (file %" PRId32 ")", + (uint32_t)the_jnode->info.file.size ); +#endif + break; + + case IMFS_HARD_LINK: + fprintf(stdout, " links not printed\n" ); + return; + + case IMFS_SYM_LINK: + fprintf(stdout, " links not printed\n" ); + return; + + case IMFS_FIFO: + fprintf(stdout, " FIFO not printed\n" ); + return; + + default: + fprintf(stdout, " bad type %d\n", the_jnode->type ); + return; + } + 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 +) +{ + rtems_chain_node *the_node; + rtems_chain_control *the_chain; + IMFS_jnode_t *the_jnode; + int i; + + IMFS_assert( the_directory ); + IMFS_assert( level >= 0 ); + IMFS_assert( the_directory->type == IMFS_DIRECTORY ); + + the_chain = &the_directory->info.directory.Entries; + + for ( the_node = rtems_chain_first( the_chain ); + !rtems_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++ ) + fprintf(stdout, "...." ); + 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 ) +{ + fprintf(stdout, "*************** Dump of Entire IMFS ***************\n" ); + fprintf(stdout, "/\n" ); + IMFS_dump_directory( rtems_filesystem_root.node_access, 0 ); + fprintf(stdout, "*************** End of Dump ***************\n" ); +} + +/* + * IMFS_memfile_maximum_size() + * + * This routine returns the size of the largest file which can be created + * using the IMFS memory file type. + * + */ +int IMFS_memfile_maximum_size( void ) +{ + return IMFS_MEMFILE_MAXIMUM_SIZE; +} diff --git a/cpukit/libfs/src/imfs/imfs_directory.c b/cpukit/libfs/src/imfs/imfs_directory.c new file mode 100644 index 0000000000..46ff335e59 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_directory.c @@ -0,0 +1,317 @@ +/* + * IMFS Directory Access Routines + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <rtems/chain.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <dirent.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +/* + * imfs_dir_open + * + * 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, + uint32_t flag, + uint32_t mode +) +{ + IMFS_jnode_t *the_jnode; + + /* Is the node a directory ? */ + the_jnode = (IMFS_jnode_t *) iop->pathinfo.node_access; + + if ( the_jnode->type != IMFS_DIRECTORY ) + return -1; /* It wasn't a directory --> return error */ + + iop->offset = 0; + return 0; +} + +/* + * imfs_dir_read + * + * 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. + */ + +ssize_t imfs_dir_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + /* + * Read up to element iop->offset in the directory chain of the + * imfs_jnode_t struct for this file descriptor. + */ + rtems_chain_node *the_node; + rtems_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->pathinfo.node_access; + the_chain = &the_jnode->info.directory.Entries; + + if ( rtems_chain_is_empty( the_chain ) ) + return 0; + + /* Move to the first of the desired directory entries */ + the_node = rtems_chain_first( the_chain ); + + 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 ( rtems_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_off = current_entry; + tmp_dirent.d_reclen = sizeof( struct dirent ); + the_jnode = (IMFS_jnode_t *) the_node; + tmp_dirent.d_ino = the_jnode->st_ino; + tmp_dirent.d_namlen = strlen( the_jnode->name ); + strcpy( tmp_dirent.d_name, 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; +} + + + +/* + * imfs_dir_close + * + * 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; +} + + + +/* + * imfs_dir_lseek + * + * 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 EINVAL to be returned. + */ + +rtems_off64_t imfs_dir_lseek( + rtems_libio_t *iop, + rtems_off64_t offset, + int whence +) +{ + switch( whence ) { + case SEEK_SET: /* absolute move from the start of the file */ + case SEEK_CUR: /* relative move */ + iop->offset = (iop->offset/sizeof(struct dirent)) * + sizeof(struct dirent); + break; + + case SEEK_END: /* Movement past the end of the directory via lseek */ + /* is not a permitted operation */ + default: + rtems_set_errno_and_return_minus_one( EINVAL ); + break; + } + + return 0; +} + + + +/* + * imfs_dir_fstat + * + * 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 + * stat_atime time of last access + * stat_mtime time of last modification + * stat_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 +) +{ + rtems_chain_node *the_node; + rtems_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->stat_atime; + buf->st_mtime = the_jnode->stat_mtime; + buf->st_ctime = the_jnode->stat_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 = rtems_chain_first( the_chain ); + !rtems_chain_is_tail( the_chain, the_node ) ; + the_node = the_node->next ) { + + buf->st_size = buf->st_size + sizeof( struct dirent ); + } + + return 0; +} + +/* + * IMFS_dir_rmnod + * + * This routine is available from the optable to remove a node + * from the IMFS file system. + */ + +int imfs_dir_rmnod( + rtems_filesystem_location_info_t *parent_pathloc, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN */ +) +{ + IMFS_jnode_t *the_jnode; + + the_jnode = (IMFS_jnode_t *) pathloc->node_access; + + /* + * You cannot remove a node that still has children + */ + + if ( ! rtems_chain_is_empty( &the_jnode->info.directory.Entries ) ) + rtems_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 ) + rtems_set_errno_and_return_minus_one( EBUSY ); + + /* + * You cannot remove a mountpoint. + */ + + if ( the_jnode->info.directory.mt_fs != NULL ) + rtems_set_errno_and_return_minus_one( EBUSY ); + + IMFS_create_orphan( the_jnode ); + IMFS_check_node_remove( the_jnode ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_eval.c b/cpukit/libfs/src/imfs/imfs_eval.c new file mode 100644 index 0000000000..503c65179a --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_eval.c @@ -0,0 +1,663 @@ +/* + * Evaluation IMFS Node Support Routines + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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; + IMFS_fs_info_t *fs_info; + + fs_info = loc->mt_entry->fs_info; + switch( node->type ) { + case IMFS_DIRECTORY: + loc->handlers = fs_info->directory_handlers; + break; + case IMFS_DEVICE: + loc->handlers = &IMFS_device_handlers; + break; + case IMFS_SYM_LINK: + case IMFS_HARD_LINK: + loc->handlers = &IMFS_link_handlers; + break; + case IMFS_LINEAR_FILE: + loc->handlers = fs_info->memfile_handlers; + break; + case IMFS_MEMORY_FILE: + loc->handlers = fs_info->memfile_handlers; + break; + case IMFS_FIFO: + loc->handlers = fs_info->fifo_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 ) ) + rtems_set_errno_and_return_minus_one( EPERM ); + + 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. + */ + IMFS_assert( jnode->type == IMFS_HARD_LINK ); + + /* + * 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 ) ) + rtems_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. + */ + IMFS_assert( jnode->type == IMFS_SYM_LINK ); + IMFS_assert( jnode->Parent ); + + /* + * 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], + strlen( &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 ) ) + rtems_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; + rtems_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[ IMFS_NAME_MAX + 1 ]; + rtems_filesystem_location_info_t newloc; + IMFS_jnode_t *node; + bool done = false; + int pathlen; + int result; + + /* + * This was filled in by the caller and is valid in the + * mount table. + */ + node = pathloc->node_access; + + /* + * Get the path length. + */ + pathlen = strlen( path ); + /* + * Evaluate all tokens until we are done or an error occurs. + */ + + while( !done ) { + + type = IMFS_get_token( &path[i], pathlen, token, &len ); + pathlen -= len; + i += len; + + if ( !pathloc->node_access ) + rtems_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 ) ) + rtems_set_errno_and_return_minus_one( EACCES ); + + node = pathloc->node_access; + + switch( type ) { + + case IMFS_UP_DIR: + /* + * Am I at the root of all filesystems? (chroot'ed?) + */ + + if ( pathloc->node_access == rtems_filesystem_root.node_access ) + break; /* Throw out the .. in this case */ + + + /* + * 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_h)( &path[i-len], pathloc, name ); + } + } else { + + if ( !node->Parent ) + rtems_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 ) + rtems_set_errno_and_return_minus_one( ENOTDIR ); + + /* + * Only a directory can be decended into. + */ + + if ( node->type != IMFS_DIRECTORY ) + rtems_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_h)( &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: + rtems_set_errno_and_return_minus_one( EEXIST ); + break; + + case IMFS_INVALID_TOKEN: + rtems_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 ] ) ) + rtems_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 ) + rtems_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 ) ) + rtems_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 */ + size_t pathnamelen, /* 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[ IMFS_NAME_MAX + 1 ]; + rtems_filesystem_location_info_t newloc; + IMFS_jnode_t *node; + int result; + + if ( !rtems_libio_is_valid_perms( flags ) ) { + rtems_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], pathnamelen, token, &len ); + pathnamelen -= len; + i += len; + + if ( !pathloc->node_access ) + rtems_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 ) ) + rtems_set_errno_and_return_minus_one( EACCES ); + + node = pathloc->node_access; + + switch( type ) { + case IMFS_UP_DIR: + /* + * Am I at the root of all filesystems? (chroot'ed?) + */ + + if ( pathloc->node_access == rtems_filesystem_root.node_access ) + break; /* Throw out the .. in this case */ + + /* + * 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_h)(&(pathname[i-len]), + pathnamelen+len, + flags,pathloc); + } + } else { + + if ( !node->Parent ) + rtems_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; + + /* + * It would be a design error if we evaluated the link and + * was broken. + */ + IMFS_assert( node ); + + } else if ( node->type == IMFS_SYM_LINK ) { + result = IMFS_evaluate_sym_link( pathloc, 0 ); + + /* + * In contrast to a hard link, it is possible to have a broken + * symbolic link. + */ + node = pathloc->node_access; + if ( result == -1 ) + return -1; + } + + /* + * Only a directory can be decended into. + */ + if ( node->type != IMFS_DIRECTORY ) + rtems_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_h)( &pathname[i-len], + pathnamelen+len, + flags, pathloc ); + } + + /* + * Otherwise find the token name in the present location. + */ + node = IMFS_find_match_in_dir( node, token ); + if ( !node ) + rtems_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: + rtems_set_errno_and_return_minus_one( ENAMETOOLONG ); + break; + + } + } + + /* + * Always return the root node. + * + * If we are at a node that is a mount point. Set loc to the + * new fs root node and let let the mounted filesystem set the handlers. + * + * NOTE: The behavior of stat() on a mount point appears to be questionable. + */ + + if ( node->type == IMFS_DIRECTORY ) { + if ( node->info.directory.mt_fs != NULL ) { + newloc = node->info.directory.mt_fs->mt_fs_root; + *pathloc = newloc; + return (*pathloc->ops->evalpath_h)( &pathname[i-len], + pathnamelen+len, + flags, pathloc ); + } else { + result = IMFS_Set_handlers( pathloc ); + } + } else { + result = IMFS_Set_handlers( pathloc ); + } + + /* + * Verify we have the correct permissions for this node. + */ + + if ( !IMFS_evaluate_permission( pathloc, flags ) ) + rtems_set_errno_and_return_minus_one( EACCES ); + + return result; +} diff --git a/cpukit/libfs/src/imfs/imfs_fchmod.c b/cpukit/libfs/src/imfs/imfs_fchmod.c new file mode 100644 index 0000000000..54a093de2f --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_fchmod.c @@ -0,0 +1,56 @@ +/* + * IMFS file change mode routine. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include <rtems/libio_.h> +#include <rtems/seterr.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 ) ) + rtems_set_errno_and_return_minus_one( EPERM ); +#endif + + /* + * Change only the RWX permissions on the jnode to mode. + */ + + jnode->st_mode &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); + jnode->st_mode |= mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX); + + IMFS_update_ctime( jnode ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_fdatasync.c b/cpukit/libfs/src/imfs/imfs_fdatasync.c new file mode 100644 index 0000000000..6b107bfaf8 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_fdatasync.c @@ -0,0 +1,29 @@ +/* + * IMFS_fdatasync + * + * The following routine does a sync on an IMFS node. The In Memory + * File System is always in sync, therefore this routine always returns + * pass. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imfs.h" + +int IMFS_fdatasync( + rtems_libio_t *iop +) +{ + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_fifo.c b/cpukit/libfs/src/imfs/imfs_fifo.c new file mode 100644 index 0000000000..7cb3bbcd85 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_fifo.c @@ -0,0 +1,148 @@ +/* + * imfs_fifo.c: FIFO support for IMFS + * + * Author: Wei Shen <cquark@gmail.com> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +#include "imfs.h" + +#define JNODE2PIPE(_jnode) ( (_jnode)->info.fifo.pipe ) + +#define LIBIO2PIPE(_iop) ( JNODE2PIPE((IMFS_jnode_t *)(_iop)->pathinfo.node_access) ) + +/* Set errno and return -1 if error, else return _err */ +#define IMFS_FIFO_RETURN(_err) \ +do { \ + if (_err < 0) \ + rtems_set_errno_and_return_minus_one(-_err); \ + return _err; \ +} while (0) + +int IMFS_fifo_open( + rtems_libio_t *iop, + const char *pathname, + uint32_t flag, + uint32_t mode +) +{ + IMFS_jnode_t *jnode = iop->pathinfo.node_access; + + int err = fifo_open(&JNODE2PIPE(jnode), iop); + IMFS_FIFO_RETURN(err); +} + +int IMFS_fifo_close( + rtems_libio_t *iop +) +{ + int err = 0; + IMFS_jnode_t *jnode = iop->pathinfo.node_access; + + pipe_release(&JNODE2PIPE(jnode), iop); + + iop->flags &= ~LIBIO_FLAGS_OPEN; + IMFS_check_node_remove(jnode); + + IMFS_FIFO_RETURN(err); +} + +ssize_t IMFS_fifo_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + IMFS_jnode_t *jnode = iop->pathinfo.node_access; + + int err = pipe_read(JNODE2PIPE(jnode), buffer, count, iop); + if (err > 0) + IMFS_update_atime(jnode); + + IMFS_FIFO_RETURN(err); +} + +ssize_t IMFS_fifo_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + IMFS_jnode_t *jnode = iop->pathinfo.node_access; + + int err = pipe_write(JNODE2PIPE(jnode), buffer, count, iop); + if (err > 0) { + IMFS_mtime_ctime_update(jnode); + } + + IMFS_FIFO_RETURN(err); +} + +int IMFS_fifo_ioctl( + rtems_libio_t *iop, + uint32_t command, + void *buffer +) +{ + int err; + + if (command == FIONBIO) { + if (buffer == NULL) + err = -EFAULT; + else { + if (*(int *)buffer) + iop->flags |= LIBIO_FLAGS_NO_DELAY; + else + iop->flags &= ~LIBIO_FLAGS_NO_DELAY; + return 0; + } + } + else + err = pipe_ioctl(LIBIO2PIPE(iop), command, buffer, iop); + + IMFS_FIFO_RETURN(err); +} + +rtems_off64_t IMFS_fifo_lseek( + rtems_libio_t *iop, + rtems_off64_t offset, + int whence +) +{ + off_t err = pipe_lseek(LIBIO2PIPE(iop), offset, whence, iop); + IMFS_FIFO_RETURN(err); +} + +/* + * Handler table for IMFS FIFO nodes + */ + +const rtems_filesystem_file_handlers_r IMFS_fifo_handlers = { + IMFS_fifo_open, + IMFS_fifo_close, + IMFS_fifo_read, + IMFS_fifo_write, + IMFS_fifo_ioctl, + IMFS_fifo_lseek, + IMFS_stat, + IMFS_fchmod, + rtems_filesystem_default_ftruncate, + rtems_filesystem_default_fpathconf, + rtems_filesystem_default_fsync, + rtems_filesystem_default_fdatasync, + rtems_filesystem_default_fcntl, + IMFS_rmnod, +}; diff --git a/cpukit/libfs/src/imfs/imfs_fsunmount.c b/cpukit/libfs/src/imfs/imfs_fsunmount.c new file mode 100644 index 0000000000..b65c20e60d --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_fsunmount.c @@ -0,0 +1,94 @@ +/* + * IMFS Initialization + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> /* for mkdir */ +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include "imfs.h" +#include <rtems/libio_.h> + +#if defined(IMFS_DEBUG) +#include <stdio.h> +#endif + +/* + * IMFS_fsunmount + */ + +#define jnode_get_control( jnode ) \ + (&jnode->info.directory.Entries) + +#define jnode_has_no_children( jnode ) \ + rtems_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 *)( rtems_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; + loc = temp_mt_entry->mt_fs_root; + + /* + * Set this to null to indicate that it is being unmounted. + */ + + temp_mt_entry->mt_fs_root.node_access = NULL; + + do { + next = jnode->Parent; + loc.node_access = (void *)jnode; + IMFS_Set_handlers( &loc ); + + if ( jnode->type != IMFS_DIRECTORY ) { + result = IMFS_unlink( NULL, &loc ); + if (result != 0) + return -1; + jnode = next; + } else if ( jnode_has_no_children( jnode ) ) { + result = IMFS_unlink( NULL, &loc ); + if (result != 0) + return -1; + jnode = next; + } + if ( jnode != NULL ) { + if ( jnode->type == IMFS_DIRECTORY ) { + if ( jnode_has_children( jnode ) ) + jnode = jnode_get_first_child( jnode ); + } + } + } while (jnode != NULL); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_getchild.c b/cpukit/libfs/src/imfs/imfs_getchild.c new file mode 100644 index 0000000000..1cfeb2a537 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_getchild.c @@ -0,0 +1,66 @@ +/* + * IMFS_find_match_in_dir() + * + * This routine returns the child name in the given directory. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <string.h> +#include "imfs.h" + +static const char dotname[2] = "."; +static const char dotdotname[3] = ".."; + +IMFS_jnode_t *IMFS_find_match_in_dir( + IMFS_jnode_t *directory, + char *name +) +{ + rtems_chain_node *the_node; + rtems_chain_control *the_chain; + IMFS_jnode_t *the_jnode; + + /* + * Check for fatal errors. A NULL directory show a problem in the + * the IMFS code. + */ + IMFS_assert( directory ); + IMFS_assert( name ); + + /* + * 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 = rtems_chain_first( the_chain ); + !rtems_chain_is_tail( the_chain, the_node ); + the_node = the_node->next ) { + + the_jnode = (IMFS_jnode_t *) the_node; + + if ( !strcmp( name, the_jnode->name ) ) + return the_jnode; + } + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_gtkn.c b/cpukit/libfs/src/imfs/imfs_gtkn.c new file mode 100644 index 0000000000..b15b2f1136 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_gtkn.c @@ -0,0 +1,91 @@ +/* + * 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-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#include "imfs.h" +#include <rtems/libio_.h> + +IMFS_token_types IMFS_get_token( + const char *path, + int pathlen, + char *token, + int *token_len +) +{ + register int i = 0; + IMFS_token_types type = IMFS_NAME; + register char c; + + /* + * Copy a name into token. (Remember NULL is a token.) + */ + c = path[i]; + while ( (!IMFS_is_separator(c)) && (i < pathlen) && (i <= IMFS_NAME_MAX) ) { + + token[i] = c; + + if ( i == IMFS_NAME_MAX ) + return IMFS_INVALID_TOKEN; + + if ( !IMFS_is_valid_name_char(c) ) + type = IMFS_INVALID_TOKEN; + + c = path [++i]; + } + + /* + * Copy a seperator into token. + */ + + if ( i == 0 ) { + token[i] = c; + + if ( (token[i] != '\0') && pathlen ) { + i++; + type = IMFS_CURRENT_DIR; + } else { + type = IMFS_NO_MORE_PATH; + } + } else if (token[ i-1 ] != '\0') { + token[i] = '\0'; + } + + /* + * Set token_len to the number of characters copied. + */ + + *token_len = i; + + /* + * If we copied something that was not a seperator see if + * it was a special name. + */ + + if ( type == IMFS_NAME ) { + if ( strcmp( token, "..") == 0 ) + type = IMFS_UP_DIR; + else if ( strcmp( token, "." ) == 0 ) + type = IMFS_CURRENT_DIR; + } + + return type; +} diff --git a/cpukit/libfs/src/imfs/imfs_handlers_device.c b/cpukit/libfs/src/imfs/imfs_handlers_device.c new file mode 100644 index 0000000000..025fb985cf --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_handlers_device.c @@ -0,0 +1,41 @@ +/* + * Device Operations Table for the IMFS + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include "imfs.h" + +/* + * Handler table for IMFS device nodes + */ + +const rtems_filesystem_file_handlers_r IMFS_device_handlers = { + device_open, + device_close, + device_read, + device_write, + device_ioctl, + device_lseek, + IMFS_stat, + IMFS_fchmod, + device_ftruncate, + rtems_filesystem_default_fpathconf, + rtems_filesystem_default_fsync, + rtems_filesystem_default_fdatasync, + rtems_filesystem_default_fcntl, + IMFS_rmnod +}; diff --git a/cpukit/libfs/src/imfs/imfs_handlers_directory.c b/cpukit/libfs/src/imfs/imfs_handlers_directory.c new file mode 100644 index 0000000000..d70957d018 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_handlers_directory.c @@ -0,0 +1,41 @@ +/* + * Operations Table for Directories for the IMFS + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include "imfs.h" + +/* + * Set of operations handlers for operations on directories. + */ + +const rtems_filesystem_file_handlers_r IMFS_directory_handlers = { + imfs_dir_open, + imfs_dir_close, + imfs_dir_read, + rtems_filesystem_default_write, + rtems_filesystem_default_ioctl, + imfs_dir_lseek, + imfs_dir_fstat, + IMFS_fchmod, + rtems_filesystem_default_ftruncate, + rtems_filesystem_default_fpathconf, + rtems_filesystem_default_fsync, + IMFS_fdatasync, + rtems_filesystem_default_fcntl, + imfs_dir_rmnod +}; diff --git a/cpukit/libfs/src/imfs/imfs_handlers_link.c b/cpukit/libfs/src/imfs/imfs_handlers_link.c new file mode 100644 index 0000000000..74f93e1a53 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_handlers_link.c @@ -0,0 +1,41 @@ +/* + * Link Operations Table for the IMFS + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include "imfs.h" + +/* + * Handler table for IMFS device nodes + */ + +const rtems_filesystem_file_handlers_r IMFS_link_handlers = { + rtems_filesystem_default_open, + rtems_filesystem_default_close, + rtems_filesystem_default_read, + rtems_filesystem_default_write, + rtems_filesystem_default_ioctl, + rtems_filesystem_default_lseek, + IMFS_stat, /* stat */ + rtems_filesystem_default_fchmod, + rtems_filesystem_default_ftruncate, + rtems_filesystem_default_fpathconf, + rtems_filesystem_default_fsync, + rtems_filesystem_default_fdatasync, + rtems_filesystem_default_fcntl, + IMFS_rmnod +}; diff --git a/cpukit/libfs/src/imfs/imfs_handlers_memfile.c b/cpukit/libfs/src/imfs/imfs_handlers_memfile.c new file mode 100644 index 0000000000..33003ecba9 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_handlers_memfile.c @@ -0,0 +1,41 @@ +/* + * Memfile Operations Tables for the IMFS + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include "imfs.h" + +/* + * Set of operations handlers for operations on memfile entities. + */ + +const rtems_filesystem_file_handlers_r IMFS_memfile_handlers = { + memfile_open, + memfile_close, + memfile_read, + memfile_write, + memfile_ioctl, + memfile_lseek, + IMFS_stat, + IMFS_fchmod, + memfile_ftruncate, + rtems_filesystem_default_fpathconf, + IMFS_fdatasync, /* fsync */ + IMFS_fdatasync, + rtems_filesystem_default_fcntl, + IMFS_rmnod +}; diff --git a/cpukit/libfs/src/imfs/imfs_init.c b/cpukit/libfs/src/imfs/imfs_init.c new file mode 100644 index 0000000000..c74d493b40 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_init.c @@ -0,0 +1,61 @@ +/** + * @file + * + * @ingroup LibFSIMFS + * + * @brief IMFS initialization. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/libio_.h> + +#include "imfs.h" + +const rtems_filesystem_operations_table IMFS_ops = { + .evalpath_h = IMFS_eval_path, + .evalformake_h = IMFS_evaluate_for_make, + .link_h = IMFS_link, + .unlink_h = IMFS_unlink, + .node_type_h = IMFS_node_type, + .mknod_h = IMFS_mknod, + .chown_h = IMFS_chown, + .freenod_h = rtems_filesystem_default_freenode, + .mount_h = IMFS_mount, + .fsmount_me_h = IMFS_initialize, + .unmount_h = IMFS_unmount, + .fsunmount_me_h = IMFS_fsunmount, + .utime_h = IMFS_utime, + .eval_link_h = IMFS_evaluate_link, + .symlink_h = IMFS_symlink, + .readlink_h = IMFS_readlink, + .rename_h = IMFS_rename, + .statvfs_h = rtems_filesystem_default_statvfs +}; + +int IMFS_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) +{ + return IMFS_initialize_support( + mt_entry, + &IMFS_ops, + &IMFS_memfile_handlers, + &IMFS_directory_handlers, + &rtems_filesystem_handlers_default /* for fifos */ + ); +} diff --git a/cpukit/libfs/src/imfs/imfs_initsupp.c b/cpukit/libfs/src/imfs/imfs_initsupp.c new file mode 100644 index 0000000000..47e1d392e8 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_initsupp.c @@ -0,0 +1,119 @@ +/* + * IMFS Initialization + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> /* for mkdir */ +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +#if defined(IMFS_DEBUG) +#include <stdio.h> +#endif + +/* + * IMFS_determine_bytes_per_block + */ +int imfs_memfile_bytes_per_block = 0; + +static int IMFS_determine_bytes_per_block( + int *dest_bytes_per_block, + int requested_bytes_per_block, + int default_bytes_per_block +) +{ + bool is_valid = false; + int bit_mask; + + /* + * check, whether requested bytes per block is valid + */ + for (bit_mask = 16; !is_valid && (bit_mask <= 512); bit_mask <<= 1) { + if (bit_mask == requested_bytes_per_block) { + is_valid = true; + break; + } + if(bit_mask > requested_bytes_per_block) + break; + } + *dest_bytes_per_block = ((is_valid) + ? requested_bytes_per_block + : default_bytes_per_block); + return 0; +} + + +/* + * IMFS_initialize + */ +int IMFS_initialize_support( + rtems_filesystem_mount_table_entry_t *temp_mt_entry, + const rtems_filesystem_operations_table *op_table, + const rtems_filesystem_file_handlers_r *memfile_handlers, + const rtems_filesystem_file_handlers_r *directory_handlers, + const rtems_filesystem_file_handlers_r *fifo_handlers +) +{ + static int imfs_instance; + IMFS_fs_info_t *fs_info; + IMFS_jnode_t *jnode; + + /* + * determine/check value for imfs_memfile_bytes_per_block + */ + IMFS_determine_bytes_per_block(&imfs_memfile_bytes_per_block, + imfs_rq_memfile_bytes_per_block, + IMFS_MEMFILE_DEFAULT_BYTES_PER_BLOCK); + + /* + * Create the root node + * + * NOTE: UNIX root is 755 and owned by root/root (0/0). + */ + temp_mt_entry->mt_fs_root.node_access = IMFS_create_root_node(); + temp_mt_entry->mt_fs_root.handlers = directory_handlers; + temp_mt_entry->mt_fs_root.ops = op_table; + 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); + rtems_set_errno_and_return_minus_one(ENOMEM); + } + temp_mt_entry->fs_info = fs_info; + + /* + * Set st_ino for the root to 1. + */ + + fs_info->instance = imfs_instance++; + fs_info->ino_count = 1; + fs_info->memfile_handlers = memfile_handlers; + fs_info->directory_handlers = directory_handlers; + fs_info->fifo_handlers = fifo_handlers; + + jnode = temp_mt_entry->mt_fs_root.node_access; + jnode->st_ino = fs_info->ino_count; + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_link.c b/cpukit/libfs/src/imfs/imfs_link.c new file mode 100644 index 0000000000..4c2136ba71 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_link.c @@ -0,0 +1,78 @@ +/* + * 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-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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[ IMFS_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 ) + rtems_set_errno_and_return_minus_one( EMLINK ); + + /* + * Remove any separators at the end of the string. + */ + IMFS_get_token( token, strlen( token ), new_name, &i ); + + /* + * Create a new link node. + * + * NOTE: Coverity Id 19 reports this as a leak + * While technically not a leak, it indicated that IMFS_create_node + * was ONLY passed a NULL when we created the root node. We + * added a new IMFS_create_root_node() so this path no longer + * existed. The result was simpler code which should not have + * this path. + */ + new_node = IMFS_create_node( + parent_loc, + IMFS_HARD_LINK, + new_name, + ( S_IFLNK | ( S_IRWXU | S_IRWXG | S_IRWXO )), + &info + ); + + if ( !new_node ) + rtems_set_errno_and_return_minus_one( ENOMEM ); + + /* + * Increment the link count of the node being pointed to. + */ + info.hard_link.link_node->st_nlink++; + IMFS_update_ctime( info.hard_link.link_node ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_load_tar.c b/cpukit/libfs/src/imfs/imfs_load_tar.c new file mode 100644 index 0000000000..3cb3c4e195 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_load_tar.c @@ -0,0 +1,186 @@ +/* + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +/* + * This file implements the "mount" procedure for tar-based IMFS + * extensions. The TAR is not actually mounted under the IMFS. + * Directories from the TAR file are created as usual in the IMFS. + * File entries are created as IMFS_LINEAR_FILE nodes with their nods + * pointing to addresses in the TAR image. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <tar.h> + +#include <string.h> + +#include <rtems.h> +#include <rtems/libio_.h> +#include <rtems/imfs.h> +#include <rtems/untar.h> + +/* + * TAR file format: + * + * Offset Length Contents + * 0 100 bytes File name ('\0' terminated, 99 maxmum length) + * 100 8 bytes File mode (in octal ascii) + * 108 8 bytes User ID (in octal ascii) + * 116 8 bytes Group ID (in octal ascii) + * 124 12 bytes File size (s) (in octal ascii) + * 136 12 bytes Modify time (in octal ascii) + * 148 8 bytes Header checksum (in octal ascii) + * 156 1 bytes Link flag + * 157 100 bytes Linkname ('\0' terminated, 99 maxmum length) + * 257 8 bytes Magic PAX ("ustar\0" + 2 bytes padding) + * 257 8 bytes Magic GNU tar ("ustar \0") + * 265 32 bytes User name ('\0' terminated, 31 maxmum length) + * 297 32 bytes Group name ('\0' terminated, 31 maxmum length) + * 329 8 bytes Major device ID (in octal ascii) + * 337 8 bytes Minor device ID (in octal ascii) + * 345 167 bytes Padding + * 512 (s+p)bytes File contents (s+p) := (((s) + 511) & ~511), + * round up to 512 bytes + * + * Checksum: + * int i, sum; + * char* header = tar_header_pointer; + * sum = 0; + * for(i = 0; i < 512; i++) + * sum += 0xFF & header[i]; + */ + +#define MAX_NAME_FIELD_SIZE 99 + +#define MIN(a,b) ((a)>(b)?(b):(a)) + +/* + * rtems_tarfs_load + * + * Here we create the mountpoint directory and load the tarfs at + * that node. Once the IMFS has been mounted, we work through the + * tar image and perform as follows: + * - For directories, simply call mkdir(). The IMFS creates nodes as + * needed. + * - For files, we make our own calls to IMFS eval_for_make and + * create_node. + */ +int rtems_tarfs_load( + char *mountpoint, + uint8_t *tar_image, + size_t tar_size +) +{ + rtems_filesystem_location_info_t root_loc; + rtems_filesystem_location_info_t loc; + const char *hdr_ptr; + char filename[100]; + char full_filename[256]; + int hdr_chksum; + unsigned char linkflag; + unsigned long file_size; + unsigned long file_mode; + int offset; + unsigned long nblocks; + IMFS_jnode_t *node; + int status; + + status = rtems_filesystem_evaluate_path( + mountpoint, + strlen(mountpoint), + 0, + &root_loc, + 0 + ); + if (status != 0) + return -1; + + if (root_loc.ops != &IMFS_ops && root_loc.ops != &fifoIMFS_ops) + return -1; + + /* + * Create an IMFS node structure pointing to tar image memory. + */ + offset = 0; + while (1) { + if (offset + 512 > tar_size) + break; + + /* + * Read a header. + */ + hdr_ptr = (char *) &tar_image[offset]; + offset += 512; + if (strncmp(&hdr_ptr[257], "ustar", 5)) + break; + + strncpy(filename, hdr_ptr, MAX_NAME_FIELD_SIZE); + filename[MAX_NAME_FIELD_SIZE] = '\0'; + + linkflag = hdr_ptr[156]; + file_mode = _rtems_octal2ulong(&hdr_ptr[100], 8); + file_size = _rtems_octal2ulong(&hdr_ptr[124], 12); + hdr_chksum = _rtems_octal2ulong(&hdr_ptr[148], 8); + + if (_rtems_tar_header_checksum(hdr_ptr) != hdr_chksum) + break; + + /* + * Generate an IMFS node depending on the file type. + * - For directories, just create directories as usual. IMFS + * will take care of the rest. + * - For files, create a file node with special tarfs properties. + */ + if (linkflag == DIRTYPE) { + strcpy(full_filename, mountpoint); + if (full_filename[strlen(full_filename)-1] != '/') + strcat(full_filename, "/"); + strcat(full_filename, filename); + mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO); + } + /* + * Create a LINEAR_FILE node + * + * NOTE: Coverity Id 20 reports this as a leak. + * While technically not a leak, it indicated that + * IMFS_create_node was ONLY passed a NULL when we created the + * root node. We added a new IMFS_create_root_node() so this + * path no longer existed. The result was simpler code which + * should not have this path. + */ + else if (linkflag == REGTYPE) { + const char *name; + + loc = root_loc; + if (IMFS_evaluate_for_make(filename, &loc, &name) == 0) { + node = IMFS_create_node( + &loc, + IMFS_LINEAR_FILE, (char *)name, + (file_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG, + NULL + ); + node->info.linearfile.size = file_size; + node->info.linearfile.direct = &tar_image[offset]; + } + + nblocks = (((file_size) + 511) & ~511) / 512; + offset += 512 * nblocks; + } + } + return status; +} + diff --git a/cpukit/libfs/src/imfs/imfs_mknod.c b/cpukit/libfs/src/imfs/imfs_mknod.c new file mode 100644 index 0000000000..1a0175af0a --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_mknod.c @@ -0,0 +1,76 @@ +/* + * IMFS_mknod + * + * Routine to create a node in the IMFS file system. + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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[ IMFS_NAME_MAX + 1 ]; + IMFS_types_union info; + + IMFS_get_token( token, strlen( 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 if (S_ISFIFO(mode)) + type = IMFS_FIFO; + else + IMFS_assert( 0 ); + + /* + * Allocate and fill in an IMFS jnode + * + * NOTE: Coverity Id 21 reports this as a leak. + * While technically not a leak, it indicated that IMFS_create_node + * was ONLY passed a NULL when we created the root node. We + * added a new IMFS_create_root_node() so this path no longer + * existed. The result was simpler code which should not have + * this path. + */ + new_node = IMFS_create_node( pathloc, type, new_name, mode, &info ); + if ( !new_node ) + rtems_set_errno_and_return_minus_one( ENOMEM ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_mount.c b/cpukit/libfs/src/imfs/imfs_mount.c new file mode 100644 index 0000000000..3ec16da3f7 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_mount.c @@ -0,0 +1,53 @@ +/* + * 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-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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 ) + rtems_set_errno_and_return_minus_one( ENOTDIR ); + + /* + * Set mt_fs pointer to point to the mount table entry for + * the mounted file system. + */ + + node->info.directory.mt_fs = mt_entry; + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_ntype.c b/cpukit/libfs/src/imfs/imfs_ntype.c new file mode 100644 index 0000000000..f80182b144 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_ntype.c @@ -0,0 +1,32 @@ +/* + * IMFS_node_type + * + * The following verifies that returns the type of node that the + * loc refers to. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include "imfs.h" + +rtems_filesystem_node_types_t IMFS_node_type( + rtems_filesystem_location_info_t *pathloc /* IN */ +) +{ + IMFS_jnode_t *node; + + node = pathloc->node_access; + return node->type; +} diff --git a/cpukit/libfs/src/imfs/imfs_readlink.c b/cpukit/libfs/src/imfs/imfs_readlink.c new file mode 100644 index 0000000000..b598fcf2c1 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_readlink.c @@ -0,0 +1,43 @@ +/* + * IMFS_readlink + * + * The following rouine puts the symblic links destination name into + * buff. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +ssize_t IMFS_readlink( + rtems_filesystem_location_info_t *loc, + char *buf, /* OUT */ + size_t bufsize +) +{ + IMFS_jnode_t *node; + ssize_t i; + + node = loc->node_access; + + IMFS_assert( node->type == IMFS_SYM_LINK ); + + for( i=0; ((i<bufsize) && (node->info.sym_link.name[i] != '\0')); i++ ) + buf[i] = node->info.sym_link.name[i]; + + return i; +} diff --git a/cpukit/libfs/src/imfs/imfs_rename.c b/cpukit/libfs/src/imfs/imfs_rename.c new file mode 100644 index 0000000000..f45aa5b694 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_rename.c @@ -0,0 +1,54 @@ +/* + * IMFS_rename + * + * The following rouine creates a new link node under parent with the + * name given in name and removes the old. + * + * COPYRIGHT (c) 1989-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +int IMFS_rename( + rtems_filesystem_location_info_t *old_parent_loc, /* IN */ + rtems_filesystem_location_info_t *old_loc, /* IN */ + rtems_filesystem_location_info_t *new_parent_loc, /* IN */ + const char *new_name /* IN */ +) +{ + IMFS_jnode_t *the_jnode; + IMFS_jnode_t *new_parent; + + the_jnode = old_loc->node_access; + + strncpy( the_jnode->name, new_name, IMFS_NAME_MAX ); + + if ( the_jnode->Parent != NULL ) + rtems_chain_extract( (rtems_chain_node *) the_jnode ); + + new_parent = new_parent_loc->node_access; + the_jnode->Parent = new_parent; + + rtems_chain_append( &new_parent->info.directory.Entries, &the_jnode->Node ); + + /* + * Update the time. + */ + IMFS_update_ctime( the_jnode ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_rmnod.c b/cpukit/libfs/src/imfs/imfs_rmnod.c new file mode 100644 index 0000000000..25c7cde084 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_rmnod.c @@ -0,0 +1,77 @@ +/* + * IMFS Node Removal Handler + * + * This file contains the handler used to remove a node when a file type + * does not require special actions. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/libio_.h> + +#include "imfs.h" + +void IMFS_create_orphan( IMFS_jnode_t *jnode ) +{ + if ( jnode->Parent != NULL ) { + rtems_chain_extract( &jnode->Node ); + jnode->Parent = NULL; + } + + --jnode->st_nlink; + + IMFS_update_ctime( jnode ); +} + +void IMFS_check_node_remove( IMFS_jnode_t *jnode ) +{ + if ( !rtems_libio_is_file_open( jnode ) && jnode->st_nlink < 1 ) { + if ( rtems_filesystem_current.node_access == jnode ) + rtems_filesystem_current.node_access = NULL; + + switch ( jnode->type ) { + case IMFS_MEMORY_FILE: + IMFS_memfile_remove( jnode ); + break; + case IMFS_SYM_LINK: + free( jnode->info.sym_link.name ); + break; + default: + break; + } + + free( jnode ); + } +} + +/* + * IMFS_rmnod + */ + +int IMFS_rmnod( + rtems_filesystem_location_info_t *parent_pathloc, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN */ +) +{ + IMFS_jnode_t *jnode = (IMFS_jnode_t *) pathloc->node_access; + + IMFS_create_orphan( jnode ); + IMFS_check_node_remove( jnode ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_stat.c b/cpukit/libfs/src/imfs/imfs_stat.c new file mode 100644 index 0000000000..29867faa7b --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_stat.c @@ -0,0 +1,81 @@ +/* + * IMFS_stat + * + * This routine provides a stat for the IMFS file system. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +int IMFS_stat( + rtems_filesystem_location_info_t *loc, + struct stat *buf +) +{ + IMFS_fs_info_t *fs_info; + 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_rdev = rtems_filesystem_make_dev_t( io->major, io->minor ); + break; + + case IMFS_LINEAR_FILE: + case IMFS_MEMORY_FILE: + buf->st_size = the_jnode->info.file.size; + break; + + case IMFS_SYM_LINK: + buf->st_size = 0; + break; + + case IMFS_FIFO: + buf->st_size = 0; + break; + + default: + rtems_set_errno_and_return_minus_one( ENOTSUP ); + break; + } + + /* + * The device number of the IMFS is the major number and the minor is the + * instance. + */ + fs_info = loc->mt_entry->fs_info; + buf->st_dev = + rtems_filesystem_make_dev_t( IMFS_DEVICE_MAJOR_NUMBER, fs_info->instance ); + + 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->stat_atime; + buf->st_mtime = the_jnode->stat_mtime; + buf->st_ctime = the_jnode->stat_ctime; + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_symlink.c b/cpukit/libfs/src/imfs/imfs_symlink.c new file mode 100644 index 0000000000..7094f219fb --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_symlink.c @@ -0,0 +1,77 @@ +/* + * 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-2009. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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[ IMFS_NAME_MAX + 1 ]; + int i; + + /* + * Remove any separators at the end of the string. + */ + IMFS_get_token( node_name, strlen( node_name ), new_name, &i ); + + /* + * Duplicate link name + */ + info.sym_link.name = strdup(link_name); + if (info.sym_link.name == NULL) { + rtems_set_errno_and_return_minus_one(ENOMEM); + } + + /* + * Create a new link node. + * + * NOTE: Coverity CID 22 notes this as a resource leak. + * While technically not a leak, it indicated that IMFS_create_node + * was ONLY passed a NULL when we created the root node. We + * added a new IMFS_create_root_node() so this path no longer + * existed. The result was simpler code which should not have + * this path. + */ + new_node = IMFS_create_node( + parent_loc, + IMFS_SYM_LINK, + new_name, + ( S_IFLNK | ( S_IRWXU | S_IRWXG | S_IRWXO )), + &info + ); + + if (new_node == NULL) { + free(info.sym_link.name); + rtems_set_errno_and_return_minus_one(ENOMEM); + } + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_unlink.c b/cpukit/libfs/src/imfs/imfs_unlink.c new file mode 100644 index 0000000000..0ec176ed03 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_unlink.c @@ -0,0 +1,82 @@ +/* + * IMFS_unlink + * + * Routine to remove a link node from the tree. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <stdlib.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.h> + +int IMFS_unlink( + rtems_filesystem_location_info_t *parentloc, /* IN */ + rtems_filesystem_location_info_t *loc /* IN */ +) +{ + IMFS_jnode_t *node; + rtems_filesystem_location_info_t the_link; + int result = 0; + + 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 ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + the_link = *loc; + the_link.node_access = node->info.hard_link.link_node; + IMFS_Set_handlers( &the_link ); + + /* + * If removing the last hard link to a node, then we need + * to remove the node that is a link and the node itself. + */ + + if ( node->info.hard_link.link_node->st_nlink == 1) + { + result = (*the_link.handlers->rmnod_h)( parentloc, &the_link ); + if ( result != 0 ) + return -1; + } + else + { + node->info.hard_link.link_node->st_nlink --; + IMFS_update_ctime( node->info.hard_link.link_node ); + } + } + + /* + * Now actually free the node we were asked to free. + */ + + result = (*loc->handlers->rmnod_h)( parentloc, loc ); + + return result; +} diff --git a/cpukit/libfs/src/imfs/imfs_unmount.c b/cpukit/libfs/src/imfs/imfs_unmount.c new file mode 100644 index 0000000000..ee1482bfa5 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_unmount.c @@ -0,0 +1,62 @@ +/* + * 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-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> + +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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 ) + rtems_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 ) + rtems_set_errno_and_return_minus_one( EINVAL ); /* XXX */ + + /* + * Set the mt_fs pointer to indicate that there is no longer + * a file system mounted to this point. + */ + + node->info.directory.mt_fs = NULL; + + return 0; +} diff --git a/cpukit/libfs/src/imfs/imfs_utime.c b/cpukit/libfs/src/imfs/imfs_utime.c new file mode 100644 index 0000000000..2867e13ed6 --- /dev/null +++ b/cpukit/libfs/src/imfs/imfs_utime.c @@ -0,0 +1,42 @@ +/* + * IMFS_utime + * + * This routine is the implementation of the utime() system + * call for the IMFS. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <errno.h> +#include <sys/time.h> + +#include <rtems/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->stat_atime = actime; + the_jnode->stat_mtime = modtime; + the_jnode->stat_ctime = time( NULL ); + + return 0; +} diff --git a/cpukit/libfs/src/imfs/ioman.c b/cpukit/libfs/src/imfs/ioman.c new file mode 100644 index 0000000000..fa9918b266 --- /dev/null +++ b/cpukit/libfs/src/imfs/ioman.c @@ -0,0 +1,93 @@ +/* + * This file emulates the old Classic RTEMS IO manager directives + * which register and lookup names using the in-memory filesystem. + * + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> + +#include <rtems.h> +#include <rtems/libio_.h> +#include <rtems/seterr.h> +#include "imfs.h" + +/* + * rtems_io_register_name + * + * This assumes that all registered devices are character devices. + */ + +rtems_status_code rtems_io_register_name( + const 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 reentrant. + * + * XXX - This is dependent upon IMFS and should not be. + * Suggest adding a filesystem routine to fill in the device_info. + */ + +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 loc; + int result; + rtems_filesystem_node_types_t node_type; + + result = rtems_filesystem_evaluate_path( + name, strlen( name ), 0x00, &loc, true ); + the_jnode = loc.node_access; + + node_type = (*loc.ops->node_type_h)( &loc ); + + if ( (result != 0) || node_type != RTEMS_FILESYSTEM_DEVICE ) { + rtems_filesystem_freenode( &loc ); + return RTEMS_UNSATISFIED; + } + + device_info->device_name = (char *) name; + device_info->device_name_length = strlen( name ); + device_info->major = the_jnode->info.device.major; + device_info->minor = the_jnode->info.device.minor; + + rtems_filesystem_freenode( &loc ); + + return RTEMS_SUCCESSFUL; +} diff --git a/cpukit/libfs/src/imfs/memfile.c b/cpukit/libfs/src/imfs/memfile.c new file mode 100644 index 0000000000..98616d1b36 --- /dev/null +++ b/cpukit/libfs/src/imfs/memfile.c @@ -0,0 +1,975 @@ +/* + * 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-2010. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <rtems.h> +#include <rtems/libio.h> +#include "imfs.h" +#include <rtems/libio_.h> +#include <rtems/seterr.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 ssize_t IMFS_memfile_read( + IMFS_jnode_t *the_jnode, + off_t start, + unsigned char *destination, + unsigned int length +); + +ssize_t IMFS_memfile_write( /* cannot be static as used in imfs_fchmod.c */ + 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, + uint32_t flag, + uint32_t mode +) +{ + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + /* + * Perform 'copy on write' for linear files + */ + if ((iop->flags & (LIBIO_FLAGS_WRITE | LIBIO_FLAGS_APPEND)) + && (the_jnode->type == IMFS_LINEAR_FILE)) { + uint32_t count = the_jnode->info.linearfile.size; + const unsigned char *buffer = the_jnode->info.linearfile.direct; + + the_jnode->type = IMFS_MEMORY_FILE; + the_jnode->info.file.size = 0; + the_jnode->info.file.indirect = 0; + the_jnode->info.file.doubly_indirect = 0; + the_jnode->info.file.triply_indirect = 0; + if ((count != 0) + && (IMFS_memfile_write(the_jnode, 0, buffer, count) == -1)) + return -1; + } + if (iop->flags & LIBIO_FLAGS_APPEND) + iop->offset = the_jnode->info.file.size; + + iop->size = the_jnode->info.file.size; + 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->pathinfo.node_access; + + if (iop->flags & LIBIO_FLAGS_APPEND) + iop->offset = the_jnode->info.file.size; + + IMFS_check_node_remove( the_jnode ); + + return 0; +} + +/* + * memfile_read + * + * This routine processes the read() system call. + */ +ssize_t memfile_read( + rtems_libio_t *iop, + void *buffer, + size_t count +) +{ + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + return IMFS_memfile_read( the_jnode, iop->offset, buffer, count ); +} + +/* + * memfile_write + * + * This routine processes the write() system call. + */ +ssize_t memfile_write( + rtems_libio_t *iop, + const void *buffer, + size_t count +) +{ + IMFS_jnode_t *the_jnode; + ssize_t status; + + the_jnode = iop->pathinfo.node_access; + + status = IMFS_memfile_write( the_jnode, iop->offset, buffer, count ); + iop->size = the_jnode->info.file.size; + + return status; +} + +/* + * 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, + uint32_t command, + void *buffer +) +{ + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + return 0; +} + +/* + * memfile_lseek + * + * This routine processes the lseek() system call. + */ +rtems_off64_t memfile_lseek( + rtems_libio_t *iop, + rtems_off64_t offset, + int whence +) +{ + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + if (the_jnode->type == IMFS_LINEAR_FILE) { + if (iop->offset > the_jnode->info.linearfile.size) + iop->offset = the_jnode->info.linearfile.size; + } + else { /* Must be a block file (IMFS_MEMORY_FILE). */ + if (IMFS_memfile_extend( the_jnode, iop->offset )) + rtems_set_errno_and_return_minus_one( ENOSPC ); + + iop->size = the_jnode->info.file.size; + } + return iop->offset; +} + +/* + * memfile_stat + * + * This IMFS_stat() can be used. + */ + +/* + * memfile_ftruncate + * + * This routine processes the ftruncate() system call. + */ +int memfile_ftruncate( + rtems_libio_t *iop, + rtems_off64_t length +) +{ + IMFS_jnode_t *the_jnode; + + the_jnode = iop->pathinfo.node_access; + + /* + * 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; + iop->size = the_jnode->info.file.size; + + 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 + */ + IMFS_assert( the_jnode ); + IMFS_assert( the_jnode->type == IMFS_MEMORY_FILE ); + + /* + * Verify new file size is supported + */ + if ( new_length >= IMFS_MEMFILE_MAXIMUM_SIZE ) + rtems_set_errno_and_return_minus_one( EINVAL ); + + /* + * Verify new file size is actually larger than current size + */ + 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 ); + } + rtems_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; + + IMFS_assert( the_jnode ); + IMFS_assert( the_jnode->type == IMFS_MEMORY_FILE ); + + /* + * Obtain the pointer for the specified block number + */ + block_entry_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 1 ); + if ( *block_entry_ptr ) + return 0; + + /* + * There is no memory for this block number so allocate it. + */ + memory = memfile_alloc_block(); + if ( !memory ) + return 1; + + *block_entry_ptr = memory; + return 0; +} + +/* + * IMFS_memfile_remove_block + * + * This routine removes the specified block from the in-memory file. + * + * NOTE: This is a support routine and is called only to remove + * the last block or set of blocks in a file. Removing a + * block from the middle of a file would be exceptionally + * dangerous and the results unpredictable. + */ +MEMFILE_STATIC int IMFS_memfile_remove_block( + IMFS_jnode_t *the_jnode, + unsigned int block +) +{ + block_p *block_ptr; + block_p ptr; + + block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 ); + IMFS_assert( block_ptr ); + + ptr = *block_ptr; + *block_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 + */ + IMFS_assert( block_table ); + + /* + * Now go through all the slots in the table and free the memory. + */ + b = *block_table; + + for ( i=0 ; i<entries ; i++ ) { + if ( b[i] ) { + memfile_free_block( b[i] ); + b[i] = 0; + } + } + + /* + * Now that all the blocks in the block table are free, we can + * free the block table itself. + */ + memfile_free_block( *block_table ); + *block_table = 0; +} + +/* + * IMFS_memfile_remove + * + * This routine frees all memory associated with an in memory file. + * + * NOTE: This is an exceptionally conservative implementation. + * It will check EVERY pointer which is non-NULL and insure + * any child non-NULL pointers are freed. Optimistically, all that + * is necessary is to scan until a NULL pointer is found. There + * should be no allocated data past that point. + * + * In experimentation on the powerpc simulator, it was noted + * that using blocks which held 128 slots versus 16 slots made + * a significant difference in the performance of this routine. + * + * Regardless until the IMFS implementation is proven, it + * is better to stick to simple, easy to understand algorithms. + */ +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 + */ + IMFS_assert( the_jnode ); + IMFS_assert( the_jnode->type == IMFS_MEMORY_FILE ); + + /* + * 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]; + if ( !p ) /* ensure we have a valid pointer */ + break; + for ( j=0 ; j<IMFS_MEMFILE_BLOCK_SLOTS ; j++ ) { + if ( p[j] ) { + memfile_free_blocks_in_table( (block_p **)&p[j], to_free); + } + } + memfile_free_blocks_in_table( + (block_p **)&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 ssize_t 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 + */ + IMFS_assert( the_jnode ); + IMFS_assert( the_jnode->type == IMFS_MEMORY_FILE || + the_jnode->type != IMFS_LINEAR_FILE ); + IMFS_assert( dest ); + + /* + * Linear files (as created from a tar file are easier to handle + * than block files). + */ + my_length = length; + + if (the_jnode->type == IMFS_LINEAR_FILE) { + unsigned char *file_ptr; + + file_ptr = (unsigned char *)the_jnode->info.linearfile.direct; + + if (my_length > (the_jnode->info.linearfile.size - start)) + my_length = the_jnode->info.linearfile.size - start; + + memcpy(dest, &file_ptr[start], my_length); + + IMFS_update_atime( the_jnode ); + + return my_length; + } + + /* + * If the last byte we are supposed to read is past the end of this + * in memory file, then shorten the length to read. + */ + last_byte = start + length; + if ( last_byte > 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 ); + 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 ); + if ( !block_ptr ) + return copied; + memcpy( dest, &(*block_ptr)[ 0 ], to_copy ); + dest += to_copy; + block++; + my_length -= to_copy; + copied += to_copy; + } + + /* + * Phase 3: possibly the first part of one block + */ + IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK ); + + if ( my_length ) { + block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 ); + 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 ssize_t 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 + */ + IMFS_assert( source ); + IMFS_assert( the_jnode ); + IMFS_assert( the_jnode->type == IMFS_MEMORY_FILE ); + + my_length = length; + /* + * If the last byte we are supposed to write is past the end of this + * in memory file, then extend the length. + */ + + last_byte = start + my_length; + if ( last_byte > the_jnode->info.file.size ) { + status = IMFS_memfile_extend( the_jnode, last_byte ); + if ( status ) + rtems_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 ); + if ( !block_ptr ) + return copied; + #if 0 + fprintf( + stderr, + "write %d at %d in %d: %*s\n", + to_copy, + start_offset, + block, + to_copy, + src + ); + #endif + memcpy( &(*block_ptr)[ start_offset ], src, to_copy ); + src += to_copy; + block++; + my_length -= to_copy; + copied += to_copy; + } + + /* + * Phase 2: all of zero of more blocks + */ + + to_copy = IMFS_MEMFILE_BYTES_PER_BLOCK; + while ( my_length >= IMFS_MEMFILE_BYTES_PER_BLOCK ) { + block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 ); + if ( !block_ptr ) + return copied; + #if 0 + fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src ); + #endif + memcpy( &(*block_ptr)[ 0 ], src, to_copy ); + src += to_copy; + block++; + my_length -= to_copy; + copied += to_copy; + } + + /* + * Phase 3: possibly the first part of one block + */ + IMFS_assert( my_length < IMFS_MEMFILE_BYTES_PER_BLOCK ); + + to_copy = my_length; + if ( my_length ) { + block_ptr = IMFS_memfile_get_block_pointer( the_jnode, block, 0 ); + if ( !block_ptr ) + return copied; + #if 0 + fprintf(stdout, "write %d in %d: %*s\n", to_copy, block, to_copy, src ); + #endif + memcpy( &(*block_ptr)[ 0 ], src, my_length ); + my_length = 0; + copied += to_copy; + } + + IMFS_mtime_ctime_update( 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. + */ +#if 0 +block_p *IMFS_memfile_get_block_pointer_DEBUG( + IMFS_jnode_t *the_jnode, + unsigned int block, + int malloc_it +); + +block_p *IMFS_memfile_get_block_pointer( + IMFS_jnode_t *the_jnode, + unsigned int block, + int malloc_it +) +{ + block_p *p; + + p = IMFS_memfile_get_block_pointer_DEBUG( the_jnode, block, malloc_it ); + fprintf(stdout, "(%d -> %p) ", block, p ); + return p; +} + +block_p *IMFS_memfile_get_block_pointer_DEBUG( +#else +block_p *IMFS_memfile_get_block_pointer( +#endif + IMFS_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 + */ + IMFS_assert( the_jnode ); + IMFS_assert( the_jnode->type == IMFS_MEMORY_FILE ); + + info = &the_jnode->info.file; + my_block = block; + + /* + * Is the block number in the simple indirect portion? + */ + if ( my_block <= LAST_INDIRECT ) { + 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 ) { + 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 *)&p1[ singly ]; + } + + if ( !p ) + return 0; + + p = (block_p *)p[ doubly ]; + if ( !p ) + return 0; + + return (block_p *)&p[ singly ]; + } + + /* + * Is the block number in the triply indirect portion? + */ + if ( my_block <= LAST_TRIPLY_INDIRECT ) { + my_block -= FIRST_TRIPLY_INDIRECT; + + singly = my_block % IMFS_MEMFILE_BLOCK_SLOTS; + doubly = my_block / IMFS_MEMFILE_BLOCK_SLOTS; + triply = doubly / IMFS_MEMFILE_BLOCK_SLOTS; + doubly %= IMFS_MEMFILE_BLOCK_SLOTS; + + p = 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; + + p1 = (block_p *) p[ triply ]; + if ( !p1 ) + return 0; + + p2 = (block_p *)p1[ doubly ]; + if ( !p2 ) + return 0; + + return (block_p *)&p2[ singly ]; + } + + /* + * This means the requested block number is out of range. + */ + return 0; +} + +/* + * memfile_alloc_block + * + * Allocate a block for an in-memory file. + */ +int memfile_blocks_allocated = 0; + +void *memfile_alloc_block(void) +{ + void *memory; + + memory = (void *)calloc(1, IMFS_MEMFILE_BYTES_PER_BLOCK); + if ( memory ) + memfile_blocks_allocated++; + + return memory; +} + +/* + * memfile_free_block + * + * Free a block from an in-memory file. + */ +void memfile_free_block( + void *memory +) +{ + free(memory); + memfile_blocks_allocated--; +} diff --git a/cpukit/libfs/src/imfs/miniimfs_init.c b/cpukit/libfs/src/imfs/miniimfs_init.c new file mode 100644 index 0000000000..b43a5318e8 --- /dev/null +++ b/cpukit/libfs/src/imfs/miniimfs_init.c @@ -0,0 +1,61 @@ +/** + * @file + * + * @ingroup LibFSIMFS + * + * @brief Mini-IMFS initialization. + */ + +/* + * COPYRIGHT (c) 1989-1999. + * On-Line Applications Research Corporation (OAR). + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + * + * $Id$ + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#include <rtems/libio_.h> + +#include "imfs.h" + +static const rtems_filesystem_operations_table miniIMFS_ops = { + .evalpath_h = IMFS_eval_path, + .evalformake_h = IMFS_evaluate_for_make, + .link_h = rtems_filesystem_default_link, + .unlink_h = rtems_filesystem_default_unlink, + .node_type_h = IMFS_node_type, + .mknod_h = IMFS_mknod, + .chown_h = rtems_filesystem_default_chown, + .freenod_h = rtems_filesystem_default_freenode, + .mount_h = IMFS_mount, + .fsmount_me_h = miniIMFS_initialize, + .unmount_h = rtems_filesystem_default_unmount, + .fsunmount_me_h = rtems_filesystem_default_unmount, + .utime_h = rtems_filesystem_default_utime, + .eval_link_h = rtems_filesystem_default_evaluate_link, + .symlink_h = rtems_filesystem_default_symlink, + .readlink_h = rtems_filesystem_default_readlink, + .rename_h = rtems_filesystem_default_rename, + .statvfs_h = rtems_filesystem_default_statvfs +}; + +int miniIMFS_initialize( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) +{ + return IMFS_initialize_support( + mt_entry, + &miniIMFS_ops, + &rtems_filesystem_handlers_default, /* for memfiles */ + &rtems_filesystem_handlers_default, /* for directories */ + &rtems_filesystem_handlers_default /* for fifos */ + ); +} |