diff options
Diffstat (limited to 'c/src/exec/libfs/src/imfs/imfs_eval.c')
-rw-r--r-- | c/src/exec/libfs/src/imfs/imfs_eval.c | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/c/src/exec/libfs/src/imfs/imfs_eval.c b/c/src/exec/libfs/src/imfs/imfs_eval.c new file mode 100644 index 0000000000..eb770a58ce --- /dev/null +++ b/c/src/exec/libfs/src/imfs/imfs_eval.c @@ -0,0 +1,638 @@ +/* + * Evaluation IMFS Node Support Routines + * + * COPYRIGHT (c) 1989-1998. + * On-Line Applications Research Corporation (OAR). + * Copyright assigned to U.S. Government, 1994. + * + * 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$ + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <assert.h> + +#include "imfs.h" +#include "libio_.h" + +#define RTEMS_LIBIO_PERMS_RX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_READ) +#define RTEMS_LIBIO_PERMS_WX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_WRITE) + +#define MAXSYMLINK 5 + +int IMFS_Set_handlers( + rtems_filesystem_location_info_t *loc +) +{ + IMFS_jnode_t *node = loc->node_access; + + switch( node->type ) { + case IMFS_DIRECTORY: + loc->handlers = &dir_handlers; + break; + case IMFS_DEVICE: + loc->handlers = &device_handlers; + break; + case IMFS_SYM_LINK: + case IMFS_HARD_LINK: + loc->handlers = &null_handlers; + break; + case IMFS_MEMORY_FILE: + loc->handlers = &memfile_handlers; + break; + } + + return 0; +} + +/* + * IMFS_evaluate_permission + * + * The following routine evaluates that we have permission + * to do flags on the node. + */ + +int IMFS_evaluate_permission( + rtems_filesystem_location_info_t *node, + int flags +) +{ + uid_t st_uid; + gid_t st_gid; + IMFS_jnode_t *jnode; + int flags_to_test; + + if (! rtems_libio_is_valid_perms( flags ) ) { + assert( 0 ); + set_errno_and_return_minus_one( EIO ); + } + + jnode = node->node_access; + +#if defined(RTEMS_POSIX_API) + st_uid = geteuid(); + st_gid = getegid(); +#else + st_uid = jnode->st_uid; + st_gid = jnode->st_gid; +#endif + + /* + * Check if I am owner or a group member or someone else. + */ + + flags_to_test = flags; + + if ( st_uid == jnode->st_uid ) + flags_to_test <<= 6; + else if ( st_gid == jnode->st_gid ) + flags_to_test <<= 3; + else + /* must be other - do nothing */; + + /* + * If all of the flags are set we have permission + * to do this. + */ + if ( ( flags_to_test & jnode->st_mode) == flags_to_test ) + return 1; + + return 0; +} + +/* + * IMFS_evaluate_hard_link + * + * The following routine evaluates a hardlink to the actual node. + */ + +int IMFS_evaluate_hard_link( + rtems_filesystem_location_info_t *node, /* IN/OUT */ + int flags /* IN */ +) +{ + IMFS_jnode_t *jnode = node->node_access; + int result = 0; + + /* + * Check for things that should never happen. + */ + + if ( jnode->type != IMFS_HARD_LINK ) + rtems_fatal_error_occurred (0xABCD0000); + + /* + * Set the hard link value and the handlers. + */ + + node->node_access = jnode->info.hard_link.link_node; + + IMFS_Set_handlers( node ); + + /* + * Verify we have the correct permissions for this node. + */ + + if (! IMFS_evaluate_permission( node, flags ) ) + set_errno_and_return_minus_one( EACCES ); + + return result; +} + + +/* + * IMFS_evaluate_sym_link + * + * The following routine evaluates a symbolic link to the actual node. + */ + +int IMFS_evaluate_sym_link( + rtems_filesystem_location_info_t *node, /* IN/OUT */ + int flags /* IN */ +) +{ + IMFS_jnode_t *jnode = node->node_access; + int result = 0; + int i; + + /* + * Check for things that should never happen. + */ + + if ( jnode->type != IMFS_SYM_LINK ) + rtems_fatal_error_occurred (0xABCD0000); + + if ( !jnode->Parent ) + rtems_fatal_error_occurred( 0xBAD00000 ); + + + /* + * Move the node_access to either the symbolic links parent or + * root depending on the symbolic links path. + */ + + node->node_access = jnode->Parent; + + rtems_filesystem_get_sym_start_loc( + jnode->info.sym_link.name, + &i, + node + ); + + /* + * Use eval path to evaluate the path of the symbolic link. + */ + + result = IMFS_eval_path( + &jnode->info.sym_link.name[i], + flags, + node + ); + + IMFS_Set_handlers( node ); + + /* + * Verify we have the correct permissions for this node. + */ + + if (! IMFS_evaluate_permission( node, flags ) ) + set_errno_and_return_minus_one( EACCES ); + + return result; +} + +/* + * IMFS_evaluate_link + * + * The following routine returns the real node pointed to by a link. + */ + +int IMFS_evaluate_link( + rtems_filesystem_location_info_t *node, /* IN/OUT */ + int flags /* IN */ +) +{ + IMFS_jnode_t *jnode; + int result = 0; + + do { + jnode = node->node_access; + + /* + * Increment and check the link counter. + */ + + rtems_filesystem_link_counts ++; + if ( rtems_filesystem_link_counts > MAXSYMLINK ) { + rtems_filesystem_link_counts = 0; + set_errno_and_return_minus_one( ELOOP ); + } + + /* + * Follow the Link node. + */ + + if ( jnode->type == IMFS_HARD_LINK ) + result = IMFS_evaluate_hard_link( node, flags ); + + else if (jnode->type == IMFS_SYM_LINK ) + result = IMFS_evaluate_sym_link( node, flags ); + + } while ( ( result == 0 ) && ( ( jnode->type == IMFS_SYM_LINK ) || + ( jnode->type == IMFS_HARD_LINK ) ) ); + + /* + * Clear link counter. + */ + + rtems_filesystem_link_counts = 0; + + return result; +} + + +/* + * IMFS_evaluate_for_make + * + * 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. + */ + +int IMFS_evaluate_for_make( + const char *path, /* IN */ + rtems_filesystem_location_info_t *pathloc, /* IN/OUT */ + const char **name /* OUT */ +) +{ + int i = 0; + int len; + IMFS_token_types type; + char token[ NAME_MAX + 1 ]; + rtems_filesystem_location_info_t newloc; + IMFS_jnode_t *node; + int done = 0; + int result; + + /* + * This was filled in by the caller and is valid in the + * mount table. + */ + node = pathloc->node_access; + + /* + * Evaluate all tokens until we are done or an error occurs. + */ + + while( !done ) { + + type = IMFS_get_token( &path[i], token, &len ); + i += len; + + if ( !pathloc->node_access ) + set_errno_and_return_minus_one( ENOENT ); + + /* + * I cannot move out of this directory without execute permission. + */ + + if ( type != IMFS_NO_MORE_PATH ) + if ( node->type == IMFS_DIRECTORY ) + if (! IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) ) + set_errno_and_return_minus_one( EACCES ); + + node = pathloc->node_access; + + switch( type ) { + + case IMFS_UP_DIR: + + /* + * 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? + */ + + if ( pathloc->node_access == rtems_filesystem_root.node_access ) { + break; + + } else { + newloc = pathloc->mt_entry->mt_point_node; + *pathloc = newloc; + return (*pathloc->ops->evalformake)( &path[i-len], pathloc, name ); + } + } else { + + if ( !node->Parent ) + set_errno_and_return_minus_one( ENOENT ); + + node = node->Parent; + } + + pathloc->node_access = node; + break; + + case IMFS_NAME: + + if ( node->type == IMFS_HARD_LINK ) { + + result = IMFS_evaluate_link( pathloc, 0 ); + if ( result == -1 ) + return -1; + + } else if ( node->type == IMFS_SYM_LINK ) { + + result = IMFS_evaluate_link( pathloc, 0 ); + + if ( result == -1 ) + return -1; + } + + node = pathloc->node_access; + if ( !node ) + set_errno_and_return_minus_one( ENOTDIR ); + + /* + * Only a directory can be decended into. + */ + + if ( node->type != IMFS_DIRECTORY ) + set_errno_and_return_minus_one( ENOTDIR ); + + /* + * If we are at a node that is a mount point. Set loc to the + * new fs root node and let them finish evaluating the path. + */ + + if ( node->info.directory.mt_fs != NULL ) { + newloc = node->info.directory.mt_fs->mt_fs_root; + *pathloc = newloc; + return (*pathloc->ops->evalformake)( &path[i-len], pathloc, name ); + } + + /* + * Otherwise find the token name in the present location. + */ + + node = IMFS_find_match_in_dir( node, token ); + + /* + * If there is no node we have found the name of the node we + * wish to create. + */ + + if ( ! node ) + done = TRUE; + else + pathloc->node_access = node; + + break; + + case IMFS_NO_MORE_PATH: + set_errno_and_return_minus_one( EEXIST ); + break; + + case IMFS_INVALID_TOKEN: + set_errno_and_return_minus_one( ENAMETOOLONG ); + break; + + case IMFS_CURRENT_DIR: + 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 (! IMFS_is_separator( path[ i ] ) ) + set_errno_and_return_minus_one( ENOENT ); + } + + /* + * Verify we can execute and write to this directory. + */ + + result = IMFS_Set_handlers( pathloc ); + + /* + * The returned node must be a directory + */ + node = pathloc->node_access; + if ( node->type != IMFS_DIRECTORY ) + set_errno_and_return_minus_one( ENOTDIR ); + + /* + * We must have Write and execute permission on the returned node. + */ + + if (! IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_WX ) ) + set_errno_and_return_minus_one( EACCES ); + + return result; +} + + +/* + * IMFS_eval_path + * + * The following routine evaluate path for a node that wishes to be + * accessed with mode. pathloc is returned with a pointer to the + * node to be accessed. + */ + +int IMFS_eval_path( + const char *pathname, /* IN */ + int flags, /* IN */ + rtems_filesystem_location_info_t *pathloc /* IN/OUT */ +) +{ + int i = 0; + int len; + IMFS_token_types type = IMFS_CURRENT_DIR; + char token[ NAME_MAX + 1 ]; + rtems_filesystem_location_info_t newloc; + IMFS_jnode_t *node; + int result; + + if (! rtems_libio_is_valid_perms( flags ) ) { + assert( 0 ); + set_errno_and_return_minus_one( EIO ); + } + + /* + * This was filled in by the caller and is valid in the + * mount table. + */ + + node = pathloc->node_access; + + /* + * Evaluate all tokens until we are done or an error occurs. + */ + + while( (type != IMFS_NO_MORE_PATH) && (type != IMFS_INVALID_TOKEN) ) { + + type = IMFS_get_token( &pathname[i], token, &len ); + i += len; + + if ( !pathloc->node_access ) + set_errno_and_return_minus_one( ENOENT ); + + /* + * I cannot move out of this directory without execute permission. + */ + if ( type != IMFS_NO_MORE_PATH ) + if ( node->type == IMFS_DIRECTORY ) + if (! IMFS_evaluate_permission( pathloc, RTEMS_LIBIO_PERMS_SEARCH ) ) + set_errno_and_return_minus_one( EACCES ); + + node = pathloc->node_access; + + switch( type ) { + case IMFS_UP_DIR: + + /* + * 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? + */ + + 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; + return (*pathloc->ops->evalpath)(&(pathname[i-len]),flags,pathloc); + } + } else { + + if ( !node->Parent ) + set_errno_and_return_minus_one( ENOENT ); + + node = node->Parent; + pathloc->node_access = node; + + } + + pathloc->node_access = node; + break; + + case IMFS_NAME: + /* + * If we are at a link follow it. + */ + + if ( node->type == IMFS_HARD_LINK ) { + + IMFS_evaluate_hard_link( pathloc, 0 ); + + node = pathloc->node_access; + if ( !node ) + set_errno_and_return_minus_one( ENOTDIR ); + + } else if ( node->type == IMFS_SYM_LINK ) { + + result = IMFS_evaluate_sym_link( pathloc, 0 ); + + node = pathloc->node_access; + if ( result == -1 ) + return -1; + } + + /* + * Only a directory can be decended into. + */ + + if ( node->type != IMFS_DIRECTORY ) + set_errno_and_return_minus_one( ENOTDIR ); + + /* + * If we are at a node that is a mount point. Set loc to the + * new fs root node and let them finish evaluating the path. + */ + + if ( node->info.directory.mt_fs != NULL ) { + newloc = node->info.directory.mt_fs->mt_fs_root; + *pathloc = newloc; + return (*pathloc->ops->evalpath)( &pathname[i-len], flags, pathloc ); + } + + /* + * Otherwise find the token name in the present location. + */ + + node = IMFS_find_match_in_dir( node, token ); + if ( !node ) + set_errno_and_return_minus_one( ENOENT ); + + /* + * Set the node access to the point we have found. + */ + + pathloc->node_access = node; + break; + + case IMFS_NO_MORE_PATH: + case IMFS_CURRENT_DIR: + break; + + case IMFS_INVALID_TOKEN: + set_errno_and_return_minus_one( ENAMETOOLONG ); + break; + + } + } + + /* + * Only return root node if this is the base file system. + */ + + if ((pathloc->node_access == pathloc->mt_entry->mt_fs_root.node_access) && + (pathloc->node_access != rtems_filesystem_root.node_access) ) { + newloc = pathloc->mt_entry->mt_point_node; + *pathloc = newloc; + } + + result = IMFS_Set_handlers( pathloc ); + + /* + * Verify we have the correct permissions for this node. + */ + + if (! IMFS_evaluate_permission( pathloc, flags ) ) + set_errno_and_return_minus_one( EACCES ); + + return result; +} + + + + + + + + + |