summaryrefslogtreecommitdiffstats
path: root/c/src/libfs/src/dosfs/msdos_eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/libfs/src/dosfs/msdos_eval.c')
-rw-r--r--c/src/libfs/src/dosfs/msdos_eval.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/c/src/libfs/src/dosfs/msdos_eval.c b/c/src/libfs/src/dosfs/msdos_eval.c
new file mode 100644
index 0000000000..3eba0e63e8
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_eval.c
@@ -0,0 +1,435 @@
+/*
+ * MSDOS evaluation routines
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_set_handlers --
+ * Set handlers for the node with specified type(i.e. handlers for file
+ * or directory).
+ *
+ * PARAMETERS:
+ * loc - node description
+ *
+ * RETURNS:
+ * None
+ */
+static void
+msdos_set_handlers(rtems_filesystem_location_info_t *loc)
+{
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ loc->handlers = fs_info->directory_handlers;
+ else
+ loc->handlers = fs_info->file_handlers;
+}
+
+/* msdos_eval_path --
+ *
+ * The following routine evaluate path for a node that wishes to be
+ * accessed. Structure 'pathloc' is returned with a pointer to the
+ * node to be accessed.
+ *
+ * PARAMETERS:
+ * pathname - path for evaluation
+ * flags - flags
+ * pathloc - node description (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK and filled pathloc on success, or -1 if error occured
+ * (errno set appropriately)
+ *
+ */
+int
+msdos_eval_path(
+ const char *pathname,
+ int flags,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ int i = 0;
+ int len = 0;
+ msdos_token_types_t type = MSDOS_CURRENT_DIR;
+ char token[MSDOS_NAME_MAX + 1];
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN))
+ {
+ type = msdos_get_token(&pathname[i], token, &len);
+ i += len;
+
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalpath_h)(&(pathname[i-len]),
+ flags, pathloc);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ /*
+ * Always return the root node.
+ *
+ * If we are at a node that is a mount point. Set loc to the
+ * new fs root node and let let the mounted filesystem set the handlers.
+ *
+ * NOTE: The behavior of stat() on a mount point appears to be
+ * questionable.
+ * NOTE: MSDOS filesystem currently doesn't support mount functionality ->
+ * action not implemented
+ */
+ fat_fd = pathloc->node_access;
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_eval4make --
+ * The following routine evaluate path for a new node to be created.
+ * 'pathloc' is returned with a pointer to the parent of the new node.
+ * 'name' is returned with a pointer to the first character in the
+ * new node name. The parent node is verified to be a directory.
+ *
+ * PARAMETERS:
+ * path - path for evaluation
+ * pathloc - IN/OUT (start point for evaluation/parent directory for
+ * creation)
+ * name - new node name
+ *
+ * RETURNS:
+ * RC_OK, filled pathloc for parent directory and name of new node on
+ * success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_eval4make(
+ const char *path,
+ rtems_filesystem_location_info_t *pathloc,
+ const char **name
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ msdos_token_types_t type;
+ int i = 0;
+ int len;
+ char token[ MSDOS_NAME_MAX + 1 ];
+ rtems_boolean done = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while (!done)
+ {
+ type = msdos_get_token(&path[i], token, &len);
+ i += len;
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalformake_h)(&path[i-len],
+ pathloc, name);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc)
+ {
+ if (rc != MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ else
+ done = TRUE;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ errno = EEXIST;
+ rc = -1;
+ goto error;
+ break;
+
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ *name = &path[i - len];
+
+ /*
+ * We have evaluated the path as far as we can.
+ * Verify there is not any invalid stuff at the end of the name.
+ */
+ for( ; path[i] != '\0'; i++)
+ {
+ if (!msdos_is_separator(path[i]))
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ }
+
+ fat_fd = pathloc->node_access;
+
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}