diff --git a/ChangeLog b/ChangeLog index 9fb44c59ea..69437b8873 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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). diff --git a/fs/fs_closedir.c b/fs/fs_closedir.c index 6aeed03a5a..f6b6edcf3d 100644 --- a/fs/fs_closedir.c +++ b/fs/fs_closedir.c @@ -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 * * 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); diff --git a/fs/fs_opendir.c b/fs/fs_opendir.c index c1f44a9d13..46421c37ef 100644 --- a/fs/fs_opendir.c +++ b/fs/fs_opendir.c @@ -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 * * 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(); diff --git a/fs/fs_readdir.c b/fs/fs_readdir.c index f5b2663927..11e23d9b17 100644 --- a/fs/fs_readdir.c +++ b/fs/fs_readdir.c @@ -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; } diff --git a/fs/fs_rewinddir.c b/fs/fs_rewinddir.c index c22c15f181..879b66363d 100644 --- a/fs/fs_rewinddir.c +++ b/fs/fs_rewinddir.c @@ -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 * * 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) { diff --git a/fs/fs_rmdir.c b/fs/fs_rmdir.c index 6c64de5cf2..317d7cc42e 100644 --- a/fs/fs_rmdir.c +++ b/fs/fs_rmdir.c @@ -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 * * 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; } diff --git a/fs/fs_seekdir.c b/fs/fs_seekdir.c index 781d35f27e..c49acef575 100644 --- a/fs/fs_seekdir.c +++ b/fs/fs_seekdir.c @@ -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 * * 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) {