Пример #1
0
int chroot(
  const char *pathname
)
{
  int                               result;
  rtems_filesystem_location_info_t  loc;

  /* an automatic call to new private env the first time */
  if (rtems_current_user_env == &rtems_global_user_env) {
   rtems_libio_set_private_env(); /* try to set a new private env*/
   if (rtems_current_user_env == &rtems_global_user_env) /* not ok */
    rtems_set_errno_and_return_minus_one( ENOTSUP );
  };

  result = chdir(pathname);
  if (result) {
    rtems_set_errno_and_return_minus_one( errno );
  };
  /* clone the new root location */
  if (rtems_filesystem_evaluate_path(".", 0, &loc, 0)) {
	/* our cwd has changed, though - but there is no easy way of return :-( */
    rtems_set_errno_and_return_minus_one( errno );
  }
  rtems_filesystem_freenode(&rtems_filesystem_root);
  rtems_filesystem_root = loc;

  return 0;
}
Пример #2
0
/**
 * Get the file system data from the specific path. Checks to make sure the path is
 * pointing to a valid RFS file system.
 */
static int
rtems_rfs_get_fs (const char* path, rtems_rfs_file_system** fs)
{
  struct statvfs sb;
  int            rc;

  rc = statvfs (path, &sb);
  if (rc < 0)
  {
    printf ("error: cannot statvfs path: %s: (%d) %s\n",
            path, errno, strerror (errno));
    return -1;
  }

  if (sb.f_fsid != RTEMS_RFS_SB_MAGIC)
  {
    printf ("error: path '%s' is not on an RFS file system\n", path);
    return -1;
  }

#if __rtems__
  /*
   * Now find the path location on the file system. This will give the file
   * system data.
   */
  {
    rtems_filesystem_location_info_t pathloc;
    rc = rtems_filesystem_evaluate_path (path, strlen (path), 0, &pathloc, true);
    *fs = rtems_rfs_rtems_pathloc_dev (&pathloc);
    rtems_filesystem_freenode (&pathloc);
  }
#endif
  
  return rc;
}
Пример #3
0
int chmod(
  const char *path,
  mode_t      mode
)
{
  int                              status;
  rtems_filesystem_location_info_t loc;
  int                              result;

  status = rtems_filesystem_evaluate_path( path, strlen( path ), 0, &loc, true );
  if ( status != 0 )
    return -1;

  if ( !loc.handlers ){
    rtems_filesystem_freenode( &loc );
    rtems_set_errno_and_return_minus_one( EBADF );
  }

  if ( !loc.handlers->fchmod_h ){
    rtems_filesystem_freenode( &loc );
    rtems_set_errno_and_return_minus_one( ENOTSUP );
  }

  result = (*loc.handlers->fchmod_h)( &loc, mode );

  rtems_filesystem_freenode( &loc );

  return result;
}
rtems_status_code rtems_libio_set_private_env(void) {
  rtems_status_code 					sc;
  rtems_id          					task_id;
  rtems_filesystem_location_info_t		loc;

  sc=rtems_task_ident(RTEMS_SELF,0,&task_id);
  if (sc != RTEMS_SUCCESSFUL) return sc;

  /* Only for the first time a malloc is necesary */
  if (rtems_current_user_env==&rtems_global_user_env) {
   rtems_user_env_t	*tmp = malloc(sizeof(rtems_user_env_t));
   if (!tmp)
     return RTEMS_NO_MEMORY;

#ifdef HAVE_USERENV_REFCNT
   tmp->refcnt = 1;
#endif

   sc = rtems_task_variable_add(RTEMS_SELF,(void*)&rtems_current_user_env,(void(*)(void *))free_user_env);
   if (sc != RTEMS_SUCCESSFUL) {
	 /* don't use free_user_env because the pathlocs are
	  * not initialized yet
	  */
     free(tmp);
     return sc;
   }
   rtems_current_user_env = tmp;
  };

  *rtems_current_user_env = rtems_global_user_env; /* get the global values*/
  rtems_current_user_env->task_id=task_id;         /* mark the local values*/

  /* Clone the pathlocs. In contrast to most other
   * code we must _not_ free the original locs because
   * what we are trying to do here is forking off
   * clones. The reason is a pathloc can be allocated by the
   * file system and needs to be freed when deleting the environment.
   */

  rtems_filesystem_evaluate_path("/", 1, 0, &loc, 0);
  rtems_filesystem_root    = loc;
  rtems_filesystem_evaluate_path("/", 1, 0, &loc, 0);
  rtems_filesystem_current = loc;

  return RTEMS_SUCCESSFUL;
}
Пример #5
0
int fchdir(
    int       fd
)
{
    rtems_libio_t *iop;
    rtems_filesystem_location_info_t loc, saved;

    rtems_libio_check_fd( fd );
    iop = rtems_libio_iop( fd );
    rtems_libio_check_is_open(iop);

    /*
     * Verify you can change directory into this node.
     */

    if ( !iop->pathinfo.ops ) {
        rtems_set_errno_and_return_minus_one( ENOTSUP );
    }

    if ( !iop->pathinfo.ops->node_type_h ) {
        rtems_set_errno_and_return_minus_one( ENOTSUP );
    }

    if (  (*iop->pathinfo.ops->node_type_h)( &iop->pathinfo ) !=
            RTEMS_FILESYSTEM_DIRECTORY ) {
        rtems_set_errno_and_return_minus_one( ENOTDIR );
    }


    /*
     * FIXME : I feel there should be another call to
     *         actually take into account the extra reference to
     *         this node which we are making here. I can
     *         see the freenode interface but do not see
     *         allocnode node interface. It maybe node_type.
     *
     * FIXED:  T.Straumann: it is evaluate_path()
     *         but note the race condition. Threads who
     *         share their rtems_filesystem_current better
     *         be synchronized!
     */

    saved                    = rtems_filesystem_current;
    rtems_filesystem_current = iop->pathinfo;

    /* clone the current node */
    if (rtems_filesystem_evaluate_path(".", 1, 0, &loc, 0)) {
        /* cloning failed; restore original and bail out */
        rtems_filesystem_current = saved;
        return -1;
    }
    /* release the old one */
    rtems_filesystem_freenode( &saved );

    rtems_filesystem_current = loc;

    return 0;
}
Пример #6
0
int utime(
  const char           *path,
  const struct utimbuf *times
)
{
  rtems_filesystem_location_info_t   temp_loc;
  int                                result;

  if ( rtems_filesystem_evaluate_path( path, 0x00, &temp_loc, TRUE ) )
    return -1;

  if ( !temp_loc.ops->utime_h ){
    rtems_filesystem_freenode( &temp_loc );
    rtems_set_errno_and_return_minus_one( ENOTSUP );
  }

  result = (*temp_loc.ops->utime_h)( &temp_loc, times->actime, times->modtime );

  rtems_filesystem_freenode( &temp_loc );

  return result;
}
Пример #7
0
int open(
  const char   *pathname,
  int           flags,
  ...
)
{
  va_list                             ap;
  int                                 mode;
  int                                 rc;
  rtems_libio_t                      *iop = 0;
  int                                 status;
  rtems_filesystem_location_info_t    loc;
  rtems_filesystem_location_info_t   *loc_to_free = NULL;
  int                                 eval_flags;


  /*
   * Set the Evaluation flags
   */

  eval_flags = 0;
  status = flags + 1;
  if ( ( status & _FREAD ) == _FREAD )
    eval_flags |= RTEMS_LIBIO_PERMS_READ;
  if ( ( status & _FWRITE ) == _FWRITE )
    eval_flags |= RTEMS_LIBIO_PERMS_WRITE;


  va_start(ap, flags);

  mode = va_arg( ap, int );

  /*
   * NOTE: This comment is OBSOLETE.  The proper way to do this now
   *       would be to support a magic mounted file system.
   *
   *             Additional external I/O handlers would be supported by adding
   *             code to pick apart the pathname appropriately. The networking
   *             code does not require changes here since network file
   *             descriptors are obtained using socket(), not open().
   */

  /* allocate a file control block */
  iop = rtems_libio_allocate();
  if ( iop == 0 ) {
    rc = ENFILE;
    goto done;
  }

  /*
   *  See if the file exists.
   */

  status = rtems_filesystem_evaluate_path(
     pathname, eval_flags, &loc, TRUE );

  if ( status == -1 ) {
    if ( errno != ENOENT ) {
      rc = errno;
      goto done;
    }

    /* If the file does not exist and we are not trying to create it--> error */
    if ( !(flags & O_CREAT) ) {
      rc = ENOENT;
      goto done;
    }

    /* Create the node for the new regular file */
    rc = mknod( pathname, S_IFREG | mode, 0LL );
    if ( rc ) {
      rc = errno;
      goto done;
    }

    /* Sanity check to see if the file name exists after the mknod() */
    status = rtems_filesystem_evaluate_path( pathname, 0x0, &loc, TRUE );
    if ( status != 0 ) {   /* The file did not exist */
      rc = EACCES;
      goto done;
    }

  } else if ((flags & (O_EXCL|O_CREAT)) == (O_EXCL|O_CREAT)) {
    /* We were trying to create a file that already exists */
    rc = EEXIST;
    loc_to_free = &loc;
    goto done;
  }

  loc_to_free = &loc;

  /*
   *  Fill in the file control block based on the loc structure
   *  returned by successful path evaluation.
   */

  iop->handlers   = loc.handlers;
  iop->file_info  = loc.node_access;
  iop->flags     |= rtems_libio_fcntl_flags( flags );
  iop->pathinfo   = loc;

  if ( !iop->handlers->open_h ) {
    rc = ENOTSUP;
    goto done;
  }

  rc = (*iop->handlers->open_h)( iop, pathname, flags, mode );
  if ( rc )
    goto done;

  /*
   *  Optionally truncate the file.
   */

  if ( (flags & O_TRUNC) == O_TRUNC ) {
    rc = ftruncate( iop - rtems_libio_iops, 0 );
    if ( rc ) {
      if(errno) rc = errno;
      close( iop - rtems_libio_iops );
      /* those are released by close(): */
      iop = 0;
      loc_to_free = NULL;
    }
  }

  /*
   *  Single exit and clean up path.
   */

done:
  va_end(ap);

  if ( rc ) {
    if ( iop )
      rtems_libio_free( iop );
    if ( loc_to_free )
      rtems_filesystem_freenode( loc_to_free );
    rtems_set_errno_and_return_minus_one( rc );
  }

  return iop - rtems_libio_iops;
}
Пример #8
0
int rmdir(
  const char *pathname
)
{
  int                               parentpathlen;
  const char                       *name;
  rtems_filesystem_location_info_t  parentloc;
  rtems_filesystem_location_info_t  loc;
  int                               i;
  int                               result;
  bool                              free_parentloc = false;

  /*
   *  Get the parent node of the node we wish to remove. Find the parent path.
   */

  parentpathlen = rtems_filesystem_dirname ( pathname );

  if ( parentpathlen == 0 )
    rtems_filesystem_get_start_loc( pathname, &i, &parentloc );
  else {
    result = rtems_filesystem_evaluate_path(pathname, parentpathlen,
                                            RTEMS_LIBIO_PERMS_WRITE,
                                            &parentloc,
                                            false );
    if ( result != 0 )
      return -1;

    free_parentloc = true;
  }

  /*
   * Start from the parent to find the node that should be under it.
   */

  loc = parentloc;
  name = pathname + parentpathlen;
  name += rtems_filesystem_prefix_separators( name, strlen( name ) );

  result = rtems_filesystem_evaluate_relative_path( name , strlen( name ),
                                                    0, &loc, false );
  if ( result != 0 ) {
    if ( free_parentloc )
      rtems_filesystem_freenode( &parentloc );
    return -1;
  }

  /*
   * Verify you can remove this node as a directory.
   */
  if ( (*loc.ops->node_type_h)( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) {
    rtems_filesystem_freenode( &loc );
    if ( free_parentloc )
      rtems_filesystem_freenode( &parentloc );
    rtems_set_errno_and_return_minus_one( ENOTDIR );
  }

  /*
   * Use the filesystems rmnod to remove the node.
   */

  result =  (*loc.handlers->rmnod_h)( &parentloc, &loc );

  rtems_filesystem_freenode( &loc );
  if ( free_parentloc )
    rtems_filesystem_freenode( &parentloc );

  return result;
}
Пример #9
0
rtems_status_code rtems_libio_set_private_env(void)
{
  rtems_status_code sc = RTEMS_SUCCESSFUL;
  rtems_id task_id = rtems_task_self();
  rtems_filesystem_location_info_t root_loc;
  rtems_filesystem_location_info_t current_loc;
  rtems_user_env_t *new_env = NULL;
  int rv = 0;

  rv = rtems_filesystem_evaluate_path("/", 1, 0, &root_loc, 0);
  if (rv != 0)
    goto error_0;

  rv = rtems_filesystem_evaluate_path("/", 1, 0, &current_loc, 0);
  if (rv != 0)
    goto error_1;

  /* 
   * Malloc is necessary whenever the current task does not
   * have its own environment in place. This could be:
   * a) it never had one
   * OR
   * b) it shared another task's environment
   */

  /* 
   * Bharath: I'm not sure if the check can be reduced to
   * if( rtems_current_user_env->task_id != task_id ) {
   */

  if (
    rtems_current_user_env == &rtems_global_user_env
      || rtems_current_user_env->task_id != task_id
  ) {
    new_env = malloc(sizeof(rtems_user_env_t));
    if (new_env == NULL)
      goto error_2;

    #ifdef HAVE_USERENV_REFCNT
      new_env->refcnt = 1;
    #endif

    sc = rtems_task_variable_add(
      RTEMS_SELF,
      (void*)&rtems_current_user_env,
      (void(*)(void *))free_user_env
    );
    if (sc != RTEMS_SUCCESSFUL)
      goto error_3;

    rtems_current_user_env = new_env;
  }

  /* Inherit the global values */
  *rtems_current_user_env = rtems_global_user_env;

  rtems_current_user_env->task_id = task_id;

  /*
   * Clone the pathlocs. In contrast to most other code we must _not_ free the
   * original locs because what we are trying to do here is forking off clones.
   * The reason is a pathloc can be allocated by the file system and needs to
   * be freed when deleting the environment.
   */
  rtems_filesystem_root = root_loc;
  rtems_filesystem_current = current_loc;

  return RTEMS_SUCCESSFUL;

error_3:
  free(new_env);

error_2:
  rtems_filesystem_freenode(&current_loc);

error_1:
  rtems_filesystem_freenode(&root_loc);

error_0:
  return RTEMS_NO_MEMORY;
}
Пример #10
0
int unlink(
  const char *path
)
{
  int                               parentpathlen;
  const char                       *name;
  rtems_filesystem_location_info_t  parentloc;
  rtems_filesystem_location_info_t  loc;
  int                               i;
  int                               result;
  bool                              free_parentloc = false;

  /*
   * Get the node to be unlinked. Find the parent path first.
   */

  parentpathlen = rtems_filesystem_dirname ( path );

  if ( parentpathlen == 0 )
    rtems_filesystem_get_start_loc( path, &i, &parentloc );
  else {
    result = rtems_filesystem_evaluate_path( path, parentpathlen,
                                             RTEMS_LIBIO_PERMS_WRITE,
                                             &parentloc,
                                             false );
    if ( result != 0 )
      return -1;

    free_parentloc = true;
  }

  /*
   * Start from the parent to find the node that should be under it.
   */

  loc = parentloc;
  name = path + parentpathlen;
  name += rtems_filesystem_prefix_separators( name, strlen( name ) );

  result = rtems_filesystem_evaluate_relative_path( name , strlen( name ),
                                                    0, &loc, false );
  if ( result != 0 ) {
    if ( free_parentloc )
      rtems_filesystem_freenode( &parentloc );
    return -1;
  }

  if ( !loc.ops->node_type_h ) {
    rtems_filesystem_freenode( &loc );
    if ( free_parentloc )
      rtems_filesystem_freenode( &parentloc );
    rtems_set_errno_and_return_minus_one( ENOTSUP );
  }

  if (  (*loc.ops->node_type_h)( &loc ) == RTEMS_FILESYSTEM_DIRECTORY ) {
    rtems_filesystem_freenode( &loc );
    if ( free_parentloc )
      rtems_filesystem_freenode( &parentloc );
    rtems_set_errno_and_return_minus_one( EISDIR );
  }

  if ( !loc.ops->unlink_h ) {
    rtems_filesystem_freenode( &loc );
    if ( free_parentloc )
      rtems_filesystem_freenode( &parentloc );
    rtems_set_errno_and_return_minus_one( ENOTSUP );
  }

  result = (*loc.ops->unlink_h)( &parentloc, &loc );

  rtems_filesystem_freenode( &loc );
  if ( free_parentloc )
    rtems_filesystem_freenode( &parentloc );

  return result;
}
Пример #11
0
int mount(
  const char                 *source,
  const char                 *target,
  const char                 *filesystemtype,
  rtems_filesystem_options_t options,
  const void                 *data
)
{
  rtems_filesystem_fsmount_me_t mount_h = NULL;
  rtems_filesystem_location_info_t      loc;
  rtems_filesystem_mount_table_entry_t *mt_entry = NULL;
  rtems_filesystem_location_info_t     *loc_to_free = NULL;
  bool has_target = target != NULL;
  size_t target_length = 0;

  /*
   *  Are the file system options valid?
   */

  if ( options != RTEMS_FILESYSTEM_READ_ONLY &&
       options != RTEMS_FILESYSTEM_READ_WRITE )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*
   *  Get mount handler
   */
  mount_h = rtems_filesystem_get_mount_handler( filesystemtype );
  if ( !mount_h )
    rtems_set_errno_and_return_minus_one( EINVAL );

  /*
   * Allocate a mount table entry
   */
  mt_entry = alloc_mount_table_entry(
    source,
    target,
    filesystemtype,
    &target_length
  );
  if ( !mt_entry )
    rtems_set_errno_and_return_minus_one( ENOMEM );

  mt_entry->mt_fs_root.mt_entry = mt_entry;
  mt_entry->options = options;
  mt_entry->pathconf_limits_and_options = rtems_filesystem_default_pathconf;

  /*
   *  The mount_point should be a directory with read/write/execute
   *  permissions in the existing tree.
   */

  if ( has_target ) {
    if ( rtems_filesystem_evaluate_path(
           target, target_length, RTEMS_LIBIO_PERMS_RWX, &loc, true ) == -1 )
      goto cleanup_and_bail;

    loc_to_free = &loc;

    /*
     * Test for node_type_h
     */

    if (!loc.ops->node_type_h) {
      errno =  ENOTSUP;
      goto cleanup_and_bail;
    }

    /*
     *  Test to see if it is a directory
     */

    if ( loc.ops->node_type_h( &loc ) != RTEMS_FILESYSTEM_DIRECTORY ) {
      errno = ENOTDIR;
      goto cleanup_and_bail;
    }

    /*
     *  You can only mount one file system onto a single mount point.
     */

    if ( rtems_filesystem_mount_iterate( is_node_fs_root, loc.node_access ) ) {
      errno = EBUSY;
      goto cleanup_and_bail;
    }

    /*
     *  This must be a good mount point, so move the location information
     *  into the allocated mount entry.  Note:  the information that
     *  may have been allocated in loc should not be sent to freenode
     *  until the system is unmounted.  It may be needed to correctly
     *  traverse the tree.
     */

    mt_entry->mt_point_node.node_access = loc.node_access;
    mt_entry->mt_point_node.handlers = loc.handlers;
    mt_entry->mt_point_node.ops = loc.ops;
    mt_entry->mt_point_node.mt_entry = loc.mt_entry;

    /*
     *  This link to the parent is only done when we are dealing with system
     *  below the base file system
     */

    if ( !loc.ops->mount_h ){
      errno = ENOTSUP;
      goto cleanup_and_bail;
    }

    if ( loc.ops->mount_h( mt_entry ) ) {
      goto cleanup_and_bail;
    }
  } else {
    /*
     * Do we already have a base file system ?
     */
    if ( !rtems_chain_is_empty( &mount_chain ) ) {
      errno = EINVAL;
      goto cleanup_and_bail;
    }

    /*
     *  This is a mount of the base file system --> The
     *  mt_point_node.node_access will be left to null to indicate that this
     *  is the root of the entire file system.
     */
  }

  if ( (*mount_h)( mt_entry, data ) ) {
    /*
     * Try to undo the mount operation
     */
    if ( loc.ops->unmount_h ) {
      loc.ops->unmount_h( mt_entry );
    }
    goto cleanup_and_bail;
  }

  /*
   *  Add the mount table entry to the mount table chain
   */
  rtems_libio_lock();
  rtems_chain_append( &mount_chain, &mt_entry->Node );
  rtems_libio_unlock();

  if ( !has_target )
    rtems_filesystem_root = mt_entry->mt_fs_root;

  return 0;

cleanup_and_bail:

  free( mt_entry );

  if ( loc_to_free )
    rtems_filesystem_freenode( loc_to_free );

  return -1;
}
Пример #12
0
/*
 * rtems_tarfs_load
 *
 * Here we create the mountpoint directory and load the tarfs at
 * that node.  Once the IMFS has been mounted, we work through the
 * tar image and perform as follows:
 *  - For directories, simply call mkdir().  The IMFS creates nodes as
 *    needed.
 *  - For files, we make our own calls to IMFS eval_for_make and
 *    create_node.
 */
int rtems_tarfs_load(
  char    *mountpoint,
  uint8_t *tar_image,
  size_t   tar_size
)
{
   rtems_filesystem_location_info_t  root_loc;
   rtems_filesystem_location_info_t  loc;
   const char                       *hdr_ptr;
   char                             filename[100];
   char                             full_filename[256];
   int                              hdr_chksum;
   unsigned char                    linkflag;
   unsigned long                    file_size;
   unsigned long                    file_mode;
   int                              offset;
   unsigned long                    nblocks;
   IMFS_jnode_t                    *node;
   int                              status;

   status = rtems_filesystem_evaluate_path(
      mountpoint,
      strlen(mountpoint),
      0,
      &root_loc,
      0
   );
   if (status != 0)
     return -1;

   if (root_loc.ops != &IMFS_ops && root_loc.ops != &fifoIMFS_ops)
     return -1;

   /*
    * Create an IMFS node structure pointing to tar image memory.
    */
   offset = 0;
   while (1) {
    if (offset + 512 > tar_size)
      break;

    /*
     * Read a header.
     */
    hdr_ptr = (char *) &tar_image[offset];
    offset += 512;
    if (strncmp(&hdr_ptr[257], "ustar", 5))
      break;

    strncpy(filename, hdr_ptr, MAX_NAME_FIELD_SIZE);
    filename[MAX_NAME_FIELD_SIZE] = '\0';

    linkflag   = hdr_ptr[156];
    file_mode  = _rtems_octal2ulong(&hdr_ptr[100], 8);
    file_size  = _rtems_octal2ulong(&hdr_ptr[124], 12);
    hdr_chksum = _rtems_octal2ulong(&hdr_ptr[148], 8);

    if (_rtems_tar_header_checksum(hdr_ptr) != hdr_chksum)
      break;

    /*
     * Generate an IMFS node depending on the file type.
     * - For directories, just create directories as usual.  IMFS
     *   will take care of the rest.
     * - For files, create a file node with special tarfs properties.
     */
    if (linkflag == DIRTYPE) {
      strcpy(full_filename, mountpoint);
      if (full_filename[strlen(full_filename)-1] != '/')
        strcat(full_filename, "/");
      strcat(full_filename, filename);
      mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO);
    }
    /*
     * Create a LINEAR_FILE node
     *
     *  NOTE: Coverity Id 20 reports this as a leak.
     *        While technically not a leak, it indicated that
     *        IMFS_create_node was ONLY passed a NULL when we created the
     *        root node.  We added a new IMFS_create_root_node() so this
     *        path no longer existed.  The result was simpler code which
     *        should not have this path. 
     */
    else if (linkflag == REGTYPE) {
      const char  *name;

      loc = root_loc;
      if (IMFS_evaluate_for_make(filename, &loc, &name) == 0) {
        node = IMFS_create_node(
          &loc,
          IMFS_LINEAR_FILE, (char *)name,
          (file_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG,
          NULL
        );
        node->info.linearfile.size   = file_size;
        node->info.linearfile.direct = &tar_image[offset];
      }

      nblocks = (((file_size) + 511) & ~511) / 512;
      offset += 512 * nblocks;
    }
  }
  return status;
}
Пример #13
0
int unmount(
    const char *path
)
{
    rtems_filesystem_location_info_t      loc;
    rtems_filesystem_location_info_t     *fs_root_loc;
    rtems_filesystem_location_info_t     *fs_mount_loc;
    rtems_filesystem_mount_table_entry_t *mt_entry;

    /*
     *  Get
     *    The root node of the mounted filesytem.
     *    The node for the directory that the fileystem is mounted on.
     *    The mount entry that is being refered to.
     */

    if ( rtems_filesystem_evaluate_path( path, strlen( path ), 0x0, &loc, true ) )
        return -1;

    mt_entry     = loc.mt_entry;
    fs_mount_loc = &mt_entry->mt_point_node;
    fs_root_loc  = &mt_entry->mt_fs_root;

    /*
     * Verify this is the root node for the file system to be unmounted.
     */

    if ( fs_root_loc->node_access != loc.node_access ) {
        rtems_filesystem_freenode( &loc );
        rtems_set_errno_and_return_minus_one( EACCES );
    }

    /*
     * Free the loc node and just use the nodes from the mt_entry .
     */

    rtems_filesystem_freenode( &loc );

    /*
     * Verify Unmount is supported by both filesystems.
     */

    if ( !fs_mount_loc->ops->unmount_h )
        rtems_set_errno_and_return_minus_one( ENOTSUP );

    if ( !fs_root_loc->ops->fsunmount_me_h )
        rtems_set_errno_and_return_minus_one( ENOTSUP );


    /*
     *  Verify the current node is not in this filesystem.
     *  XXX - Joel I have a question here wasn't code added
     *        that made the current node thread based instead
     *        of system based?  I thought it was but it doesn't
     *        look like it in this version.
     */

    if ( rtems_filesystem_current.mt_entry == mt_entry )
        rtems_set_errno_and_return_minus_one( EBUSY );

    /*
     *  Verify there are no file systems below the path specified
     */

    if ( rtems_filesystem_mount_iterate( is_fs_below_mount_point,
                                         fs_root_loc->mt_entry ) )
        rtems_set_errno_and_return_minus_one( EBUSY );

    /*
     *  Run the file descriptor table to determine if there are any file
     *  descriptors that are currently active and reference nodes in the
     *  file system that we are trying to unmount
     */

    if ( rtems_libio_is_open_files_in_fs( mt_entry ) == 1 )
        rtems_set_errno_and_return_minus_one( EBUSY );

    /*
     * Allow the file system being unmounted on to do its cleanup.
     * If it fails it will set the errno to the approprate value
     * and the fileystem will not be modified.
     */

    if (( fs_mount_loc->ops->unmount_h )( mt_entry ) != 0 )
        return -1;

    /*
     *  Allow the mounted filesystem to unmark the use of the root node.
     *
     *  Run the unmount function for the subordinate file system.
     *
     *  If we fail to unmount the filesystem remount it on the base filesystems
     *  directory node.
     *
     *  NOTE:  Fatal error is called in a case which should never happen
     *         This was response was questionable but the best we could
     *         come up with.
     */

    if ((fs_root_loc->ops->fsunmount_me_h )( mt_entry ) != 0) {
        if (( fs_mount_loc->ops->mount_h )( mt_entry ) != 0 )
            rtems_fatal_error_occurred( 0 );
        return -1;
    }

    /*
     *  Extract the mount table entry from the chain
     */

    rtems_libio_lock();
    rtems_chain_extract( &mt_entry->Node );
    rtems_libio_unlock();

    /*
     *  Free the memory node that was allocated in mount
     *  Free the memory associated with the extracted mount table entry.
     */

    rtems_filesystem_freenode( fs_mount_loc );
    free( mt_entry );

    return 0;
}