diff options
Diffstat (limited to 'cpukit/libcsupport/src')
47 files changed, 2200 insertions, 1781 deletions
diff --git a/cpukit/libcsupport/src/__usrenv.c b/cpukit/libcsupport/src/__usrenv.c index 0b3469fa1a..d26e73658f 100644 --- a/cpukit/libcsupport/src/__usrenv.c +++ b/cpukit/libcsupport/src/__usrenv.c @@ -2,6 +2,9 @@ * COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -10,18 +13,246 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <rtems.h> -#include <rtems/libio.h> +#include <sys/stat.h> + #include <rtems/libio_.h> -/* - * Global information for POSIX Process Environment Support - */ +static int null_handler_open( + rtems_libio_t *iop, + const char *path, + int oflag, + mode_t mode +) +{ + return -1; +} + +static int null_handler_fstat( + const rtems_filesystem_location_info_t *pathloc, + struct stat *buf +) +{ + return -1; +} + +const rtems_filesystem_file_handlers_r rtems_filesystem_null_handlers = { + .open_h = null_handler_open, + .close_h = rtems_filesystem_default_close, + .read_h = rtems_filesystem_default_read, + .write_h = rtems_filesystem_default_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = null_handler_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync, + .fdatasync_h = rtems_filesystem_default_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl +}; + +static void null_op_lock_or_unlock( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + /* Do nothing */ +} + +static int null_op_mknod( + const rtems_filesystem_location_info_t *parentloc, + const char *name, + size_t namelen, + mode_t mode, + dev_t dev +) +{ + return -1; +} + +static int null_op_rmnod( + const rtems_filesystem_location_info_t *parentloc, + const rtems_filesystem_location_info_t *loc +) +{ + return -1; +} + +static int null_op_link( + const rtems_filesystem_location_info_t *parentloc, + const rtems_filesystem_location_info_t *targetloc, + const char *name, + size_t namelen +) +{ + return -1; +} + +static int null_op_fchmod( + const rtems_filesystem_location_info_t *pathloc, + mode_t mode +) +{ + return -1; +} + +static int null_op_chown( + const rtems_filesystem_location_info_t *loc, + uid_t owner, + gid_t group +) +{ + return -1; +} + +static int null_op_clonenode( + rtems_filesystem_location_info_t *loc +) +{ + return -1; +} + +static int null_op_mount( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + return -1; +} + +static int null_op_fsmount_me( + rtems_filesystem_mount_table_entry_t *mt_entry, + const void *data +) +{ + return -1; +} + +static int null_op_unmount( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + return -1; +} + +static void null_op_fsunmount_me( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + /* Do nothing */ +} + +static int null_op_utime( + const rtems_filesystem_location_info_t *loc, + time_t actime, + time_t modtime +) +{ + return -1; +} + +static int null_op_symlink( + const rtems_filesystem_location_info_t *parentloc, + const char *name, + size_t namelen, + const char *target +) +{ + return -1; +} + +static ssize_t null_op_readlink( + const rtems_filesystem_location_info_t *loc, + char *buf, + size_t bufsize +) +{ + return -1; +} + +static int null_op_rename( + const rtems_filesystem_location_info_t *oldparentloc, + const rtems_filesystem_location_info_t *oldloc, + const rtems_filesystem_location_info_t *newparentloc, + const char *name, + size_t namelen +) +{ + return -1; +} + +static int null_op_statvfs( + const rtems_filesystem_location_info_t *loc, + struct statvfs *buf +) +{ + return -1; +} + +static const rtems_filesystem_operations_table null_ops = { + .lock_h = null_op_lock_or_unlock, + .unlock_h = null_op_lock_or_unlock, + .eval_path_h = rtems_filesystem_default_eval_path, + .link_h = null_op_link, + .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal, + .node_type_h = rtems_filesystem_default_node_type, + .mknod_h = null_op_mknod, + .rmnod_h = null_op_rmnod, + .fchmod_h = null_op_fchmod, + .chown_h = null_op_chown, + .clonenod_h = null_op_clonenode, + .freenod_h = rtems_filesystem_default_freenode, + .mount_h = null_op_mount, + .fsmount_me_h = null_op_fsmount_me, + .unmount_h = null_op_unmount, + .fsunmount_me_h = null_op_fsunmount_me, + .utime_h = null_op_utime, + .symlink_h = null_op_symlink, + .readlink_h = null_op_readlink, + .rename_h = null_op_rename, + .statvfs_h = null_op_statvfs +}; + +rtems_filesystem_mount_table_entry_t rtems_filesystem_null_mt_entry = { + .location_chain = { + .Head = { + .Node = { + .next = &rtems_filesystem_global_location_null.location.mt_entry_node, + .previous = NULL + }, + .fill = &rtems_filesystem_global_location_null.location.mt_entry_node, + } + }, + .mt_point_node = &rtems_filesystem_global_location_null, + .mt_fs_root = &rtems_filesystem_global_location_null, + .mounted = false, + .writeable = false +}; + +rtems_filesystem_global_location_t rtems_filesystem_global_location_null = { + .location = { + .mt_entry_node = { + .next = &rtems_filesystem_null_mt_entry.location_chain.Tail.Node, + .previous = &rtems_filesystem_null_mt_entry.location_chain.Head.Node + }, + .handlers = &rtems_filesystem_null_handlers, + .ops = &null_ops, + .mt_entry = &rtems_filesystem_null_mt_entry + }, -rtems_user_env_t rtems_global_user_env; -rtems_user_env_t * rtems_current_user_env = &rtems_global_user_env; + /* + * The initial reference count accounts for the following references + * o the root directory of the user environment, + * o the current directory of the user environment, + * o the root node of the null file system instance, and + * o the mount point node of the null file system instance. + */ + .reference_count = 4 +}; +rtems_user_env_t rtems_global_user_env = { + .current_directory = &rtems_filesystem_global_location_null, + .root_directory = &rtems_filesystem_global_location_null, + .umask = S_IWGRP | S_IWOTH +}; +rtems_user_env_t *rtems_current_user_env = &rtems_global_user_env; diff --git a/cpukit/libcsupport/src/_rename_r.c b/cpukit/libcsupport/src/_rename_r.c index 51010df28e..7a2637aa89 100644 --- a/cpukit/libcsupport/src/_rename_r.c +++ b/cpukit/libcsupport/src/_rename_r.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-2007. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -16,12 +19,10 @@ #endif #if defined(RTEMS_NEWLIB) && !defined(HAVE__RENAME_R) -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> + +#include <stdio.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> int _rename_r( struct _reent *ptr __attribute__((unused)), @@ -29,85 +30,47 @@ int _rename_r( const char *new ) { - int old_parent_pathlen; - rtems_filesystem_location_info_t old_loc; - rtems_filesystem_location_info_t old_parent_loc; - rtems_filesystem_location_info_t new_parent_loc; - int i; - int result; - const char *name; - bool free_old_parentloc = false; - - /* - * Get the parent node of the old path to be renamed. Find the parent path. - */ - - old_parent_pathlen = rtems_filesystem_dirname ( old ); - - if ( old_parent_pathlen == 0 ) - rtems_filesystem_get_start_loc( old, &i, &old_parent_loc ); - else { - result = rtems_filesystem_evaluate_path( old, old_parent_pathlen, - RTEMS_LIBIO_PERMS_WRITE, - &old_parent_loc, - false ); - if ( result != 0 ) - return -1; - - free_old_parentloc = true; + int rv = 0; + rtems_filesystem_eval_path_context_t old_ctx; + int old_eval_flags = 0; + rtems_filesystem_location_info_t old_parentloc; + int old_parent_eval_flags = RTEMS_LIBIO_PERMS_WRITE + | RTEMS_LIBIO_FOLLOW_HARD_LINK; + const rtems_filesystem_location_info_t *old_currentloc = + rtems_filesystem_eval_path_start_with_parent( + &old_ctx, + old, + old_eval_flags, + &old_parentloc, + old_parent_eval_flags + ); + rtems_filesystem_eval_path_context_t new_ctx; + + /* FIXME: This is not POSIX conform */ + int new_eval_flags = RTEMS_LIBIO_FOLLOW_HARD_LINK + | RTEMS_LIBIO_MAKE + | RTEMS_LIBIO_EXCLUSIVE; + + const rtems_filesystem_location_info_t *new_currentloc = + rtems_filesystem_eval_path_start( &new_ctx, new, new_eval_flags ); + + rv = rtems_filesystem_location_exists_in_same_fs_instance_as( + old_currentloc, + new_currentloc + ); + if ( rv == 0 ) { + rv = (*new_currentloc->ops->rename_h)( + &old_parentloc, + old_currentloc, + new_currentloc, + rtems_filesystem_eval_path_get_token( &new_ctx ), + rtems_filesystem_eval_path_get_tokenlen( &new_ctx ) + ); } - /* - * Start from the parent to find the node that should be under it. - */ - - old_loc = old_parent_loc; - name = old + old_parent_pathlen; - name += rtems_filesystem_prefix_separators( name, strlen( name ) ); - - result = rtems_filesystem_evaluate_relative_path( name , strlen( name ), - 0, &old_loc, false ); - if ( result != 0 ) { - if ( free_old_parentloc ) - rtems_filesystem_freenode( &old_parent_loc ); - return -1; - } - - /* - * Get the parent of the new node we are renaming to. - */ - - rtems_filesystem_get_start_loc( new, &i, &new_parent_loc ); - - result = (*new_parent_loc.ops->evalformake_h)( &new[i], &new_parent_loc, &name ); - if ( result != 0 ) { - rtems_filesystem_freenode( &new_parent_loc ); - if ( free_old_parentloc ) - rtems_filesystem_freenode( &old_parent_loc ); - rtems_filesystem_freenode( &old_loc ); - return -1; - } - - /* - * Check to see if the caller is trying to rename across file system - * boundaries. - */ - - if ( old_parent_loc.mt_entry != new_parent_loc.mt_entry ) { - rtems_filesystem_freenode( &new_parent_loc ); - if ( free_old_parentloc ) - rtems_filesystem_freenode( &old_parent_loc ); - rtems_filesystem_freenode( &old_loc ); - rtems_set_errno_and_return_minus_one( EXDEV ); - } - - result = (*new_parent_loc.ops->rename_h)( &old_parent_loc, &old_loc, &new_parent_loc, name ); - - rtems_filesystem_freenode( &new_parent_loc ); - if ( free_old_parentloc ) - rtems_filesystem_freenode( &old_parent_loc ); - rtems_filesystem_freenode( &old_loc ); + rtems_filesystem_eval_path_cleanup_with_parent( &old_ctx, &old_parentloc ); + rtems_filesystem_eval_path_cleanup( &new_ctx ); - return result; + return rv; } #endif diff --git a/cpukit/libcsupport/src/base_fs.c b/cpukit/libcsupport/src/base_fs.c index b5681eda63..bbf6d8d4be 100644 --- a/cpukit/libcsupport/src/base_fs.c +++ b/cpukit/libcsupport/src/base_fs.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -35,62 +38,20 @@ void rtems_filesystem_initialize( void ) { - int status; - const rtems_filesystem_mount_table_t *mt; - rtems_filesystem_location_info_t loc; - - /* - * Set the default umask to "022". - */ - - rtems_filesystem_umask = 022; - - /* - * mount the first filesystem. - */ - if ( rtems_filesystem_mount_table_size == 0 ) - rtems_fatal_error_occurred( 0xABCD0001 ); - - mt = &rtems_filesystem_mount_table[0]; - - status = mount( mt->device, mt->mount_point, mt->type, mt->fsoptions, NULL ); - if ( status == -1 ) + int rv = 0; + const rtems_filesystem_mount_configuration *root_config = + &rtems_filesystem_root_configuration; + + rv = mount( + root_config->source, + root_config->target, + root_config->filesystemtype, + root_config->options, + root_config->data + ); + if ( rv != 0 ) rtems_fatal_error_occurred( 0xABCD0002 ); - rtems_filesystem_link_counts = 0; - - /* setup the 'current' and 'root' directories - * - * NOTE: cloning the pathlocs is not strictly - * necessary. Since we implicitely let - * all threads that don't call - * libio_set_private_env() share the same - * (initial) 'root' and 'current' locs, - * we (also implicitely) assume that the - * root filesystem doesn't care about - * reference counts. - * I just inserted the code snippet below - * to remind everybody of the fact by - * making it more explicit... - * Ideally, every thread would have to - * call either share_private_env() or - * set_private_env() - but then: that's - * gonna hit performance. - * - * Till Straumann, 10/25/2002 - */ - /* Clone the root pathloc */ - rtems_filesystem_evaluate_path("/", 1, 0, &loc, 0); - rtems_filesystem_root = loc; - /* One more clone for the current node */ - rtems_filesystem_evaluate_path("/", 1, 0, &loc, 0); - rtems_filesystem_current = loc; - - /* Note: the global_env's refcnt doesn't matter - * as the global env is never released - */ - - /* * Traditionally RTEMS devices are under "/dev" so install this directory. * @@ -100,8 +61,8 @@ void rtems_filesystem_initialize( void ) * created that way by the IMFS. */ - status = mkdir( "/dev", 0777); - if ( status != 0 ) + rv = mkdir( "/dev", 0777); + if ( rv != 0 ) rtems_fatal_error_occurred( 0xABCD0003 ); /* diff --git a/cpukit/libcsupport/src/chdir.c b/cpukit/libcsupport/src/chdir.c index c9d05f0bef..df65170936 100644 --- a/cpukit/libcsupport/src/chdir.c +++ b/cpukit/libcsupport/src/chdir.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-2010. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -12,46 +15,47 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <rtems.h> - #include <unistd.h> -#include <errno.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int chdir( - const char *pathname -) +int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc ) { - rtems_filesystem_location_info_t loc; - int result; - - if ( !pathname ) - rtems_set_errno_and_return_minus_one( EFAULT ); - - /* - * Get the node where we wish to go. - */ - result = rtems_filesystem_evaluate_path( - pathname, strlen( pathname ), RTEMS_LIBIO_PERMS_SEARCH, &loc, true ); - if ( result != 0 ) - return -1; - - /* - * Verify you can change directory into this node. - */ - if ( (*loc.ops->node_type_h)( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) { - rtems_filesystem_freenode( &loc ); - rtems_set_errno_and_return_minus_one( ENOTDIR ); + int rv = 0; + rtems_filesystem_global_location_t *global_loc = + rtems_filesystem_location_transform_to_global( loc ); + rtems_filesystem_node_types_t type = + rtems_filesystem_node_type( &global_loc->location ); + + if ( type == RTEMS_FILESYSTEM_DIRECTORY ) { + rtems_filesystem_global_location_assign( + &rtems_filesystem_current, + global_loc + ); + } else { + rtems_filesystem_location_error( &global_loc->location, ENOTDIR ); + rtems_filesystem_global_location_release( global_loc ); + rv = -1; } - rtems_filesystem_freenode( &rtems_filesystem_current ); - - rtems_filesystem_current = loc; + return rv; +} - return 0; +int chdir( const char *path ) +{ + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_PERMS_EXEC + | RTEMS_LIBIO_FOLLOW_LINK; + rtems_filesystem_location_info_t pathloc; + + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); + rtems_filesystem_eval_path_extract_currentloc( &ctx, &pathloc ); + rv = rtems_filesystem_chdir( &pathloc ); + rtems_filesystem_eval_path_cleanup( &ctx ); + + return rv; } diff --git a/cpukit/libcsupport/src/chmod.c b/cpukit/libcsupport/src/chmod.c index d1d9ae0f5f..ff3039a557 100644 --- a/cpukit/libcsupport/src/chmod.c +++ b/cpukit/libcsupport/src/chmod.c @@ -12,35 +12,24 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <rtems.h> -#include <rtems/libio.h> #include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int chmod( - const char *path, - mode_t mode -) +int chmod( const char *path, mode_t mode ) { - int status; - rtems_filesystem_location_info_t loc; - int result; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); - status = rtems_filesystem_evaluate_path( path, strlen( path ), 0, &loc, true ); - if ( status != 0 ) - return -1; + rv = (*currentloc->ops->fchmod_h)( currentloc, mode ); - result = (*loc.handlers->fchmod_h)( &loc, mode ); + rtems_filesystem_eval_path_cleanup( &ctx ); - rtems_filesystem_freenode( &loc ); - - return result; + return rv; } diff --git a/cpukit/libcsupport/src/chown.c b/cpukit/libcsupport/src/chown.c index 9ecaea11f7..1d07384d7d 100644 --- a/cpukit/libcsupport/src/chown.c +++ b/cpukit/libcsupport/src/chown.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-1999. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -12,39 +15,38 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif #include <unistd.h> -#include <rtems.h> #include <rtems/libio_.h> -int _chown_helper( +int rtems_filesystem_chown( const char *path, - uid_t owner, - gid_t group, - int follow_link + uid_t owner, + gid_t group, + int eval_follow_link ) { - rtems_filesystem_location_info_t loc; - int result; - - if ( rtems_filesystem_evaluate_path( path, strlen( path ), 0x00, &loc, follow_link ) ) - return -1; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = eval_follow_link; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); - result = (*loc.ops->chown_h)( &loc, owner, group ); + rv = (*currentloc->ops->chown_h)( + currentloc, + owner, + group + ); - rtems_filesystem_freenode( &loc ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return result; + return rv; } -int chown( - const char *path, - uid_t owner, - gid_t group -) +int chown( const char *path, uid_t owner, gid_t group ) { - return _chown_helper( path, owner, group, true ); + return rtems_filesystem_chown( path, owner, group, RTEMS_LIBIO_FOLLOW_LINK ); } diff --git a/cpukit/libcsupport/src/chroot.c b/cpukit/libcsupport/src/chroot.c index ccda4d6d7a..fd802ff32b 100644 --- a/cpukit/libcsupport/src/chroot.c +++ b/cpukit/libcsupport/src/chroot.c @@ -5,6 +5,9 @@ * COPYRIGHT (c) 1989-2008. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -13,43 +16,77 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <rtems.h> - #include <unistd.h> -#include <errno.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int chroot( - const char *pathname -) +int chroot( const char *path ) { - int result; - rtems_filesystem_location_info_t loc; - - /* an automatic call to new private env the first time */ - if (rtems_current_user_env == &rtems_global_user_env) { - rtems_libio_set_private_env(); /* try to set a new private env*/ - if (rtems_current_user_env == &rtems_global_user_env) /* not ok */ - rtems_set_errno_and_return_minus_one( ENOTSUP ); - } + int rv = 0; + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_PERMS_SEARCH + | RTEMS_LIBIO_FOLLOW_LINK; + rtems_filesystem_location_info_t loc; + rtems_filesystem_global_location_t *new_current_loc; + + /* + * We use the global environment for path evaluation. This makes it possible + * to escape from a chroot environment referencing an unmounted file system. + */ + rtems_filesystem_eval_path_start_with_root_and_current( + &ctx, + path, + eval_flags, + &rtems_global_user_env.root_directory, + &rtems_global_user_env.current_directory + ); - result = chdir(pathname); - if (result) { - rtems_set_errno_and_return_minus_one( errno ); + rtems_filesystem_eval_path_extract_currentloc( &ctx, &loc ); + new_current_loc = rtems_filesystem_location_transform_to_global( &loc ); + if ( !rtems_filesystem_global_location_is_null( new_current_loc ) ) { + rtems_filesystem_global_location_t *new_root_loc = + rtems_filesystem_global_location_obtain( &new_current_loc ); + rtems_filesystem_node_types_t type = + (*new_root_loc->location.ops->node_type_h)( &new_root_loc->location ); + + if ( type == RTEMS_FILESYSTEM_DIRECTORY ) { + sc = rtems_libio_set_private_env(); + if (sc == RTEMS_SUCCESSFUL) { + rtems_filesystem_global_location_assign( + &rtems_filesystem_root, + new_root_loc + ); + rtems_filesystem_global_location_assign( + &rtems_filesystem_current, + new_current_loc + ); + } else { + if (sc != RTEMS_UNSATISFIED) { + errno = ENOMEM; + } + rv = -1; + } + } else { + rtems_filesystem_location_error( &new_root_loc->location, ENOTDIR ); + rv = -1; + } + + if ( rv != 0 ) { + rtems_filesystem_global_location_release( new_root_loc ); + } + } else { + rv = -1; } - /* clone the new root location */ - if (rtems_filesystem_evaluate_path(".", 1, 0, &loc, 0)) { - /* our cwd has changed, though - but there is no easy way of return :-( */ - rtems_set_errno_and_return_minus_one( errno ); + rtems_filesystem_eval_path_cleanup( &ctx ); + + if ( rv != 0 ) { + rtems_filesystem_global_location_release( new_current_loc ); } - rtems_filesystem_freenode(&rtems_filesystem_root); - rtems_filesystem_root = loc; - return 0; + return rv; } diff --git a/cpukit/libcsupport/src/clonenode.c b/cpukit/libcsupport/src/clonenode.c new file mode 100644 index 0000000000..380ad90699 --- /dev/null +++ b/cpukit/libcsupport/src/clonenode.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +void rtems_filesystem_location_clone( + rtems_filesystem_location_info_t *clone, + const rtems_filesystem_location_info_t *master +) +{ + int rv = 0; + + clone = rtems_filesystem_location_copy( clone, master ); + rv = (*clone->ops->clonenod_h)( clone ); + if ( rv != 0 ) { + rtems_filesystem_location_remove_from_mt_entry( clone ); + rtems_filesystem_location_initialize_to_null( clone ); + } +} diff --git a/cpukit/libcsupport/src/close.c b/cpukit/libcsupport/src/close.c index 726bca11d9..3cdd0bffba 100644 --- a/cpukit/libcsupport/src/close.c +++ b/cpukit/libcsupport/src/close.c @@ -22,16 +22,14 @@ int close( ) { rtems_libio_t *iop; - rtems_status_code rc; + int rc; rtems_libio_check_fd(fd); iop = rtems_libio_iop(fd); rtems_libio_check_is_open(iop); - rc = RTEMS_SUCCESSFUL; rc = (*iop->pathinfo.handlers->close_h)( iop ); - rtems_filesystem_freenode( &iop->pathinfo ); rtems_libio_free( iop ); return rc; diff --git a/cpukit/libcsupport/src/eval.c b/cpukit/libcsupport/src/eval.c deleted file mode 100644 index 5a9118d3e1..0000000000 --- a/cpukit/libcsupport/src/eval.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * rtems_filesystem_evaluate_path() - * - * Routine to seed the evaluate path routine. - * - * 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 <rtems.h> -#include <rtems/libio_.h> -#include <rtems/seterr.h> - -int rtems_filesystem_evaluate_relative_path( - const char *pathname, - size_t pathnamelen, - int flags, - rtems_filesystem_location_info_t *pathloc, - int follow_link -) -{ - int result; - rtems_filesystem_node_types_t type; - - #if defined(RTEMS_DEBUG) - /* - * Verify Input parameters that should never be bad unless someone - * is implementing a new filesystem and has bugs. - */ - if ( !pathname ) - rtems_set_errno_and_return_minus_one( EFAULT ); - - if ( !pathloc ) - rtems_set_errno_and_return_minus_one( EIO ); - #endif - - result = (*pathloc->ops->evalpath_h)( pathname, pathnamelen, flags, pathloc ); - - /* - * Get the Node type and determine if you need to follow the link or - * not. - */ - - if ( (result == 0) && follow_link ) { - - type = (*pathloc->ops->node_type_h)( pathloc ); - - if ( ( type == RTEMS_FILESYSTEM_HARD_LINK ) || - ( type == RTEMS_FILESYSTEM_SYM_LINK ) ) { - - /* what to do with the valid node pathloc points to - * if eval_link_h fails? - * Let the FS implementation deal with this case. It - * should probably free pathloc in either case: - * - if the link evaluation fails, it must free the - * original (valid) pathloc because we are going - * to return -1 and hence the FS generics won't - * cleanup pathloc. - * - if the link evaluation is successful, the updated - * pathloc will be passed up (and eventually released). - * Hence, the (valid) originial node that we submit to - * eval_link_h() should be released by the handler. - */ - - result = (*pathloc->ops->eval_link_h)( pathloc, flags ); - } - } - - return result; -} - -int rtems_filesystem_evaluate_path( - const char *pathname, - size_t pathnamelen, - int flags, - rtems_filesystem_location_info_t *pathloc, - int follow_link -) -{ - int i = 0; - - #if defined(RTEMS_DEBUG) - /* - * Verify Input parameters that should never be bad unless someone - * is implementing a new filesystem and has bugs. - */ - if ( !pathname ) - rtems_set_errno_and_return_minus_one( EFAULT ); - - if ( !pathloc ) - rtems_set_errno_and_return_minus_one( EIO ); - #endif - - /* - * Evaluate the path using the optable evalpath. - */ - - rtems_filesystem_get_start_loc( pathname, &i, pathloc ); - - /* - * We evaluation the path relative to the start location we get got. - */ - return rtems_filesystem_evaluate_relative_path( &pathname[i], - pathnamelen - i, - flags, - pathloc, - follow_link ); -} - -int rtems_filesystem_dirname( - const char *pathname -) -{ - int len = strlen( pathname ); - - while ( len ) { - len--; - if ( rtems_filesystem_is_separator( pathname[len] ) ) - break; - } - - return len; -} - -int rtems_filesystem_prefix_separators( - const char *pathname, - int pathnamelen -) -{ - /* - * Eat any separators at start of the path. - */ - int stripped = 0; - while ( *pathname && pathnamelen && rtems_filesystem_is_separator( *pathname ) ) - { - pathname++; - pathnamelen--; - stripped++; - } - return stripped; -} diff --git a/cpukit/libcsupport/src/fchdir.c b/cpukit/libcsupport/src/fchdir.c index c95e2b7fb3..7b64ea8f21 100644 --- a/cpukit/libcsupport/src/fchdir.c +++ b/cpukit/libcsupport/src/fchdir.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-2011. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -12,65 +15,50 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif #include <unistd.h> -#include <sys/stat.h> -#include <errno.h> -#include <rtems.h> -#include <rtems/libio.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int fchdir( - int fd -) +int fchdir( int fd ) { + int rv = 0; rtems_libio_t *iop; - rtems_filesystem_location_info_t loc, saved; + struct stat st; + rtems_filesystem_location_info_t loc; + + st.st_mode = 0; + st.st_uid = 0; + st.st_gid = 0; rtems_libio_check_fd( fd ); iop = rtems_libio_iop( fd ); - rtems_libio_check_is_open(iop); + rtems_libio_check_is_open( iop ); - /* - * Verify you can change directory into this node. - */ + rtems_filesystem_instance_lock( &iop->pathinfo ); + rv = (*iop->pathinfo.handlers->fstat_h)( &iop->pathinfo, &st ); + if ( rv == 0 ) { + bool access_ok = rtems_filesystem_check_access( + RTEMS_LIBIO_PERMS_EXEC, + st.st_mode, + st.st_uid, + st.st_gid + ); - if ( (*iop->pathinfo.ops->node_type_h)( &iop->pathinfo ) != - RTEMS_FILESYSTEM_DIRECTORY ) { - rtems_set_errno_and_return_minus_one( ENOTDIR ); + if ( access_ok ) { + rtems_filesystem_location_clone( &loc, &iop->pathinfo ); + } else { + errno = EACCES; + rv = -1; + } } + rtems_filesystem_instance_unlock( &iop->pathinfo ); - - /* - * FIXME : I feel there should be another call to - * actually take into account the extra reference to - * this node which we are making here. I can - * see the freenode interface but do not see - * allocnode node interface. It maybe node_type. - * - * FIXED: T.Straumann: it is evaluate_path() - * but note the race condition. Threads who - * share their rtems_filesystem_current better - * be synchronized! - */ - - saved = rtems_filesystem_current; - rtems_filesystem_current = iop->pathinfo; - - /* clone the current node */ - if (rtems_filesystem_evaluate_path(".", 1, 0, &loc, 0)) { - /* cloning failed; restore original and bail out */ - rtems_filesystem_current = saved; - return -1; + if ( rv == 0 ) { + rv = rtems_filesystem_chdir( &loc ); } - /* release the old one */ - rtems_filesystem_freenode( &saved ); - - rtems_filesystem_current = loc; - return 0; + return rv; } diff --git a/cpukit/libcsupport/src/fchmod.c b/cpukit/libcsupport/src/fchmod.c index e90a155bdb..e651066a77 100644 --- a/cpukit/libcsupport/src/fchmod.c +++ b/cpukit/libcsupport/src/fchmod.c @@ -12,31 +12,25 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <unistd.h> #include <sys/stat.h> -#include <errno.h> -#include <rtems.h> -#include <rtems/libio.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int fchmod( - int fd, - mode_t mode -) +int fchmod( int fd, mode_t mode ) { + int rv; rtems_libio_t *iop; rtems_libio_check_fd( fd ); iop = rtems_libio_iop( fd ); rtems_libio_check_is_open(iop); - /* - * Now process the fchmod(). - */ - return (*iop->pathinfo.handlers->fchmod_h)( &iop->pathinfo, mode ); + rtems_filesystem_instance_lock( &iop->pathinfo ); + rv = (*iop->pathinfo.ops->fchmod_h)( &iop->pathinfo, mode ); + rtems_filesystem_instance_unlock( &iop->pathinfo ); + + return rv; } diff --git a/cpukit/libcsupport/src/fchown.c b/cpukit/libcsupport/src/fchown.c index 13bb2b9da0..b5891bf36d 100644 --- a/cpukit/libcsupport/src/fchown.c +++ b/cpukit/libcsupport/src/fchown.c @@ -12,24 +12,16 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <sys/stat.h> -#include <errno.h> - -#include <rtems.h> -#include <rtems/libio.h> +#include <unistd.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int fchown( - int fd, - uid_t owner, - gid_t group -) +int fchown( int fd, uid_t owner, gid_t group ) { + int rv = 0; rtems_libio_t *iop; rtems_libio_check_fd( fd ); @@ -38,5 +30,9 @@ int fchown( rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE ); - return (*iop->pathinfo.ops->chown_h)( &iop->pathinfo, owner, group ); + rtems_filesystem_instance_lock( &iop->pathinfo ); + rv = (*iop->pathinfo.ops->chown_h)( &iop->pathinfo, owner, group ); + rtems_filesystem_instance_unlock( &iop->pathinfo ); + + return rv; } diff --git a/cpukit/libcsupport/src/fcntl.c b/cpukit/libcsupport/src/fcntl.c index 988a9414ee..10f783b910 100644 --- a/cpukit/libcsupport/src/fcntl.c +++ b/cpukit/libcsupport/src/fcntl.c @@ -12,17 +12,53 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif #include <stdarg.h> #include <unistd.h> #include <fcntl.h> -#include <errno.h> -#include <rtems.h> #include <rtems/libio_.h> +static int duplicate_iop( rtems_libio_t *iop, int fd2 ) +{ + int rv = 0; + + /* + * FIXME: We ignore the start value fd2 for the file descriptor search. This + * is not POSIX conform. + */ + rtems_libio_t *diop = rtems_libio_allocate(); + + if (diop != NULL) { + int oflag = rtems_libio_to_fcntl_flags( iop->flags ); + + oflag &= ~O_CREAT; + diop->flags |= rtems_libio_fcntl_flags( oflag ); + + rtems_filesystem_instance_lock( &iop->pathinfo ); + rtems_filesystem_location_clone( &diop->pathinfo, &iop->pathinfo ); + rtems_filesystem_instance_unlock( &iop->pathinfo ); + + /* + * XXX: We call the open handler here to have a proper open and close pair. + * + * FIXME: What to do with the path? + */ + rv = (*diop->pathinfo.handlers->open_h)( diop, NULL, oflag, 0 ); + if ( rv == 0 ) { + rv = diop - rtems_libio_iops; + } else { + rtems_libio_free( diop ); + } + } else { + rv = -1; + } + + return rv; +} + static int vfcntl( int fd, int cmd, @@ -30,7 +66,6 @@ static int vfcntl( ) { rtems_libio_t *iop; - rtems_libio_t *diop; int fd2; int flags; int mask; @@ -51,20 +86,7 @@ static int vfcntl( switch ( cmd ) { case F_DUPFD: /* dup */ fd2 = va_arg( ap, int ); - if ( fd2 ) - diop = rtems_libio_iop( fd2 ); - else { - /* allocate a file control block */ - diop = rtems_libio_allocate(); - if ( diop == 0 ) { - ret = -1; - break; - } - } - - diop->flags = iop->flags; - diop->pathinfo = iop->pathinfo; - ret = (int) (diop - rtems_libio_iops); + ret = duplicate_iop( iop, fd2 ); break; case F_GETFD: /* get f_flags */ @@ -138,7 +160,7 @@ static int vfcntl( */ if (ret >= 0) { - int err = (*iop->pathinfo.handlers->fcntl_h)( cmd, iop ); + int err = (*iop->pathinfo.handlers->fcntl_h)( iop, cmd ); if (err) { errno = err; ret = -1; diff --git a/cpukit/libcsupport/src/freenode.c b/cpukit/libcsupport/src/freenode.c index 21a9c1de91..cc05b6034a 100644 --- a/cpukit/libcsupport/src/freenode.c +++ b/cpukit/libcsupport/src/freenode.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-2010. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -11,10 +14,16 @@ * $Id$ */ -#include <stdlib.h> +#if HAVE_CONFIG_H + #include "config.h" +#endif + #include <rtems/libio_.h> -void rtems_filesystem_freenode( rtems_filesystem_location_info_t *_node ) +void rtems_filesystem_location_free( rtems_filesystem_location_info_t *loc ) { - _node->ops->freenod_h(_node ); + rtems_filesystem_instance_lock( loc ); + (*loc->ops->freenod_h)( loc ); + rtems_filesystem_instance_unlock( loc ); + rtems_filesystem_location_remove_from_mt_entry( loc ); } diff --git a/cpukit/libcsupport/src/ftruncate.c b/cpukit/libcsupport/src/ftruncate.c index 9c50ca2fbe..66c1dc0cc6 100644 --- a/cpukit/libcsupport/src/ftruncate.c +++ b/cpukit/libcsupport/src/ftruncate.c @@ -12,39 +12,30 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif #include <unistd.h> -#include <errno.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int ftruncate( - int fd, - off_t length -) +int ftruncate( int fd, off_t length ) { - rtems_libio_t *iop; - rtems_filesystem_location_info_t loc; + int rv = 0; - rtems_libio_check_fd( fd ); - iop = rtems_libio_iop( fd ); - rtems_libio_check_is_open(iop); - rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE ); + if ( length >= 0 ) { + rtems_libio_t *iop; - /* - * Now process the ftruncate() request. - */ + rtems_libio_check_fd( fd ); + iop = rtems_libio_iop( fd ); + rtems_libio_check_is_open( iop ); + rtems_libio_check_permissions( iop, LIBIO_FLAGS_WRITE ); - /* - * Make sure we are not working on a directory - */ + rv = (*iop->pathinfo.handlers->ftruncate_h)( iop, length ); + } else { + errno = EINVAL; + rv = -1; + } - loc = iop->pathinfo; - if ( (*loc.ops->node_type_h)( &loc ) == RTEMS_FILESYSTEM_DIRECTORY ) - rtems_set_errno_and_return_minus_one( EISDIR ); - - return (*iop->pathinfo.handlers->ftruncate_h)( iop, length ); + return rv; } diff --git a/cpukit/libcsupport/src/getdents.c b/cpukit/libcsupport/src/getdents.c index d0b787cd88..82fa678978 100644 --- a/cpukit/libcsupport/src/getdents.c +++ b/cpukit/libcsupport/src/getdents.c @@ -32,8 +32,8 @@ int getdents( int dd_len ) { - rtems_libio_t *iop; - rtems_filesystem_location_info_t loc; + rtems_libio_t *iop; + rtems_filesystem_node_types_t type; /* * Get the file control block structure associated with the file descriptor @@ -43,8 +43,8 @@ int getdents( /* * Make sure we are working on a directory */ - loc = iop->pathinfo; - if ( (*loc.ops->node_type_h)( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) + type = rtems_filesystem_node_type( &iop->pathinfo ); + if ( type != RTEMS_FILESYSTEM_DIRECTORY ) rtems_set_errno_and_return_minus_one( ENOTDIR ); /* diff --git a/cpukit/libcsupport/src/lchown.c b/cpukit/libcsupport/src/lchown.c index 1092f9017e..83bdf6f95c 100644 --- a/cpukit/libcsupport/src/lchown.c +++ b/cpukit/libcsupport/src/lchown.c @@ -12,20 +12,19 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif #include <unistd.h> -#include <rtems.h> +#include <rtems/libio_.h> -int _chown_helper( const char *path, uid_t owner, gid_t group, int follow_link); - -int lchown( - const char *path, - uid_t owner, - gid_t group -) +int lchown( const char *path, uid_t owner, gid_t group ) { - return _chown_helper( path, owner, group, false ); + return rtems_filesystem_chown( + path, + owner, + group, + RTEMS_LIBIO_FOLLOW_HARD_LINK + ); } diff --git a/cpukit/libcsupport/src/libio.c b/cpukit/libcsupport/src/libio.c index d080d01596..985ad8bad9 100644 --- a/cpukit/libcsupport/src/libio.c +++ b/cpukit/libcsupport/src/libio.c @@ -47,14 +47,14 @@ * Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand */ -const rtems_assoc_t access_modes_assoc[] = { +static const rtems_assoc_t access_modes_assoc[] = { { "READ", LIBIO_FLAGS_READ, O_RDONLY }, { "WRITE", LIBIO_FLAGS_WRITE, O_WRONLY }, { "READ/WRITE", LIBIO_FLAGS_READ_WRITE, O_RDWR }, { 0, 0, 0 }, }; -const rtems_assoc_t status_flags_assoc[] = { +static const rtems_assoc_t status_flags_assoc[] = { #ifdef ACCEPT_O_NDELAY_ALIAS { "NO DELAY", LIBIO_FLAGS_NO_DELAY, O_NDELAY }, #endif @@ -64,9 +64,7 @@ const rtems_assoc_t status_flags_assoc[] = { { 0, 0, 0 }, }; -uint32_t rtems_libio_fcntl_flags( - uint32_t fcntl_flags -) +uint32_t rtems_libio_fcntl_flags( int fcntl_flags ) { uint32_t flags = 0; uint32_t access_modes; @@ -75,7 +73,7 @@ uint32_t rtems_libio_fcntl_flags( * Access mode is a small integer */ - access_modes = fcntl_flags & O_ACCMODE; + access_modes = (uint32_t) (fcntl_flags & O_ACCMODE); fcntl_flags &= ~O_ACCMODE; flags = rtems_assoc_local_by_remote( access_modes_assoc, access_modes ); @@ -83,8 +81,11 @@ uint32_t rtems_libio_fcntl_flags( * Everything else is single bits */ - flags |= - rtems_assoc_local_by_remote_bitfield(status_flags_assoc, fcntl_flags); + flags |= rtems_assoc_local_by_remote_bitfield( + status_flags_assoc, + (uint32_t) fcntl_flags + ); + return flags; } @@ -94,11 +95,9 @@ uint32_t rtems_libio_fcntl_flags( * Convert RTEMS internal flags to UNIX fnctl(2) flags */ -uint32_t rtems_libio_to_fcntl_flags( - uint32_t flags -) +int rtems_libio_to_fcntl_flags( uint32_t flags ) { - uint32_t fcntl_flags = 0; + int fcntl_flags = 0; if ( (flags & LIBIO_FLAGS_READ_WRITE) == LIBIO_FLAGS_READ_WRITE ) { fcntl_flags |= O_RDWR; @@ -176,6 +175,8 @@ void rtems_libio_free( rtems_libio_t *iop ) { + rtems_filesystem_location_free( &iop->pathinfo ); + rtems_libio_lock(); if (iop->sem) @@ -187,92 +188,3 @@ void rtems_libio_free( rtems_libio_unlock(); } - -/* - * rtems_libio_is_open_files_in_fs - * - * This routine scans the entire file descriptor table to determine if the - * are any active file descriptors that refer to the at least one node in the - * file system that we are trying to dismount. - * - * If there is at least one node in the file system referenced by the mount - * table entry a 1 is returned, otherwise a 0 is returned. - */ - -int rtems_libio_is_open_files_in_fs( - rtems_filesystem_mount_table_entry_t * fs_mt_entry -) -{ - rtems_libio_t *iop; - int result = 0; - uint32_t i; - - rtems_libio_lock(); - - /* - * Look for any active file descriptor entry. - */ - - for (iop=rtems_libio_iops,i=0; i < rtems_libio_number_iops; iop++, i++){ - - if ((iop->flags & LIBIO_FLAGS_OPEN) != 0) { - - /* - * Check if this node is under the file system that we - * are trying to dismount. - */ - - if ( iop->pathinfo.mt_entry == fs_mt_entry ) { - result = 1; - break; - } - } - } - - rtems_libio_unlock(); - - return result; -} - -/* - * rtems_libio_is_file_open - * - * This routine scans the entire file descriptor table to determine if the - * given file refers to an active file descriptor. - * - * If the given file is open a 1 is returned, otherwise a 0 is returned. - */ - -int rtems_libio_is_file_open( - void *node_access -) -{ - rtems_libio_t *iop; - int result=0; - uint32_t i; - - rtems_libio_lock(); - - /* - * Look for any active file descriptor entry. - */ - - for (iop=rtems_libio_iops,i=0; i < rtems_libio_number_iops; iop++, i++){ - if ((iop->flags & LIBIO_FLAGS_OPEN) != 0) { - - /* - * Check if this node is under the file system that we - * are trying to dismount. - */ - - if ( iop->pathinfo.node_access == node_access ) { - result = 1; - break; - } - } - } - - rtems_libio_unlock(); - - return result; -} diff --git a/cpukit/libcsupport/src/libio_sockets.c b/cpukit/libcsupport/src/libio_sockets.c index c67e19d78c..ff02e0f4ea 100644 --- a/cpukit/libcsupport/src/libio_sockets.c +++ b/cpukit/libcsupport/src/libio_sockets.c @@ -18,6 +18,7 @@ #include <rtems/libio_.h> #include <rtems/seterr.h> +#include <rtems/rtems_bsdnet_internal.h> /* * Convert an RTEMS file descriptor to a BSD socket pointer. @@ -69,5 +70,7 @@ int rtems_bsdnet_makeFdForSocket( iop->data1 = so; iop->pathinfo.handlers = h; iop->pathinfo.ops = &rtems_filesystem_operations_default; + iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry; + rtems_filesystem_location_add_to_mt_entry(&iop->pathinfo); return fd; } diff --git a/cpukit/libcsupport/src/link.c b/cpukit/libcsupport/src/link.c index 11b6521dea..cf370fb9dc 100644 --- a/cpukit/libcsupport/src/link.c +++ b/cpukit/libcsupport/src/link.c @@ -12,65 +12,44 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <rtems.h> -#include <rtems/libio.h> -#include <errno.h> +#include <unistd.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int link( - const char *existing, - const char *new -) +int link( const char *path1, const char *path2 ) { - rtems_filesystem_location_info_t existing_loc; - rtems_filesystem_location_info_t parent_loc; - int i; - int result; - const char *name_start; - - /* - * Get the node we are linking to. - */ - - result = rtems_filesystem_evaluate_path( existing, strlen( existing ), - 0, &existing_loc, true ); - if ( result != 0 ) - return -1; - - /* - * Get the parent of the node we are creating. - */ - - rtems_filesystem_get_start_loc( new, &i, &parent_loc ); - - result = (*parent_loc.ops->evalformake_h)( &new[i], &parent_loc, &name_start ); - if ( result != 0 ) { - rtems_filesystem_freenode( &existing_loc ); - return -1; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx_1; + rtems_filesystem_eval_path_context_t ctx_2; + int eval_flags_1 = RTEMS_LIBIO_FOLLOW_LINK; + int eval_flags_2 = RTEMS_LIBIO_FOLLOW_LINK + | RTEMS_LIBIO_MAKE + | RTEMS_LIBIO_EXCLUSIVE; + const rtems_filesystem_location_info_t *currentloc_1 = + rtems_filesystem_eval_path_start( &ctx_1, path1, eval_flags_1 ); + const rtems_filesystem_location_info_t *currentloc_2 = + rtems_filesystem_eval_path_start( &ctx_2, path2, eval_flags_2 ); + + rv = rtems_filesystem_location_exists_in_same_fs_instance_as( + currentloc_1, + currentloc_2 + ); + if ( rv == 0 ) { + rv = (*currentloc_2->ops->link_h)( + currentloc_2, + currentloc_1, + rtems_filesystem_eval_path_get_token( &ctx_2 ), + rtems_filesystem_eval_path_get_tokenlen( &ctx_2 ) + ); } - /* - * Check to see if the caller is trying to link across file system - * boundaries. - */ - - if ( parent_loc.mt_entry != existing_loc.mt_entry ) { - rtems_filesystem_freenode( &existing_loc ); - rtems_filesystem_freenode( &parent_loc ); - rtems_set_errno_and_return_minus_one( EXDEV ); - } - - result = (*parent_loc.ops->link_h)( &existing_loc, &parent_loc, name_start ); - - rtems_filesystem_freenode( &existing_loc ); - rtems_filesystem_freenode( &parent_loc ); + rtems_filesystem_eval_path_cleanup( &ctx_1 ); + rtems_filesystem_eval_path_cleanup( &ctx_2 ); - return result; + return rv; } /* @@ -85,10 +64,10 @@ int link( int _link_r( struct _reent *ptr __attribute__((unused)), - const char *existing, - const char *new + const char *path1, + const char *path2 ) { - return link( existing, new ); + return link( path1, path2 ); } #endif diff --git a/cpukit/libcsupport/src/lseek.c b/cpukit/libcsupport/src/lseek.c index 3f37029807..7c1f76b36b 100644 --- a/cpukit/libcsupport/src/lseek.c +++ b/cpukit/libcsupport/src/lseek.c @@ -12,64 +12,74 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <stdio.h> +#include <unistd.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -off_t lseek( - int fd, - off_t offset, - int whence -) +off_t lseek( int fd, off_t offset, int whence ) { + off_t rv = 0; rtems_libio_t *iop; - off_t old_offset; - off_t status; + off_t reference_offset; + off_t old_offset; + off_t new_offset; rtems_libio_check_fd( fd ); iop = rtems_libio_iop( fd ); rtems_libio_check_is_open(iop); - /* - * Now process the lseek(). - */ - old_offset = iop->offset; switch ( whence ) { case SEEK_SET: - iop->offset = offset; + reference_offset = 0; break; - case SEEK_CUR: - iop->offset += offset; + reference_offset = old_offset; break; - case SEEK_END: - iop->offset = iop->size + offset; + reference_offset = iop->size; break; - default: - rtems_set_errno_and_return_minus_one( EINVAL ); + errno = EINVAL; + rv = (off_t) -1; + break; + } + new_offset = reference_offset + offset; + + if ( rv == 0 ) { + if ( + (reference_offset >= 0 && new_offset >= offset) + || (reference_offset < 0 && new_offset <= offset) + ) { + switch ( rtems_filesystem_node_type( &iop->pathinfo ) ) { + case RTEMS_FILESYSTEM_DIRECTORY: + case RTEMS_FILESYSTEM_MEMORY_FILE: + if ( new_offset < 0 ) { + errno = EINVAL; + rv = (off_t) -1; + } + break; + default: + break; + } + + if ( rv == 0 ) { + iop->offset = new_offset; + rv = (*iop->pathinfo.handlers->lseek_h)( iop, offset, whence ); + if ( rv == (off_t) -1 ) { + iop->offset = old_offset; + } + } + } else { + errno = EOVERFLOW; + rv = (off_t) -1; + } } - /* - * At this time, handlers assume iop->offset has the desired - * new offset. - */ - - status = (*iop->pathinfo.handlers->lseek_h)( iop, offset, whence ); - if ( status == (off_t) -1 ) - iop->offset = old_offset; - - /* - * So if the operation failed, we have to restore iop->offset. - */ - - return status; + return rv; } /* diff --git a/cpukit/libcsupport/src/lstat.c b/cpukit/libcsupport/src/lstat.c index f034f4aa76..d35713eb04 100644 --- a/cpukit/libcsupport/src/lstat.c +++ b/cpukit/libcsupport/src/lstat.c @@ -17,6 +17,6 @@ #define _STAT_NAME lstat #define _STAT_R_NAME _lstat_r -#define _STAT_FOLLOW_LINKS false +#define _STAT_FOLLOW_LINKS RTEMS_LIBIO_FOLLOW_HARD_LINK #include "stat.c" diff --git a/cpukit/libcsupport/src/mknod.c b/cpukit/libcsupport/src/mknod.c index 29aff43c31..dae2b3bf98 100644 --- a/cpukit/libcsupport/src/mknod.c +++ b/cpukit/libcsupport/src/mknod.c @@ -16,58 +16,65 @@ */ #if HAVE_CONFIG_H -#include "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 <rtems/libio_.h> -#include <rtems/seterr.h> -int mknod( - const char *pathname, - mode_t mode, - dev_t dev +int rtems_filesystem_mknod( + const rtems_filesystem_location_info_t *parentloc, + const char *name, + size_t namelen, + mode_t mode, + dev_t dev ) { - rtems_filesystem_location_info_t temp_loc; - int i; - const char *name_start; - int result; + int rv = 0; - /* - * The file type is field within the mode. Check we have a sane mode set. - */ - switch (mode & S_IFMT) - { - case S_IFDIR: - case S_IFCHR: + mode &= ~rtems_filesystem_umask; + + switch (mode & S_IFMT) { case S_IFBLK: - case S_IFREG: + case S_IFCHR: + case S_IFDIR: case S_IFIFO: + case S_IFREG: break; default: - rtems_set_errno_and_return_minus_one( EINVAL ); + errno = EINVAL; + rv = -1; + break; } - rtems_filesystem_get_start_loc( pathname, &i, &temp_loc ); + if ( rv == 0 ) { + rv = (*parentloc->ops->mknod_h)( parentloc, name, namelen, mode, dev ); + } - result = (*temp_loc.ops->evalformake_h)( - &pathname[i], - &temp_loc, - &name_start - ); - if ( result != 0 ) - return -1; + return rv; +} - result = (*temp_loc.ops->mknod_h)( name_start, mode, dev, &temp_loc ); +int mknod( const char *path, mode_t mode, dev_t dev ) +{ + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_LINK + | RTEMS_LIBIO_MAKE + | RTEMS_LIBIO_EXCLUSIVE + | (S_ISDIR(mode) ? RTEMS_LIBIO_ACCEPT_RESIDUAL_DELIMITERS : 0); + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); + + rv = rtems_filesystem_mknod( + currentloc, + rtems_filesystem_eval_path_get_token( &ctx ), + rtems_filesystem_eval_path_get_tokenlen( &ctx ), + mode, + dev + ); - rtems_filesystem_freenode( &temp_loc ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return result; + return rv; } diff --git a/cpukit/libcsupport/src/mount.c b/cpukit/libcsupport/src/mount.c index 00a07aab3a..47c08f7dba 100644 --- a/cpukit/libcsupport/src/mount.c +++ b/cpukit/libcsupport/src/mount.c @@ -20,22 +20,15 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <sys/types.h> -#include <sys/stat.h> -#include <rtems/chain.h> -#include <rtems/seterr.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> #include <stdlib.h> #include <string.h> #include <rtems/libio_.h> -static RTEMS_CHAIN_DEFINE_EMPTY(mount_chain); +RTEMS_CHAIN_DEFINE_EMPTY(rtems_filesystem_mount_table); /* * Default pathconfs. @@ -55,14 +48,6 @@ const rtems_filesystem_limits_and_options_t rtems_filesystem_default_pathconf = 0 /* posix_vdisable: special char processing, 0=no, 1=yes */ }; -static bool is_node_fs_root( - const rtems_filesystem_mount_table_entry_t *mt_entry, - void *arg -) -{ - return arg == mt_entry->mt_fs_root.node_access; -} - static rtems_filesystem_mount_table_entry_t *alloc_mount_table_entry( const char *source_or_null, const char *target_or_null, @@ -76,11 +61,15 @@ static rtems_filesystem_mount_table_entry_t *alloc_mount_table_entry( strlen( source_or_null ) + 1 : 0; size_t target_size = strlen( target ) + 1; size_t size = sizeof( rtems_filesystem_mount_table_entry_t ) - + filesystemtype_size + source_size + target_size; + + filesystemtype_size + source_size + target_size + + sizeof( rtems_filesystem_global_location_t ); rtems_filesystem_mount_table_entry_t *mt_entry = calloc( 1, size ); if ( mt_entry != NULL ) { - char *str = (char *) mt_entry + sizeof( *mt_entry ); + rtems_filesystem_global_location_t *mt_fs_root = + (rtems_filesystem_global_location_t *) + ((char *) mt_entry + sizeof( *mt_entry )); + char *str = (char *) mt_fs_root + sizeof( *mt_fs_root ); memcpy( str, filesystemtype, filesystemtype_size ); mt_entry->type = str; @@ -92,6 +81,23 @@ static rtems_filesystem_mount_table_entry_t *alloc_mount_table_entry( memcpy( str, target, target_size ); mt_entry->target = str; + str += target_size; + + mt_entry->mounted = true; + mt_entry->mt_fs_root = mt_fs_root; + mt_entry->pathconf_limits_and_options = rtems_filesystem_default_pathconf; + + mt_fs_root->location.mt_entry = mt_entry; + mt_fs_root->reference_count = 1; + + rtems_chain_initialize( + &mt_entry->location_chain, + mt_fs_root, + 1, + sizeof(*mt_fs_root) + ); + } else { + free( mt_entry ); } *target_length_ptr = target_size - 1; @@ -99,184 +105,140 @@ static rtems_filesystem_mount_table_entry_t *alloc_mount_table_entry( return mt_entry; } -/* - * mount - * - * This routine will attempt to mount a new file system at the specified - * mount point. A series of tests will be run to determine if any of the - * following reasons exist to prevent the mount operation: - * - * 1) The file system type or options are not valid - * 2) No new file system root node is specified - * 3) The selected file system has already been mounted - * 4) The mount point exists with the proper permissions to allow mounting - * 5) The selected mount point already has a file system mounted to it - * - */ - -int mount( - const char *source, - const char *target, - const char *filesystemtype, - rtems_filesystem_options_t options, - const void *data +static int register_subordinate_file_system( + rtems_filesystem_mount_table_entry_t *mt_entry, + const char *target ) { - rtems_filesystem_fsmount_me_t mount_h = NULL; - rtems_filesystem_location_info_t loc; - rtems_filesystem_mount_table_entry_t *mt_entry = NULL; - rtems_filesystem_location_info_t *loc_to_free = NULL; - bool has_target = target != NULL; - size_t target_length = 0; - - /* - * Are the file system options valid? - */ - - if ( options != RTEMS_FILESYSTEM_READ_ONLY && - options != RTEMS_FILESYSTEM_READ_WRITE ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - /* - * Get mount handler - */ - mount_h = rtems_filesystem_get_mount_handler( filesystemtype ); - if ( !mount_h ) - rtems_set_errno_and_return_minus_one( EINVAL ); - - /* - * Allocate a mount table entry - */ - mt_entry = alloc_mount_table_entry( - source, - target, - filesystemtype, - &target_length - ); - if ( !mt_entry ) - rtems_set_errno_and_return_minus_one( ENOMEM ); - - mt_entry->mt_fs_root.mt_entry = mt_entry; - mt_entry->options = options; - mt_entry->pathconf_limits_and_options = rtems_filesystem_default_pathconf; - - /* - * The mount_point should be a directory with read/write/execute - * permissions in the existing tree. - */ - - if ( has_target ) { - if ( rtems_filesystem_evaluate_path( - target, target_length, RTEMS_LIBIO_PERMS_RWX, &loc, true ) == -1 ) - goto cleanup_and_bail; - - loc_to_free = &loc; - - /* - * Test to see if it is a directory - */ - - if ( loc.ops->node_type_h( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) { - errno = ENOTDIR; - goto cleanup_and_bail; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_PERMS_RWX + | RTEMS_LIBIO_FOLLOW_LINK; + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, target, eval_flags ); + + if ( !rtems_filesystem_location_is_root( currentloc ) ) { + rtems_filesystem_location_info_t targetloc; + rtems_filesystem_global_location_t *mt_point_node; + + rtems_filesystem_eval_path_extract_currentloc( &ctx, &targetloc ); + mt_point_node = rtems_filesystem_location_transform_to_global( &targetloc ); + mt_entry->mt_point_node = mt_point_node; + rv = (*mt_point_node->location.ops->mount_h)( mt_entry ); + if ( rv == 0 ) { + rtems_filesystem_mt_lock(); + rtems_chain_append_unprotected( + &rtems_filesystem_mount_table, + &mt_entry->mt_node + ); + rtems_filesystem_mt_unlock(); + } else { + rtems_filesystem_global_location_release( mt_point_node ); } + } else { + rtems_filesystem_eval_path_error( &ctx, EBUSY ); + rv = -1; + } - /* - * You can only mount one file system onto a single mount point. - */ + rtems_filesystem_eval_path_cleanup( &ctx ); - if ( rtems_filesystem_mount_iterate( is_node_fs_root, loc.node_access ) ) { - errno = EBUSY; - goto cleanup_and_bail; - } + return rv; +} - /* - * This must be a good mount point, so move the location information - * into the allocated mount entry. Note: the information that - * may have been allocated in loc should not be sent to freenode - * until the system is unmounted. It may be needed to correctly - * traverse the tree. - */ - - mt_entry->mt_point_node.node_access = loc.node_access; - mt_entry->mt_point_node.handlers = loc.handlers; - mt_entry->mt_point_node.ops = loc.ops; - mt_entry->mt_point_node.mt_entry = loc.mt_entry; - - /* - * This link to the parent is only done when we are dealing with system - * below the base file system - */ - - if ( loc.ops->mount_h( mt_entry ) ) { - goto cleanup_and_bail; - } +static int register_root_file_system( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + int rv = 0; + + rtems_filesystem_mt_lock(); + if ( rtems_chain_is_empty( &rtems_filesystem_mount_table ) ) { + rtems_chain_append_unprotected( + &rtems_filesystem_mount_table, + &mt_entry->mt_node + ); } else { - /* - * Do we already have a base file system ? - */ - if ( !rtems_chain_is_empty( &mount_chain ) ) { - errno = EINVAL; - goto cleanup_and_bail; - } - - /* - * This is a mount of the base file system --> The - * mt_point_node.node_access will be left to null to indicate that this - * is the root of the entire file system. - */ + errno = EINVAL; + rv = -1; } - - if ( (*mount_h)( mt_entry, data ) ) { - /* - * Try to undo the mount operation - */ - loc.ops->unmount_h( mt_entry ); - goto cleanup_and_bail; + rtems_filesystem_mt_unlock(); + + if ( rv == 0 ) { + rtems_filesystem_global_location_t *new_fs_root = + rtems_filesystem_global_location_obtain( &mt_entry->mt_fs_root ); + rtems_filesystem_global_location_t *new_fs_current = + rtems_filesystem_global_location_obtain( &mt_entry->mt_fs_root ); + + rtems_filesystem_global_location_assign( + &rtems_filesystem_root, + new_fs_root + ); + rtems_filesystem_global_location_assign( + &rtems_filesystem_current, + new_fs_current + ); } - /* - * Add the mount table entry to the mount table chain - */ - rtems_libio_lock(); - rtems_chain_append( &mount_chain, &mt_entry->Node ); - rtems_libio_unlock(); - - if ( !has_target ) - rtems_filesystem_root = mt_entry->mt_fs_root; - - return 0; - -cleanup_and_bail: - - free( mt_entry ); - - if ( loc_to_free ) - rtems_filesystem_freenode( loc_to_free ); - - return -1; + return rv; } -bool rtems_filesystem_mount_iterate( - rtems_per_filesystem_mount_routine routine, - void *routine_arg +int mount( + const char *source, + const char *target, + const char *filesystemtype, + rtems_filesystem_options_t options, + const void *data ) { - rtems_chain_node *node = NULL; - bool stop = false; - - rtems_libio_lock(); - for ( - node = rtems_chain_first( &mount_chain ); - !rtems_chain_is_tail( &mount_chain, node ) && !stop; - node = rtems_chain_next( node ) - ) { - const rtems_filesystem_mount_table_entry_t *mt_entry = - (rtems_filesystem_mount_table_entry_t *) node; + int rv = 0; - stop = (*routine)( mt_entry, routine_arg ); + if ( + options == RTEMS_FILESYSTEM_READ_ONLY + || options == RTEMS_FILESYSTEM_READ_WRITE + ) { + rtems_filesystem_fsmount_me_t fsmount_me_h = + rtems_filesystem_get_mount_handler( filesystemtype ); + + if ( fsmount_me_h != NULL ) { + size_t target_length = 0; + rtems_filesystem_mount_table_entry_t *mt_entry = alloc_mount_table_entry( + source, + target, + filesystemtype, + &target_length + ); + + if ( mt_entry != NULL ) { + mt_entry->writeable = options == RTEMS_FILESYSTEM_READ_WRITE; + + rv = (*fsmount_me_h)( mt_entry, data ); + if ( rv == 0 ) { + if ( target != NULL ) { + rv = register_subordinate_file_system( mt_entry, target ); + } else { + rv = register_root_file_system( mt_entry ); + } + + if ( rv != 0 ) { + (*mt_entry->mt_fs_root->location.ops->fsunmount_me_h)( mt_entry ); + } + } + + if ( rv != 0 ) { + free( mt_entry ); + } + } else { + errno = ENOMEM; + rv = -1; + } + } else { + errno = EINVAL; + rv = -1; + } + } else { + errno = EINVAL; + rv = -1; } - rtems_libio_unlock(); - return stop; + return rv; } diff --git a/cpukit/libcsupport/src/open.c b/cpukit/libcsupport/src/open.c index a2e1b507e3..6fa7783322 100644 --- a/cpukit/libcsupport/src/open.c +++ b/cpukit/libcsupport/src/open.c @@ -4,6 +4,9 @@ * COPYRIGHT (c) 1989-2010. * On-Line Applications Research Corporation (OAR). * + * Modifications to support reference counting in the file system are + * Copyright (c) 2012 embedded brains GmbH. + * * 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. @@ -12,185 +15,135 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <stdarg.h> +#include <sys/stat.h> #include <fcntl.h> -#include <rtems/libio_.h> -#include <rtems/seterr.h> - +#include <stdarg.h> #include <unistd.h> -/* - * Returns file descriptor on success or -1 and errno set to one of the - * following: - * - * EACCESS - Seach permission is denied on a component of the path prefix, - * or the file exists and the permissions specified by the - * flags are denied, or the file does not exist and write - * permission is denied for the parent directory of the file - * to be created, or O_TRUNC is specified and write permission - * is denied. - * EEXIST - O_CREAT and O_EXCL are set and the named file exists. - * EINTR - The open( operation was interrupted by a signal. - * EINVAL - This implementation does not support synchronized IO for this - * file. - * EISDIR - The named file is a directory and the flags argument - * specified write or read/write access. - * EMFILE - Too many file descriptors are in used by this process. - * ENAMETOOLONG - - * The length of the path exceeds PATH_MAX or a pathname - * component is longer than NAME_MAX while POSIX_NO_TRUNC - * is in effect. - * ENFILE - Too many files are open in the system. - * ENOENT - O_CREAT is not set and and the anmed file does not exist, - * or O_CREAT is set and either the path prefix does not exist - * or the path argument points to an empty string. - * ENOSPC - The directory or file system that would contain the new file - * cannot be extended. - * ENOTDIR - A component of the path prefix is not a directory. - * ENXIO - O_NONBLOCK is set, the named file is a FIFO, O_WRONLY is - * set, and no process has the file open for reading. - * EROFS - The named file resides on a read-only file system and either - * O_WRONLY, O_RDWR, O_CREAT (if the file does not exist), or - * O_TRUNC is set in the flags argument. - */ +#include <rtems/libio_.h> -int open( - const char *pathname, - int flags, - ... +static void create_regular_file( + rtems_filesystem_eval_path_context_t *ctx, + mode_t mode ) { - va_list ap; - mode_t mode; - int rc; - rtems_libio_t *iop = 0; - int status; - rtems_filesystem_location_info_t loc; - rtems_filesystem_location_info_t *loc_to_free = NULL; - int eval_flags; - - /* - * Set the Evaluation flags - */ - eval_flags = 0; - status = flags + 1; - if ( ( status & _FREAD ) == _FREAD ) - eval_flags |= RTEMS_LIBIO_PERMS_READ; - if ( ( status & _FWRITE ) == _FWRITE ) - eval_flags |= RTEMS_LIBIO_PERMS_WRITE; - - va_start(ap, flags); - - mode = va_arg( ap, mode_t ); + int rv = 0; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc( ctx ); + const char *token = rtems_filesystem_eval_path_get_token( ctx ); + size_t tokenlen = rtems_filesystem_eval_path_get_tokenlen( ctx ); + + rv = rtems_filesystem_mknod( + currentloc, + token, + tokenlen, + S_IFREG | mode, + 0 + ); + + if ( rv == 0 ) { + /* The mode only applies to future accesses of the newly created file */ + rtems_filesystem_eval_path_set_flags( ctx, 0 ); + + rtems_filesystem_eval_path_set_path( ctx, token, tokenlen ); + rtems_filesystem_eval_path_continue( ctx ); + } else { + rtems_filesystem_eval_path_error( ctx, 0 ); + } +} - /* - * NOTE: This comment is OBSOLETE. The proper way to do this now - * would be to support a magic mounted file system. - * - * Additional external I/O handlers would be supported by adding - * code to pick apart the pathname appropriately. The networking - * code does not require changes here since network file - * descriptors are obtained using socket(), not open(). - */ - - /* allocate a file control block */ - iop = rtems_libio_allocate(); - if ( iop == 0 ) { - rc = ENFILE; - goto done; +static int do_open( + rtems_libio_t *iop, + const char *path, + int oflag, + mode_t mode +) +{ + int rv = 0; + int fd = iop - rtems_libio_iops; + int rwflag = oflag + 1; + bool read_access = (rwflag & _FREAD) == _FREAD; + bool write_access = (rwflag & _FWRITE) == _FWRITE; + bool make = (oflag & O_CREAT) == O_CREAT; + bool exclusive = (oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL); + bool truncate = (oflag & O_TRUNC) == O_TRUNC; + int eval_flags = RTEMS_LIBIO_FOLLOW_LINK + | (read_access ? RTEMS_LIBIO_PERMS_READ : 0) + | (write_access ? RTEMS_LIBIO_PERMS_WRITE : 0) + | (make ? RTEMS_LIBIO_MAKE : 0) + | (exclusive ? RTEMS_LIBIO_EXCLUSIVE : 0); + rtems_filesystem_eval_path_context_t ctx; + + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); + + if ( rtems_filesystem_eval_path_has_token( &ctx ) ) { + create_regular_file( &ctx, mode ); } - /* - * See if the file exists. - */ - status = rtems_filesystem_evaluate_path( - pathname, strlen( pathname ), eval_flags, &loc, true ); + if ( write_access ) { + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc( &ctx ); + rtems_filesystem_node_types_t type = + (*currentloc->ops->node_type_h)( currentloc ); - if ( status == -1 ) { - if ( errno != ENOENT ) { - rc = errno; - goto done; + if ( type == RTEMS_FILESYSTEM_DIRECTORY ) { + rtems_filesystem_eval_path_error( &ctx, EISDIR ); } + } - /* If the file does not exist and we are not trying to create it--> error */ - if ( !(flags & O_CREAT) ) { - rc = ENOENT; - goto done; - } + iop->flags |= rtems_libio_fcntl_flags( oflag ); + rtems_filesystem_eval_path_extract_currentloc( &ctx, &iop->pathinfo ); + rtems_filesystem_eval_path_cleanup( &ctx ); - /* Create the node for the new regular file */ - rc = mknod( pathname, S_IFREG | mode, 0LL ); - if ( rc ) { - rc = errno; - goto done; + rv = (*iop->pathinfo.handlers->open_h)( iop, path, oflag, mode ); + + if ( rv == 0 ) { + if ( truncate ) { + rv = ftruncate( fd, 0 ); + if ( rv != 0 ) { + (*iop->pathinfo.handlers->close_h)( iop ); + } } - /* - * After we do the mknod(), we have to evaluate the path to get the - * "loc" structure needed to actually have the file itself open. - * So we created it, and then we need to have "look it up." - */ - status = rtems_filesystem_evaluate_path( - pathname, strlen( pathname ), 0x0, &loc, true ); - if ( status != 0 ) { /* The file did not exist */ - rc = EACCES; - goto done; + if ( rv == 0 ) { + rv = fd; + } else { + rv = -1; } + } - } else if ((flags & (O_EXCL|O_CREAT)) == (O_EXCL|O_CREAT)) { - /* We were trying to create a file that already exists */ - rc = EEXIST; - loc_to_free = &loc; - goto done; + if ( rv < 0 ) { + rtems_libio_free( iop ); } - loc_to_free = &loc; + return rv; +} + +int open( const char *path, int oflag, ... ) +{ + int rv = 0; + va_list ap; + mode_t mode = 0; + rtems_libio_t *iop = NULL; - /* - * Fill in the file control block based on the loc structure - * returned by successful path evaluation. - */ - iop->flags |= rtems_libio_fcntl_flags( flags ); - iop->pathinfo = loc; + va_start( ap, oflag ); - rc = (*iop->pathinfo.handlers->open_h)( iop, pathname, flags, mode ); - if ( rc ) { - rc = errno; - goto done; - } + mode = va_arg( ap, mode_t ); - /* - * Optionally truncate the file. - */ - if ( (flags & O_TRUNC) == O_TRUNC ) { - rc = ftruncate( iop - rtems_libio_iops, 0 ); - if ( rc ) { - if(errno) rc = errno; - close( iop - rtems_libio_iops ); - /* those are released by close(): */ - iop = 0; - loc_to_free = NULL; - } + iop = rtems_libio_allocate(); + if ( iop != NULL ) { + rv = do_open( iop, path, oflag, mode ); + } else { + errno = ENFILE; + rv = -1; } - /* - * Single exit and clean up path. - */ -done: - va_end(ap); - - if ( rc ) { - if ( iop ) - rtems_libio_free( iop ); - if ( loc_to_free ) - rtems_filesystem_freenode( loc_to_free ); - rtems_set_errno_and_return_minus_one( rc ); - } + va_end( ap ); - return iop - rtems_libio_iops; + return rv; } /* @@ -206,10 +159,10 @@ done: int _open_r( struct _reent *ptr __attribute__((unused)), const char *buf, - int flags, + int oflag, int mode ) { - return open( buf, flags, mode ); + return open( buf, oflag, mode ); } #endif diff --git a/cpukit/libcsupport/src/privateenv.c b/cpukit/libcsupport/src/privateenv.c index 89137200b7..28f866272b 100644 --- a/cpukit/libcsupport/src/privateenv.c +++ b/cpukit/libcsupport/src/privateenv.c @@ -1,3 +1,9 @@ +/** + * @file + * + * @ingroup LibIOEnv + */ + /* * Instantiate a private user environment for the calling thread. * @@ -14,191 +20,148 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <stdlib.h> /* free */ +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ + +#include <stdlib.h> -#include <rtems.h> -#include <rtems/chain.h> #include <rtems/libio_.h> +#include <rtems/score/thread.h> -/* cleanup a user environment - * NOTE: this must be called with - * thread dispatching disabled! - */ -static void -free_user_env(void *venv) +static void free_user_env(void *arg) { - rtems_user_env_t *env = (rtems_user_env_t*) venv ; - - if (env != &rtems_global_user_env - #ifdef HAVE_USERENV_REFCNT - && --env->refcnt <= 0 - #endif - ) { - rtems_filesystem_freenode( &env->current_directory); - rtems_filesystem_freenode( &env->root_directory); - free(env); + rtems_user_env_t *env = arg; + bool uses_global_env = env == &rtems_global_user_env; + + if (!uses_global_env) { + if (env->reference_count == 1) { + rtems_filesystem_global_location_release(env->current_directory); + rtems_filesystem_global_location_release(env->root_directory); + free(env); + } else { + --env->reference_count; + } } } +static void free_user_env_protected(rtems_user_env_t *env) +{ + _Thread_Disable_dispatch(); + free_user_env(env); + _Thread_Enable_dispatch(); +} + rtems_status_code rtems_libio_set_private_env(void) { rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_id task_id = rtems_task_self(); - rtems_filesystem_location_info_t root_loc; - rtems_filesystem_location_info_t current_loc; - rtems_user_env_t *new_env = NULL; - int rv = 0; - - rv = rtems_filesystem_evaluate_path("/", 1, 0, &root_loc, 0); - if (rv != 0) - goto error_0; - - rv = rtems_filesystem_evaluate_path("/", 1, 0, ¤t_loc, 0); - if (rv != 0) - goto error_1; - - /* - * Malloc is necessary whenever the current task does not - * have its own environment in place. This could be: - * a) it never had one - * OR - * b) it shared another task's environment - */ - - /* - * Bharath: I'm not sure if the check can be reduced to - * if( rtems_current_user_env->task_id != task_id ) { - */ - - if ( - rtems_current_user_env == &rtems_global_user_env - || rtems_current_user_env->task_id != task_id - ) { - new_env = malloc(sizeof(rtems_user_env_t)); - if (new_env == NULL) - goto error_2; - - #ifdef HAVE_USERENV_REFCNT - new_env->refcnt = 1; - #endif - - sc = rtems_task_variable_add( - RTEMS_SELF, - (void*)&rtems_current_user_env, - (void(*)(void *))free_user_env - ); - if (sc != RTEMS_SUCCESSFUL) - goto error_3; - - rtems_current_user_env = new_env; + rtems_id self_task_id = rtems_task_self(); + rtems_user_env_t *old_env = rtems_current_user_env; + bool uses_global_env = old_env == &rtems_global_user_env; + bool uses_shared_env = old_env->task_id != self_task_id; + + if (uses_global_env || uses_shared_env) { + rtems_user_env_t *new_env = calloc(1, sizeof(*new_env)); + + if (new_env != NULL) { + *new_env = *old_env; + new_env->reference_count = 1; + new_env->task_id = self_task_id; + new_env->root_directory = + rtems_filesystem_global_location_obtain(&old_env->root_directory); + new_env->current_directory = + rtems_filesystem_global_location_obtain(&old_env->current_directory); + + if ( + !rtems_filesystem_global_location_is_null(new_env->root_directory) + && !rtems_filesystem_global_location_is_null(new_env->current_directory) + ) { + sc = rtems_task_variable_add( + RTEMS_SELF, + (void **) &rtems_current_user_env, + free_user_env + ); + if (sc == RTEMS_SUCCESSFUL) { + free_user_env_protected(old_env); + rtems_current_user_env = new_env; + } else { + sc = RTEMS_TOO_MANY; + } + } else { + sc = RTEMS_UNSATISFIED; + } + + if (sc != RTEMS_SUCCESSFUL) { + free_user_env(new_env); + } + } else { + sc = RTEMS_NO_MEMORY; + } } - /* Inherit the global values */ - *rtems_current_user_env = rtems_global_user_env; - - rtems_current_user_env->task_id = task_id; - - /* - * Clone the pathlocs. In contrast to most other code we must _not_ free the - * original locs because what we are trying to do here is forking off clones. - * The reason is a pathloc can be allocated by the file system and needs to - * be freed when deleting the environment. - */ - rtems_filesystem_root = root_loc; - rtems_filesystem_current = current_loc; - - return RTEMS_SUCCESSFUL; - -error_3: - free(new_env); - -error_2: - rtems_filesystem_freenode(¤t_loc); - -error_1: - rtems_filesystem_freenode(&root_loc); - -error_0: - return RTEMS_NO_MEMORY; + return sc; } -/* - * Share the same private environment between two tasks: - * Task_id (remote) and RTEMS_SELF(current). - */ - -/* NOTE: - * - * THIS CODE HAS NO PROTECTION IMPLEMENTED - * - * Tasks who wish to share their environments must - * - * a) assert that no participants are concurrently - * executing - * libio_share_private_env() and/or libio_set_private_env() - * - * b) mutex access to rtems_filesystem_current, rtems_filesytem_root - * while changing any of those (chdir(), chroot()). - */ - rtems_status_code rtems_libio_share_private_env(rtems_id task_id) { - rtems_status_code sc; - rtems_user_env_t * shared_user_env; - rtems_id current_task_id; - - /* - * get current task id - */ - current_task_id = rtems_task_self(); - - /* - * If this was an attempt to share the task with self, - * if somebody wanted to do it... Lets tell them, its shared - */ - - if( task_id == current_task_id ) - return RTEMS_SUCCESSFUL; - /* - * Try to get the requested user environment - */ - sc = rtems_task_variable_get( - task_id, - (void*)&rtems_current_user_env, - (void*)&shared_user_env ); - - /* - * If it was not successful, return the error code - */ - if (sc != RTEMS_SUCCESSFUL) - return sc; - - /* - * If we are here, we have the required environment to be - * shared with the current task - */ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_id self_task_id = rtems_task_self(); + + if (task_id != RTEMS_SELF && self_task_id != task_id) { + rtems_user_env_t *env; /* - * If we have a current environment in place, we need to - * free it, since we will be sharing the variable with the - * shared_user_env + * We have to disable the thread dispatching to prevent deletion of the + * environment in the meantime. */ - - if (rtems_current_user_env->task_id==current_task_id) { - rtems_user_env_t *tmp = rtems_current_user_env; - free_user_env( tmp ); + _Thread_Disable_dispatch(); + sc = rtems_task_variable_get( + task_id, + (void *) &rtems_current_user_env, + (void *) &env + ); + if (sc == RTEMS_SUCCESSFUL) { + ++env->reference_count; + } else { + sc = RTEMS_UNSATISFIED; + } + _Thread_Enable_dispatch(); + + if (sc == RTEMS_SUCCESSFUL) { + sc = rtems_task_variable_add( + RTEMS_SELF, + (void **) &rtems_current_user_env, + free_user_env + ); + if (sc == RTEMS_SUCCESSFUL) { + free_user_env_protected(rtems_current_user_env); + rtems_current_user_env = env; + } else { + free_user_env_protected(env); + sc = RTEMS_TOO_MANY; + } + } } - /* the current_user_env is the same pointer that remote env */ - rtems_current_user_env = shared_user_env; + return sc; +} - /* increase the reference count */ -#ifdef HAVE_USERENV_REFCNT - rtems_current_user_env->refcnt++; -#endif +void rtems_libio_use_global_env(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_user_env_t *env = rtems_current_user_env; + bool uses_private_env = env != &rtems_global_user_env; - return RTEMS_SUCCESSFUL; + if (uses_private_env) { + sc = rtems_task_variable_delete( + RTEMS_SELF, + (void **) &rtems_current_user_env + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_fatal_error_occurred(0xdeadbeef); + } + + rtems_current_user_env = &rtems_global_user_env; + } } diff --git a/cpukit/libcsupport/src/readlink.c b/cpukit/libcsupport/src/readlink.c index 1880ed667e..e2c88e866c 100644 --- a/cpukit/libcsupport/src/readlink.c +++ b/cpukit/libcsupport/src/readlink.c @@ -12,37 +12,31 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif +#include <unistd.h> + #include <rtems/libio_.h> -#include <rtems/seterr.h> -ssize_t readlink( - const char *pathname, - char *buf, - size_t bufsize -) +ssize_t readlink( const char *path, char *buf, size_t bufsize ) { - rtems_filesystem_location_info_t loc; - int result; - - if (!buf) - rtems_set_errno_and_return_minus_one( EFAULT ); - - result = rtems_filesystem_evaluate_path( pathname, strlen( pathname ), - 0, &loc, false ); - if ( result != 0 ) - return -1; - - if ( (*loc.ops->node_type_h)( &loc ) != RTEMS_FILESYSTEM_SYM_LINK ){ - rtems_filesystem_freenode( &loc ); - rtems_set_errno_and_return_minus_one( EINVAL ); + ssize_t rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_HARD_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); + rtems_filesystem_node_types_t type = + (*currentloc->ops->node_type_h)( currentloc ); + + if ( type == RTEMS_FILESYSTEM_SYM_LINK ) { + rv = (*currentloc->ops->readlink_h)( currentloc, buf, bufsize ); + } else { + rtems_filesystem_eval_path_error( &ctx, EINVAL ); + rv = -1; } - result = (*loc.ops->readlink_h)( &loc, buf, bufsize ); - - rtems_filesystem_freenode( &loc ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return result; + return rv; } diff --git a/cpukit/libcsupport/src/rmdir.c b/cpukit/libcsupport/src/rmdir.c index d7d4edf675..07ecbb3a0d 100644 --- a/cpukit/libcsupport/src/rmdir.c +++ b/cpukit/libcsupport/src/rmdir.c @@ -12,84 +12,44 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <sys/types.h> -#include <fcntl.h> #include <unistd.h> -#include <errno.h> -#include <stdlib.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int rmdir( - const char *pathname -) +int rmdir( const char *path ) { - int parentpathlen; - const char *name; - rtems_filesystem_location_info_t parentloc; - rtems_filesystem_location_info_t loc; - int i; - int result; - bool free_parentloc = false; - - /* - * Get the parent node of the node we wish to remove. Find the parent path. - */ - - parentpathlen = rtems_filesystem_dirname ( pathname ); - - if ( parentpathlen == 0 ) - rtems_filesystem_get_start_loc( pathname, &i, &parentloc ); - else { - result = rtems_filesystem_evaluate_path(pathname, parentpathlen, - RTEMS_LIBIO_PERMS_WRITE, - &parentloc, - false ); - if ( result != 0 ) - return -1; - - free_parentloc = true; - } - - /* - * Start from the parent to find the node that should be under it. - */ - - loc = parentloc; - name = pathname + parentpathlen; - name += rtems_filesystem_prefix_separators( name, strlen( name ) ); - - result = rtems_filesystem_evaluate_relative_path( name , strlen( name ), - 0, &loc, false ); - if ( result != 0 ) { - if ( free_parentloc ) - rtems_filesystem_freenode( &parentloc ); - return -1; - } - - /* - * Verify you can remove this node as a directory. - */ - if ( (*loc.ops->node_type_h)( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) { - rtems_filesystem_freenode( &loc ); - if ( free_parentloc ) - rtems_filesystem_freenode( &parentloc ); - rtems_set_errno_and_return_minus_one( ENOTDIR ); + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_REJECT_TERMINAL_DOT; + rtems_filesystem_location_info_t parentloc; + int parent_eval_flags = RTEMS_LIBIO_PERMS_WRITE + | RTEMS_LIBIO_PERMS_SEARCH + | RTEMS_LIBIO_FOLLOW_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start_with_parent( + &ctx, + path, + eval_flags, + &parentloc, + parent_eval_flags + ); + rtems_filesystem_node_types_t type = + (*currentloc->ops->node_type_h)( currentloc ); + + if ( type == RTEMS_FILESYSTEM_DIRECTORY ) { + rv = (*currentloc->ops->rmnod_h)( + &parentloc, + currentloc + ); + } else { + rtems_filesystem_eval_path_error( &ctx, ENOTDIR ); + rv = -1; } - /* - * Use the filesystems rmnod to remove the node. - */ - - result = (*loc.handlers->rmnod_h)( &parentloc, &loc ); - - rtems_filesystem_freenode( &loc ); - if ( free_parentloc ) - rtems_filesystem_freenode( &parentloc ); + rtems_filesystem_eval_path_cleanup_with_parent( &ctx, &parentloc ); - return result; + return rv; } diff --git a/cpukit/libcsupport/src/stat.c b/cpukit/libcsupport/src/stat.c index 9f06deaa52..af56fd87be 100644 --- a/cpukit/libcsupport/src/stat.c +++ b/cpukit/libcsupport/src/stat.c @@ -14,7 +14,7 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif /* @@ -25,55 +25,29 @@ #ifndef _STAT_NAME #define _STAT_NAME stat #define _STAT_R_NAME _stat_r -#define _STAT_FOLLOW_LINKS true +#define _STAT_FOLLOW_LINKS RTEMS_LIBIO_FOLLOW_LINK #endif - -#include <rtems.h> - -#include <rtems/libio.h> -#include <sys/types.h> #include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> #include <string.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int _STAT_NAME( - const char *path, - struct stat *buf -) +int _STAT_NAME( const char *path, struct stat *buf ) { - int status; - rtems_filesystem_location_info_t loc; - - /* - * Check to see if we were passed a valid pointer. - */ - - if ( !buf ) - rtems_set_errno_and_return_minus_one( EFAULT ); - - status = rtems_filesystem_evaluate_path( path, strlen( path ), - 0, &loc, _STAT_FOLLOW_LINKS ); - if ( status != 0 ) - return -1; - - /* - * Zero out the stat structure so the various support - * versions of stat don't have to. - */ + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = _STAT_FOLLOW_LINKS; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); - memset( buf, 0, sizeof(struct stat) ); + memset( buf, 0, sizeof( *buf ) ); - status = (*loc.handlers->fstat_h)( &loc, buf ); + rv = (*currentloc->handlers->fstat_h)( currentloc, buf ); - rtems_filesystem_freenode( &loc ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return status; + return rv; } /* diff --git a/cpukit/libcsupport/src/statvfs.c b/cpukit/libcsupport/src/statvfs.c index 599aa7edc1..61d6d8e271 100644 --- a/cpukit/libcsupport/src/statvfs.c +++ b/cpukit/libcsupport/src/statvfs.c @@ -13,40 +13,27 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <rtems/libio_.h> -#include <rtems/seterr.h> - #include <sys/statvfs.h> +#include <string.h> -int -statvfs (const char *path, struct statvfs *sb) -{ - rtems_filesystem_location_info_t loc; - rtems_filesystem_location_info_t *fs_mount_root; - rtems_filesystem_mount_table_entry_t *mt_entry; - int result; - - /* - * Get - * The root node of the mounted filesytem. - * The node for the directory that the fileystem is mounted on. - * The mount entry that is being refered to. - */ - - if ( rtems_filesystem_evaluate_path( path, strlen( path ), 0x0, &loc, true ) ) - return -1; +#include <rtems/libio_.h> - mt_entry = loc.mt_entry; - fs_mount_root = &mt_entry->mt_fs_root; +int statvfs( const char *path, struct statvfs *buf ) +{ + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); - memset (sb, 0, sizeof (struct statvfs)); + memset( buf, 0, sizeof( *buf ) ); - result = ( fs_mount_root->ops->statvfs_h )( fs_mount_root, sb ); + rv = (*currentloc->ops->statvfs_h)( currentloc, buf ); - rtems_filesystem_freenode( &loc ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return result; + return rv; } diff --git a/cpukit/libcsupport/src/sup_fs_check_permissions.c b/cpukit/libcsupport/src/sup_fs_check_permissions.c new file mode 100644 index 0000000000..8dcecb6119 --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_check_permissions.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +bool rtems_filesystem_check_access( + int eval_flags, + mode_t node_mode, + uid_t node_uid, + gid_t node_gid +) +{ + mode_t perm_flags = eval_flags & RTEMS_LIBIO_PERMS_RWX; + uid_t task_uid = geteuid(); + + if (task_uid == 0 || task_uid == node_uid) { + perm_flags <<= 6; + } else { + gid_t task_gid = getegid(); + + if (task_gid == 0 || task_gid == node_gid) { + perm_flags <<= 3; + } else { + perm_flags <<= 0; + } + } + + return (perm_flags & node_mode) == perm_flags; +} + +bool rtems_filesystem_eval_path_check_access( + rtems_filesystem_eval_path_context_t *ctx, + int eval_flags, + mode_t node_mode, + uid_t node_uid, + gid_t node_gid +) +{ + bool access_ok = rtems_filesystem_check_access( + eval_flags, + node_mode, + node_uid, + node_gid + ); + + if (!access_ok) { + rtems_filesystem_eval_path_error(ctx, EACCES); + } + + return access_ok; +} diff --git a/cpukit/libcsupport/src/sup_fs_eval_path.c b/cpukit/libcsupport/src/sup_fs_eval_path.c new file mode 100644 index 0000000000..1940cce745 --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_eval_path.c @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +static size_t get_parentpathlen(const char *path, size_t pathlen) +{ + while (pathlen > 0) { + size_t i = pathlen - 1; + + if (rtems_filesystem_is_delimiter(path [i])) { + return pathlen; + } + + pathlen = i; + } + + return 0; +} + +static void set_startloc( + rtems_filesystem_eval_path_context_t *ctx, + rtems_filesystem_global_location_t *const *global_root_ptr, + rtems_filesystem_global_location_t *const *global_current_ptr +) +{ + if (ctx->pathlen > 0) { + char c = ctx->path [0]; + + ctx->rootloc = rtems_filesystem_global_location_obtain(global_root_ptr); + + if (rtems_filesystem_is_delimiter(c)) { + ++ctx->path; + --ctx->pathlen; + ctx->startloc = rtems_filesystem_global_location_obtain( + &ctx->rootloc + ); + } else { + ctx->startloc = rtems_filesystem_global_location_obtain( + global_current_ptr + ); + } + } else { + ctx->rootloc = rtems_filesystem_global_location_obtain_null(); + ctx->startloc = rtems_filesystem_global_location_obtain_null(); + errno = ENOENT; + } +} + +static void check_access( + rtems_filesystem_eval_path_context_t *ctx, + int eval_flags +) +{ + const rtems_filesystem_location_info_t *currentloc = &ctx->currentloc; + struct stat st; + int rv; + + st.st_mode = 0; + st.st_uid = 0; + st.st_gid = 0; + rv = (*currentloc->handlers->fstat_h)(currentloc, &st); + if (rv == 0) { + bool access_ok = rtems_filesystem_check_access( + eval_flags, + st.st_mode, + st.st_uid, + st.st_gid + ); + + if (!access_ok) { + rtems_filesystem_eval_path_error(ctx, EACCES); + } + } else { + rtems_filesystem_eval_path_error(ctx, 0); + } +} + +void rtems_filesystem_eval_path_continue( + rtems_filesystem_eval_path_context_t *ctx +) +{ + int eval_flags; + + while (ctx->pathlen > 0) { + (*ctx->currentloc.ops->eval_path_h)(ctx); + } + + eval_flags = rtems_filesystem_eval_path_get_flags(ctx); + if (rtems_filesystem_eval_path_has_token(ctx)) { + bool make = (eval_flags & RTEMS_LIBIO_MAKE) != 0; + + if (make) { + check_access(ctx, RTEMS_LIBIO_PERMS_WRITE); + } else { + rtems_filesystem_eval_path_error(ctx, ENOENT); + } + } else { + bool exclusive = (eval_flags & RTEMS_LIBIO_EXCLUSIVE) != 0; + + if (!exclusive) { + check_access(ctx, ctx->flags); + } else { + rtems_filesystem_eval_path_error(ctx, EEXIST); + } + } +} + +static rtems_filesystem_location_info_t * +eval_path_start( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + size_t pathlen, + int eval_flags, + rtems_filesystem_global_location_t *const *global_root_ptr, + rtems_filesystem_global_location_t *const *global_current_ptr +) +{ + memset(ctx, 0, sizeof(*ctx)); + + ctx->path = path; + ctx->pathlen = pathlen; + ctx->flags = eval_flags; + + set_startloc(ctx, global_root_ptr, global_current_ptr); + + rtems_filesystem_instance_lock(&ctx->startloc->location); + + rtems_filesystem_location_clone( + &ctx->currentloc, + &ctx->startloc->location + ); + + rtems_filesystem_eval_path_continue(ctx); + + return &ctx->currentloc; +} + +rtems_filesystem_location_info_t * +rtems_filesystem_eval_path_start_with_root_and_current( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + int eval_flags, + rtems_filesystem_global_location_t *const *global_root_ptr, + rtems_filesystem_global_location_t *const *global_current_ptr +) +{ + return eval_path_start( + ctx, + path, + strlen(path), + eval_flags, + global_root_ptr, + global_current_ptr + ); +} + +rtems_filesystem_location_info_t * +rtems_filesystem_eval_path_start( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + int eval_flags +) +{ + return rtems_filesystem_eval_path_start_with_root_and_current( + ctx, + path, + eval_flags, + &rtems_filesystem_root, + &rtems_filesystem_current + ); +} + +rtems_filesystem_location_info_t * +rtems_filesystem_eval_path_start_with_parent( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + int eval_flags, + rtems_filesystem_location_info_t *parentloc, + int parent_eval_flags +) +{ + size_t pathlen = strlen(path); + const char *parentpath = path; + size_t parentpathlen = get_parentpathlen(path, pathlen); + const char *name = NULL; + size_t namelen = 0; + const rtems_filesystem_location_info_t *currentloc = NULL; + + if (pathlen > 0) { + if (parentpathlen == 0) { + parentpath = "."; + parentpathlen = 1; + name = path; + namelen = pathlen; + } else { + name = path + parentpathlen; + namelen = pathlen - parentpathlen; + } + } + + currentloc = eval_path_start( + ctx, + parentpath, + parentpathlen, + parent_eval_flags, + &rtems_filesystem_root, + &rtems_filesystem_current + ); + + rtems_filesystem_location_clone(parentloc, currentloc); + + ctx->path = name; + ctx->pathlen = namelen; + ctx->flags = eval_flags; + + rtems_filesystem_eval_path_continue(ctx); + + return &ctx->currentloc; +} + +void rtems_filesystem_eval_path_recursive( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + size_t pathlen +) +{ + if (pathlen > 0) { + if (ctx->recursionlevel < RTEMS_FILESYSTEM_SYMLOOP_MAX) { + const char *saved_path = ctx->path; + size_t saved_pathlen = ctx->pathlen; + + if (rtems_filesystem_is_delimiter(path [0])) { + rtems_filesystem_eval_path_restart(ctx, &ctx->rootloc); + } + + ctx->path = path; + ctx->pathlen = pathlen; + + ++ctx->recursionlevel; + while (ctx->pathlen > 0) { + (*ctx->currentloc.ops->eval_path_h)(ctx); + } + --ctx->recursionlevel; + + ctx->path = saved_path; + ctx->pathlen = saved_pathlen; + } else { + rtems_filesystem_eval_path_error(ctx, ELOOP); + } + } else { + rtems_filesystem_eval_path_error(ctx, ENOENT); + } +} + +void rtems_filesystem_eval_path_error( + rtems_filesystem_eval_path_context_t *ctx, + int eno +) +{ + ctx->path = NULL; + ctx->pathlen = 0; + ctx->token = NULL; + ctx->tokenlen = 0; + + if (!rtems_filesystem_location_is_null(&ctx->currentloc)) { + if (eno != 0) { + errno = eno; + } + + rtems_filesystem_location_detach(&ctx->currentloc); + } +} + +static void free_location(rtems_filesystem_location_info_t *loc) +{ + rtems_filesystem_mt_entry_declare_lock_context(lock_context); + + (*loc->ops->freenod_h)(loc); + + rtems_filesystem_mt_entry_lock(lock_context); + rtems_chain_extract_unprotected(&loc->mt_entry_node); + rtems_filesystem_mt_entry_unlock(lock_context); +} + +void rtems_filesystem_eval_path_cleanup( + rtems_filesystem_eval_path_context_t *ctx +) +{ + free_location(&ctx->currentloc); + rtems_filesystem_instance_unlock(&ctx->startloc->location); + rtems_filesystem_global_location_release(ctx->startloc); + rtems_filesystem_global_location_release(ctx->rootloc); +} + +void rtems_filesystem_eval_path_cleanup_with_parent( + rtems_filesystem_eval_path_context_t *ctx, + rtems_filesystem_location_info_t *parentloc +) +{ + free_location(parentloc); + rtems_filesystem_eval_path_cleanup(ctx); +} + +void rtems_filesystem_eval_path_restart( + rtems_filesystem_eval_path_context_t *ctx, + rtems_filesystem_global_location_t **newstartloc_ptr +) +{ + free_location(&ctx->currentloc); + rtems_filesystem_instance_unlock(&ctx->startloc->location); + rtems_filesystem_global_location_assign( + &ctx->startloc, + rtems_filesystem_global_location_obtain(newstartloc_ptr) + ); + rtems_filesystem_instance_lock(&ctx->startloc->location); + rtems_filesystem_location_clone(&ctx->currentloc, &ctx->startloc->location); +} diff --git a/cpukit/libcsupport/src/sup_fs_eval_path_generic.c b/cpukit/libcsupport/src/sup_fs_eval_path_generic.c new file mode 100644 index 0000000000..c789ee4f64 --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_eval_path_generic.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +static bool is_fs_root( const rtems_filesystem_location_info_t *loc ) +{ + const rtems_filesystem_location_info_t *mt_fs_root = + &loc->mt_entry->mt_fs_root->location; + + return (*loc->ops->are_nodes_equal_h)( loc, mt_fs_root ); +} + +static bool is_eval_path_root( + const rtems_filesystem_eval_path_context_t *ctx, + const rtems_filesystem_location_info_t *loc +) +{ + const rtems_filesystem_location_info_t *rootloc = &ctx->rootloc->location; + + return loc->mt_entry == rootloc->mt_entry + && (*loc->ops->are_nodes_equal_h)( loc, rootloc ); +} + +void rtems_filesystem_eval_path_generic( + rtems_filesystem_eval_path_context_t *ctx, + void *arg, + const rtems_filesystem_eval_path_generic_config *config +) +{ + rtems_filesystem_eval_path_generic_status status = + RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE; + + while (status == RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE) { + const char *token; + size_t tokenlen; + + rtems_filesystem_eval_path_get_next_token(ctx, &token, &tokenlen); + + if (tokenlen > 0) { + if ((*config->is_directory)(ctx, arg)) { + if (rtems_filesystem_is_current_directory(token, tokenlen)) { + if (rtems_filesystem_eval_path_has_path(ctx)) { + status = (*config->eval_token)(ctx, arg, ".", 1); + } else { + int eval_flags = rtems_filesystem_eval_path_get_flags(ctx); + + if ((eval_flags & RTEMS_LIBIO_REJECT_TERMINAL_DOT) == 0) { + status = (*config->eval_token)(ctx, arg, ".", 1); + } else { + rtems_filesystem_eval_path_error(ctx, EINVAL); + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE; + } + } + } else if (rtems_filesystem_is_parent_directory(token, tokenlen)) { + rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_get_currentloc( ctx ); + + if (is_eval_path_root(ctx, currentloc)) { + /* This prevents the escape from a chroot() environment */ + status = (*config->eval_token)(ctx, arg, ".", 1); + } else if (is_fs_root(currentloc)) { + if (currentloc->mt_entry->mt_point_node != NULL) { + rtems_filesystem_eval_path_put_back_token(ctx); + rtems_filesystem_eval_path_restart( + ctx, + ¤tloc->mt_entry->mt_point_node + ); + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE; + } else { + /* This is the root file system */ + status = (*config->eval_token)(ctx, arg, ".", 1); + } + } else { + status = (*config->eval_token)(ctx, arg, "..", 2); + } + } else { + status = (*config->eval_token)(ctx, arg, token, tokenlen); + } + + if (status == RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY) { + if (rtems_filesystem_eval_path_has_path(ctx)) { + int eval_flags; + + rtems_filesystem_eval_path_eat_delimiter(ctx); + eval_flags = rtems_filesystem_eval_path_get_flags(ctx); + if ( + (eval_flags & RTEMS_LIBIO_ACCEPT_RESIDUAL_DELIMITERS) == 0 + || rtems_filesystem_eval_path_has_path(ctx) + ) { + rtems_filesystem_eval_path_error(ctx, ENOENT); + } + } + } + } else { + rtems_filesystem_eval_path_error(ctx, ENOTDIR); + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE; + } + } else { + status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE; + } + } +} diff --git a/cpukit/libcsupport/src/sup_fs_exist_in_same_instance.c b/cpukit/libcsupport/src/sup_fs_exist_in_same_instance.c new file mode 100644 index 0000000000..71a4d43b7c --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_exist_in_same_instance.c @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +int rtems_filesystem_location_exists_in_same_fs_instance_as( + const rtems_filesystem_location_info_t *a, + const rtems_filesystem_location_info_t *b +) +{ + int rv = -1; + + if ( + !rtems_filesystem_location_is_null( a ) + && !rtems_filesystem_location_is_null( b ) + ) { + if ( a->mt_entry == b->mt_entry ) { + rv = 0; + } else { + errno = EXDEV; + } + } + + return rv; +} diff --git a/cpukit/libcsupport/src/sup_fs_get_start_loc.c b/cpukit/libcsupport/src/sup_fs_get_start_loc.c deleted file mode 100644 index 89f7efbb0d..0000000000 --- a/cpukit/libcsupport/src/sup_fs_get_start_loc.c +++ /dev/null @@ -1,48 +0,0 @@ - /** - * @file src/sup_fs_get_start_loc.c - */ - -/* - * - * 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$ - */ - -/* - * rtems_filesystem_get_start_loc - * - * Function to determine if path is absolute or relative - * - * Parameters: - * - * path : IN - path to be checked - * index: OUT - 0, if relative, 1 if absolute - * loc : OUT - location info of root fs if absolute - * location info of current fs if relative - * - * Returns: void - */ - -/* Includes */ - -#include "rtems/libio_.h" - -void rtems_filesystem_get_start_loc(const char *path, - int *index, - rtems_filesystem_location_info_t *loc) -{ - if (rtems_filesystem_is_separator(path[0])) { - *loc = rtems_filesystem_root; - *index = 1; - } - else { - *loc = rtems_filesystem_current; - *index = 0; - } -} diff --git a/cpukit/libcsupport/src/sup_fs_get_sym_start_loc.c b/cpukit/libcsupport/src/sup_fs_get_sym_start_loc.c deleted file mode 100644 index 4bcc964a46..0000000000 --- a/cpukit/libcsupport/src/sup_fs_get_sym_start_loc.c +++ /dev/null @@ -1,47 +0,0 @@ - /** - * @file src/sup_fs_get_sym_start_loc.c - */ - -/* - * - * 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$ - */ - -/* - * rtems_filesystem_get_sym_start_loc - * - * Function to determine if path is absolute or relative - * - * Parameters: - * - * path : IN - path to be checked - * index: OUT - 0, if relative, 1 if absolute - * loc : OUT - location info of root fs if absolute - * location info of current fs if relative - * - * Returns: void - */ - -/* Includes */ - -#include "rtems/libio_.h" - -void rtems_filesystem_get_sym_start_loc(const char *path, - int *index, - rtems_filesystem_location_info_t *loc) -{ - if (rtems_filesystem_is_separator(path[0])) { - *loc = rtems_filesystem_root; - *index = 1; - } - else { - *index = 0; - } -} diff --git a/cpukit/libcsupport/src/sup_fs_is_separator.c b/cpukit/libcsupport/src/sup_fs_is_separator.c deleted file mode 100644 index 2c695e0335..0000000000 --- a/cpukit/libcsupport/src/sup_fs_is_separator.c +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @file src/sup_fs_is_separator.c - */ - -/* - * - * 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$ - */ - -#include <rtems/libio_.h> - -/* - * rtems_filesystem_is_separator - * - * Function to determine if a character is a path name separator. - * This was originally a macro in libio_.h - * - * NOTE: This function handles MS-DOS and UNIX style names. - */ - -int rtems_filesystem_is_separator(char ch) -{ - return ((ch == '/') || (ch == '\\') || (ch == '\0')); -} diff --git a/cpukit/libcsupport/src/sup_fs_location.c b/cpukit/libcsupport/src/sup_fs_location.c new file mode 100644 index 0000000000..5234c01ddc --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_location.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 + +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ + +#include <stdlib.h> + +#include <rtems/libio_.h> +#include <rtems/score/thread.h> + +static rtems_filesystem_global_location_t *deferred_released_global_locations; + +rtems_filesystem_location_info_t *rtems_filesystem_location_copy( + rtems_filesystem_location_info_t *dst, + const rtems_filesystem_location_info_t *src +) +{ + dst->node_access = src->node_access; + dst->node_access_2 = src->node_access_2; + dst->handlers = src->handlers; + dst->ops = src->ops; + dst->mt_entry = src->mt_entry; + rtems_filesystem_location_add_to_mt_entry(dst); + + return dst; +} + +void rtems_filesystem_location_detach( + rtems_filesystem_location_info_t *detach +) +{ + rtems_filesystem_location_free(detach); + rtems_filesystem_location_initialize_to_null(detach); +} + +void rtems_filesystem_location_copy_and_detach( + rtems_filesystem_location_info_t *copy, + rtems_filesystem_location_info_t *detach +) +{ + rtems_filesystem_location_copy(copy, detach); + rtems_filesystem_location_remove_from_mt_entry(detach); + rtems_filesystem_location_initialize_to_null(detach); +} + +rtems_filesystem_global_location_t *rtems_filesystem_location_transform_to_global( + rtems_filesystem_location_info_t *loc +) +{ + rtems_filesystem_global_location_t *global_loc = malloc(sizeof(*global_loc)); + + if (global_loc != NULL) { + global_loc->reference_count = 1; + global_loc->deferred_released_next = NULL; + global_loc->deferred_released_count = 0; + rtems_filesystem_location_copy(&global_loc->location, loc); + rtems_filesystem_location_remove_from_mt_entry(loc); + } else { + rtems_filesystem_location_free(loc); + global_loc = rtems_filesystem_global_location_obtain_null(); + errno = ENOMEM; + } + + return global_loc; +} + +void rtems_filesystem_global_location_assign( + rtems_filesystem_global_location_t **lhs_global_loc_ptr, + rtems_filesystem_global_location_t *rhs_global_loc +) +{ + rtems_filesystem_mt_entry_declare_lock_context(lock_context); + rtems_filesystem_global_location_t *lhs_global_loc; + + rtems_filesystem_mt_entry_lock(lock_context); + lhs_global_loc = *lhs_global_loc_ptr; + *lhs_global_loc_ptr = rhs_global_loc; + rtems_filesystem_mt_entry_unlock(lock_context); + + rtems_filesystem_global_location_release(lhs_global_loc); +} + +static void release_with_count( + rtems_filesystem_global_location_t *global_loc, + int count +) +{ + rtems_filesystem_mount_table_entry_t *mt_entry = + global_loc->location.mt_entry; + rtems_filesystem_mt_entry_declare_lock_context(lock_context); + bool do_free; + bool do_unmount; + + rtems_filesystem_mt_entry_lock(lock_context); + global_loc->reference_count -= count; + do_free = global_loc->reference_count == 0; + do_unmount = rtems_filesystem_is_ready_for_unmount(mt_entry); + rtems_filesystem_mt_entry_unlock(lock_context); + + if (do_free) { + rtems_filesystem_location_free(&global_loc->location); + free(global_loc); + } + + if (do_unmount) { + rtems_filesystem_do_unmount(mt_entry); + } +} + +static void deferred_release(void) +{ + rtems_filesystem_global_location_t *current = NULL; + + do { + int count = 0; + + _Thread_Disable_dispatch(); + current = deferred_released_global_locations; + if (current != NULL) { + deferred_released_global_locations = current->deferred_released_next; + count = current->deferred_released_count; + current->deferred_released_next = NULL; + current->deferred_released_count = 0; + } + _Thread_Enable_dispatch(); + + if (current != NULL) { + release_with_count(current, count); + } + } while (current != NULL); +} + +rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain( + rtems_filesystem_global_location_t *const *global_loc_ptr +) +{ + rtems_filesystem_mt_entry_declare_lock_context(lock_context); + rtems_filesystem_global_location_t *global_loc; + + if (deferred_released_global_locations != NULL) { + deferred_release(); + } + + rtems_filesystem_mt_entry_lock(lock_context); + global_loc = *global_loc_ptr; + if (global_loc == NULL || !global_loc->location.mt_entry->mounted) { + global_loc = &rtems_filesystem_global_location_null; + errno = ENXIO; + } + ++global_loc->reference_count; + rtems_filesystem_mt_entry_unlock(lock_context); + + return global_loc; +} + +void rtems_filesystem_global_location_release( + rtems_filesystem_global_location_t *global_loc +) +{ + if (!_Thread_Dispatch_in_critical_section()) { + release_with_count(global_loc, 1); + } else { + if (global_loc->deferred_released_count == 0) { + rtems_filesystem_global_location_t *head = + deferred_released_global_locations; + + global_loc->deferred_released_count = 1; + global_loc->deferred_released_next = head; + deferred_released_global_locations = global_loc; + } else { + ++global_loc->deferred_released_count; + } + } +} + +void rtems_filesystem_location_remove_from_mt_entry( + rtems_filesystem_location_info_t *loc +) +{ + rtems_filesystem_mt_entry_declare_lock_context(lock_context); + bool do_unmount; + + rtems_filesystem_mt_entry_lock(lock_context); + rtems_chain_extract_unprotected(&loc->mt_entry_node); + do_unmount = rtems_filesystem_is_ready_for_unmount(loc->mt_entry); + rtems_filesystem_mt_entry_unlock(lock_context); + + if (do_unmount) { + rtems_filesystem_do_unmount(loc->mt_entry); + } +} + +void rtems_filesystem_do_unmount( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + rtems_filesystem_mt_lock(); + rtems_chain_extract_unprotected(&mt_entry->mt_node); + rtems_filesystem_mt_unlock(); + rtems_filesystem_global_location_release(mt_entry->mt_point_node); + (*mt_entry->mt_fs_root->location.ops->fsunmount_me_h)(mt_entry); + free(mt_entry); +} diff --git a/cpukit/libcsupport/src/sup_fs_mount_iterate.c b/cpukit/libcsupport/src/sup_fs_mount_iterate.c new file mode 100644 index 0000000000..88cfca828c --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_mount_iterate.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +bool rtems_filesystem_mount_iterate( + rtems_filesystem_mt_entry_visitor visitor, + void *visitor_arg +) +{ + rtems_chain_control *chain = &rtems_filesystem_mount_table; + rtems_chain_node *node = NULL; + bool stop = false; + + rtems_filesystem_mt_lock(); + for ( + node = rtems_chain_first( chain ); + !rtems_chain_is_tail( chain, node ) && !stop; + node = rtems_chain_next( node ) + ) { + const rtems_filesystem_mount_table_entry_t *mt_entry = + (rtems_filesystem_mount_table_entry_t *) node; + + stop = (*visitor)( mt_entry, visitor_arg ); + } + rtems_filesystem_mt_unlock(); + + return stop; +} diff --git a/cpukit/libcsupport/src/sup_fs_next_token.c b/cpukit/libcsupport/src/sup_fs_next_token.c new file mode 100644 index 0000000000..451d81bbfe --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_next_token.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +void rtems_filesystem_eval_path_eat_delimiter( + rtems_filesystem_eval_path_context_t *ctx +) +{ + const char *current = ctx->path; + const char *end = current + ctx->pathlen; + + while (current != end && rtems_filesystem_is_delimiter(*current)) { + ++current; + } + + ctx->path = current; + ctx->pathlen = (size_t) (end - current); +} + +static void next_token(rtems_filesystem_eval_path_context_t *ctx) +{ + const char *begin = ctx->path; + const char *end = begin + ctx->pathlen; + const char *current = begin; + + while (current != end && !rtems_filesystem_is_delimiter(*current)) { + ++current; + } + + ctx->path = current; + ctx->pathlen = (size_t) (end - current); + ctx->token = begin; + ctx->tokenlen = (size_t) (current - begin); +} + +void rtems_filesystem_eval_path_next_token( + rtems_filesystem_eval_path_context_t *ctx +) +{ + rtems_filesystem_eval_path_eat_delimiter(ctx); + next_token(ctx); +} diff --git a/cpukit/libcsupport/src/sup_fs_node_type.c b/cpukit/libcsupport/src/sup_fs_node_type.c new file mode 100644 index 0000000000..f78451dee1 --- /dev/null +++ b/cpukit/libcsupport/src/sup_fs_node_type.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 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 <rtems/libio_.h> + +rtems_filesystem_node_types_t rtems_filesystem_node_type( + const rtems_filesystem_location_info_t *loc +) +{ + rtems_filesystem_node_types_t type; + + rtems_filesystem_instance_lock(loc); + type = (*loc->ops->node_type_h)(loc); + rtems_filesystem_instance_unlock(loc); + + return type; +} diff --git a/cpukit/libcsupport/src/symlink.c b/cpukit/libcsupport/src/symlink.c index be29980911..3a3eabc9e9 100644 --- a/cpukit/libcsupport/src/symlink.c +++ b/cpukit/libcsupport/src/symlink.c @@ -12,31 +12,31 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif +#include <unistd.h> + #include <rtems/libio_.h> -#include <rtems/seterr.h> -int symlink( - const char *actualpath, - const char *sympath -) +int symlink( const char *path1, const char *path2 ) { - rtems_filesystem_location_info_t loc; - int i; - const char *name_start; - int result; - - rtems_filesystem_get_start_loc( sympath, &i, &loc ); - - result = (*loc.ops->evalformake_h)( &sympath[i], &loc, &name_start ); - if ( result != 0 ) - return -1; - - result = (*loc.ops->symlink_h)( &loc, actualpath, name_start); - - rtems_filesystem_freenode( &loc ); - - return result; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_HARD_LINK + | RTEMS_LIBIO_MAKE + | RTEMS_LIBIO_EXCLUSIVE; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path2, eval_flags ); + + rv = (*currentloc->ops->symlink_h)( + currentloc, + rtems_filesystem_eval_path_get_token( &ctx ), + rtems_filesystem_eval_path_get_tokenlen( &ctx ), + path1 + ); + + rtems_filesystem_eval_path_cleanup( &ctx ); + + return rv; } diff --git a/cpukit/libcsupport/src/umask.c b/cpukit/libcsupport/src/umask.c index 32bf79e2b9..1c34acf10b 100644 --- a/cpukit/libcsupport/src/umask.c +++ b/cpukit/libcsupport/src/umask.c @@ -12,22 +12,27 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <sys/types.h> +#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ + #include <sys/stat.h> #include <rtems/libio_.h> -mode_t umask( - mode_t cmask -) +mode_t umask( mode_t cmask ) { mode_t old_mask; - old_mask = rtems_filesystem_umask; - rtems_filesystem_umask = cmask; + /* + * We must use the same protection mechanism as in + * rtems_libio_set_private_env(). + */ + _Thread_Disable_dispatch(); + old_mask = rtems_filesystem_umask; + rtems_filesystem_umask = cmask & (S_IRWXU | S_IRWXG | S_IRWXO); + _Thread_Enable_dispatch(); return old_mask; } diff --git a/cpukit/libcsupport/src/unlink.c b/cpukit/libcsupport/src/unlink.c index bb28959b6d..f8f91705ca 100644 --- a/cpukit/libcsupport/src/unlink.c +++ b/cpukit/libcsupport/src/unlink.c @@ -12,75 +12,39 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include <errno.h> +#include <unistd.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int unlink( - const char *path -) +int unlink( const char *path ) { - int parentpathlen; - const char *name; - rtems_filesystem_location_info_t parentloc; - rtems_filesystem_location_info_t loc; - int i; - int result; - bool free_parentloc = false; - - /* - * Get the node to be unlinked. Find the parent path first. - */ - - parentpathlen = rtems_filesystem_dirname ( path ); - - if ( parentpathlen == 0 ) - rtems_filesystem_get_start_loc( path, &i, &parentloc ); - else { - result = rtems_filesystem_evaluate_path( path, parentpathlen, - RTEMS_LIBIO_PERMS_WRITE, - &parentloc, - false ); - if ( result != 0 ) - return -1; - - free_parentloc = true; - } - - /* - * Start from the parent to find the node that should be under it. - */ - - loc = parentloc; - name = path + parentpathlen; - name += rtems_filesystem_prefix_separators( name, strlen( name ) ); - - result = rtems_filesystem_evaluate_relative_path( name , strlen( name ), - 0, &loc, false ); - if ( result != 0 ) { - if ( free_parentloc ) - rtems_filesystem_freenode( &parentloc ); - return -1; - } - - if ( (*loc.ops->node_type_h)( &loc ) == RTEMS_FILESYSTEM_DIRECTORY ) { - rtems_filesystem_freenode( &loc ); - if ( free_parentloc ) - rtems_filesystem_freenode( &parentloc ); - rtems_set_errno_and_return_minus_one( EISDIR ); - } - - result = (*loc.ops->unlink_h)( &parentloc, &loc ); - - rtems_filesystem_freenode( &loc ); - if ( free_parentloc ) - rtems_filesystem_freenode( &parentloc ); - - return result; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_REJECT_TERMINAL_DOT; + rtems_filesystem_location_info_t parentloc; + int parent_eval_flags = RTEMS_LIBIO_PERMS_WRITE + | RTEMS_LIBIO_PERMS_SEARCH + | RTEMS_LIBIO_FOLLOW_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start_with_parent( + &ctx, + path, + eval_flags, + &parentloc, + parent_eval_flags + ); + + rv = (*currentloc->ops->rmnod_h)( + &parentloc, + currentloc + ); + + rtems_filesystem_eval_path_cleanup_with_parent( &ctx, &parentloc ); + + return rv; } /* diff --git a/cpukit/libcsupport/src/unmount.c b/cpukit/libcsupport/src/unmount.c index a2c67f7098..5f65e588d0 100644 --- a/cpukit/libcsupport/src/unmount.c +++ b/cpukit/libcsupport/src/unmount.c @@ -17,146 +17,37 @@ */ #if HAVE_CONFIG_H -#include "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 <string.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -#include <rtems/chain.h> -static bool is_fs_below_mount_point( - const rtems_filesystem_mount_table_entry_t *mt_entry, - void *arg -) +int unmount( const char *path ) { - return arg == mt_entry->mt_point_node.mt_entry; -} - -/* - * unmount - * - * This routine will attempt to unmount the file system that has been - * is mounted a path. If the operation is successful, 0 will - * be returned to the calling routine. Otherwise, 1 will be returned. - */ - -int unmount( - const char *path -) -{ - rtems_filesystem_location_info_t loc; - rtems_filesystem_location_info_t *fs_root_loc; - rtems_filesystem_location_info_t *fs_mount_loc; - rtems_filesystem_mount_table_entry_t *mt_entry; - - /* - * Get - * The root node of the mounted filesytem. - * The node for the directory that the fileystem is mounted on. - * The mount entry that is being refered to. - */ - - if ( rtems_filesystem_evaluate_path( path, strlen( path ), 0x0, &loc, true ) ) - return -1; - - mt_entry = loc.mt_entry; - fs_mount_loc = &mt_entry->mt_point_node; - fs_root_loc = &mt_entry->mt_fs_root; - - /* - * Verify this is the root node for the file system to be unmounted. - */ - - if ( fs_root_loc->node_access != loc.node_access ){ - rtems_filesystem_freenode( &loc ); - rtems_set_errno_and_return_minus_one( EACCES ); - } - - /* - * Free the loc node and just use the nodes from the mt_entry . - */ - - rtems_filesystem_freenode( &loc ); - - /* - * Verify the current node is not in this filesystem. - * XXX - Joel I have a question here wasn't code added - * that made the current node thread based instead - * of system based? I thought it was but it doesn't - * look like it in this version. - */ - - if ( rtems_filesystem_current.mt_entry == mt_entry ) - rtems_set_errno_and_return_minus_one( EBUSY ); - - /* - * Verify there are no file systems below the path specified - */ - - if ( rtems_filesystem_mount_iterate( is_fs_below_mount_point, - fs_root_loc->mt_entry ) ) - rtems_set_errno_and_return_minus_one( EBUSY ); - - /* - * Run the file descriptor table to determine if there are any file - * descriptors that are currently active and reference nodes in the - * file system that we are trying to unmount - */ - - if ( rtems_libio_is_open_files_in_fs( mt_entry ) == 1 ) - rtems_set_errno_and_return_minus_one( EBUSY ); - - /* - * Allow the file system being unmounted on to do its cleanup. - * If it fails it will set the errno to the approprate value - * and the fileystem will not be modified. - */ - - if (( fs_mount_loc->ops->unmount_h )( mt_entry ) != 0 ) - return -1; - - /* - * Allow the mounted filesystem to unmark the use of the root node. - * - * Run the unmount function for the subordinate file system. - * - * If we fail to unmount the filesystem remount it on the base filesystems - * directory node. - * - * NOTE: Fatal error is called in a case which should never happen - * This was response was questionable but the best we could - * come up with. - */ - - if ((fs_root_loc->ops->fsunmount_me_h )( mt_entry ) != 0){ - if (( fs_mount_loc->ops->mount_h )( mt_entry ) != 0 ) - rtems_fatal_error_occurred( 0 ); - return -1; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); + rtems_filesystem_mount_table_entry_t *mt_entry = currentloc->mt_entry; + + if ( rtems_filesystem_location_is_root( currentloc ) ) { + rv = (*mt_entry->mt_point_node->location.ops->unmount_h)( mt_entry ); + if ( rv == 0 ) { + rtems_filesystem_mt_entry_declare_lock_context( lock_context ); + + rtems_filesystem_mt_entry_lock( lock_context ); + mt_entry->mounted = false; + rtems_filesystem_mt_entry_unlock( lock_context ); + } + } else { + errno = EACCES; + rv = -1; } - /* - * Extract the mount table entry from the chain - */ - - rtems_libio_lock(); - rtems_chain_extract( &mt_entry->Node ); - rtems_libio_unlock(); - - /* - * Free the memory node that was allocated in mount - * Free the memory associated with the extracted mount table entry. - */ - - rtems_filesystem_freenode( fs_mount_loc ); - free( mt_entry ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return 0; + return rv; } diff --git a/cpukit/libcsupport/src/utime.c b/cpukit/libcsupport/src/utime.c index 25bcb0761b..49158700c0 100644 --- a/cpukit/libcsupport/src/utime.c +++ b/cpukit/libcsupport/src/utime.c @@ -12,36 +12,41 @@ */ #if HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif +/* FIXME: This include is a workaround for a broken <utime.h> in Newlib */ #include <sys/types.h> + #include <utime.h> -#include <errno.h> #include <rtems/libio_.h> -#include <rtems/seterr.h> -int utime( - const char *path, - const struct utimbuf *times -) +int utime( const char *path, const struct utimbuf *times ) { - rtems_filesystem_location_info_t temp_loc; - int result; - struct utimbuf now; - - if ( rtems_filesystem_evaluate_path( path, strlen( path ), 0x00, &temp_loc, true ) ) - return -1; + int rv = 0; + rtems_filesystem_eval_path_context_t ctx; + int eval_flags = RTEMS_LIBIO_FOLLOW_LINK; + const rtems_filesystem_location_info_t *currentloc = + rtems_filesystem_eval_path_start( &ctx, path, eval_flags ); + struct utimbuf now_times; if ( times == NULL ) { - now.actime = now.modtime = time( NULL ); - times = &now; + time_t now = time( NULL ); + + now_times.actime = now; + now_times.modtime = now; + + times = &now_times; } - result = (*temp_loc.ops->utime_h)( &temp_loc, times->actime, times->modtime ); + rv = (*currentloc->ops->utime_h)( + currentloc, + times->actime, + times->modtime + ); - rtems_filesystem_freenode( &temp_loc ); + rtems_filesystem_eval_path_cleanup( &ctx ); - return result; + return rv; } |