Beispiel #1
0
void seekdir(FAR DIR *dirp, off_t offset)
{
  struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;

  /* Verify that we were provided with a valid directory structure,
   * A special case is when we enumerate an "empty", unused inode (fd_root
   * == 0).  That is an inode in the pseudo-filesystem that has no
   * operations and no children.  This is a "dangling" directory entry that
   * has lost its children.
   */

  if (!idir || !idir->fd_root)
    {
      return;
    }

  /* The way we handle the readdir depends on the type of inode
   * that we are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if (INODE_IS_MOUNTPT(idir->fd_root))
    {
      /* The node is a file system mointpoint */

      seekmountptdir(idir, offset);
    }
  else
#endif
    {
      /* The node is part of the root pseudo file system */

      seekpseudodir(idir, offset);
    }
}
Beispiel #2
0
void seekdir(FAR DIR *dirp, off_t offset)
{
  struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;

  /* Sanity checks */

  if (!idir || !idir->fd_root)
    {
      return;
    }

  /* The way we handle the readdir depends on the type of inode
   * that we are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if (INODE_IS_MOUNTPT(idir->fd_root))
    {
      /* The node is a file system mointpoint */

      seekmountptdir(idir, offset);
    }
  else
#endif
    {
      /* The node is part of the root pseudo file system */

      seekpseudodir(idir, offset);
    }
}
Beispiel #3
0
int rmdir(FAR const char *pathname)
{
  FAR struct inode *inode;
  const char       *relpath = NULL;
  int               ret;

  /* Get an inode for this file */

  inode = inode_find(pathname, &relpath);
  if (!inode)
    {
      /* There is no mountpoint that includes in this path */

      ret = ENOENT;
      goto errout;
    }

  /* Verify that the inode is a valid mountpoint. */

  if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops)
    {
      ret = ENXIO;
      goto errout_with_inode;
    }

  /* Perform the rmdir operation using the relative path
   * at the mountpoint.
   */

  if (inode->u.i_mops->rmdir)
    {
      ret = inode->u.i_mops->rmdir(inode, relpath);
      if (ret < 0)
        {
          ret = -ret;
          goto errout_with_inode;
        }
    }
  else
    { 
      ret = ENOSYS;
      goto errout_with_inode;
    }

  /* Successfully removed the directory */

  inode_release(inode);
  return OK;

 errout_with_inode:
  inode_release(inode);
 errout:
  set_errno(ret);
  return ERROR;
}
static int mountpoint_filter(FAR struct inode *node,
                             FAR char dirpath[PATH_MAX], FAR void *arg)
{
  FAR struct enum_mountpoint_s *info = (FAR struct enum_mountpoint_s *)arg;
  struct statfs statbuf;
  int pathlen;
  int namlen;
  int ret = OK;

  DEBUGASSERT(node && info && info->handler);

  /* Check if the inode is a mountpoint.  Mountpoints must support statfs.
   * If this one does not for some reason, then it will be ignored.
   *
   * The root node is a special case:  It has no operations (u.i_mops == NULL)
   */

  if (INODE_IS_MOUNTPT(node) && node->u.i_mops && node->u.i_mops->statfs)
    {
      /* Yes... get the full path to the inode by concatenating the inode
       * name and the path to the directory containing the inode.
       */

      pathlen = strlen(dirpath);
      namlen  = strlen(node->i_name) + 1;

      /* Make sure that this would not exceed the maximum path length */

      if (pathlen + namlen > PATH_MAX)
        {
          return -ENAMETOOLONG;
        }

      /* Append the inode name to the directory path */

      sprintf(&dirpath[pathlen], "/%s", node->i_name);

      /* Get the status of the file system */

      ret = node->u.i_mops->statfs(node, &statbuf);
      if (ret == OK)
        {
          /* And pass the full path and file system status to the handler */

          ret = info->handler(dirpath, &statbuf, info->arg);
        }

      /* Truncate the path name back to the correct length */

      dirpath[pathlen] = '\0';
    }

  return ret;
}
Beispiel #5
0
static inline void syslog_flush(void)
{
  FAR struct inode *inode = g_sysdev.sl_file.f_inode;

  /* Is this a mountpoint? Does it support the sync method? */

  if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops->sync)
    {
      /* Yes... synchronize to the stream */

      (void)inode->u.i_mops->sync(&g_sysdev.sl_file);
    }
}
Beispiel #6
0
int inode_stat(FAR struct inode *inode, FAR struct stat *buf)
{
	DEBUGASSERT(inode != NULL && buf != NULL);

	memset(buf, 0, sizeof(*buf));

	if (INODE_IS_SPECIAL(inode)) {
#if defined(CONFIG_FS_NAMED_SEMAPHORES)
		if (INODE_IS_NAMEDSEM(inode)) {
			buf->st_mode = S_IFSEM;
		} else
#endif
#if !defined(CONFIG_DISABLE_MQUEUE)
		if (INODE_IS_MQUEUE(inode)) {
			buf->st_mode = S_IFMQ;
		} else
#endif
		{
		}
	} else if (inode->u.i_ops != NULL) {
		/* Determine read/write privileges based on the existence of read
		 * and write methods.
		 */
		if (inode->u.i_ops->read) {
			buf->st_mode = S_IROTH | S_IRGRP | S_IRUSR;
		}
		if (inode->u.i_ops->write) {
			buf->st_mode |= S_IWOTH | S_IWGRP | S_IWUSR;
		}
		/* Determine the type of the inode */
		if (INODE_IS_MOUNTPT(inode)) {
			buf->st_mode |= S_IFDIR;
		} else if (INODE_IS_BLOCK(inode)) {
			/* What is if also has child inodes? */
			buf->st_mode |= S_IFBLK;
		} else /* if (INODE_IS_DRIVER(inode)) */ {
			/* What is it if it also has child inodes? */
			buf->st_mode |= S_IFCHR;
		}
	} else {
		/* If it has no operations, then it must just be a intermediate
		 * node in the inode tree. It is something like a directory.
		 * We'll say that all pseudo-directories are read-able but not
		 * write-able.
		 */
		buf->st_mode |= S_IFDIR | S_IROTH | S_IRGRP | S_IRUSR;
	}

	return OK;
}
Beispiel #7
0
static inline int statpseudo(FAR struct inode *inode, FAR struct stat *buf)
{
  /* Most of the stat entries just do not apply */

  memset(buf, 0, sizeof(struct stat) );
  if (inode->u.i_ops)
    {
      if (inode->u.i_ops->read)
        {
          buf->st_mode = S_IROTH|S_IRGRP|S_IRUSR;
        }

      if (inode->u.i_ops->write)
        {
          buf->st_mode |= S_IWOTH|S_IWGRP|S_IWUSR;
        }

      if (INODE_IS_MOUNTPT(inode))
        {
          buf->st_mode |= S_IFDIR;
        }
      else if (INODE_IS_BLOCK(inode))
        {
          /* What is it also has child inodes? */

          buf->st_mode |= S_IFBLK;
        }
      else
        {
          /* What is it if it also has child inodes? */

          buf->st_mode |= S_IFCHR;
        }
    }
  else
    {
      /* If it has no operations, then it must just be a intermediate
       * node in the inode tree.  It is something like a directory.
       * We'll say that all pseudo-directories are read-able but not
       * write-able.
       */

      buf->st_mode |= S_IFDIR|S_IROTH|S_IRGRP|S_IRUSR;
    }

  return OK;
}
Beispiel #8
0
int file_fstat(FAR struct file *filep, FAR struct stat *buf)
{
  FAR struct inode *inode;
  int ret;

  DEBUGASSERT(filep != NULL);

  /* Get the inode from the file structure */

  inode = filep->f_inode;
  DEBUGASSERT(inode != NULL);

  /* The way we handle the stat depends on the type of inode that we
   * are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if (INODE_IS_MOUNTPT(inode))
    {
      /* The inode is a file system mountpoint. Verify that the mountpoint
       * supports the fstat() method
       */

      ret = -ENOSYS;
      if (inode->u.i_mops && inode->u.i_mops->fstat)
        {
          /* Perform the fstat() operation */

          ret = inode->u.i_mops->fstat(filep, buf);
        }
    }
  else
