diff options
Diffstat (limited to 'cpukit/libcsupport/include/rtems/libio_.h')
-rw-r--r-- | cpukit/libcsupport/include/rtems/libio_.h | 658 |
1 files changed, 599 insertions, 59 deletions
diff --git a/cpukit/libcsupport/include/rtems/libio_.h b/cpukit/libcsupport/include/rtems/libio_.h index e0396daa24..84882908fb 100644 --- a/cpukit/libcsupport/include/rtems/libio_.h +++ b/cpukit/libcsupport/include/rtems/libio_.h @@ -8,6 +8,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. @@ -18,17 +21,18 @@ #ifndef _RTEMS_RTEMS_LIBIO__H #define _RTEMS_RTEMS_LIBIO__H -#include <rtems.h> -#include <rtems/libio.h> /* include before standard IO */ - -#include <sys/types.h> - #include <errno.h> +#include <rtems.h> +#include <rtems/libio.h> +#include <rtems/seterr.h> + #ifdef __cplusplus extern "C" { #endif +#define RTEMS_FILESYSTEM_SYMLOOP_MAX 32 + /* * Semaphore to protect the io table */ @@ -47,6 +51,27 @@ extern rtems_libio_t *rtems_libio_iops; extern rtems_libio_t *rtems_libio_last_iop; extern rtems_libio_t *rtems_libio_iop_freelist; +extern const rtems_filesystem_file_handlers_r rtems_filesystem_null_handlers; + +extern rtems_filesystem_mount_table_entry_t rtems_filesystem_null_mt_entry; + +/** + * @brief The global null location. + * + * Every operation and the open and fstat handlers of this location returns an + * error status. The errno is not touched by these operations and handlers. + * The purpose of this location is to deliver the error return status for a + * previous error condition which must set the errno accordingly. + * + * The usage of this null location instead of the NULL pointer eliminates a lot + * of branches. + * + * The user environment root and current directory are statically initialized + * with the null location. Due to that all file system services are in a + * defined state even if no root file system was mounted. + */ +extern rtems_filesystem_global_location_t rtems_filesystem_global_location_null; + /* * rtems_libio_iop * @@ -147,28 +172,54 @@ extern rtems_libio_t *rtems_libio_iop_freelist; #define rtems_libio_check_permissions(_iop, _flag) \ rtems_libio_check_permissions_with_error(_iop, _flag, EINVAL ) -/* - * rtems_filesystem_freenode +/** + * @brief Clones a node. * - * Macro to free a node. + * The caller must hold the file system instance lock. + * + * @param[out] clone The cloned location. + * @param[in] master The master location. + * + * @see rtems_filesystem_instance_lock(). */ +void rtems_filesystem_location_clone( + rtems_filesystem_location_info_t *clone, + const rtems_filesystem_location_info_t *master +); -void rtems_filesystem_freenode( rtems_filesystem_location_info_t* node ); - -/* - * External structures +/** + * @brief Returns the type of a node. + * + * This function obtains and releases the file system instance lock. + * + * @param[in] loc The location of the node. + * + * @return The node type. + * + * @see rtems_filesystem_instance_lock(). */ -#include <rtems/userenv.h> +rtems_filesystem_node_types_t rtems_filesystem_node_type( + const rtems_filesystem_location_info_t *loc +); -extern rtems_user_env_t * rtems_current_user_env; -extern rtems_user_env_t rtems_global_user_env; +/** + * @brief Releases all resources of a location. + * + * This function may block on a mutex and may complete an unmount process. + * + * @param[in] loc The location to free. + * + * @note The file system root location is released by the file system instance + * destruction handler (see @ref rtems_filesystem_fsunmount_me_t). + * + * @see rtems_filesystem_freenode_t. + */ +void rtems_filesystem_location_free( rtems_filesystem_location_info_t *loc ); /* - * Instantiate a private copy of the per user information for the calling task. + * External structures */ - -rtems_status_code rtems_libio_set_private_env(void); -rtems_status_code rtems_libio_share_private_env(rtems_id task_id) ; +#include <rtems/userenv.h> static inline void rtems_libio_lock( void ) { @@ -180,80 +231,569 @@ static inline void rtems_libio_unlock( void ) rtems_semaphore_release( rtems_libio_semaphore ); } +static inline void rtems_filesystem_mt_lock( void ) +{ + rtems_libio_lock(); +} + +static inline void rtems_filesystem_mt_unlock( void ) +{ + rtems_libio_unlock(); +} + +#define rtems_filesystem_mt_entry_declare_lock_context( ctx ) \ + rtems_interrupt_level ctx + +#define rtems_filesystem_mt_entry_lock( ctx ) rtems_interrupt_disable( ctx ) + +#define rtems_filesystem_mt_entry_unlock( ctx ) rtems_interrupt_enable( ctx ) + +static inline void rtems_filesystem_instance_lock( + const rtems_filesystem_location_info_t *loc +) +{ + (*loc->ops->lock_h)( loc->mt_entry ); +} + +static inline void rtems_filesystem_instance_unlock( + const rtems_filesystem_location_info_t *loc +) +{ + (*loc->ops->unlock_h)( loc->mt_entry ); +} + /* * File Descriptor Routine Prototypes */ rtems_libio_t *rtems_libio_allocate(void); -uint32_t rtems_libio_fcntl_flags( - uint32_t fcntl_flags -); +uint32_t rtems_libio_fcntl_flags( int fcntl_flags ); -uint32_t rtems_libio_to_fcntl_flags( - uint32_t flags -); +int rtems_libio_to_fcntl_flags( uint32_t flags ); void rtems_libio_free( rtems_libio_t *iop ); -int rtems_libio_is_open_files_in_fs( - rtems_filesystem_mount_table_entry_t *mt_entry +/* + * File System Routine Prototypes + */ + +rtems_filesystem_location_info_t * +rtems_filesystem_eval_path_start( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + int eval_flags ); -int rtems_libio_is_file_open( - void *node_access +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 ); -/* - * File System Routine Prototypes - */ +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 +); + +void rtems_filesystem_eval_path_continue( + rtems_filesystem_eval_path_context_t *ctx +); -int rtems_filesystem_evaluate_relative_path( - const char *pathname, - size_t pathnamelen, - int flags, - rtems_filesystem_location_info_t *pathloc, - int follow_link +void rtems_filesystem_eval_path_cleanup( + rtems_filesystem_eval_path_context_t *ctx ); -int rtems_filesystem_evaluate_path( - const char *pathname, - size_t pathnamelen, - int flags, - rtems_filesystem_location_info_t *pathloc, - int follow_link +void rtems_filesystem_eval_path_recursive( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + size_t pathlen ); -int rtems_filesystem_dirname( - const char *pathname +void rtems_filesystem_eval_path_cleanup_with_parent( + rtems_filesystem_eval_path_context_t *ctx, + rtems_filesystem_location_info_t *parentloc ); -int rtems_filesystem_prefix_separators( - const char *pathname, - int pathnamelen +/** + * @brief Requests a path evaluation restart. + * + * Sets the start and current location to the new start location. The caller + * must terminate its current evaluation process. The path evaluation + * continues in the next loop iteration within + * rtems_filesystem_eval_path_continue(). This avoids recursive invokations. + * The function obtains the new start location and clones it to set the new + * current location. The previous start and current locations are released. + * + * @param[in, out] ctx The path evaluation context. + * @param[in, out] newstartloc_ptr Pointer to new start location. + */ +void rtems_filesystem_eval_path_restart( + rtems_filesystem_eval_path_context_t *ctx, + rtems_filesystem_global_location_t **newstartloc_ptr +); + +typedef enum { + RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE, + RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE, + RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY +} rtems_filesystem_eval_path_generic_status; + +/** + * @brief Tests if the current location is a directory. + * + * @param[in, out] ctx The path evaluation context. + * @param[in, out] arg The handler argument. + * + * @retval true The current location is a directory. + * @retval false Otherwise. + * + * @see rtems_filesystem_eval_path_generic(). + */ +typedef bool (*rtems_filesystem_eval_path_is_directory)( + rtems_filesystem_eval_path_context_t *ctx, + void *arg +); + +/** + * @brief Evaluates a token. + * + * @param[in, out] ctx The path evaluation context. + * @param[in, out] arg The handler argument. + * @param[in] token The token contents. + * @param[in] tokenlen The token length in characters. + * + * @retval status The generic path evaluation status. + * + * @see rtems_filesystem_eval_path_generic(). + */ +typedef rtems_filesystem_eval_path_generic_status +(*rtems_filesystem_eval_path_eval_token)( + rtems_filesystem_eval_path_context_t *ctx, + void *arg, + const char *token, + size_t tokenlen +); + +typedef struct { + rtems_filesystem_eval_path_is_directory is_directory; + rtems_filesystem_eval_path_eval_token eval_token; +} rtems_filesystem_eval_path_generic_config; + +void rtems_filesystem_eval_path_generic( + rtems_filesystem_eval_path_context_t *ctx, + void *arg, + const rtems_filesystem_eval_path_generic_config *config ); void rtems_filesystem_initialize(void); -int init_fs_mount_table(void); +/** + * @brief Copies a location. + * + * A bitwise copy is performed. The destination location will be added to the + * corresponding mount entry. + * + * @param[out] dst The destination location. + * @param[in] src The source location. + * + * @retval dst The destination location. + * + * @see rtems_filesystem_location_clone(). + */ +rtems_filesystem_location_info_t *rtems_filesystem_location_copy( + rtems_filesystem_location_info_t *dst, + const rtems_filesystem_location_info_t *src +); + +static inline rtems_filesystem_location_info_t * +rtems_filesystem_location_initialize_to_null( + rtems_filesystem_location_info_t *loc +) +{ + return rtems_filesystem_location_copy( + loc, + &rtems_filesystem_global_location_null.location + ); +} -int rtems_filesystem_is_separator(char ch); +rtems_filesystem_global_location_t * +rtems_filesystem_location_transform_to_global( + rtems_filesystem_location_info_t *loc +); -void rtems_filesystem_get_start_loc(const char *path, - int *index, - rtems_filesystem_location_info_t *loc); +/** + * @brief Assigns a global file system location. + * + * @param[in, out] lhs_global_loc_ptr Pointer to the global left hand side file + * system location. The current left hand side location will be released. + * @param[in] rhs_global_loc The global right hand side file system location. + */ +void rtems_filesystem_global_location_assign( + rtems_filesystem_global_location_t **lhs_global_loc_ptr, + rtems_filesystem_global_location_t *rhs_global_loc +); -void rtems_filesystem_get_sym_start_loc(const char *path, - int *index, - rtems_filesystem_location_info_t *loc); +/** + * @brief Obtains a global file system location. + * + * Deferred releases will be processed in this function. + * + * This function must be called from normal thread context and may block on a + * mutex. Thread dispatching is disabled to protect some critical sections. + * + * @param[in] global_loc_ptr Pointer to the global file system location. + * + * @return A global file system location. It returns always a valid object. + * In case of an error, the global null location will be returned. Each + * operation or handler of the null location returns an error status. The + * errno indicates the error. The NULL pointer is never returned. + * + * @see rtems_filesystem_location_transform_to_global(), + * rtems_filesystem_global_location_obtain_null(), and + * rtems_filesystem_global_location_release(). + */ +rtems_filesystem_global_location_t *rtems_filesystem_global_location_obtain( + rtems_filesystem_global_location_t *const *global_loc_ptr +); + +/** + * @brief Releases a global file system location. + * + * In case the reference count reaches zero, all associated resources will be + * released. This may include the complete unmount of the corresponding file + * system instance. + * + * This function may block on a mutex. It may be called within critical + * sections of the operating system. In this case the release will be + * deferred. The next obtain call will do the actual release. + * + * @param[in] global_loc The global file system location. It must not be NULL. + * + * @see rtems_filesystem_global_location_obtain(). + */ +void rtems_filesystem_global_location_release( + rtems_filesystem_global_location_t *global_loc +); + +void rtems_filesystem_location_detach( + rtems_filesystem_location_info_t *detach +); + +void rtems_filesystem_location_copy_and_detach( + rtems_filesystem_location_info_t *copy, + rtems_filesystem_location_info_t *detach +); + +static inline rtems_filesystem_global_location_t * +rtems_filesystem_global_location_obtain_null(void) +{ + rtems_filesystem_global_location_t *global_loc = NULL; -static inline bool rtems_filesystem_is_root_location( + return rtems_filesystem_global_location_obtain( &global_loc ); +} + +static inline bool rtems_filesystem_location_is_null( + const rtems_filesystem_location_info_t *loc +) +{ + return loc->handlers == &rtems_filesystem_null_handlers; +} + +static inline bool rtems_filesystem_global_location_is_null( + const rtems_filesystem_global_location_t *global_loc +) +{ + return rtems_filesystem_location_is_null( &global_loc->location ); +} + +static inline void rtems_filesystem_location_error( + const rtems_filesystem_location_info_t *loc, + int eno +) +{ + if ( !rtems_filesystem_location_is_null( loc ) ) { + errno = eno; + } +} + +int rtems_filesystem_mknod( + const rtems_filesystem_location_info_t *parentloc, + const char *name, + size_t namelen, + mode_t mode, + dev_t dev +); + +int rtems_filesystem_chdir( rtems_filesystem_location_info_t *loc ); + +int rtems_filesystem_chown( + const char *path, + uid_t owner, + gid_t group, + int eval_follow_link +); + +static inline bool rtems_filesystem_is_ready_for_unmount( + rtems_filesystem_mount_table_entry_t *mt_entry +) +{ + bool ready = !mt_entry->mounted + && rtems_chain_has_only_one_node( &mt_entry->location_chain ) + && mt_entry->mt_fs_root->reference_count == 1; + + if ( ready ) { + rtems_chain_initialize_empty( &mt_entry->location_chain ); + } + + return ready; +} + +static inline void rtems_filesystem_location_add_to_mt_entry( + rtems_filesystem_location_info_t *loc +) +{ + rtems_filesystem_mt_entry_declare_lock_context( lock_context ); + + rtems_filesystem_mt_entry_lock( lock_context ); + rtems_chain_append_unprotected( + &loc->mt_entry->location_chain, + &loc->mt_entry_node + ); + rtems_filesystem_mt_entry_unlock( lock_context ); +} + +void rtems_filesystem_location_remove_from_mt_entry( + rtems_filesystem_location_info_t *loc +); + +void rtems_filesystem_do_unmount( + rtems_filesystem_mount_table_entry_t *mt_entry +); + +static inline bool rtems_filesystem_location_is_root( const rtems_filesystem_location_info_t *loc ) { - return loc->mt_entry->mt_fs_root.node_access == loc->node_access; + return (*loc->ops->are_nodes_equal_h)( + loc, + &loc->mt_entry->mt_fs_root->location + ); +} + +static inline const char *rtems_filesystem_eval_path_get_path( + rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->path; +} + +static inline size_t rtems_filesystem_eval_path_get_pathlen( + rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->pathlen; +} + +static inline void rtems_filesystem_eval_path_set_path( + rtems_filesystem_eval_path_context_t *ctx, + const char *path, + size_t pathlen +) +{ + ctx->path = path; + ctx->pathlen = pathlen; +} + +static inline void rtems_filesystem_eval_path_clear_path( + rtems_filesystem_eval_path_context_t *ctx +) +{ + ctx->pathlen = 0; +} + +static inline const char *rtems_filesystem_eval_path_get_token( + rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->token; +} + +static inline size_t rtems_filesystem_eval_path_get_tokenlen( + rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->tokenlen; +} + +static inline void rtems_filesystem_eval_path_set_token( + rtems_filesystem_eval_path_context_t *ctx, + const char *token, + size_t tokenlen +) +{ + ctx->token = token; + ctx->tokenlen = tokenlen; +} + +static inline void rtems_filesystem_eval_path_clear_token( + rtems_filesystem_eval_path_context_t *ctx +) +{ + ctx->tokenlen = 0; +} + +static inline void rtems_filesystem_eval_path_put_back_token( + rtems_filesystem_eval_path_context_t *ctx +) +{ + size_t tokenlen = ctx->tokenlen; + + ctx->path -= tokenlen; + ctx->pathlen += tokenlen; + ctx->tokenlen = 0; +} + +void rtems_filesystem_eval_path_eat_delimiter( + rtems_filesystem_eval_path_context_t *ctx +); + +void rtems_filesystem_eval_path_next_token( + rtems_filesystem_eval_path_context_t *ctx +); + +static inline void rtems_filesystem_eval_path_get_next_token( + rtems_filesystem_eval_path_context_t *ctx, + const char **token, + size_t *tokenlen +) +{ + rtems_filesystem_eval_path_next_token(ctx); + *token = ctx->token; + *tokenlen = ctx->tokenlen; +} + +static inline rtems_filesystem_location_info_t * +rtems_filesystem_eval_path_get_currentloc( + rtems_filesystem_eval_path_context_t *ctx +) +{ + return &ctx->currentloc; +} + +static inline bool rtems_filesystem_eval_path_has_path( + const rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->pathlen > 0; +} + +static inline bool rtems_filesystem_eval_path_has_token( + const rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->tokenlen > 0; +} + +static inline int rtems_filesystem_eval_path_get_flags( + const rtems_filesystem_eval_path_context_t *ctx +) +{ + return ctx->flags; +} + +static inline void rtems_filesystem_eval_path_set_flags( + rtems_filesystem_eval_path_context_t *ctx, + int flags +) +{ + ctx->flags = flags; +} + +static inline void rtems_filesystem_eval_path_clear_and_set_flags( + rtems_filesystem_eval_path_context_t *ctx, + int clear, + int set +) +{ + int flags = ctx->flags; + + flags &= ~clear; + flags |= set; + + ctx->flags = flags; +} + +static inline void rtems_filesystem_eval_path_extract_currentloc( + rtems_filesystem_eval_path_context_t *ctx, + rtems_filesystem_location_info_t *get +) +{ + rtems_filesystem_location_copy_and_detach( + get, + &ctx->currentloc + ); +} + +void rtems_filesystem_eval_path_error( + rtems_filesystem_eval_path_context_t *ctx, + int eno +); + +/** + * @brief Checks that the locations exist in the same file system instance. + * + * @retval 0 The locations exist and are in the same file system instance. + * @retval -1 An error occured. The @c errno indicates the error. + */ +int rtems_filesystem_location_exists_in_same_fs_instance_as( + const rtems_filesystem_location_info_t *a, + const rtems_filesystem_location_info_t *b +); + +bool rtems_filesystem_check_access( + int eval_flags, + mode_t node_mode, + uid_t node_uid, + gid_t node_gid +); + +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 +); + +static inline bool rtems_filesystem_is_delimiter(char c) +{ + return c == '/' || c == '\\'; +} + +static inline bool rtems_filesystem_is_current_directory( + const char *token, + size_t tokenlen +) +{ + return tokenlen == 1 && token [0] == '.'; +} + +static inline bool rtems_filesystem_is_parent_directory( + const char *token, + size_t tokenlen +) +{ + return tokenlen == 2 && token [0] == '.' && token [1] == '.'; } #ifdef __cplusplus |