OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libfs/] [src/] [imfs/] [imfs_eval.c] - Rev 1765

Compare with Previous | Blame | View Log

/*
 *  Evaluation IMFS Node Support Routines
 *
 *  COPYRIGHT (c) 1989-1999.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  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.
 *
 *  imfs_eval.c,v 1.16 2002/01/04 18:30:58 joel Exp
 */
 
#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 "imfs.h"
#include <rtems/libio_.h>
#include <rtems/seterr.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;
  IMFS_fs_info_t  *fs_info;
 
  fs_info = loc->mt_entry->fs_info;
  switch( node->type ) {
    case IMFS_DIRECTORY:
      loc->handlers = fs_info->directory_handlers;
      break;
    case IMFS_DEVICE:
      loc->handlers = &IMFS_device_handlers;
      break;
    case IMFS_SYM_LINK:
    case IMFS_HARD_LINK:
      loc->handlers = &IMFS_link_handlers;
      break;
    case IMFS_LINEAR_FILE:
      loc->handlers = fs_info->linearfile_handlers;
      break;
    case IMFS_MEMORY_FILE:
      loc->handlers = fs_info->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 );
    rtems_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 ) )
    rtems_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 ) )
    rtems_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;
      rtems_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[ IMFS_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 )
      rtems_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 ) )
           rtems_set_errno_and_return_minus_one( EACCES );
 
    node = pathloc->node_access;
 
    switch( type ) {
 
      case IMFS_UP_DIR:
       /*
        *  Am I at the root of all filesystems? (chroot'ed?)
	*/
 
       if ( pathloc->node_access == rtems_filesystem_root.node_access )
         break;       /* Throw out the .. in this case */
 
 
	/*
	 * 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_h)( &path[i-len], pathloc, name );
	  }
	} else {
 
          if ( !node->Parent )
            rtems_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 )
          rtems_set_errno_and_return_minus_one( ENOTDIR ); 
 
        /*
         * Only a directory can be decended into.
	 */
 
        if ( node->type != IMFS_DIRECTORY )
          rtems_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_h)( &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:
        rtems_set_errno_and_return_minus_one( EEXIST );
        break;
 
      case IMFS_INVALID_TOKEN:
        rtems_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 ] ) ) 
      rtems_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 )
    rtems_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 ) )
    rtems_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[ IMFS_NAME_MAX + 1 ];
  rtems_filesystem_location_info_t    newloc;
  IMFS_jnode_t                       *node;
  int                                 result; 
 
  if ( !rtems_libio_is_valid_perms( flags ) ) {
    assert( 0 );
    rtems_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 )
      rtems_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 ) )
           rtems_set_errno_and_return_minus_one( EACCES );
 
    node = pathloc->node_access;
 
    switch( type ) {
      case IMFS_UP_DIR:
       /*
        *  Am I at the root of all filesystems? (chroot'ed?)
	*/
 
       if ( pathloc->node_access == rtems_filesystem_root.node_access )
         break;       /* Throw out the .. in this case */
 
	/*
	 *  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_h)(&(pathname[i-len]),flags,pathloc);
	  }
	} else {
 
          if ( !node->Parent )
            rtems_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 )
            rtems_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 )
          rtems_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_h)( &pathname[i-len], flags, pathloc );
	}
 
	/*
	 *  Otherwise find the token name in the present location.
	 */
 
        node = IMFS_find_match_in_dir( node, token );
        if ( !node )
          rtems_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:
        rtems_set_errno_and_return_minus_one( ENAMETOOLONG );
        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.
   */
 
  if ( node->type == IMFS_DIRECTORY ) {
    if ( node->info.directory.mt_fs != NULL ) {
      newloc   = node->info.directory.mt_fs->mt_fs_root;
      *pathloc = newloc;
      return (*pathloc->ops->evalpath_h)( &pathname[i-len], flags, pathloc );
    } else {
      result = IMFS_Set_handlers( pathloc );
    }
  } else {
    result = IMFS_Set_handlers( pathloc );
  }
 
  /*
   * Verify we have the correct permissions for this node.
   */
 
  if ( !IMFS_evaluate_permission( pathloc, flags ) )
    rtems_set_errno_and_return_minus_one( EACCES );
 
  return result;
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.