#endif
    {
      /* The inode is part of the root pseudo file system. */

      ret = inode_stat(inode, buf);
    }

  return ret;
}
Beispiel #9
0
void rewinddir(FAR DIR *dirp)
{
  struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
#ifndef CONFIG_DISABLE_MOUNTPOINT
  struct inode *inode;
#endif

  /* Sanity checks */

  if (!idir || !idir->fd_root)
    {
      return;
    }

  /* The way we handle the readdir depends on the type of inode
   * that we are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  inode = idir->fd_root;
  if (INODE_IS_MOUNTPT(inode))
    {
      /* The node is a file system mointpoint. Verify that the mountpoint
       * supports the rewinddir() method
       */

      if (inode->u.i_mops && inode->u.i_mops->rewinddir)
        {
          /* Perform the rewinddir() operation */

          inode->u.i_mops->rewinddir(inode, idir);
        }
    }
  else
#endif
    {
      /* The node is part of the root pseudo file system */

      rewindpseudodir(idir);
    }
}
Beispiel #10
0
FAR struct dirent *readdir(DIR *dirp)
{
  FAR struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
  struct inode *inode;
  int ret;

  /* Verify that we were provided with a valid directory structure */

  if (!idir)
    {
      ret = EBADF;
      goto errout;
    }

  /* A special case is when we enumerate an "empty", unused inode.  That is
   * an inode in the pseudo-filesystem that has no operations and no children.
   * This is a "dangling" directory entry that has lost its children.
   */

  inode = idir->fd_root;
  if (!inode)
    {
      /* End of file and error conditions are not distinguishable
       * with readdir.  We return NULL to signal either case.
       */

      ret = OK;
      goto errout;
    }

  /* The way we handle the readdir depends on the type of inode
   * that we are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSEUDONODE(idir->fd_flags))
    {
      /* The node is a file system mointpoint. Verify that the mountpoint
       * supports the readdir() method
       */

      if (!inode->u.i_mops || !inode->u.i_mops->readdir)
        {
          ret = EACCES;
          goto errout;
        }

      /* Perform the readdir() operation */

      ret = inode->u.i_mops->readdir(inode, idir);
    }
  else
#endif
    {
      /* The node is part of the root pseudo file system */

      ret = readpseudodir(idir);
    }

  /* ret < 0 is an error.  Special case: ret = -ENOENT is end of file */

  if (ret < 0)
    {
      if (ret == -ENOENT)
        {
          ret = OK;
        }
      else
        {
          ret = -ret;
        }

      goto errout;
    }

  /* Success */

  idir->fd_position++;
  return &idir->fd_dir;

errout:
  set_errno(ret);
  return NULL;
}
Beispiel #11
0
FAR DIR *opendir(FAR const char *path)
{
  FAR struct inode *inode = NULL;
  FAR struct fs_dirent_s *dir;
  FAR const char *relpath;
  bool isroot = false;
  int ret;

  /* If we are given 'nothing' then we will interpret this as
   * request for the root inode.
   */

  inode_semtake();
  if (!path || *path == 0 || strcmp(path, "/") == 0)
    {
      inode   = root_inode;
      isroot = true;
      relpath = NULL;
    }
  else
    {
      /* We don't know what to do with relative pathes */

      if (*path != '/')
        {
          ret = -ENOTDIR;
          goto errout_with_semaphore;
        }

      /* Find the node matching the path. */

      inode = inode_search(&path, (FAR struct inode**)NULL, (FAR struct inode**)NULL, &relpath);
    }

  /* Did we get an inode? */

  if (!inode)
    {
      /* 'path' is not a does not exist.*/

      ret = ENOTDIR;
      goto errout_with_semaphore;
    }

  /* Allocate a type DIR -- which is little more than an inode
   * container.
   */

  dir = (FAR struct fs_dirent_s *)kuzalloc(sizeof(struct fs_dirent_s));
  if (!dir)
    {
      /* Insufficient memory to complete the operation.*/

      ret = ENOMEM;
      goto errout_with_semaphore;
    }

  /* Populate the DIR structure and return it to the caller.  The way that
   * we do this depends on whenever this is a "normal" pseudo-file-system
   * inode or a file system mountpoint.
   */

  dir->fd_position = 0;      /* This is the position in the read stream */

  /* First, handle the special case of the root inode.  This must be
   * special-cased here because the root inode might ALSO be a mountpoint.
   */

  if (isroot)
    {
      /* Whatever payload the root inode carries, the root inode is always
       * a directory inode in the pseudo-file system
       */

      open_pseudodir(inode, dir);
    }

  /* Is this a node in the pseudo filesystem? Or a mountpoint?  If the node
   * is the root (isroot == TRUE), then this is a special case.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
   else if (INODE_IS_MOUNTPT(inode))
     {
       /* Yes, the node is a file system mountpoint */

      dir->fd_root = inode;  /* Save the inode where we start */

      /* Open the directory at the relative path */

      ret = open_mountpoint(inode, relpath, dir);
      if (ret != OK)
        {
           goto errout_with_direntry;
        }
    }
