FS: directory operations will now work on empty directory nodes in the pseudo-filesystem
This commit is contained in:
parent
6bae54fe35
commit
66a0cfe88f
@ -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).
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user