summaryrefslogtreecommitdiffstats
path: root/cpukit/libcsupport/src/sup_fs_eval_path.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libcsupport/src/sup_fs_eval_path.c')
-rw-r--r--cpukit/libcsupport/src/sup_fs_eval_path.c333
1 files changed, 333 insertions, 0 deletions
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);
+}