#endif
  else
    {
      /* The node is part of the root pseudo file system.  Does the inode
       * have a child? If so that the child would be the 'root' of a list
       * of nodes under the directory.
       */

      FAR struct inode *child = inode->i_child;
      if (child)
        {
          /* It looks we have a valid pseudo-filesystem directory node. */

          open_pseudodir(child, dir);
        }
      else if (!inode->u.i_ops)
        {
          /* This is a dangling node with no children and no operations. Set
           * up to enumerate an empty directory.
           */

          open_emptydir(dir);
        }
      else
        {
          ret = ENOTDIR;
          goto errout_with_direntry;
        }
    }

  inode_semgive();
  return ((DIR*)dir);

  /* Nasty goto's make error handling simpler */

errout_with_direntry:
  kufree(dir);

errout_with_semaphore:
  inode_semgive();
  set_errno(ret);
  return NULL;
}
Beispiel #12
0
int rmdir(FAR const char *pathname)
{
  FAR struct inode *inode;
  const char       *relpath = NULL;
  int               errcode;

  /* Get an inode for this file.  inode_find() automatically increments the
   * reference count on the inode if one is found.
   */

  inode = inode_find(pathname, &relpath);
  if (!inode)
    {
      /* There is no inode that includes in this path */

      errcode = ENOENT;
      goto errout;
    }

#ifndef CONFIG_DISABLE_MOUNTPOINT
  /* Check if the inode is a valid mountpoint. */

  if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops)
    {
      /* Perform the rmdir operation using the relative path
       * from the mountpoint.
       */

      if (inode->u.i_mops->rmdir)
        {
          int ret = inode->u.i_mops->rmdir(inode, relpath);
          if (ret < 0)
            {
              errcode = -ret;
              goto errout_with_inode;
            }
        }
      else
        {
          errcode = ENOSYS;
          goto errout_with_inode;
        }
    }
  else
#endif

#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  /* If this is a "dangling" pseudo-directory node (i.e., it has no operations)
   * then rmdir should remove the node.
   */

  if (!inode->u.i_ops)
    {
      int ret;

      /* If the directory inode has children, however, then it cannot be
       * removed.
       */

      if (inode->i_child)
        {
          errcode = ENOTEMPTY;
          goto errout_with_inode;
        }

      /* Remove the inode.  NOTE: Because we hold a reference count on the
       * inode, it will not be deleted now.  But probably when inode_release()
       * is called below.  inode_remove should return -EBUSY to indicate that
       * the inode was not deleted now.
       */

      inode_semtake();
      ret = inode_remove(pathname);
      inode_semgive();

      if (ret < 0 && ret != -EBUSY)
        {
          errcode = -ret;
          goto errout_with_inode;
        }
    }
  else
    {
      errcode = ENOTDIR;
      goto errout_with_inode;
    }
#else
    {
      errcode = ENXIO;
      goto errout_with_inode;
    }
#endif

  /* Successfully removed the directory */

  inode_release(inode);
  return OK;

errout_with_inode:
  inode_release(inode);
