FS: directory operations will now work on empty directory nodes in the pseudo-filesystem

This commit is contained in:
Gregory Nutt 2014-02-19 09:21:38 -06:00
parent 6bae54fe35
commit 66a0cfe88f
7 changed files with 159 additions and 69 deletions

View File

@ -6607,4 +6607,7 @@
kconfig-frontends tools by Alan Carvalho de Assis (2014-2-18).
* configs/mbed: All mbed configurations have been converted to use
the kconfig-frontends tools (unverified) (2014-2-18).
* fs/fs_opendir.c, fs_readdir.c, et al: Modified so that errors
will not be reported if you attempt to list a empty pseudo-directory
(2014-2-18).

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/fs_closedir.c
*
* Copyright (C) 2007-2009, 2011, 2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011, 2013-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -81,58 +81,69 @@ int closedir(FAR DIR *dirp)
#endif
int ret;
if (!idir || !idir->fd_root)
/* Verify that we were provided with a valid directory structure */
if (!idir)
{
ret = EBADF;
goto errout;
}
/* This is the 'root' inode of the directory. This means different
* things wih different filesystems.
/* 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 childre.
*/
if (idir->fd_root)
{
/* This is the 'root' inode of the directory. This means different
* things wih different filesystems.
*/
#ifndef CONFIG_DISABLE_MOUNTPOINT
inode = idir->fd_root;
inode = idir->fd_root;
/* The way that we handle the close operation depends on what kind of root
* inode we have open.
*/
if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSEUDONODE(idir->fd_flags))
{
/* The node is a file system mointpoint. Verify that the mountpoint
* supports the closedir() method (not an error if it does not)
/* The way that we handle the close operation depends on what kind of
* root inode we have open.
*/
if (inode->u.i_mops && inode->u.i_mops->closedir)
if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSEUDONODE(idir->fd_flags))
{
/* Perform the closedir() operation */
/* The node is a file system mointpoint. Verify that the
* mountpoint supports the closedir() method (not an error if it
* does not)
*/
ret = inode->u.i_mops->closedir(inode, idir);
if (ret < 0)
if (inode->u.i_mops && inode->u.i_mops->closedir)
{
ret = -ret;
goto errout_with_inode;
/* Perform the closedir() operation */
ret = inode->u.i_mops->closedir(inode, idir);
if (ret < 0)
{
ret = -ret;
goto errout_with_inode;
}
}
}
}
else
else
#endif
{
/* The node is part of the root pseudo file system, release
* our contained reference to the 'next' inode.
*/
if (idir->u.pseudo.fd_next)
{
inode_release(idir->u.pseudo.fd_next);
/* The node is part of the root pseudo file system, release
* our contained reference to the 'next' inode.
*/
if (idir->u.pseudo.fd_next)
{
inode_release(idir->u.pseudo.fd_next);
}
}
/* Release our references on the contained 'root' inode */
inode_release(idir->fd_root);
}
/* Release our references on the contained 'root' inode */
inode_release(idir->fd_root);
/* Then release the container */
kufree(idir);

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/fs_opendir.c
*
* Copyright (C) 2007-2009, 2011, 2013 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011, 2013-2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -89,8 +89,8 @@ static inline int open_mountpoint(FAR struct inode *inode,
return ENOSYS;
}
/* Take reference to the mountpoint inode (fd_root). Note that we do
* not use inode_addref() because we already hold the tree semaphore.
/* Take reference to the mountpoint inode. Note that we do not use
* inode_addref() because we already hold the tree semaphore.
*/
inode->i_crefs++;
@ -132,7 +132,7 @@ static inline int open_mountpoint(FAR struct inode *inode,
* dir -- the dirent structure to be initialized
*
* Return:
* On success, OK is returned; Otherwise, a positive errno is returned.
* None
*
****************************************************************************/
@ -144,7 +144,8 @@ static void open_pseudodir(FAR struct inode *inode, FAR struct fs_dirent_s *dir)
* semaphore and that would result in deadlock.
*/
inode->i_crefs += 2;
inode->i_crefs += 2;
dir->fd_root = inode; /* Save the inode where we start */
dir->u.pseudo.fd_next = inode; /* This is the next node to use for readdir() */
/* Flag the inode as belonging to the pseudo-filesystem */
@ -154,6 +155,43 @@ static void open_pseudodir(FAR struct inode *inode, FAR struct fs_dirent_s *dir)
#endif
}
/****************************************************************************
* Name: open_emptydir
*
* Description:
* Handle the case where the inode to be opened is an empty, directory node
* within the top-level pseudo-file system. That is, it has no operations
* and, therefore, it must be a directory node. But is has no children
* to be enumerated either.
*
* Inputs:
* dir -- the dirent structure to be initialized
*
* Return:
* None
*
****************************************************************************/
static inline void open_emptydir(FAR struct fs_dirent_s *dir)
{
/* We have a valid, but empty pseudo-filesystem node. fd_next is NULL
* meaning that we are already at the end of the list of its children.
* fd_root is NULL so that if the directory is rewound, it will still be
* at the end of the list.
*/
#if 0 /* Already nullified by kuzalloc */
dir->fd_root = NULL; /* Save the inode where we start */
dir->u.pseudo.fd_next = NULL; /* We are at the end of the list */
#endif
/* Flag the inode as belonging to the pseudo-filesystem */
#ifndef CONFIG_DISABLE_MOUNTPOINT
DIRENT_SETPSEUDONODE(dir->fd_flags);
#endif
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -189,7 +227,7 @@ FAR DIR *opendir(FAR const char *path)
FAR struct inode *inode = NULL;
FAR struct fs_dirent_s *dir;
FAR const char *relpath;
bool bisroot = false;
bool isroot = false;
int ret;
/* If we are given 'nothing' then we will interpret this as
@ -200,7 +238,7 @@ FAR DIR *opendir(FAR const char *path)
if (!path || *path == 0 || strcmp(path, "/") == 0)
{
inode = root_inode;
bisroot = true;
isroot = true;
relpath = NULL;
}
else
@ -246,14 +284,13 @@ FAR DIR *opendir(FAR const char *path)
* inode or a file system mountpoint.
*/
dir->fd_root = inode; /* Save the inode where we start */
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 (bisroot)
if (isroot)
{
/* Whatever payload the root inode carries, the root inode is always
* a directory inode in the pseudo-file system
@ -263,13 +300,17 @@ FAR DIR *opendir(FAR const char *path)
}
/* Is this a node in the pseudo filesystem? Or a mountpoint? If the node
* is the root (bisroot == TRUE), then this is a special case.
* 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 mointpoint. */
/* 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)
@ -280,21 +321,31 @@ FAR DIR *opendir(FAR const char *path)
#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.
/* 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.
*/
inode = inode->i_child;
if (!inode)
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;
}
/* It looks we have a valid pseudo-filesystem directory node. */
open_pseudodir(inode, dir);
}
inode_semgive();

