diff options
Diffstat (limited to 'cpukit/libcsupport/src/sup_fs_eval_path_generic.c')
-rw-r--r-- | cpukit/libcsupport/src/sup_fs_eval_path_generic.c | 118 |
1 files changed, 118 insertions, 0 deletions
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; + } + } +} |