errout:
  set_errno(errcode);
  return ERROR;
}
Beispiel #13
0
int open(const char *path, int oflags, ...)
{
  FAR struct filelist *list;
  FAR struct inode    *inode;
  FAR const char      *relpath = NULL;
#if defined(CONFIG_FILE_MODE) || !defined(CONFIG_DISABLE_MOUNTPOINT)
  mode_t               mode = 0666;
#endif
  int                  ret;
  int                  fd;

  /* Get the thread-specific file list */

  list = sched_getfiles();
  if (!list)
    {
      ret = EMFILE;
      goto errout;
    }

#ifdef CONFIG_FILE_MODE
#  ifdef CONFIG_CPP_HAVE_WARNING
#    warning "File creation not implemented"
#  endif

  /* If the file is opened for creation, then get the mode bits */

  if (oflags & (O_WRONLY|O_CREAT) != 0)
    {
      va_list ap;
      va_start(ap, oflags);
      mode = va_arg(ap, mode_t);
      va_end(ap);
    }
#endif

  /* Get an inode for this file */

  inode = inode_find(path, &relpath);
  if (!inode)
    {
      /* "O_CREAT is not set and the named file does not exist.  Or, a
       * directory component in pathname does not exist or is a dangling
       * symbolic link."
       */

      ret = ENOENT;
      goto errout;
    }

  /* Verify that the inode is valid and either a "normal" or a mountpoint.  We
   * specifically exclude block drivers.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if ((!INODE_IS_DRIVER(inode) && !INODE_IS_MOUNTPT(inode)) || !inode->u.i_ops)
#else
  if (!INODE_IS_DRIVER(inode) || !inode->u.i_ops)
#endif
    {
      ret = ENXIO;
      goto errout_with_inode;
    }

  /* Make sure that the inode supports the requested access */

  ret = inode_checkflags(inode, oflags);
  if (ret < 0)
    {
      ret = -ret;
      goto errout_with_inode;
    }

  /* Associate the inode with a file structure */

  fd = files_allocate(inode, oflags, 0, 0);
  if (fd < 0)
    {
      ret = EMFILE;
      goto errout_with_inode;
    }

  /* Perform the driver open operation.  NOTE that the open method may be
   * called many times.  The driver/mountpoint logic should handled this
   * because it may also be closed that many times.
   */

  ret = OK;
  if (inode->u.i_ops->open)
    {
#ifndef CONFIG_DISABLE_MOUNTPOINT
      if (INODE_IS_MOUNTPT(inode))
        {
          ret = inode->u.i_mops->open((FAR struct file*)&list->fl_files[fd],
                                      relpath, oflags, mode);
        }
      else
#endif
        {
          ret = inode->u.i_ops->open((FAR struct file*)&list->fl_files[fd]);
        }
    }

  if (ret < 0)
    {
      ret = -ret;
      goto errout_with_fd;
    }

  return fd;

 errout_with_fd:
  files_release(fd);
 errout_with_inode:
  inode_release(inode);
 errout:
  set_errno(ret);
  return ERROR;
}
Beispiel #14
0
int rename(FAR const char *oldpath, FAR const char *newpath)
{
  FAR struct inode *oldinode;
  FAR struct inode *newinode;
  const char       *oldrelpath = NULL;
#ifndef CONFIG_DISABLE_MOUNTPOINT
  const char       *newrelpath = NULL;
#endif
  int               errcode;
  int               ret;

  /* Ignore paths that are interpreted as the root directory which has no name
   * and cannot be moved
   */

  if (!oldpath || *oldpath == '\0' || oldpath[0] != '/' ||
      !newpath || *newpath == '\0' || newpath[0] != '/')
    {
      return -EINVAL;
    }

  /* Get an inode that includes the oldpath */

  oldinode = inode_find(oldpath, &oldrelpath);
  if (!oldinode)
    {
      /* There is no inode that includes in this path */

      errcode = ENOENT;
      goto errout;
    }

#ifndef CONFIG_DISABLE_MOUNTPOINT
  /* Verify that the old inode is a valid mountpoint. */

  if (INODE_IS_MOUNTPT(oldinode) && oldinode->u.i_mops)
    {
      /* Get an inode for the new relpath -- it should like on the same
       * mountpoint
       */

      newinode = inode_find(newpath, &newrelpath);
      if (!newinode)
        {
          /* There is no mountpoint that includes in this path */

          errcode = ENOENT;
          goto errout_with_oldinode;
        }

      /* Verify that the two paths lie on the same mountpoint inode */

      if (oldinode != newinode)
        {
          errcode = EXDEV;
          goto errout_with_newinode;
        }

      /* Perform the rename operation using the relative paths
       * at the common mountpoint.
       */

      if (oldinode->u.i_mops->rename)
        {
          ret = oldinode->u.i_mops->rename(oldinode, oldrelpath, newrelpath);
          if (ret < 0)
            {
              errcode = -ret;
              goto errout_with_newinode;
            }
        }
      else
        {
          errcode = ENOSYS;
          goto errout_with_newinode;
        }

      /* Successfully renamed */

      inode_release(newinode);
    }
  else
#endif
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
    {
      /* Create a new, empty inode at the destination location.
       * NOTE that the new inode will be created with a reference count
       * of  zero.
       */

      inode_semtake();
      ret = inode_reserve(newpath, &newinode);
      if (ret < 0)
        {
          /* It is an error if a node at newpath already exists in the tree
           * OR if we fail to allocate memory for the new inode (and possibly
           * any new intermediate path segments).
           */

          inode_semgive();
          errcode = EEXIST;
          goto errout_with_oldinode;
        }

      /* Copy the inode state from the old inode to the newly allocated inode */

      newinode->i_child   = oldinode->i_child;   /* Link to lower level inode */
      newinode->i_flags   = oldinode->i_flags;   /* Flags for inode */
      newinode->u.i_ops   = oldinode->u.i_ops;   /* Inode operations */
#ifdef CONFIG_FILE_MODE
      newinode->i_mode    = oldinode->i_mode;    /* Access mode flags */
#endif
      newinode->i_private = oldinode->i_private; /* Per inode driver private data */

      /* We now have two copies of the inode.  One with a reference count of
       * zero (the new one), and one that may have multiple references
       * including one by this logic (the old one)
       *
       * Remove the old inode.  Because we hold a reference count on the
       * inode, it will not be deleted now.  It will be deleted when all of
       * the references to to the inode have been released (perhaps when
       * inode_release() is called below).  inode_remove() should return
       * -EBUSY to indicate that the inode was not deleted now.
       */

      ret = inode_remove(oldpath);
      if (ret < 0 && ret != -EBUSY)
        {
          /* Remove the new node we just recreated */

          (void)inode_remove(newpath);
          inode_semgive();

          errcode = -ret;
          goto errout_with_oldinode;
        }

      /* Remove all of the children from the unlinked inode */

      oldinode->i_child = NULL;
      inode_semgive();
    }
#else
    {
      errcode = ENXIO;
      goto errout;
    }
#endif

  /* Successfully renamed */

  inode_release(oldinode);
  return OK;

#ifndef CONFIG_DISABLE_MOUNTPOINT
errout_with_newinode:
  inode_release(newinode);
#endif
errout_with_oldinode:
  inode_release(oldinode);
errout:
  set_errno(errcode);
  return ERROR;
}
Beispiel #15
0
int stat(const char *path, FAR struct stat *buf)
{
  FAR struct inode *inode;
  const char       *relpath = NULL;
  int               ret     = OK;

  /* Sanity checks */

  if (!path || !buf)
    {
      ret = EFAULT;
      goto errout;
    }

  if (!path[0])
    {
      ret = ENOENT;
      goto errout;
    }

  /* Check for the fake root directory (which has no inode) */

  if (strcmp(path, "/") == 0)
    {
      return statroot(buf);
    }

  /* Get an inode for this file */

  inode = inode_find(path, &relpath);
  if (!inode)
    {
      /* This name does not refer to a psudeo-inode and there is no
       * mountpoint that includes in this path.
       */

      ret = ENOENT;
      goto errout;
    }

  /* The way we handle the stat depends on the type of inode that we
   * are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if (INODE_IS_MOUNTPT(inode))
    {
      /* The node is a file system mointpoint. Verify that the mountpoint
       * supports the stat() method
       */

      if (inode->u.i_mops && inode->u.i_mops->stat)
        {
          /* Perform the stat() operation */

          ret = inode->u.i_mops->stat(inode, relpath, buf);
        }
    }
  else
#endif
    {
      /* The node is part of the root pseudo file system */

      ret = statpseudo(inode, buf);
    }

  /* Check if the stat operation was successful */

  if (ret < 0)
    {
      ret = -ret;
      goto errout_with_inode;
    }

  /* Successfully stat'ed the file */

  inode_release(inode);
  return OK;

/* Failure conditions always set the errno appropriately */

errout_with_inode:
  inode_release(inode);
