/**
* @file
*
* @brief LibIO Internal Interface
*
* This file is the libio internal interface.
*/
/*
* 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.org/license/LICENSE.
*/
#ifndef _RTEMS_RTEMS_LIBIO__H
#define _RTEMS_RTEMS_LIBIO__H
#include <sys/uio.h>
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#include <rtems.h>
#include <rtems/libio.h>
#include <rtems/seterr.h>
#include <rtems/score/assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup LibIOInternal IO Internal Library
*
* @ingroup LibIO
*
* @brief Internal IO library API and implementation.
*
*/
/**@{**/
#define RTEMS_FILESYSTEM_SYMLOOP_MAX 32
/*
* Not defined in newlib so provide here. Users should use dup2 and
* not this non-portable fcntl command. Provided here to allow the
* RTEMS implementation to work.
*/
#define F_DUP2FD 20
/*
* File descriptor Table Information
*/
extern const uint32_t rtems_libio_number_iops;
extern rtems_libio_t rtems_libio_iops[];
extern void *rtems_libio_iop_free_head;
extern void **rtems_libio_iop_free_tail;
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;
/**
* @brief Sets the specified flags in the iop.
*
* @param[in] iop The iop.
* @param[in] set The flags to set.
*
* @return The previous flags.
*/
static inline unsigned int rtems_libio_iop_flags_set(
rtems_libio_t *iop,
unsigned int set
)
{
return _Atomic_Fetch_or_uint( &iop->flags, set, ATOMIC_ORDER_RELAXED );
}
/**
* @brief Clears the specified flags in the iop.
*
* @param[in] iop The iop.
* @param[in] clear The flags to clear.
*
* @return The previous flags.
*/
static inline unsigned int rtems_libio_iop_flags_clear(
rtems_libio_t *iop,
unsigned int clear
)
{
return _Atomic_Fetch_and_uint( &iop->flags, ~clear, ATOMIC_ORDER_RELAXED );
}
/**
* @brief Maps a file descriptor to the iop.
*
* The file descriptor must be a valid index into the iop table.
*
* @param[in] fd The file descriptor.
*
* @return The iop corresponding to the specified file descriptor.
*/
static inline rtems_libio_t *rtems_libio_iop( int fd )
{
return &rtems_libio_iops[ fd ];
}
/**
* @brief Holds a refernece to the iop.
*
* @param[in] iop The iop.
*
* @return The flags corresponding to the specified iop.
*/
static inline unsigned int rtems_libio_iop_hold( rtems_libio_t *iop )
{
return _Atomic_Fetch_add_uint(
&iop->flags,
LIBIO_FLAGS_REFERENCE_INC,
ATOMIC_ORDER_ACQUIRE
);
}
/**
* @brief Drops a refernece to the iop.
*
* @param[in] iop The iop.
*/
static inline void rtems_libio_iop_drop( rtems_libio_t *iop )
{
#if defined(RTEMS_DEBUG)
unsigned int flags;
bool success;
flags = _Atomic_Load_uint( &iop->flags, ATOMIC_ORDER_RELAXED );
do {
unsigned int desired;
_Assert( flags >= LIBIO_FLAGS_REFERENCE_INC );
desired = flags - LIBIO_FLAGS_REFERENCE_INC;
success = _Atomic_Compare_exchange_uint(
&iop->flags,
&flags,
desired,
ATOMIC_ORDER_RELEASE,
ATOMIC_ORDER_RELAXED
);
} while ( !success );
#else
_Atomic_Fetch_sub_uint(
&iop->flags,
LIBIO_FLAGS_REFERENCE_INC,
ATOMIC_ORDER_RELEASE
);
#endif
}
/*
* rtems_libio_iop_to_descriptor
*
* Macro to convert an internal file descriptor pointer (iop) into
* the integer file descriptor used by the "section 2" system calls.
*/
#define rtems_libio_iop_to_descriptor(_iop) \
((_iop) - &rtems_libio_iops[0])
/*
* rtems_libio_check_is_open
*
* Macro to check if a file descriptor is actually open.
*/
#define rtems_libio_check_is_open(_iop) \
do { \
if ((rtems_libio_iop_flags(_iop) & LIBIO_FLAGS_OPEN) == 0) { \
errno = EBADF; \
return -1; \
} \
} while (0)
/**
* @brief Macro to get the iop for the specified file descriptor.
*
* Checks that the file descriptor is in the valid range and open.
*/
#define LIBIO_GET_IOP( _fd, _iop ) \
do { \
unsigned int _flags; \
if ( (uint32_t) ( _fd ) >= rtems_libio_number_iops ) { \
rtems_set_errno_and_return_minus_one( EBADF ); \
} \
_iop = rtems_libio_iop( _fd ); \
_flags = rtems_libio_iop_hold( _iop ); \
if ( ( _flags & LIBIO_FLAGS_OPEN ) == 0 ) { \
rtems_libio_iop_drop( _iop ); \
rtems_set_errno_and_return_minus_one( EBADF ); \
} \
} while ( 0 )
/**
* @brief Macro to get the iop for the specified file descriptor with access
* flags and error.
*
* Checks that the file descriptor is in the valid range and open.
*/
#define LIBIO_GET_IOP_WITH_ACCESS( _fd, _iop, _access_flags, _access_error ) \
do { \
unsigned int _flags; \
unsigned int _mandatory; \
if ( (uint32_t) ( _fd ) >= rtems_libio_number_iops ) { \
rtems_set_errno_and_return_minus_one( EBADF ); \
} \
_iop = rtems_libio_iop( _fd ); \
_flags = rtems_libio_iop_hold( _iop ); \
_mandatory = LIBIO_FLAGS_OPEN | ( _access_flags ); \
if ( ( _flags & _mandatory ) != _mandatory ) { \
int _error; \
rtems_libio_iop_drop( _iop ); \
if ( ( _flags & LIBIO_FLAGS_OPEN ) == 0 ) { \
_error = EBADF; \
} else { \
_error = _access_error; \
} \
rtems_set_errno_and_return_minus_one( _error ); \
} \
} while ( 0 )
/*
* rtems_libio_check_buffer
*
* Macro to check if a buffer pointer is valid.
*/
#define rtems_libio_check_buffer(_buffer) \
do { \
if ((_buffer) == 0) { \
errno = EINVAL; \
return -1; \
} \
} while (0)
/*
* rtems_libio_check_count
*
* Macro to check if a count or length is valid.
*/
#define rtems_libio_check_count(_count) \
do { \
if ((_count) == 0) { \
return 0; \
} \
} while (0)
/**
* @brief Clones 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
);
/**
* @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 );
/*
* External structures
*/
#include <rtems/userenv.h>
void rtems_libio_lock( void );
void rtems_libio_unlock( void );
static inline void rtems_filesystem_mt_lock( void )
{
rtems_libio_lock();
}
static inline void rtems_filesystem_mt_unlock( void )
{
rtems_libio_unlock();
}
extern rtems_interrupt_lock rtems_filesystem_mt_entry_lock_control;
#define rtems_filesystem_mt_entry_declare_lock_context( ctx ) \
rtems_interrupt_lock_context ctx
#define rtems_filesystem_mt_entry_lock( ctx ) \
rtems_interrupt_lock_acquire( &rtems_filesystem_mt_entry_lock_control, &ctx )
#define rtems_filesystem_mt_entry_unlock( ctx ) \
rtems_interrupt_lock_release( &rtems_filesystem_mt_entry_lock_control, &ctx )
static inline void rtems_filesystem_instance_lock(
const rtems_filesystem_location_info_t *loc
)
{
const rtems_filesystem_mount_table_entry_t *mt_entry = loc->mt_entry;
(*mt_entry->ops->lock_h)( mt_entry );
}
static inline void rtems_filesystem_instance_unlock(
const rtems_filesystem_location_info_t *loc
)
{
const rtems_filesystem_mount_table_entry_t *mt_entry = loc->mt_entry;
(*mt_entry->ops->unlock_h)( mt_entry );
}
/*
* File Descriptor Routine Prototypes
*/
/**
* This routine searches the IOP Table for an unused entry. If it
* finds one, it returns it. Otherwise, it returns NULL.
*/
rtems_libio_t *rtems_libio_allocate(void);
/**
* Convert UNIX fnctl(2) flags to ones that RTEMS drivers understand
*/
unsigned int rtems_libio_fcntl_flags( int fcntl_flags );
/**
* Convert RTEMS internal flags to UNIX fnctl(2) flags
*/
int rtems_libio_to_fcntl_flags( unsigned int flags );
/**
* This routine frees the resources associated with an IOP (file descriptor)
* and clears the slot in the IOP Table.
*/
void rtems_libio_free(
rtems_libio_t *iop
);
/*
* 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
);
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
);
rtems_filesystem_location_info_t *
rtems_filesystem_eval_path_start_with_root_and_current(
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
);
void rtems_filesystem_eval_path_continue(
rtems_filesystem_eval_path_context_t *ctx
);
void rtems_filesystem_eval_path_cleanup(
rtems_filesystem_eval_path_context_t *ctx
);
void rtems_filesystem_eval_path_recursive(
rtems_filesystem_eval_path_context_t *ctx,
const char *path,
size_t pathlen
);
void rtems_filesystem_eval_path_cleanup_with_parent(
rtems_filesystem_eval_path_context_t *ctx,
rtems_filesystem_location_info_t *parentloc
);
/**
* @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 invocations.
* 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 the 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);
/**
* @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
);
}
rtems_filesystem_global_location_t *
rtems_filesystem_location_transform_to_global(
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
);
/**
* @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.
* @param[in] deferred If true, then do a deferred release, otherwise release
* it immediately.
*
* @see rtems_filesystem_global_location_obtain().
*/
void rtems_filesystem_global_location_release(
rtems_filesystem_global_location_t *global_loc,
bool deferred
);
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;
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_chmod(
const rtems_filesystem_location_info_t *loc,
mode_t mode
);
int rtems_filesystem_chown(
const rtems_filesystem_location_info_t *loc,
uid_t owner,
gid_t group
);
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_instance_root(
const rtems_filesystem_location_info_t *loc
)
{
const rtems_filesystem_mount_table_entry_t *mt_entry = loc->mt_entry;
return (*mt_entry->ops->are_nodes_equal_h)(
loc,
&mt_entry->mt_fs_root->location
);
}
static inline const char *rtems_filesystem_eval_path_get_path(
const rtems_filesystem_eval_path_context_t *ctx
)
{
return ctx->path;
}
static inline size_t rtems_filesystem_eval_path_get_pathlen(
const 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(
const rtems_filesystem_eval_path_context_t *ctx
)
{
return ctx->token;
}
static inline size_t rtems_filesystem_eval_path_get_tokenlen(
const 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 occurred. The @c errno indicates the error.
*/
int rtems_filesystem_location_exists_in_same_instance_as(
const rtems_filesystem_location_info_t *a,
const rtems_filesystem_location_info_t *b
);
/**
* @brief Checks if access to an object is allowed for the current user.
*
* If the effective UID is zero or equals the UID of the object, then the user
* permission flags of the object will be used. Otherwise if the effective GID
* is zero or equals the GID of the object or one of the supplementary group
* IDs is equal to the GID of the object, then the group permission flags of
* the object will be used. Otherwise the other permission flags of the object
* will be used.
*
* @param[in] flags The flags determining the access type. It can be
* RTEMS_FS_PERMS_READ, RTEMS_FS_PERMS_WRITE or RTEMS_FS_PERMS_EXEC.
* @param[in] object_mode The mode of the object specifying the permission flags.
* @param[in] object_uid The UID of the object.
* @param[in] object_gid The GID of the object.
*
* @retval true Access is allowed.
* @retval false Otherwise.
*/
bool rtems_filesystem_check_access(
int flags,
mode_t object_mode,
uid_t object_uid,
gid_t object_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] == '.';
}
typedef ssize_t ( *rtems_libio_iovec_adapter )(
rtems_libio_t *iop,
const struct iovec *iov,
int iovcnt,
ssize_t total
);
static inline ssize_t rtems_libio_iovec_eval(
int fd,
const struct iovec *iov,
int iovcnt,
unsigned int flags,
rtems_libio_iovec_adapter adapter
)
{
ssize_t total;
int v;
rtems_libio_t *iop;
/*
* Argument validation on IO vector
*/
if ( iov == NULL )
rtems_set_errno_and_return_minus_one( EINVAL );
if ( iovcnt <= 0 )
rtems_set_errno_and_return_minus_one( EINVAL );
if ( iovcnt > IOV_MAX )
rtems_set_errno_and_return_minus_one( EINVAL );
/*
* OpenGroup says that you are supposed to return EINVAL if the
* sum of the iov_len values in the iov array would overflow a
* ssize_t.
*/
total = 0;
for ( v = 0 ; v < iovcnt ; ++v ) {
size_t len = iov[ v ].iov_len;
if ( len > ( size_t ) ( SSIZE_MAX - total ) ) {
rtems_set_errno_and_return_minus_one( EINVAL );
}
total += ( ssize_t ) len;
if ( iov[ v ].iov_base == NULL && len != 0 ) {
rtems_set_errno_and_return_minus_one( EINVAL );
}
}
LIBIO_GET_IOP_WITH_ACCESS( fd, iop, flags, EBADF );
if ( total > 0 ) {
total = ( *adapter )( iop, iov, iovcnt, total );
}
rtems_libio_iop_drop( iop );
return total;
}
/**
* @brief Returns the file type of the file referenced by the filesystem
* location.
*
* @brief[in] loc The filesystem location.
*
* @return The type of the file or an invalid file type in case of an error.
*/
static inline mode_t rtems_filesystem_location_type(
const rtems_filesystem_location_info_t *loc
)
{
struct stat st;
st.st_mode = 0;
(void) ( *loc->handlers->fstat_h )( loc, &st );
return st.st_mode;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif
/* end of include file */