View File

@ -84,11 +84,11 @@ static inline int readpseudodir(struct fs_dirent_s *idir)
if (idir->u.pseudo.fd_next->u.i_ops)
{
#ifndef CONFIG_DISABLE_MOUNTPOINT
if (INODE_IS_BLOCK(idir->u.pseudo.fd_next))
if (INODE_IS_BLOCK(idir->u.pseudo.fd_next))
{
idir->fd_dir.d_type |= DTYPE_BLK;
}
if (INODE_IS_MOUNTPT(idir->u.pseudo.fd_next))
if (INODE_IS_MOUNTPT(idir->u.pseudo.fd_next))
{
idir->fd_dir.d_type |= DTYPE_DIRECTORY;
}
@ -99,8 +99,9 @@ static inline int readpseudodir(struct fs_dirent_s *idir)
}
}
/* If the node has child node(s), then we will say that it
* is a directory. NOTE: that the node can be both!
/* If the node has child node(s) or no operations, then we will say that
* it is a directory rather than a special file. NOTE: that the node can
* be both!
*/
if (idir->u.pseudo.fd_next->i_child || !idir->u.pseudo.fd_next->u.i_ops)
@ -160,25 +161,38 @@ static inline int readpseudodir(struct fs_dirent_s *idir)
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 */
/* Verify that we were provided with a valid directory structure */
if (!idir || !idir->fd_root)
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
inode = idir->fd_root;
if (INODE_IS_MOUNTPT(inode) && !DIRENT_ISPSEUDONODE(idir->fd_flags))
{
/* The node is a file system mointpoint. Verify that the mountpoint
@ -188,7 +202,7 @@ FAR struct dirent *readdir(DIR *dirp)
if (!inode->u.i_mops || !inode->u.i_mops->readdir)
{
ret = EACCES;
goto errout;
goto errout;
}
/* Perform the readdir() operation */
@ -205,7 +219,7 @@ FAR struct dirent *readdir(DIR *dirp)
/* ret < 0 is an error. Special case: ret = -ENOENT is end of file */
if ( ret < 0)
if (ret < 0)
{
if (ret == -ENOENT)
{
@ -215,6 +229,7 @@ FAR struct dirent *readdir(DIR *dirp)
{
ret = -ret;
}
goto errout;
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/fs_rewinddir.c
*
* Copyright (C) 2007-2009, 2011 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2011, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -109,7 +109,12 @@ void rewinddir(FAR DIR *dirp)
struct inode *inode;
#endif
/* Sanity checks */
/* 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)
{

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/fs_rmdir.c
*
* Copyright (C) 2007-2009 Gregory Nutt. All rights reserved.
* Copyright (C) 2007-2009, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -111,7 +111,7 @@ int rmdir(FAR const char *pathname)
}
}
else
{
{
ret = ENOSYS;
goto errout_with_inode;
}

View File

@ -1,7 +1,7 @@
/****************************************************************************
* fs/fs_seekdir.c
*
* Copyright (C) 2007, 2008, 2011 Gregory Nutt. All rights reserved.
* Copyright (C) 2007, 2008, 2011, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -202,7 +202,12 @@ void seekdir(FAR DIR *dirp, off_t offset)
{
struct fs_dirent_s *idir = (struct fs_dirent_s *)dirp;
/* Sanity checks */
/* 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)
{