errout:
  set_errno(ret);
  return ERROR;
}
Beispiel #16
0
int umount(const char *target)
{
  FAR struct inode *mountpt_inode;
  FAR struct inode *blkdrvr_inode = NULL;
  int errcode = OK;
  int status;

  /* Verify required pointer arguments */

  if (!target)
    {
      errcode = EFAULT;
      goto errout;
    }

  /* Find the mountpt */

  mountpt_inode = inode_find(target, NULL);
  if (!mountpt_inode)
    {
      errcode = ENOENT;
      goto errout;
    }

  /* Verify that the inode is a mountpoint */

  if (!INODE_IS_MOUNTPT(mountpt_inode))
    {
      errcode = EINVAL;
      goto errout_with_mountpt;
    }

  /* Unbind the block driver from the file system (destroying any fs
   * private data.
   */

  if (!mountpt_inode->u.i_mops->unbind)
    {
      /* The filesystem does not support the unbind operation ??? */

      errcode = EINVAL;
      goto errout_with_mountpt;
    }

  /* The unbind method returns the number of references to the
   * filesystem (i.e., open files), zero if the unbind was
   * performed, or a negated error code on a failure.
   */

  inode_semtake(); /* Hold the semaphore through the unbind logic */
  status = mountpt_inode->u.i_mops->unbind( mountpt_inode->i_private, &blkdrvr_inode);
  if (status < 0)
    {
      /* The inode is unhappy with the blkdrvr for some reason */

      errcode = -status;
      goto errout_with_semaphore;
    }
  else if (status > 0)
    {
      errcode = EBUSY;
      goto errout_with_semaphore;
    }

  /* Successfully unbound */

  mountpt_inode->i_private = NULL;

  /* Successfully unbound, remove the mountpoint inode from
   * the inode tree.  The inode will not be deleted yet because
   * there is still at least reference on it (from the mount)
   */

  status = inode_remove(target);
  inode_semgive();

  /* The return value of -EBUSY is normal (in fact, it should
   * not be OK)
   */

  if (status != OK && status != -EBUSY)
    {
      errcode = -status;
      goto errout_with_mountpt;
    }

  /* Release the mountpoint inode and any block driver inode
   * returned by the file system unbind above.  This should cause
   * the inode to be deleted (unless there are other references)
   */

  inode_release(mountpt_inode);

  /* Did the unbind method return a contained block driver */

  if (blkdrvr_inode)
    {
      inode_release(blkdrvr_inode);
    }

  return OK;

  /* A lot of goto's!  But they make the error handling much simpler */

errout_with_semaphore:
  inode_semgive();
errout_with_mountpt:
  inode_release(mountpt_inode);
  if (blkdrvr_inode)
    {
      inode_release(blkdrvr_inode);
    }
errout:
  set_errno(errcode);
  return ERROR;
}
Beispiel #17
0
FAR struct dirent *readdir(DIR *dirp)
{
  FAR struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
#ifndef CONFIG_DISABLE_MOUNTPOINT
  struct inode *inode;
#endif
  int ret;

  /* Sanity checks */

  if (!idir || !idir->fd_root)
    {
      ret = EBADF;
      goto errout;
    }

  /* The way we handle the readdir depends on the type of inode
   * that we are dealing with.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  inode = idir->fd_root;
  if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSUEDONODE(idir->fd_flags))
    {
      /* The node is a file system mointpoint. Verify that the mountpoint
       * supports the readdir() method
       */

      if (!inode->u.i_mops || !inode->u.i_mops->readdir)
         {
           ret = EACCES;
            goto errout;
         }

      /* Perform the readdir() operation */

      ret = inode->u.i_mops->readdir(inode, idir);
    }
  else
#endif
    {
      /* The node is part of the root psuedo file system */

      ret = readpsuedodir(idir);
    }

  /* ret < 0 is an error.  Special case: ret = -ENOENT is end of file */

  if ( ret < 0)
    {
      if (ret == -ENOENT)
        {
          ret = OK;
        }
      else
        {
          ret = -ret;
        }
      goto errout;
    }

  /* Success */

  idir->fd_position++;
  return &idir->fd_dir;

errout:
  *get_errno_ptr() = ret;
  return NULL;
}
Beispiel #18
0
int open(const char *path, int oflags, ...)
{
  FAR struct file *filep;
  FAR struct inode *inode;
  FAR const char *relpath = NULL;
#if defined(CONFIG_FILE_MODE) || !defined(CONFIG_DISABLE_MOUNTPOINT)
  mode_t mode = 0666;
#endif
  int ret;
  int fd;

#ifdef CONFIG_FILE_MODE
#  ifdef CONFIG_CPP_HAVE_WARNING
#    warning "File creation not implemented"
#  endif

  /* If the file is opened for creation, then get the mode bits */

  if ((oflags & (O_WRONLY | O_CREAT)) != 0)
    {
      va_list ap;
      va_start(ap, oflags);
      mode = va_arg(ap, mode_t);
      va_end(ap);
    }
#endif

  /* Get an inode for this file */

  inode = inode_find(path, &relpath);
  if (!inode)
    {
      /* "O_CREAT is not set and the named file does not exist.  Or, a
       * directory component in pathname does not exist or is a dangling
       * symbolic link."
       */

      ret = ENOENT;
      goto errout;
    }

#if !defined(CONFIG_DISABLE_PSEUDOFS_OPERATIONS) && \
    !defined(CONFIG_DISABLE_MOUNTPOINT)
   /* If the inode is block driver, then we may return a character driver
    * proxy for the block driver.  block_proxy() will instantiate a BCH
    * character driver wrapper around the block driver, open(), then
    * unlink() the character driver.  On success, block_proxy() will
    * return the file descriptor of the opened character driver.
    *
    * NOTE: This will recurse to open the character driver proxy.
    */

   if (INODE_IS_BLOCK(inode))
     {
       /* Release the inode reference */

       inode_release(inode);

       /* Get the file descriptor of the opened character driver proxy */

       fd = block_proxy(path, oflags);
       if (fd < 0)
         {
           ret = fd;
           goto errout;
         }

       /* Return the file descriptor */

       return fd;
     }
   else
#endif

  /* Verify that the inode is either a "normal" character driver or a
   * mountpoint.  We specifically "special" inodes (semaphores, message
   * queues, shared memory).
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if ((!INODE_IS_DRIVER(inode) && !INODE_IS_MOUNTPT(inode)) || !inode->u.i_ops)
#else
  if (!INODE_IS_DRIVER(inode) || !inode->u.i_ops)
#endif
    {
      ret = ENXIO;
      goto errout_with_inode;
    }

  /* Make sure that the inode supports the requested access */

  ret = inode_checkflags(inode, oflags);
  if (ret < 0)
    {
      ret = -ret;
      goto errout_with_inode;
    }

  /* Associate the inode with a file structure */

  fd = files_allocate(inode, oflags, 0, 0);
  if (fd < 0)
    {
      ret = EMFILE;
      goto errout_with_inode;
    }

  /* Get the file structure corresponding to the file descriptor. */

  filep = fs_getfilep(fd);
  if (!filep)
    {
      /* The errno value has already been set */

      return ERROR;
    }

  /* Perform the driver open operation.  NOTE that the open method may be
   * called many times.  The driver/mountpoint logic should handled this
   * because it may also be closed that many times.
   */

  ret = OK;
  if (inode->u.i_ops->open)
    {
#ifndef CONFIG_DISABLE_MOUNTPOINT
      if (INODE_IS_MOUNTPT(inode))
        {
          ret = inode->u.i_mops->open(filep, relpath, oflags, mode);
        }
      else
#endif
        {
          ret = inode->u.i_ops->open(filep);
        }
    }

  if (ret < 0)
    {
      ret = -ret;
      goto errout_with_fd;
    }

  return fd;

errout_with_fd:
  files_release(fd);
errout_with_inode:
  inode_release(inode);
errout:
  set_errno(ret);
  return ERROR;
}
Beispiel #19
0
FAR struct inode *inode_search(const char **path,
                               FAR struct inode **peer,
                               FAR struct inode **parent,
                               const char **relpath)
{
  const char       *name  = *path + 1; /* Skip over leading '/' */
  FAR struct inode *node  = root_inode;
  FAR struct inode *left  = NULL;
  FAR struct inode *above = NULL;

  while (node)
    {
      int result = _inode_compare(name, node);

      /* Case 1:  The name is less than the name of the node.
       * Since the names are ordered, these means that there
       * is no peer node with this name and that there can be
       * no match in the fileystem.
       */

      if (result < 0)
        {
          node = NULL;
          break;
        }

      /* Case 2: the name is greater than the name of the node.
       * In this case, the name may still be in the list to the
       * "right"
       */

      else if (result > 0)
        {
          left = node;
          node = node->i_peer;
        }

      /* The names match */

      else
        {
          /* Now there are three more possibilities:
           *   (1) This is the node that we are looking for or,
           *   (2) The node we are looking for is "below" this one.
           *   (3) This node is a mountpoint and will absorb all request
           *       below this one
           */

          name = inode_nextname(name);
          if (!*name || INODE_IS_MOUNTPT(node))
            {
              /* Either (1) we are at the end of the path, so this must be the
               * node we are looking for or else (2) this node is a mountpoint
               * and will handle the remaining part of the pathname
               */

              if (relpath)
                {
                  *relpath = name;
                }
              break;
            }
          else
            {
              /* More to go, keep looking at the next level "down" */

              above = node;
              left  = NULL;
              node = node->i_child;
            }
        }
    }

  /* node is null.  This can happen in one of four cases:
   * With node = NULL
   *   (1) We went left past the final peer:  The new node
   *       name is larger than any existing node name at
   *       that level.
   *   (2) We broke out in the middle of the list of peers
   *       because the name was not found in the ordered
   *       list.
   *   (3) We went down past the final parent:  The new node
   *       name is "deeper" than anything that we currently
   *       have in the tree.
   * with node != NULL
   *   (4) When the node matching the full path is found
   */

  if (peer)
    {
      *peer = left;
    }

  if (parent)
    {
      *parent = above;
    }

  *path = name;
  return node;
}
Beispiel #20
0
int mkdir(const char *pathname, mode_t mode)
{
  FAR struct inode *inode;
  const char       *relpath = NULL;
  int               errcode;
  int               ret;

  /* Find the inode that includes this path */

  inode = inode_find(pathname, &relpath);
  if (inode)
    {
      /* An inode was found that includes this path and possibly refers to a
       * mountpoint.
       */

#ifndef CONFIG_DISABLE_MOUNTPOINT
      /* Check if the inode is a valid mountpoint. */

      if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops)
        {
          /* The inode is not a mountpoint */

          errcode = ENXIO;
          goto errout_with_inode;
        }

      /* Perform the mkdir operation using the relative path
       * at the mountpoint.
       */

      if (inode->u.i_mops->mkdir)
        {
          ret = inode->u.i_mops->mkdir(inode, relpath, mode);
          if (ret < 0)
            {
              errcode = -ret;
              goto errout_with_inode;
            }
        }
      else
        {
          errcode = ENOSYS;
          goto errout_with_inode;
        }

      /* Release our reference on the inode */

      inode_release(inode);
#else
      /* But mountpoints are not supported in this configuration */

      errcode = EEXIST;
      goto errout_with_inode;
#endif
    }

