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; }
int IMFS_initialize_support( rtems_filesystem_mount_table_entry_t *mt_entry, const void *data ) { const IMFS_mount_data *mount_data = data; IMFS_fs_info_t *fs_info = mount_data->fs_info; IMFS_jnode_t *root_node; fs_info->mknod_controls = mount_data->mknod_controls; root_node = IMFS_initialize_node( &fs_info->Root_directory.Node, &fs_info->mknod_controls->directory->node_control, "", 0, (S_IFDIR | 0755), NULL ); IMFS_assert( root_node != NULL ); mt_entry->fs_info = fs_info; mt_entry->ops = mount_data->ops; mt_entry->pathconf_limits_and_options = &IMFS_LIMITS_AND_OPTIONS; mt_entry->mt_fs_root->location.node_access = root_node; IMFS_Set_handlers( &mt_entry->mt_fs_root->location ); IMFS_determine_bytes_per_block( &imfs_memfile_bytes_per_block, imfs_rq_memfile_bytes_per_block, IMFS_MEMFILE_DEFAULT_BYTES_PER_BLOCK ); return 0; }
int IMFS_unlink( rtems_filesystem_location_info_t *parentloc, /* IN */ rtems_filesystem_location_info_t *loc /* IN */ ) { IMFS_jnode_t *node; rtems_filesystem_location_info_t the_link; int result = 0; node = loc->node_access; /* * Decrement the link counter of node pointed to and free the * space. */ /* * If this is the last last pointer to the node * free the node. */ if ( node->type == IMFS_HARD_LINK ) { if ( !node->info.hard_link.link_node ) rtems_set_errno_and_return_minus_one( EINVAL ); the_link = *loc; the_link.node_access = node->info.hard_link.link_node; IMFS_Set_handlers( &the_link ); /* * If removing the last hard link to a node, then we need * to remove the node that is a link and the node itself. */ if ( node->info.hard_link.link_node->st_nlink == 1) { result = (*the_link.handlers->rmnod_h)( parentloc, &the_link ); if ( result != 0 ) return -1; } else { node->info.hard_link.link_node->st_nlink --; IMFS_update_ctime( node->info.hard_link.link_node ); } } /* * Now actually free the node we were asked to free. */ result = (*loc->handlers->rmnod_h)( parentloc, loc ); return result; }
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], strlen( &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; }
int IMFS_initialize_support( rtems_filesystem_mount_table_entry_t *mt_entry, const rtems_filesystem_operations_table *op_table, const IMFS_node_control *const node_controls [IMFS_TYPE_COUNT] ) { static int imfs_instance; int rv = 0; IMFS_fs_info_t *fs_info = calloc( 1, sizeof( *fs_info ) ); if ( fs_info != NULL ) { IMFS_jnode_t *root_node; fs_info->instance = imfs_instance++; memcpy( fs_info->node_controls, node_controls, sizeof( fs_info->node_controls ) ); root_node = IMFS_allocate_node( fs_info, fs_info->node_controls [IMFS_DIRECTORY], "", 0, (S_IFDIR | 0755), NULL ); if ( root_node != NULL ) { mt_entry->fs_info = fs_info; mt_entry->ops = op_table; mt_entry->pathconf_limits_and_options = &IMFS_LIMITS_AND_OPTIONS; mt_entry->mt_fs_root->location.node_access = root_node; IMFS_Set_handlers( &mt_entry->mt_fs_root->location ); } else { errno = ENOMEM; rv = -1; } } else { errno = ENOMEM; rv = -1; } if ( rv == 0 ) { IMFS_determine_bytes_per_block( &imfs_memfile_bytes_per_block, imfs_rq_memfile_bytes_per_block, IMFS_MEMFILE_DEFAULT_BYTES_PER_BLOCK ); } return rv; }
static int IMFS_stat_hard_link( const rtems_filesystem_location_info_t *loc, struct stat *buf ) { const IMFS_link_t *hard_link = loc->node_access; rtems_filesystem_location_info_t targetloc = *loc; targetloc.node_access = hard_link->link_node; IMFS_Set_handlers( &targetloc ); return (targetloc.handlers->fstat_h)( &targetloc, buf ); }
void IMFS_fsunmount( rtems_filesystem_mount_table_entry_t *temp_mt_entry ) { IMFS_jnode_t *jnode; IMFS_jnode_t *next; rtems_filesystem_location_info_t loc; int result = 0; /* * Traverse tree that starts at the mt_fs_root and deallocate memory * associated memory space */ loc = temp_mt_entry->mt_fs_root->location; jnode = (IMFS_jnode_t *)loc.node_access; /* * Set this to null to indicate that it is being unmounted. */ temp_mt_entry->mt_fs_root->location.node_access = NULL; do { next = jnode->Parent; loc.node_access = (void *)jnode; IMFS_Set_handlers( &loc ); if ( !IMFS_is_directory( jnode ) || jnode_has_no_children( jnode ) ) { result = IMFS_rmnod( NULL, &loc ); if ( result != 0 ) rtems_fatal_error_occurred( 0xdeadbeef ); IMFS_node_destroy( jnode ); jnode = next; } if ( jnode != NULL ) { if ( IMFS_is_directory( jnode ) ) { if ( jnode_has_children( jnode ) ) jnode = jnode_get_first_child( jnode ); } } } while (jnode != NULL); }
static int IMFS_stat_link( const rtems_filesystem_location_info_t *loc, struct stat *buf ) { const IMFS_jnode_t *node = loc->node_access; if ( IMFS_type( node ) != IMFS_HARD_LINK ) { buf->st_size = strlen( node->info.sym_link.name ); return IMFS_stat( loc, buf ); } else { rtems_filesystem_location_info_t targetloc = *loc; targetloc.node_access = node->info.hard_link.link_node; IMFS_Set_handlers( &targetloc ); return (targetloc.handlers->fstat_h)( &targetloc, buf ); } }
static rtems_filesystem_eval_path_generic_status IMFS_eval_token( rtems_filesystem_eval_path_context_t *ctx, void *arg, const char *token, size_t tokenlen ) { rtems_filesystem_eval_path_generic_status status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_DONE; rtems_filesystem_location_info_t *currentloc = rtems_filesystem_eval_path_get_currentloc( ctx ); IMFS_jnode_t *dir = currentloc->node_access; bool access_ok = rtems_filesystem_eval_path_check_access( ctx, RTEMS_FS_PERMS_EXEC, dir->st_mode, dir->st_uid, dir->st_gid ); if ( access_ok ) { IMFS_jnode_t *entry = IMFS_search_in_directory( dir, token, tokenlen ); if ( entry != NULL ) { bool terminal = !rtems_filesystem_eval_path_has_path( ctx ); int eval_flags = rtems_filesystem_eval_path_get_flags( ctx ); bool follow_hard_link = (eval_flags & RTEMS_FS_FOLLOW_HARD_LINK) != 0; bool follow_sym_link = (eval_flags & RTEMS_FS_FOLLOW_SYM_LINK) != 0; IMFS_jnode_types_t type = IMFS_type( entry ); rtems_filesystem_eval_path_clear_token( ctx ); if ( type == IMFS_HARD_LINK && (follow_hard_link || !terminal)) { entry = entry->info.hard_link.link_node; } if ( type == IMFS_SYM_LINK && (follow_sym_link || !terminal)) { const char *target = entry->info.sym_link.name; rtems_filesystem_eval_path_recursive( ctx, target, strlen( target ) ); } else { rtems_filesystem_global_location_t **fs_root_ptr = IMFS_is_mount_point( entry, type ); if ( fs_root_ptr == NULL ) { --dir->reference_count; ++entry->reference_count; currentloc->node_access = entry; currentloc->node_access_2 = IMFS_generic_get_context_by_node( entry ); IMFS_Set_handlers( currentloc ); if ( !terminal ) { status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_CONTINUE; } } else { access_ok = rtems_filesystem_eval_path_check_access( ctx, RTEMS_FS_PERMS_EXEC, entry->st_mode, entry->st_uid, entry->st_gid ); if ( access_ok ) { rtems_filesystem_eval_path_restart( ctx, fs_root_ptr ); } } } } else { status = RTEMS_FILESYSTEM_EVAL_PATH_GENERIC_NO_ENTRY; } } return status; }
int IMFS_eval_path( const char *pathname, /* IN */ size_t pathnamelen, /* 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 ]; 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], pathnamelen, token, &len ); pathnamelen -= 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 { *pathloc = pathloc->mt_entry->mt_point_node; return (*pathloc->ops->evalpath_h)(&(pathname[i-len]), pathnamelen+len, flags,pathloc); } } else { if ( !node->Parent ) rtems_set_errno_and_return_minus_one( ENOENT ); node = node->Parent; } 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 ); /* * Find the token name in the current node. */ node = IMFS_find_match_in_dir( node, token ); if ( !node ) rtems_set_errno_and_return_minus_one( ENOENT ); /* * If we are at a node that is a mount point so current directory * actually exists on the mounted file system and not in the node that * contains the mount point node. For example a stat of the mount * point should return the details of the root of the mounted file * system not the mount point node of parent file system. * * If the node we have just moved to is a mount point do not loop and * get the token because the token may be suitable for the mounted * file system and not the IMFS. For example the IMFS length is * limited. If the token is a parent directory move back up otherwise * set loc to the new fs root node and let them finish evaluating the * path. */ if (( node->type == IMFS_DIRECTORY ) && ( node->info.directory.mt_fs != NULL )) { IMFS_skip_separator( pathname, &pathnamelen, &i); if ((pathname[i] != '.') || (pathname[i + 1] != '.')) { *pathloc = node->info.directory.mt_fs->mt_fs_root; return (*pathloc->ops->evalpath_h)( &pathname[i], pathnamelen, flags, pathloc ); } i += 2; pathnamelen -= 2; node = node->Parent; } /* * 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 ) { *pathloc = node->info.directory.mt_fs->mt_fs_root; return (*pathloc->ops->evalpath_h)( &pathname[i-len], pathnamelen+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; }
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 ]; IMFS_jnode_t *node; bool done = false; size_t pathlen; int result; /* * This was filled in by the caller and is valid in the * mount table. */ node = pathloc->node_access; /* * Get the path length. */ pathlen = strlen( path ); /* * Evaluate all tokens until we are done or an error occurs. */ while( !done ) { type = IMFS_get_token( &path[i], pathlen, token, &len ); pathlen -= 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 { *pathloc = pathloc->mt_entry->mt_point_node; 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 we are at a link follow it. */ 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 ); /* * 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 { if (( node->type == IMFS_DIRECTORY ) && ( node->info.directory.mt_fs != NULL )) { IMFS_skip_separator( path, &pathlen, &i); if ((path[i] != '.') || (path[i + 1] != '.')) { *pathloc = node->info.directory.mt_fs->mt_fs_root; return (*pathloc->ops->evalformake_h)( &path[i], pathloc, name ); } i += 2; pathlen -= 2; node = node->Parent; } 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; }