/** * @file * * @brief RTEMS File Sysyem Path Eval Support * @ingroup LibIOInternal */ /* * Copyright (c) 2012 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Obere Lagerstr. 30 * 82178 Puchheim * Germany * * * 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. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include 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; const rtems_filesystem_mount_table_entry_t *mt_entry = currentloc->mt_entry; if ((eval_flags & RTEMS_FS_PERMS_WRITE) == 0 || mt_entry->writeable) { 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); } } else { rtems_filesystem_eval_path_error(ctx, EROFS); } } void rtems_filesystem_eval_path_continue( rtems_filesystem_eval_path_context_t *ctx ) { int eval_flags; while (ctx->pathlen > 0) { (*ctx->currentloc.mt_entry->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_FS_MAKE) != 0; if (make) { check_access(ctx, RTEMS_FS_PERMS_WRITE); } else { rtems_filesystem_eval_path_error(ctx, ENOENT); } } else { bool exclusive = (eval_flags & RTEMS_FS_EXCLUSIVE) != 0; if (!exclusive) { check_access(ctx, ctx->flags); } else { rtems_filesystem_eval_path_error(ctx, EEXIST); } } } 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 ) { 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( 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, strlen(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 = rtems_filesystem_eval_path_start_with_root_and_current( 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.mt_entry->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->mt_entry->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, false); rtems_filesystem_global_location_release(ctx->rootloc, false); } 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); }