#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  /* No inode exists that contains this path.  Create a new inode in the
   * pseudo-filesystem at this location.
   */

  else
    {
      /* Create an inode in the pseudo-filesystem at this path */

      inode_semtake();
      ret = inode_reserve(pathname, &inode);
      inode_semgive();

      if (ret < 0)
        {
          errcode = -ret;
          goto errout;
        }
    }
#else
  else
    {
Beispiel #21
0
static inline int readpsuedodir(struct fs_dirent_s *idir)
{
  FAR struct inode *prev;

  /* Check if we are at the end of the list */

  if (!idir->u.psuedo.fd_next)
    {
      /* End of file and error conditions are not distinguishable
       * with readdir.  Here we return -ENOENT to signal the end
       * of the directory.
       */

      return -ENOENT;
    }

  /* Copy the inode name into the dirent structure */

  strncpy(idir->fd_dir.d_name, idir->u.psuedo.fd_next->i_name, NAME_MAX+1);

  /* If the node has file operations, we will say that it is
   * a file.
   */

  idir->fd_dir.d_type = 0;
  if (idir->u.psuedo.fd_next->u.i_ops)
    {
#ifndef CONFIG_DISABLE_MOUNTPOINT
      if (INODE_IS_BLOCK(idir->u.psuedo.fd_next)) 
        {
           idir->fd_dir.d_type |= DTYPE_BLK;
        }
      if (INODE_IS_MOUNTPT(idir->u.psuedo.fd_next)) 
        {
           idir->fd_dir.d_type |= DTYPE_DIRECTORY;
        }
      else
#endif
        {
           idir->fd_dir.d_type |= DTYPE_CHR;
        }
    }

  /* If the node has child node(s), then we will say that it
   * is a directory.  NOTE: that the node can be both!
   */

  if (idir->u.psuedo.fd_next->i_child || !idir->u.psuedo.fd_next->u.i_ops)
    {
      idir->fd_dir.d_type |= DTYPE_DIRECTORY;
    }

  /* Now get the inode to vist next time that readdir() is called */

  inode_semtake();

  prev                   = idir->u.psuedo.fd_next;
  idir->u.psuedo.fd_next = prev->i_peer; /* The next node to visit */

  if (idir->u.psuedo.fd_next)
    {
      /* Increment the reference count on this next node */

      idir->u.psuedo.fd_next->i_crefs++;
    }

  inode_semgive();

  if (prev)
    {
      inode_release(prev);
    }

  return OK;
}
Beispiel #22
0
int umount2(FAR const char *target, unsigned int flags)
{
  FAR struct inode *mountpt_inode;
  FAR struct inode *blkdrvr_inode = NULL;
  struct inode_search_s desc;
  int errcode = OK;
  int ret;

  /* Verify required pointer arguments */

  if (!target)
    {
      errcode = EFAULT;
      goto errout;
    }

  /* Find the mountpt */

  SETUP_SEARCH(&desc, target, false);

  ret = inode_find(&desc);
  if (ret < 0)
    {
      errcode = ENOENT;
      goto errout_with_search;
    }

  /* Get the search results */

  mountpt_inode = desc.node;
  DEBUGASSERT(mountpt_inode != NULL);

  /* Verify that the inode is a mountpoint */

  if (!INODE_IS_MOUNTPT(mountpt_inode))
    {
      errcode = EINVAL;
      goto errout_with_mountpt;
    }

  /* Unbind the block driver from the file system (destroying any fs
   * private data.
   */

  if (!mountpt_inode->u.i_mops->unbind)
    {
      /* The filesystem does not support the unbind operation ??? */

      errcode = EINVAL;
      goto errout_with_mountpt;
    }

  /* The unbind method returns the number of references to the
   * filesystem (i.e., open files), zero if the unbind was
   * performed, or a negated error code on a failure.
   */

  inode_semtake(); /* Hold the semaphore through the unbind logic */
  ret = mountpt_inode->u.i_mops->unbind(mountpt_inode->i_private,
                                       &blkdrvr_inode, flags);
  if (ret < 0)
    {
      /* The inode is unhappy with the blkdrvr for some reason */

      errcode = -ret;
      goto errout_with_semaphore;
    }
  else if (ret > 0)
    {
      errcode = EBUSY;
      goto errout_with_semaphore;
    }

  /* Successfully unbound.  Convert the mountpoint inode to regular
   * pseudo-file inode.
   */


  mountpt_inode->i_flags  &= ~FSNODEFLAG_TYPE_MASK;
  mountpt_inode->i_private = NULL;
  mountpt_inode->u.i_mops  = NULL;

#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  /* If the node has children, then do not delete it. */

  if (mountpt_inode->i_child != NULL)
    {
       /* Just decrement the reference count (without deleting it) */

       DEBUGASSERT(mountpt_inode->i_crefs > 0);
       mountpt_inode->i_crefs--;
    }
  else
#endif
    {
      /* Remove the mountpoint inode from the inode tree.  The inode will
       * not be deleted yet because there is still at least reference on
       * it (from the mount)
       */

      ret = inode_remove(target);
      inode_semgive();

      /* The return value of -EBUSY is normal (in fact, it should
       * not be OK)
       */

      if (ret != OK && ret != -EBUSY)
        {
          errcode = -ret;
          goto errout_with_mountpt;
       }

      /* Release the mountpoint inode and any block driver inode
       * returned by the file system unbind above.  This should cause
       * the inode to be deleted (unless there are other references)
       */

      inode_release(mountpt_inode);
    }

  /* Did the unbind method return a contained block driver */

  if (blkdrvr_inode)
    {
      inode_release(blkdrvr_inode);
    }

  RELEASE_SEARCH(&desc);
  return OK;

  /* A lot of goto's!  But they make the error handling much simpler */

errout_with_semaphore:
  inode_semgive();

errout_with_mountpt:
  inode_release(mountpt_inode);
  if (blkdrvr_inode)
    {
      inode_release(blkdrvr_inode);
    }

errout_with_search:
  RELEASE_SEARCH(&desc);

errout:
  set_errno(errcode);
  return ERROR;
}
Beispiel #23
0
int syslog_initialize(void)
{
  FAR struct inode    *inode;
  FAR const char      *relpath = NULL;
  int                  ret;

  /* At this point, the only expected states are SYSLOG_UNINITIALIZED or
   * SYSLOG_REOPEN..  Not SYSLOG_INITIALIZING, SYSLOG_FAILURE, SYSLOG_OPENED.
   */

  DEBUGASSERT(g_sysdev.sl_state == SYSLOG_UNINITIALIZED ||
              g_sysdev.sl_state == SYSLOG_REOPEN);

  g_sysdev.sl_state = SYSLOG_INITIALIZING;

  /* Try to open the device.
   *
   * Note that we cannot just call open.  The syslog device must work on all
   * threads.  Open returns a file descriptor that is valid only for the
   * task that opened the device (and its pthread children).  Instead, we
   * essentially re-implement the guts of open() here so that we can get to
   * the thread-independent structures of the inode.
   */

  /* Get an inode for this file/device */

  inode = inode_find(CONFIG_SYSLOG_DEVPATH, &relpath);
  if (!inode)
    {
      /* The inode was not found.  In this case, we will attempt to re-open
       * the device repeatedly.  The assumption is that the device path is
       * valid but that the driver has not yet been registered.
       */

      g_sysdev.sl_state = SYSLOG_REOPEN;
      return -ENOENT;
    }

  /* Verify that the inode is valid and either a character driver or a
   * mountpoint.
   */

#ifndef CONFIG_DISABLE_MOUNTPOINT
  if ((!INODE_IS_DRIVER(inode) && !INODE_IS_MOUNTPT(inode)))
#else
  if (!INODE_IS_DRIVER(inode))
#endif
    {
      ret = -ENXIO;
      goto errout_with_inode;
    }

  /* Make sure that the "entity" at this inode supports write access */

  if (!inode->u.i_ops || !inode->u.i_ops->write)
    {
      ret = -EACCES;
      goto errout_with_inode;
    }

  /* Initialize the file structure */

  g_sysdev.sl_file.f_oflags = SYSLOG_OFLAGS;
  g_sysdev.sl_file.f_pos    = 0;
  g_sysdev.sl_file.f_inode  = inode;

  /* Perform the low-level open operation. */

  ret = OK;
  if (inode->u.i_ops->open)
    {
      /* Is the inode a mountpoint? */

#ifndef CONFIG_DISABLE_MOUNTPOINT
      if (INODE_IS_MOUNTPT(inode))
        {
          /* Yes.  Open the device write-only, try to create it if it
           * doesn't exist, if the file that already exists, then append the
           * new log data to end of the file.
           */

          ret = inode->u.i_mops->open(&g_sysdev.sl_file, relpath,
                                      SYSLOG_OFLAGS, 0666);
        }

      /* No... then it must be a character driver in the NuttX pseudo-
       * file system.
       */

      else
#endif
        {
          ret = inode->u.i_ops->open(&g_sysdev.sl_file);
        }
    }

  /* Was the file/device successfully opened? */

  if (ret < 0)
    {
      ret = -ret;
      goto errout_with_inode;
    }

  /* The SYSLOG device is open and ready for writing. */

  sem_init(&g_sysdev.sl_sem, 0, 1);
  g_sysdev.sl_holder = NO_HOLDER;
  g_sysdev.sl_state  = SYSLOG_OPENED;
  return OK;

 errout_with_inode:
  inode_release(inode);
  g_sysdev.sl_state = SYSLOG_FAILURE;
  return ret;
}
Beispiel #24
0
static int fat_attrib(const char *path, fat_attrib_t *retattrib,
                      fat_attrib_t setbits, fat_attrib_t clearbits)
{
  struct fat_mountpt_s *fs;
  struct fat_dirinfo_s  dirinfo;
  FAR struct inode     *inode;
  const char           *relpath = NULL;
  uint8_t              *direntry;
  uint8_t               oldattributes;
  uint8_t               newattributes;
  int                   ret;

  /* Get an inode for this file */

  inode = inode_find(path, &relpath);
  if (!inode)
    {
      /* There is no mountpoint that includes in this path */

      ret = ENOENT;
      goto errout;
    }

  /* Verify that the inode is a valid mountpoint. */

  if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops || !inode->i_private)
    {
      ret = ENXIO;
      goto errout_with_inode;
    }

  /* Get the mountpoint private data from the inode structure */

  fs = inode->i_private;

  /* Check if the mount is still healthy */

  fat_semtake(fs);
  ret = fat_checkmount(fs);
  if (ret != OK)
    {
      goto errout_with_semaphore;
    }

  /* Find the file/directory entry for the oldrelpath */

  ret = fat_finddirentry(fs, &dirinfo, relpath);
  if (ret != OK)
    {
      /* Some error occurred -- probably -ENOENT */

      goto errout_with_semaphore;
    }

  /* Make sure that we found some valid file or directory */

  if (dirinfo.fd_root)
    {
      /* Ooops.. we found the root directory */

      ret = EACCES;
      goto errout_with_semaphore;
    }

  /* Get the current attributes */

  direntry      = &fs->fs_buffer[dirinfo.fd_seq.ds_offset];
  oldattributes = DIR_GETATTRIBUTES(direntry);
  newattributes = oldattributes;

  /* Set or clear any bits as requested */

  newattributes &= ~(clearbits & (FATATTR_READONLY|FATATTR_HIDDEN|FATATTR_SYSTEM|FATATTR_ARCHIVE));
  newattributes |=  (setbits   & (FATATTR_READONLY|FATATTR_HIDDEN|FATATTR_SYSTEM|FATATTR_ARCHIVE));

  /* Did any thingchange? */

  if (newattributes != oldattributes)
    {
      DIR_PUTATTRIBUTES(direntry, newattributes);
      fs->fs_dirty = true;
      ret = fat_updatefsinfo(fs);
      if (ret != OK)
        {
          ret = -ret;
          goto errout_with_semaphore;
        }
    }

  /* Success */

  if (retattrib)
    {
      *retattrib = newattributes;
    }

  fat_semgive(fs);
  inode_release(inode);
  return OK;

errout_with_semaphore:
  fat_semgive(fs);
errout_with_inode:
  inode_release(inode);
errout:
  *get_errno_ptr() = ret;
  return ERROR;
}
Beispiel #25
0
int unlink(FAR const char *pathname)
{
  FAR struct inode *inode;
  const char       *relpath = NULL;
  int               errcode;
  int               ret;

  /* Get an inode for this file */

  inode = inode_find(pathname, &relpath);
  if (!inode)
    {
      /* There is no inode that includes in this path */

      errcode = ENOENT;
      goto errout;
    }

#ifndef CONFIG_DISABLE_MOUNTPOINT
  /* Check if the inode is a valid mountpoint. */

  if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops)
    {
      /* Perform the unlink operation using the relative path at the
       * mountpoint.
       */

      if (inode->u.i_mops->unlink)
        {
          ret = inode->u.i_mops->unlink(inode, relpath);
          if (ret < 0)
            {
              errcode = -ret;
              goto errout_with_inode;
            }
        }
      else
        {
          errcode = ENOSYS;
          goto errout_with_inode;
        }
    }
  else
#endif

#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
  /* If this is a "dangling" pseudo-file node (i.e., it has operations) then rm
   * should remove the node.
   */

  if (!INODE_IS_SPECIAL(inode) && inode->u.i_ops)
    {
      /* If this is a pseudo-file node (i.e., it has no operations)
       * then rmdir should remove the node.
       */

      if (inode->u.i_ops)
        {
          inode_semtake();

          /* Refuse to unlink the inode if it has children.  I.e., if it is
           * functioning as a directory and the directory is not empty.
           */

          if (inode->i_child != NULL)
            {
              errcode = ENOTEMPTY;
              inode_semgive();
              goto errout_with_inode;
            }

          /* Remove the old inode.  Because we hold a reference count on the
           * inode, it will not be deleted now.  It will be deleted when all
           * of the references to to the inode have been released (perhaps
           * when inode_release() is called below).  inode_remove() will
           * return -EBUSY to indicate that the inode was not deleted now.
           */

          ret = inode_remove(pathname);
          inode_semgive();

          if (ret < 0 && ret != -EBUSY)
            {
              errcode = -ret;
              goto errout_with_inode;
            }
        }
      else
        {
          errcode = EISDIR;
          goto errout_with_inode;
        }
    }
  else
#endif
    {
      errcode = ENXIO;
      goto errout_with_inode;
    }

  /* Successfully unlinked */

  inode_release(inode);
  return OK;

 errout_with_inode:
  inode_release(inode);
 errout:
  set_errno(errcode);
  return ERROR;
}
Beispiel #26
0
int files_dup(FAR struct file *filep1, FAR struct file *filep2)
{
  FAR struct filelist *list;
  FAR struct inode *inode;
  int err;
  int ret;

  if (!filep1 || !filep1->f_inode || !filep2)
    {
      err = EBADF;
      goto errout;
    }

  list = sched_getfiles();
  DEBUGASSERT(list);

  _files_semtake(list);

  /* If there is already an inode contained in the new file structure,
   * close the file and release the inode.
   */

  ret = _files_close(filep2);
  if (ret < 0)
    {
      /* An error occurred while closing the driver */

      goto errout_with_ret;
    }

  /* Increment the reference count on the contained inode */

  inode = filep1->f_inode;
  inode_addref(inode);

  /* Then clone the file structure */

  filep2->f_oflags = filep1->f_oflags;
  filep2->f_pos    = filep1->f_pos;
  filep2->f_inode  = inode;

  /* Call the open method on the file, driver, mountpoint so that it
   * can maintain the correct open counts.
   */

  if (inode->u.i_ops && inode->u.i_ops->open)
    {
#ifndef CONFIG_DISABLE_MOUNTPOINT
      if (INODE_IS_MOUNTPT(inode))
        {
         /* Dup the open file on the in the new file structure */

          ret = inode->u.i_mops->dup(filep1, filep2);
        }
      else
#endif
        {
          /* (Re-)open the pseudo file or device driver */

          ret = inode->u.i_ops->open(filep2);
        }

      /* Handle open failures */

      if (ret < 0)
        {
          goto errout_with_inode;
        }
    }

  _files_semgive(list);
  return OK;

/* Handler various error conditions */

errout_with_inode:
  inode_release(filep2->f_inode);
  filep2->f_oflags = 0;
  filep2->f_pos    = 0;
  filep2->f_inode  = NULL;

errout_with_ret:
  err              = -ret;
  _files_semgive(list);

errout:
  set_errno(err);
  return ERROR;
}